740a2563dd9ed3261e631d2bee0eb7cd62a5647a
[yaffs2.git] / yaffs_guts.c
1
2 /*
3  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
6  *   for Toby Churchill Ltd and Brightstar Engineering
7  *
8  * Created by Charles Manning <charles@aleph1.co.uk>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  */
15  //yaffs_guts.c
16
17 const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.5 2005-03-16 04:00:36 charles Exp $";
18
19 #include "yportenv.h"
20
21 #include "yaffsinterface.h"
22 #include "yaffs_guts.h"
23
24 #include "yaffs_tagscompat.h"
25
26 #ifdef CONFIG_YAFFS_WINCE
27 void yfsd_LockYAFFS(BOOL fsLockOnly);
28 void yfsd_UnlockYAFFS(BOOL fsLockOnly);
29 #endif
30
31 #define YAFFS_PASSIVE_GC_CHUNKS 2
32
33 #if 0
34 // Use Steven Hill's ECC struff instead
35 // External functions for ECC on data
36 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
37 int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
38 #define yaffs_ECCCalculate(data,ecc) nand_calculate_ecc(data,ecc)
39 #define yaffs_ECCCorrect(data,read_ecc,calc_ecc) nand_correct_ecc(data,read_ecc,calc_ecc)
40 #else
41 #include "yaffs_ecc.h"
42 #endif
43
44 // countBits is a quick way of counting the number of bits in a byte.
45 // ie. countBits[n] holds the number of 1 bits in a byte with the value n.
46
47 static const char yaffs_countBitsTable[256] =
48 {
49 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
50 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
51 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
52 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
53 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
54 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
55 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
56 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
57 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
58 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
59 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
60 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
61 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
62 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
63 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
64 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
65 };
66
67 static int yaffs_CountBits(__u8 x)
68 {
69         int retVal;
70         retVal = yaffs_countBitsTable[x];
71         return retVal;
72 }
73
74
75 #if 0
76 // Stuff using yea olde tags
77 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
78 static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
79
80 static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted);
81 static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted);
82 #else
83 #endif
84
85 // NAND access
86
87
88 static Y_INLINE int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags);
89 static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *data, yaffs_ExtendedTags *tags);
90 static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
91 static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state,unsigned *sequenceNumber);
92 // Local prototypes
93 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve);
94 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
95 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
96
97 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
98 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
99 static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink);
100 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
101 static int yaffs_CheckStructures(void);
102 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
103 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
104
105 static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev,int blockNo);
106
107 static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo);
108 static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
109
110
111 static int  yaffs_ValidateTags(yaffs_ExtendedTags *tags);
112
113 // Robustification (if it ever comes about...)
114 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);
115 static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
116 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
117 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
118 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND,  const yaffs_ExtendedTags *tags);
119
120 static int  yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);
121
122 static int yaffs_UnlinkWorker(yaffs_Object *obj);
123 static void yaffs_DestroyObject(yaffs_Object *obj);
124
125 #if 0
126 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize);
127 #endif
128
129 static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject);
130
131
132 loff_t yaffs_GetFileSize(yaffs_Object *obj);
133
134
135 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
136
137 #ifdef YAFFS_PARANOID
138 static int yaffs_CheckFileSanity(yaffs_Object *in);
139 #else
140 #define yaffs_CheckFileSanity(in)
141 #endif
142
143 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
144 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
145
146 static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags)
147 {
148         if(dev->readChunkWithTagsFromNAND)
149                 return dev->readChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
150         else
151                 return yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
152 }
153
154 static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_ExtendedTags *tags)
155 {
156         if(tags)
157         {
158                 tags->sequenceNumber = dev->sequenceNumber;
159                 tags->chunkUsed = 1;
160                 if(!yaffs_ValidateTags(tags))
161                 {
162                         T(YAFFS_TRACE_ERROR,(TSTR("Writing uninitialised tags" TENDSTR)));
163                         YBUG();
164                 }
165                 T(YAFFS_TRACE_WRITE,(TSTR("Writing chunk %d tags %d %d"TENDSTR),chunkInNAND,tags->objectId,tags->chunkId));
166         }
167         else
168         {
169                         T(YAFFS_TRACE_ERROR,(TSTR("Writing with no tags" TENDSTR)));
170                         YBUG();
171         }
172
173         if(dev->writeChunkWithTagsToNAND)
174                 return dev->writeChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
175         else
176                 return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
177 }
178
179 static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
180 {
181         if(dev->markNANDBlockBad)
182                 return dev->markNANDBlockBad(dev,blockNo);
183         else
184                 return yaffs_TagsCompatabilityMarkNANDBlockBad(dev,blockNo);
185 }
186 static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state, unsigned *sequenceNumber)
187 {
188         if(dev->queryNANDBlock)
189                 return dev->queryNANDBlock(dev,blockNo,state,sequenceNumber);
190         else
191                 return yaffs_TagsCompatabilityQueryNANDBlock(dev,blockNo,state,sequenceNumber);
192 }
193
194 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
195 {
196         int result;
197
198         dev->nBlockErasures++;
199         result = dev->eraseBlockInNAND(dev,blockInNAND);
200
201         if(!result)result = dev->eraseBlockInNAND(dev,blockInNAND); // If at first we don't succeed, try again *once*.
202         return result;
203 }
204
205 static int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
206 {
207         return dev->initialiseNAND(dev);
208 }
209
210
211
212
213 // Temporary buffer manipulations
214
215 static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo)
216 {
217         int i,j;
218         for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
219         {
220                 if(dev->tempBuffer[i].line == 0)
221                 {
222                         dev->tempBuffer[i].line = lineNo;
223                         if((i+1) > dev->maxTemp)
224                         {
225                                 dev->maxTemp = i + 1;
226                                 for(j = 0; j <= i; j++)
227                                         dev->tempBuffer[j].maxLine = dev->tempBuffer[j].line;
228                         }       
229                         
230                         return dev->tempBuffer[i].buffer;
231                 }
232         }
233
234         T(YAFFS_TRACE_BUFFERS,(TSTR("Out of temp buffers at line %d, other held by lines:"),lineNo));
235         for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
236         {
237                 T(YAFFS_TRACE_BUFFERS,(TSTR(" %d "),dev->tempBuffer[i].line));
238         }
239         T(YAFFS_TRACE_BUFFERS,(TSTR(" "TENDSTR)));
240         
241         dev->unmanagedTempAllocations++;
242         // Get an unmanaged one
243         return YMALLOC(dev->nBytesPerChunk);    
244         
245         
246 }
247
248 static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo)
249 {
250         int i;
251         for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
252         {
253                 if(dev->tempBuffer[i].buffer == buffer)
254                 {
255                         dev->tempBuffer[i].line = 0;
256                         return;
257                 }
258         }
259         
260         if(buffer)
261         {
262                 // assume it is an unmanaged one.
263                 T(YAFFS_TRACE_BUFFERS,(TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),lineNo));
264                 YFREE(buffer);
265                 dev->unmanagedTempDeallocations++;
266         }
267
268 }
269
270
271 // Chunk bitmap manipulations
272
273 static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
274 {
275         if(blk < dev->startBlock || blk > dev->endBlock)
276         {
277                 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),blk));
278                 YBUG();
279         }
280         return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->startBlock));
281 }
282
283 static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev,int blk)
284 {
285         __u8 *blkBits = yaffs_BlockBits(dev,blk);
286
287          memset(blkBits,0,dev->chunkBitmapStride);
288 }
289
290 static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev,int blk,int chunk)
291 {
292         __u8 *blkBits = yaffs_BlockBits(dev,blk);
293         
294         blkBits[chunk/8] &=  ~ (1<<(chunk & 7));
295 }
296
297 static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev,int blk,int chunk)
298 {
299         __u8 *blkBits = yaffs_BlockBits(dev,blk);
300
301         blkBits[chunk/8] |=   (1<<(chunk & 7));
302 }
303
304 static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev,int blk,int chunk)
305 {
306         __u8 *blkBits = yaffs_BlockBits(dev,blk);
307         return (blkBits[chunk/8] &  (1<<(chunk & 7))) ? 1 :0;
308 }
309
310 static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk)
311 {
312         __u8 *blkBits = yaffs_BlockBits(dev,blk);
313         int i;
314         for(i = 0; i < dev->chunkBitmapStride; i++)
315         {
316                 if(*blkBits) return 1;
317                 blkBits++;
318         }
319         return 0;
320 }
321
322 #if 0
323 // Function to manipulate block info
324 static  Y_INLINE yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk)
325 {
326         if(blk < dev->startBlock || blk > dev->endBlock)
327         {
328                 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),blk));
329                 YBUG();
330         }
331         return &dev->blockInfo[blk - dev->startBlock];
332 }
333 #endif
334
335
336 static  Y_INLINE int yaffs_HashFunction(int n)
337 {
338         return (n % YAFFS_NOBJECT_BUCKETS);
339 }
340
341
342 yaffs_Object *yaffs_Root(yaffs_Device *dev)
343 {
344         return dev->rootDir;
345 }
346
347 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
348 {
349         return dev->lostNFoundDir;
350 }
351
352 #if 0
353 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
354 {
355         if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock)
356         {
357                 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND));
358                 return YAFFS_FAIL;
359         }
360
361         dev->nPageWrites++;
362         return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
363 }
364
365
366
367 static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
368                                                         int chunkInNAND, 
369                                                         __u8 *data, 
370                                                         yaffs_Spare *spare, 
371                                                         int doErrorCorrection)
372 {
373         int retVal;
374         yaffs_Spare localSpare;
375
376         dev->nPageReads++;
377         
378         
379
380         
381         if(!spare && data)
382         {
383                 // If we don't have a real spare, then we use a local one.
384                 // Need this for the calculation of the ecc
385                 spare = &localSpare;
386         }
387         
388
389         if(!dev->useNANDECC)
390         {
391                 retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
392                 if(data && doErrorCorrection)
393                 {
394                         // Do ECC correction
395                         //Todo handle any errors
396                 int eccResult1,eccResult2;
397                 __u8 calcEcc[3];
398                 
399                         yaffs_ECCCalculate(data,calcEcc);
400                         eccResult1 = yaffs_ECCCorrect (data,spare->ecc1, calcEcc);
401                         yaffs_ECCCalculate(&data[256],calcEcc);
402                         eccResult2 = yaffs_ECCCorrect(&data[256],spare->ecc2, calcEcc);
403
404                         if(eccResult1>0)
405                         {
406                                 T(YAFFS_TRACE_ERROR, (TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
407                                 dev->eccFixed++;
408                         }
409                         else if(eccResult1<0)
410                         {
411                                 T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
412                                 dev->eccUnfixed++;
413                         }
414
415                         if(eccResult2>0)
416                         {
417                                 T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
418                                 dev->eccFixed++;
419                         }
420                         else if(eccResult2<0)
421                         {
422                                 T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
423                                 dev->eccUnfixed++;
424                         }
425
426                         if(eccResult1 || eccResult2)
427                         {
428                                 // Hoosterman, we had a data problem on this page
429                                 yaffs_HandleReadDataError(dev,chunkInNAND);
430                         }
431                 }
432         }
433         else
434         {
435         // Must allocate enough memory for spare+2*sizeof(int) for ecc results from device.
436         struct yaffs_NANDSpare nspare;
437                 retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare);
438                 memcpy (spare, &nspare, sizeof(yaffs_Spare));
439                 if(data && doErrorCorrection)
440                 {
441                         if(nspare.eccres1>0)
442                         {
443                                 T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
444                         }
445                         else if(nspare.eccres1<0)
446                         {
447                                 T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
448                         }
449
450                         if(nspare.eccres2>0)
451                         {
452                                 T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
453                         }
454                         else if(nspare.eccres2<0)
455                         {
456                                 T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
457                         }
458
459                         if(nspare.eccres1 || nspare.eccres2)
460                         {
461                                 // Hoosterman, we had a data problem on this page
462                                 yaffs_HandleReadDataError(dev,chunkInNAND);
463                         }
464
465                 }
466         }
467         return retVal;
468 }
469
470 #endif
471
472
473
474 int yaffs_CheckFF(__u8 *buffer,int nBytes)
475 {
476         //Horrible, slow implementation
477         while(nBytes--)
478         {
479                 if(*buffer != 0xFF) return 0;
480                 buffer++;
481         }
482         return 1;
483 }
484
485 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
486 {
487
488         int retval = YAFFS_OK;
489         __u8 *data = yaffs_GetTempBuffer(dev,__LINE__);
490         yaffs_ExtendedTags tags;
491
492 // NCB          dev->readChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
493         yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
494         
495         if(!yaffs_CheckFF(data,dev->nBytesPerChunk) || tags.chunkUsed)
496         {
497                 T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not erased" TENDSTR),chunkInNAND));
498                 retval = YAFFS_FAIL;
499         }
500
501         yaffs_ReleaseTempBuffer(dev,data,__LINE__);
502         
503         return retval;
504         
505 }
506
507
508
509 #if 1
510 static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_ExtendedTags *tags,int useReserve)
511 {
512         int chunk;
513         
514         int writeOk = 1;
515         int attempts = 0;
516         
517
518         
519         do{
520                 chunk = yaffs_AllocateChunk(dev,useReserve);
521         
522                 if(chunk >= 0)
523                 {
524
525                         // First check this chunk is erased...
526 #ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
527                         writeOk = yaffs_CheckChunkErased(dev,chunk);
528 #endif          
529                         if(!writeOk)
530                         {
531                                 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));
532                         }
533                         else
534                         {
535                                 writeOk =  yaffs_WriteChunkWithTagsToNAND(dev,chunk,data,tags);
536                         }
537                         attempts++;
538
539                         if(writeOk)
540                         {
541                                 // Copy the data into the robustification buffer.
542                                 // NB We do this at the end to prevent duplicates in the case of a write error.
543                                 //Todo
544                                 yaffs_HandleWriteChunkOk(dev,chunk,data,tags);
545                         }
546                         else
547                         {
548                                 yaffs_HandleWriteChunkError(dev,chunk);
549                         }
550                 }
551                 
552         } while(chunk >= 0 && ! writeOk);
553         
554         if(attempts > 1)
555         {
556                 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));
557                 dev->nRetriedWrites+= (attempts - 1);   
558         }
559         
560
561         
562         return chunk;
563 }
564 #endif
565
566
567 ///
568 // Functions for robustisizing
569 //
570 //
571
572 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
573 {
574         
575         yaffs_MarkBlockBad(dev,blockInNAND);
576         
577         yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
578
579         dev->nRetiredBlocks++;
580 }
581
582
583
584 static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
585 {
586         dev->doingBufferedBlockRewrite = 1;
587         //
588         //      Remove erased chunks
589         //  Rewrite existing chunks to a new block
590         //      Set current write block to the new block
591         
592         dev->doingBufferedBlockRewrite = 0;
593         
594         return 1;
595 }
596
597
598 static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
599 {
600         int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
601
602         // Mark the block for retirement
603         yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
604         T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));
605
606
607         //TODO  
608         // Just do a garbage collection on the affected block then retire the block
609         // NB recursion
610 }
611
612
613 static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
614 {
615 }
616
617 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
618 {
619 }
620
621 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_ExtendedTags *tags)
622 {
623 }
624
625 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
626 {
627         int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
628
629         // Mark the block for retirement
630         yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
631         // Delete the chunk
632         yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
633 }
634
635
636
637 #if 0
638 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize)
639 {
640
641
642         if( memcmp(d0,d1,dataSize) != 0 ||
643                 s0->tagByte0 != s1->tagByte0 ||
644                 s0->tagByte1 != s1->tagByte1 ||
645                 s0->tagByte2 != s1->tagByte2 ||
646                 s0->tagByte3 != s1->tagByte3 ||
647                 s0->tagByte4 != s1->tagByte4 ||
648                 s0->tagByte5 != s1->tagByte5 ||
649                 s0->tagByte6 != s1->tagByte6 ||
650                 s0->tagByte7 != s1->tagByte7 ||
651                 s0->ecc1[0]  != s1->ecc1[0]  ||
652                 s0->ecc1[1]  != s1->ecc1[1]  ||
653                 s0->ecc1[2]  != s1->ecc1[2]  ||
654                 s0->ecc2[0]  != s1->ecc2[0]  ||
655                 s0->ecc2[1]  != s1->ecc2[1]  ||
656                 s0->ecc2[2]  != s1->ecc2[2] )
657                 {
658                         return 0;
659                 }
660         
661         return 1;
662 }
663 #endif
664
665
666 ///////////////////////// Object management //////////////////
667 // List of spare objects
668 // The list is hooked together using the first pointer
669 // in the object
670
671 // static yaffs_Object *yaffs_freeObjects = NULL;
672
673 // static int yaffs_nFreeObjects;
674
675 // static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
676
677 // static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
678
679
680 static __u16 yaffs_CalcNameSum(const YCHAR *name)
681 {
682         __u16 sum = 0;
683         __u16 i = 1;
684         
685         YUCHAR *bname = (YUCHAR *)name;
686         if(bname)
687         {
688                 while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH))
689                 {
690
691 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
692                         sum += yaffs_toupper(*bname) * i;
693 #else
694                         sum += (*bname) * i;
695 #endif
696                         i++;
697                         bname++;
698                 }
699         }
700         return sum;
701 }
702
703 void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
704 {
705 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
706                                         if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
707                                         {
708                                                 yaffs_strcpy(obj->shortName,name);
709                                         }
710                                         else
711                                         {
712                                                 obj->shortName[0]=_Y('\0');
713                                         }
714 #endif
715                                         obj->sum = yaffs_CalcNameSum(name);
716 }
717
718 #if 0
719 void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
720 {
721         yaffs_ECCCalculate(data , spare->ecc1);
722         yaffs_ECCCalculate(&data[256] , spare->ecc2);
723 }
724 #endif
725
726
727 ///////////////////////// TNODES ///////////////////////
728
729 // List of spare tnodes
730 // The list is hooked together using the first pointer
731 // in the tnode.
732
733 //static yaffs_Tnode *yaffs_freeTnodes = NULL;
734
735 // static int yaffs_nFreeTnodes;
736
737 //static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
738
739
740
741 // yaffs_CreateTnodes creates a bunch more tnodes and
742 // adds them to the tnode free list.
743 // Don't use this function directly
744
745 static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
746 {
747     int i;
748     yaffs_Tnode *newTnodes;
749     yaffs_TnodeList *tnl;
750     
751     if(nTnodes < 1) return YAFFS_OK;
752    
753         // make these things
754         
755     newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
756    
757     if (!newTnodes)
758     {
759                 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not allocate Tnodes"TENDSTR)));
760                 return YAFFS_FAIL;
761     }
762     
763     // Hook them into the free list
764     for(i = 0; i < nTnodes - 1; i++)
765     {
766         newTnodes[i].internal[0] = &newTnodes[i+1];
767 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
768         newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = 1;
769 #endif
770     }
771         
772         newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
773 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
774         newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = 1;
775 #endif
776         dev->freeTnodes = newTnodes;
777         dev->nFreeTnodes+= nTnodes;
778         dev->nTnodesCreated += nTnodes;
779
780         // Now add this bunch of tnodes to a list for freeing up.
781         // NB If we can't add this to the management list it isn't fatal
782         // but it just means we can't free this bunch of tnodes later.
783         tnl = YMALLOC(sizeof(yaffs_TnodeList));
784         if(!tnl)
785         {
786                 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not add tnodes to management list" TENDSTR)));
787                 
788         }
789         else
790         {
791                 tnl->tnodes = newTnodes;
792                 tnl->next = dev->allocatedTnodeList;
793                 dev->allocatedTnodeList = tnl;
794         }
795
796
797         T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Tnodes added" TENDSTR)));
798
799
800         return YAFFS_OK;
801 }
802
803
804 // GetTnode gets us a clean tnode. Tries to make allocate more if we run out
805 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
806 {
807         yaffs_Tnode *tn = NULL;
808         
809         // If there are none left make more
810         if(!dev->freeTnodes)
811         {
812                 yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
813         }
814         
815         if(dev->freeTnodes)
816         {
817                 tn = dev->freeTnodes;
818 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
819         if(tn->internal[YAFFS_NTNODES_INTERNAL] != 1)
820                 {
821                         // Hoosterman, this thing looks like it isn't in the list
822                                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
823                 }
824 #endif
825                 dev->freeTnodes = dev->freeTnodes->internal[0];
826                 dev->nFreeTnodes--;
827                 // zero out
828                 memset(tn,0,sizeof(yaffs_Tnode));
829         }
830         
831
832         return tn;
833 }
834
835
836 // FreeTnode frees up a tnode and puts it back on the free list
837 static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
838 {
839         if(tn)
840         {
841 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
842         if(tn->internal[YAFFS_NTNODES_INTERNAL] != 0)
843                 {
844                         // Hoosterman, this thing looks like it is already in the list
845                                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
846                 }
847                 tn->internal[YAFFS_NTNODES_INTERNAL] = 1;
848 #endif
849                 tn->internal[0] = dev->freeTnodes;
850                 dev->freeTnodes = tn;
851                 dev->nFreeTnodes++;
852         }
853 }
854
855
856 static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
857 {
858         // Free the list of allocated tnodes
859         yaffs_TnodeList *tmp;
860                 
861         while(dev->allocatedTnodeList)
862         {
863                 tmp =  dev->allocatedTnodeList->next;
864
865                 YFREE(dev->allocatedTnodeList->tnodes);
866                 YFREE(dev->allocatedTnodeList);
867                 dev->allocatedTnodeList = tmp;
868                 
869         }
870         
871         dev->freeTnodes = NULL;
872         dev->nFreeTnodes = 0;
873 }
874
875 static void yaffs_InitialiseTnodes(yaffs_Device*dev)
876 {
877         dev->allocatedTnodeList = NULL;
878         dev->freeTnodes = NULL;
879         dev->nFreeTnodes = 0;
880         dev->nTnodesCreated = 0;
881
882 }
883
884 #if 0
885 void yaffs_TnodeTest(yaffs_Device *dev)
886 {
887
888         int i;
889         int j;
890         yaffs_Tnode *tn[1000];
891         
892         YINFO("Testing TNodes");
893         
894         for(j = 0; j < 50; j++)
895         {
896                 for(i = 0; i < 1000; i++)
897                 {
898                         tn[i] = yaffs_GetTnode(dev);
899                         if(!tn[i])
900                         {
901                                 YALERT("Getting tnode failed");
902                         }
903                 }
904                 for(i = 0; i < 1000; i+=3)
905                 {
906                         yaffs_FreeTnode(dev,tn[i]);
907                         tn[i] = NULL;
908                 }
909                 
910         }
911 }
912 #endif
913
914
915 ////////////////// END OF TNODE MANIPULATION ///////////////////////////
916
917 /////////////// Functions to manipulate the look-up tree (made up of tnodes)
918 // The look up tree is represented by the top tnode and the number of topLevel
919 // in the tree. 0 means only the level 0 tnode is in the tree.
920
921
922 // FindLevel0Tnode finds the level 0 tnode, if one exists.
923 // Used when reading.....
924 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure *fStruct, __u32 chunkId)
925 {
926         
927         yaffs_Tnode *tn = fStruct->top;
928         __u32 i;
929         int requiredTallness;   
930         int level = fStruct->topLevel;
931         
932         // Check sane level and chunk Id
933         if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
934         {
935 //              char str[50];
936 //              sprintf(str,"Bad level %d",level);
937 //              YALERT(str);
938                 return NULL;
939         }
940         
941         if(chunkId > YAFFS_MAX_CHUNK_ID)
942         {
943 //              char str[50];
944 //              sprintf(str,"Bad chunkId %d",chunkId);
945 //              YALERT(str);
946                 return NULL;
947         }
948
949         // First check we're tall enough (ie enough topLevel)
950         
951         i = chunkId >> (/*dev->chunkGroupBits  + */YAFFS_TNODES_LEVEL0_BITS);
952         requiredTallness = 0;
953         while(i)
954         {
955                 i >>= YAFFS_TNODES_INTERNAL_BITS;
956                 requiredTallness++;
957         }
958         
959         
960         if(requiredTallness > fStruct->topLevel)
961         {
962                 // Not tall enough, so we can't find it, return NULL.
963                 return NULL;
964         }
965                 
966         
967         // Traverse down to level 0
968         while (level > 0 && tn)
969         {
970             tn = tn->internal[(chunkId >>(/* dev->chunkGroupBits + */ YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
971                                YAFFS_TNODES_INTERNAL_MASK]; 
972                 level--;
973         
974         }
975         
976         return tn;              
977 }
978
979 // AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
980 // This happens in two steps:
981 //  1. If the tree isn't tall enough, then make it taller.
982 //  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
983 //
984 // Used when modifying the tree.
985 //
986 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
987 {
988         
989         yaffs_Tnode *tn; 
990         
991         int requiredTallness;
992         int i;
993         int l;
994         
995         __u32 x;
996                 
997         
998         //T((TSTR("AddOrFind topLevel=%d, chunk=%d"),fStruct->topLevel,chunkId));
999         
1000         // Check sane level and page Id
1001         if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
1002         {
1003 //              char str[50];
1004 //              sprintf(str,"Bad level %d",fStruct->topLevel);
1005 //              YALERT(str);
1006                 return NULL;
1007         }
1008         
1009         if(chunkId > YAFFS_MAX_CHUNK_ID)
1010         {
1011 //              char str[50];
1012 //              sprintf(str,"Bad chunkId %d",chunkId);
1013 //              YALERT(str);
1014                 return NULL;
1015         }
1016         
1017         // First check we're tall enough (ie enough topLevel)
1018         
1019         x = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
1020         requiredTallness = 0;
1021         while(x)
1022         {
1023                 x >>= YAFFS_TNODES_INTERNAL_BITS;
1024                 requiredTallness++;
1025         }
1026         
1027         //T((TSTR(" required=%d"),requiredTallness));
1028         
1029         
1030         if(requiredTallness > fStruct->topLevel)
1031         {
1032                 // Not tall enough,gotta make the tree taller
1033                 for(i = fStruct->topLevel; i < requiredTallness; i++)
1034                 {
1035                         //T((TSTR(" add new top")));
1036                         
1037                         tn = yaffs_GetTnode(dev);
1038                         
1039                         if(tn)
1040                         {
1041                                 tn->internal[0] = fStruct->top;
1042                                 fStruct->top = tn;
1043                         }
1044                         else
1045                         {
1046                                         T(YAFFS_TRACE_ERROR,(TSTR("yaffs: no more tnodes" TENDSTR)));
1047                         }
1048                 }
1049                 
1050                 fStruct->topLevel = requiredTallness;
1051         }
1052         
1053         
1054         // Traverse down to level 0, adding anything we need
1055         
1056         l = fStruct->topLevel;
1057         tn = fStruct->top;
1058         while (l > 0 && tn)
1059         {
1060                 x = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
1061                                YAFFS_TNODES_INTERNAL_MASK;
1062                                
1063                 //T((TSTR(" [%d:%d]"),l,i));
1064                 
1065             if(!tn->internal[x])
1066             {
1067                 //T((TSTR(" added")));
1068                 
1069                 tn->internal[x] = yaffs_GetTnode(dev);
1070             }
1071             
1072             tn =        tn->internal[x];
1073                 l--;
1074         
1075         }
1076         
1077         //TSTR(TENDSTR)));
1078         
1079         return tn;              
1080 }
1081
1082
1083 int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
1084 {
1085         int j;
1086         
1087                                         
1088         for(j = 0; theChunk && j < dev->chunkGroupSize; j++)
1089         {
1090                 if(yaffs_CheckChunkBit(dev,theChunk / dev->nChunksPerBlock,theChunk % dev->nChunksPerBlock))
1091                 {
1092                         yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL,tags);
1093                         if(yaffs_TagsMatch(tags,objectId,chunkInInode))
1094                         {
1095                                 // found it;
1096                                 return theChunk;
1097                                         
1098                         }
1099                 }
1100                 theChunk++;
1101         }
1102         return -1;
1103 }
1104
1105 // DeleteWorker scans backwards through the tnode tree and deletes all the
1106 // chunks and tnodes in the file
1107 // Returns 1 if the tree was deleted. Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
1108
1109 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
1110 {
1111         int i;
1112         int chunkInInode;
1113         int theChunk;
1114         yaffs_ExtendedTags tags;
1115         int foundChunk;
1116         yaffs_Device *dev = in->myDev;
1117
1118         int allDone = 1;
1119         
1120         
1121         if(tn)
1122         {
1123                 if(level > 0)
1124                 {
1125                 
1126                         for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
1127                         {
1128                             if(tn->internal[i])
1129                         {
1130                                         if(limit && (*limit) < 0)
1131                                         {
1132                                                 allDone = 0;
1133                                         }
1134                                         else
1135                                         {
1136                                                 allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,
1137                                                                                 (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);
1138                                         }
1139                                         if(allDone)
1140                                         {
1141                                                 yaffs_FreeTnode(dev,tn->internal[i]);
1142                                         tn->internal[i] = NULL;
1143                                         }
1144                             }
1145                     
1146                         }
1147                         return (allDone) ? 1 : 0;
1148                 }
1149                 else if(level == 0)
1150                 {
1151                         int hitLimit = 0;
1152                         
1153                         for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0 && !hitLimit; i--)
1154                         {
1155                             if(tn->level0[i])
1156                         {
1157                                         
1158                                         chunkInInode = (chunkOffset << YAFFS_TNODES_LEVEL0_BITS ) + i;
1159                                         
1160                                         theChunk =  tn->level0[i] << dev->chunkGroupBits;
1161                                         
1162                                         foundChunk = yaffs_FindChunkInGroup(dev,theChunk,&tags,in->objectId,chunkInInode);
1163                                         
1164                                         if(foundChunk > 0)
1165                                         {
1166                                                 yaffs_DeleteChunk(dev,foundChunk,1,__LINE__);
1167                                                 in->nDataChunks--;
1168                                                 if(limit)
1169                                                 { 
1170                                                         *limit = *limit-1;
1171                                                         if(*limit <= 0) 
1172                                                         { 
1173                                                                 hitLimit = 1;
1174                                                         }
1175                                                 }
1176                                         
1177                                         }
1178                                         
1179                                 tn->level0[i] = 0;
1180                             }
1181                     
1182                         }
1183                         return (i < 0) ? 1 : 0;
1184
1185                         
1186                 }
1187                 
1188         }
1189         
1190         return 1;
1191         
1192 }
1193
1194
1195 static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
1196 {
1197
1198         yaffs_BlockInfo *theBlock;                                      
1199         
1200         T(YAFFS_TRACE_DELETION,(TSTR("soft delete chunk %d" TENDSTR),chunk));
1201                                                 
1202         theBlock =      yaffs_GetBlockInfo(dev,  chunk/dev->nChunksPerBlock);
1203         if(theBlock)
1204         {
1205                 theBlock->softDeletions++;
1206         }
1207 }
1208
1209 // SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
1210 // All soft deleting does is increment the block's softdelete count and pulls the chunk out
1211 // of the tnode.
1212 // THus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
1213 //
1214 static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset)
1215 {
1216         int i;
1217         int theChunk;
1218         int allDone = 1;
1219         yaffs_Device *dev = in->myDev;
1220         
1221         
1222         if(tn)
1223         {
1224                 if(level > 0)
1225                 {
1226                 
1227                         for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
1228                         {
1229                             if(tn->internal[i])
1230                         {
1231                                                 allDone = yaffs_SoftDeleteWorker(in,tn->internal[i],level - 1,
1232                                                                                 (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i);
1233                                         if(allDone)
1234                                         {
1235                                                 yaffs_FreeTnode(dev,tn->internal[i]);
1236                                         tn->internal[i] = NULL;
1237                                         }
1238                                         else
1239                                         {
1240                                                 //Hoosterman... how could this happen.
1241                                         }                           
1242                                 }                   
1243                         }
1244                         return (allDone) ? 1 : 0;
1245                 }
1246                 else if(level == 0)
1247                 {
1248                         
1249                         for(i = YAFFS_NTNODES_LEVEL0 -1; i >=0; i--)
1250                         {
1251                             if(tn->level0[i])
1252                         {
1253                                         // Note this does not find the real chunk, only the chunk group.
1254                                         // We make an assumption that a chunk group is niot larger than a block.
1255                                         theChunk =  (tn->level0[i] << dev->chunkGroupBits);
1256                                         
1257                                         yaffs_SoftDeleteChunk(dev,theChunk);
1258                                 tn->level0[i] = 0;
1259                             }
1260                     
1261                         }
1262                         return 1;
1263                         
1264                 }
1265                 
1266         }
1267         
1268         return 1;
1269                 
1270 }
1271
1272
1273
1274 static void yaffs_SoftDeleteFile(yaffs_Object *obj)
1275 {
1276         if(obj->deleted &&
1277            obj->variantType == YAFFS_OBJECT_TYPE_FILE &&
1278            !obj->softDeleted)
1279         {
1280                 if(obj->nDataChunks <= 0)
1281                 {
1282                                 // Empty file with no duplicate object headers, just delete it immediately
1283                                 yaffs_FreeTnode(obj->myDev,obj->variant.fileVariant.top);
1284                                 obj->variant.fileVariant.top = NULL;
1285                                 T(YAFFS_TRACE_TRACING,(TSTR("yaffs: Deleting empty file %d" TENDSTR),obj->objectId));
1286                                 yaffs_DoGenericObjectDeletion(obj);     
1287                 }
1288                 else
1289                 {
1290                         yaffs_SoftDeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0);
1291                         obj->softDeleted = 1;
1292                 }
1293         }
1294 }
1295
1296
1297
1298
1299
1300 // Pruning removes any part of the file structure tree that is beyond the
1301 // bounds of the file (ie that does not point to chunks).
1302 //
1303 // A file should only get pruned when its size is reduced.
1304 //
1305 // Before pruning, the chunks must be pulled from the tree and the
1306 // level 0 tnode entries must be zeroed out.
1307 // Could also use this for file deletion, but that's probably better handled
1308 // by a special case.
1309
1310 // yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
1311
1312 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
1313 {
1314         int i;
1315         int hasData;
1316         
1317         if(tn)
1318         {
1319                 hasData = 0;
1320                 
1321                 for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
1322                 {
1323                     if(tn->internal[i] && level > 0)
1324                     {
1325                         tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
1326                     }
1327                     
1328                     if(tn->internal[i])
1329                     {
1330                         hasData++;
1331                         }
1332                 }
1333                 
1334                 if(hasData == 0 && del0)
1335                 {
1336                         // Free and return NULL
1337                         
1338                         yaffs_FreeTnode(dev,tn);
1339                         tn = NULL;
1340                 }
1341                 
1342         }
1343
1344         return tn;
1345         
1346 }
1347
1348 static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
1349 {
1350         int i;
1351         int hasData;
1352         int done = 0;
1353         yaffs_Tnode *tn;
1354         
1355         if(fStruct->topLevel > 0)
1356         {
1357                 fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
1358                 
1359                 // Now we have a tree with all the non-zero branches NULL but the height
1360                 // is the same as it was.
1361                 // Let's see if we can trim internal tnodes to shorten the tree.
1362                 // We can do this if only the 0th element in the tnode is in use 
1363                 // (ie all the non-zero are NULL)
1364                 
1365                 while(fStruct->topLevel && !done)
1366                 {
1367                         tn = fStruct->top;
1368                         
1369                         hasData = 0;
1370                         for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
1371                         {
1372                                 if(tn->internal[i])
1373                         {
1374                                 hasData++;
1375                                 }
1376                         }
1377                         
1378                         if(!hasData)
1379                         {
1380                                 fStruct->top = tn->internal[0];
1381                                 fStruct->topLevel--;
1382                                 yaffs_FreeTnode(dev,tn);
1383                         }
1384                         else
1385                         {
1386                                 done = 1;
1387                         }
1388                 }
1389         }
1390         
1391         return YAFFS_OK;
1392 }
1393
1394
1395
1396
1397
1398 /////////////////////// End of File Structure functions. /////////////////
1399
1400 // yaffs_CreateFreeObjects creates a bunch more objects and
1401 // adds them to the object free list.
1402 static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
1403 {
1404     int i;
1405     yaffs_Object *newObjects;
1406     yaffs_ObjectList *list;
1407     
1408     if(nObjects < 1) return YAFFS_OK;
1409    
1410         // make these things
1411         
1412     newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
1413    
1414     if (!newObjects)
1415     {
1416                 T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
1417                 return YAFFS_FAIL;
1418     }
1419     
1420     // Hook them into the free list
1421     for(i = 0; i < nObjects - 1; i++)
1422     {
1423         newObjects[i].siblings.next = (struct list_head *)(&newObjects[i+1]);
1424     }
1425         
1426         newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
1427         dev->freeObjects = newObjects;
1428         dev->nFreeObjects+= nObjects;
1429         dev->nObjectsCreated+= nObjects;
1430         
1431         // Now add this bunch of Objects to a list for freeing up.
1432         
1433         list = YMALLOC(sizeof(yaffs_ObjectList));
1434         if(!list)
1435         {
1436                 T(YAFFS_TRACE_ALLOCATE,(TSTR("Could not add objects to management list" TENDSTR)));
1437         }
1438         else
1439         {
1440                 list->objects = newObjects;
1441                 list->next = dev->allocatedObjectList;
1442                 dev->allocatedObjectList = list;
1443         }
1444         
1445         
1446         
1447         return YAFFS_OK;
1448 }
1449
1450
1451 // AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
1452 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
1453 {
1454         yaffs_Object *tn = NULL;
1455         
1456         // If there are none left make more
1457         if(!dev->freeObjects)
1458         {
1459                 yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
1460         }
1461         
1462         if(dev->freeObjects)
1463         {
1464                 tn = dev->freeObjects;
1465                 dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
1466                 dev->nFreeObjects--;
1467                 
1468                 // Now sweeten it up...
1469         
1470                 memset(tn,0,sizeof(yaffs_Object));
1471                 tn->myDev = dev;
1472                 tn->chunkId = -1;
1473                 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
1474                 INIT_LIST_HEAD(&(tn->hardLinks));
1475                 INIT_LIST_HEAD(&(tn->hashLink));
1476                 INIT_LIST_HEAD(&tn->siblings);
1477                 
1478                 // Add it to the lost and found directory.
1479                 // NB Can't put root or lostNFound in lostNFound so
1480                 // check if lostNFound exists first
1481                 if(dev->lostNFoundDir)
1482                 {
1483                         yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);      
1484                 }
1485         }
1486         
1487
1488         return tn;
1489 }
1490
1491 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
1492 {
1493
1494         yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);              
1495         if(obj)
1496         {
1497                 obj->fake = 1;                  // it is fake so it has no NAND presence...
1498                 obj->renameAllowed= 0;  // ... and we're not allowed to rename it...
1499                 obj->unlinkAllowed= 0;  // ... or unlink it
1500                 obj->deleted = 0;
1501                 obj->unlinked = 0;
1502                 obj->st_mode = mode;
1503                 obj->myDev = dev;
1504                 obj->chunkId = 0; // Not a valid chunk.
1505         }
1506         
1507         return obj;
1508         
1509 }
1510
1511
1512 static void yaffs_UnhashObject(yaffs_Object *tn)
1513 {
1514         int bucket;
1515         yaffs_Device *dev = tn->myDev;
1516         
1517         
1518         // If it is still linked into the bucket list, free from the list
1519         if(!list_empty(&tn->hashLink))
1520         {
1521                 list_del_init(&tn->hashLink);
1522                 bucket =  yaffs_HashFunction(tn->objectId);
1523                 dev->objectBucket[bucket].count--;
1524         }
1525         
1526 }
1527
1528
1529 // FreeObject frees up a Object and puts it back on the free list
1530 static void yaffs_FreeObject(yaffs_Object *tn)
1531 {
1532
1533         yaffs_Device *dev = tn->myDev;
1534         
1535 #ifdef  __KERNEL__
1536         if(tn->myInode)
1537         {
1538                 // We're still hooked up to a cached inode.
1539                 // Don't delete now, but mark for later deletion
1540                 tn->deferedFree = 1;
1541                 return;
1542         }
1543 #endif
1544         
1545         yaffs_UnhashObject(tn);
1546         
1547         // Link into the free list.
1548         tn->siblings.next = (struct list_head *)(dev->freeObjects);
1549         dev->freeObjects = tn;
1550         dev->nFreeObjects++;
1551 }
1552
1553
1554
1555 #ifdef __KERNEL__
1556
1557 void yaffs_HandleDeferedFree(yaffs_Object *obj)
1558 {
1559         if(obj->deferedFree)
1560         {
1561            yaffs_FreeObject(obj);
1562         }
1563 }
1564
1565 #endif
1566
1567
1568
1569 static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
1570 {
1571         // Free the list of allocated Objects
1572         
1573         yaffs_ObjectList *tmp;
1574         
1575         while( dev->allocatedObjectList)
1576         {
1577                 tmp =  dev->allocatedObjectList->next;
1578                 YFREE(dev->allocatedObjectList->objects);
1579                 YFREE(dev->allocatedObjectList);
1580                 
1581                 dev->allocatedObjectList =  tmp;
1582         }
1583         
1584         dev->freeObjects = NULL;
1585         dev->nFreeObjects = 0;
1586 }
1587
1588 static void yaffs_InitialiseObjects(yaffs_Device *dev)
1589 {
1590         int i;
1591         
1592         dev->allocatedObjectList = NULL;
1593         dev->freeObjects = NULL;
1594         dev->nFreeObjects = 0;
1595         
1596         for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
1597         {
1598                 INIT_LIST_HEAD(&dev->objectBucket[i].list);
1599                 dev->objectBucket[i].count = 0; 
1600         }
1601
1602 }
1603
1604
1605
1606
1607
1608
1609 int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
1610 {
1611         static int x = 0;
1612         int i;
1613         int l = 999;
1614         int lowest = 999999;
1615
1616                 
1617         // First let's see if we can find one that's empty.
1618         
1619         for(i = 0; i < 10 && lowest > 0; i++)
1620          {
1621                 x++;
1622                 x %=  YAFFS_NOBJECT_BUCKETS;
1623                 if(dev->objectBucket[x].count < lowest)
1624                 {
1625                         lowest = dev->objectBucket[x].count;
1626                         l = x;
1627                 }
1628                 
1629         }
1630         
1631         // If we didn't find an empty list, then try
1632         // looking a bit further for a short one
1633         
1634         for(i = 0; i < 10 && lowest > 3; i++)
1635          {
1636                 x++;
1637                 x %=  YAFFS_NOBJECT_BUCKETS;
1638                 if(dev->objectBucket[x].count < lowest)
1639                 {
1640                         lowest = dev->objectBucket[x].count;
1641                         l = x;
1642                 }
1643                 
1644         }
1645         
1646         return l;
1647 }
1648
1649 static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
1650 {
1651         int bucket = yaffs_FindNiceObjectBucket(dev);
1652         
1653         // Now find an object value that has not already been taken
1654         // by scanning the list.
1655         
1656         int found = 0;
1657         struct list_head *i;
1658         
1659         __u32 n = (__u32)bucket;
1660
1661         //yaffs_CheckObjectHashSanity();        
1662         
1663         while(!found)
1664         {
1665                 found = 1;
1666                 n +=  YAFFS_NOBJECT_BUCKETS;
1667                 if(1 ||dev->objectBucket[bucket].count > 0)
1668                 {
1669                         list_for_each(i,&dev->objectBucket[bucket].list)
1670                         {
1671                                 // If there is already one in the list
1672                                 if(i && list_entry(i, yaffs_Object,hashLink)->objectId == n)
1673                                 {
1674                                         found = 0;
1675                                 }
1676                         }
1677                 }
1678         }
1679         
1680         //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
1681         
1682         return n;       
1683 }
1684
1685 void yaffs_HashObject(yaffs_Object *in)
1686 {
1687         int bucket = yaffs_HashFunction(in->objectId);
1688         yaffs_Device *dev = in->myDev;
1689         
1690         if(!list_empty(&in->hashLink))
1691         {
1692                 //YINFO("!!!");
1693         }
1694
1695         
1696         list_add(&in->hashLink,&dev->objectBucket[bucket].list);
1697         dev->objectBucket[bucket].count++;
1698
1699 }
1700
1701 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number)
1702 {
1703         int bucket = yaffs_HashFunction(number);
1704         struct list_head *i;
1705         yaffs_Object *in;
1706         
1707         list_for_each(i,&dev->objectBucket[bucket].list)
1708         {
1709                 // Look if it is in the list
1710                 if(i)
1711                 {
1712                         in = list_entry(i, yaffs_Object,hashLink);
1713                         if(in->objectId == number)
1714                         {
1715                                 return in;
1716                         }
1717                 }
1718         }
1719         
1720         return NULL;
1721 }
1722
1723
1724
1725 yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
1726 {
1727                 
1728         yaffs_Object *theObject;
1729
1730         if(number < 0)
1731         {
1732                 number = yaffs_CreateNewObjectNumber(dev);
1733         }
1734         
1735         theObject = yaffs_AllocateEmptyObject(dev);
1736         
1737         if(theObject)
1738         {
1739                 theObject->fake = 0;
1740                 theObject->renameAllowed = 1;
1741                 theObject->unlinkAllowed = 1;
1742                 theObject->objectId = number;
1743                 yaffs_HashObject(theObject);
1744                 theObject->variantType = type;
1745 #ifdef CONFIG_YAFFS_WINCE
1746                 yfsd_WinFileTimeNow(theObject->win_atime);
1747                 theObject->win_ctime[0] = theObject->win_mtime[0] = theObject->win_atime[0];
1748                 theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];
1749
1750 #else
1751
1752                 theObject->st_atime = theObject->st_mtime = theObject->st_ctime = Y_CURRENT_TIME;               
1753 #endif
1754                 switch(type)
1755                 {
1756                         case YAFFS_OBJECT_TYPE_FILE: 
1757                                 theObject->variant.fileVariant.fileSize = 0;
1758                                 theObject->variant.fileVariant.scannedFileSize = 0;
1759                                 theObject->variant.fileVariant.topLevel = 0;
1760                                 theObject->variant.fileVariant.top  = yaffs_GetTnode(dev);
1761                                 break;
1762                         case YAFFS_OBJECT_TYPE_DIRECTORY:
1763                                 INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
1764                                 break;
1765                         case YAFFS_OBJECT_TYPE_SYMLINK:
1766                                 // No action required
1767                                 break;
1768                         case YAFFS_OBJECT_TYPE_HARDLINK:
1769                                 // No action required
1770                                 break;
1771                         case YAFFS_OBJECT_TYPE_SPECIAL:
1772                                 // No action required
1773                                 break;
1774                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1775                                 // todo this should not happen
1776                                 break;
1777                 }
1778         }
1779         
1780         return theObject;
1781 }
1782
1783 yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
1784 {
1785         yaffs_Object *theObject = NULL;
1786         
1787         if(number > 0)
1788         {
1789                 theObject = yaffs_FindObjectByNumber(dev,number);
1790         }
1791         
1792         if(!theObject)
1793         {
1794                 theObject = yaffs_CreateNewObject(dev,number,type);
1795         }
1796         
1797         return theObject;
1798
1799 }
1800
1801 YCHAR *yaffs_CloneString(const YCHAR *str)
1802 {
1803         YCHAR *newStr = NULL;
1804         
1805         if(str && *str)
1806         {
1807                 newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
1808                 yaffs_strcpy(newStr,str);
1809         }
1810
1811         return newStr;
1812         
1813 }
1814
1815 //
1816 // Mknod (create) a new object.
1817 // equivalentObject only has meaning for a hard link;
1818 // aliasString only has meaning for a sumlink.
1819 // rdev only has meaning for devices (a subset of special objects)
1820 yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
1821                                                                  yaffs_Object *parent,
1822                                                                  const YCHAR *name, 
1823                                                                  __u32 mode,
1824                                                                  __u32 uid,
1825                                                                  __u32 gid,
1826                                                                  yaffs_Object *equivalentObject,
1827                                                                  const YCHAR *aliasString,
1828                                                                  __u32 rdev)
1829 {
1830         yaffs_Object *in;
1831
1832         yaffs_Device *dev = parent->myDev;
1833         
1834         // Check if the entry exists. If it does then fail the call since we don't want a dup.
1835         if(yaffs_FindObjectByName(parent,name))
1836         {
1837                 return NULL;
1838         }
1839         
1840         in = yaffs_CreateNewObject(dev,-1,type);
1841         
1842         if(in)
1843         {
1844                 in->chunkId = -1;
1845                 in->valid = 1;
1846                 in->variantType = type;
1847
1848                 in->st_mode  = mode;
1849                 
1850 #ifdef CONFIG_YAFFS_WINCE
1851                 yfsd_WinFileTimeNow(in->win_atime);
1852                 in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
1853                 in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
1854                 
1855 #else
1856                 in->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME;
1857
1858                 in->st_rdev  = rdev;
1859                 in->st_uid   = uid;
1860                 in->st_gid   = gid;
1861 #endif          
1862                 in->nDataChunks = 0;
1863
1864                 yaffs_SetObjectName(in,name);
1865                 in->dirty = 1;
1866                 
1867                 yaffs_AddObjectToDirectory(parent,in);
1868                 
1869                 in->myDev = parent->myDev;
1870                 
1871                                 
1872                 switch(type)
1873                 {
1874                         case YAFFS_OBJECT_TYPE_SYMLINK:
1875                                 in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
1876                                 break;
1877                         case YAFFS_OBJECT_TYPE_HARDLINK:
1878                                 in->variant.hardLinkVariant.equivalentObject = equivalentObject;
1879                                 in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
1880                                 list_add(&in->hardLinks,&equivalentObject->hardLinks);
1881                                 break;
1882                         case YAFFS_OBJECT_TYPE_FILE: // do nothing
1883                         case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
1884                         case YAFFS_OBJECT_TYPE_SPECIAL: // do nothing
1885                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1886                                 break;
1887                 }
1888
1889                 if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
1890                    yaffs_UpdateObjectHeader(in,name,0,0) < 0)
1891                 {
1892                         // Could not create the object header, fail the creation
1893                         yaffs_DestroyObject(in);
1894                         in = NULL;
1895                 }
1896
1897         }
1898         
1899         return in;
1900 }
1901
1902 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
1903 {
1904         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL,0);
1905 }
1906
1907 yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
1908 {
1909         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,0);
1910 }
1911
1912 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
1913 {
1914         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,rdev);
1915 }
1916
1917 yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid,const YCHAR *alias)
1918 {
1919         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias,0);
1920 }
1921
1922 // NB yaffs_Link returns the object id of the equivalent object.
1923 yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object *equivalentObject)
1924 {
1925         // Get the real object in case we were fed a hard link as an equivalent object
1926         equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
1927         
1928         if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL,0))
1929         {
1930                 return equivalentObject;
1931         }
1932         else
1933         {
1934                 return NULL;
1935         }
1936         
1937 }
1938
1939
1940 static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force)
1941 {
1942         int unlinkOp;
1943         int deleteOp;
1944
1945         if(newDir == NULL)
1946         {
1947                 newDir = obj->parent; // use the old directory
1948         }
1949
1950         // TODO: Do we need this different handling for YAFFS2 and YAFFS1??
1951         if(obj->myDev->isYaffs2)
1952         {
1953                 unlinkOp = (newDir == obj->myDev->unlinkedDir);
1954         }
1955         else
1956         {
1957                 unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
1958         }
1959
1960         deleteOp = (newDir == obj->myDev->deletedDir);
1961         
1962         // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
1963         // duplicate names are allowed.
1964         // Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
1965         if( (unlinkOp|| 
1966                  deleteOp ||
1967                  force || 
1968                  !yaffs_FindObjectByName(newDir,newName))  &&
1969              newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1970         {
1971                 yaffs_SetObjectName(obj,newName);
1972                 obj->dirty = 1;
1973                 
1974                 yaffs_AddObjectToDirectory(newDir,obj);
1975                 
1976                 if(unlinkOp) obj->unlinked = 1;
1977                 
1978                 // If it is a dletion then we mark it as a shrink for gc purposes.
1979                 if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp) >= 0)
1980                 {
1981                         return YAFFS_OK;
1982                 }
1983         }
1984         
1985         return YAFFS_FAIL;
1986 }
1987
1988
1989
1990 int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName)
1991 {
1992         yaffs_Object *obj;
1993         int force = 0;
1994         
1995 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
1996         // Special case for case insemsitive systems (eg. WinCE).
1997         // While look-up is case insensitive, the name isn't.
1998         // THerefore we might want to change x.txt to X.txt
1999         if(oldDir == newDir && yaffs_strcmp(oldName,newName) == 0)
2000         {
2001                 force = 1;
2002         }       
2003 #endif
2004         
2005         obj = yaffs_FindObjectByName(oldDir,oldName);
2006         if(obj && obj->renameAllowed)
2007         {
2008                 return yaffs_ChangeObjectName(obj,newDir,newName,force);
2009         }
2010         return YAFFS_FAIL;
2011 }
2012
2013
2014
2015 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
2016 {
2017         // Scan the buckets and check that the lists 
2018         // have as many members as the count says there are
2019         int bucket;
2020         int countEm;
2021         struct list_head *j;
2022         int ok = YAFFS_OK;
2023         
2024         for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
2025         {
2026                 countEm = 0;
2027                 
2028                 list_for_each(j,&dev->objectBucket[bucket].list)
2029                 {
2030                         countEm++;
2031                 }
2032                 
2033                 if(countEm != dev->objectBucket[bucket].count)
2034                 {
2035                         T(YAFFS_TRACE_ERROR,(TSTR("Inode hash inconsistency" TENDSTR)));
2036                         ok = YAFFS_FAIL;
2037                 }
2038         }
2039
2040         return ok;
2041 }
2042
2043 #if 0
2044 void yaffs_ObjectTest(yaffs_Device *dev)
2045 {
2046         yaffs_Object *in[1000];
2047         int inNo[1000];
2048         yaffs_Object *inold[1000];
2049         int i;
2050         int j;
2051         
2052         memset(in,0,1000*sizeof(yaffs_Object *));
2053         memset(inold,0,1000*sizeof(yaffs_Object *));
2054         
2055         yaffs_CheckObjectHashSanity(dev);
2056         
2057         for(j = 0; j < 10; j++)
2058         {
2059                 //T(("%d\n",j));
2060                 
2061                 for(i = 0; i < 1000; i++)
2062                 {
2063                         in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
2064                         if(!in[i])
2065                         {
2066                                 YINFO("No more inodes");
2067                         }
2068                         else
2069                         {
2070                                 inNo[i] = in[i]->objectId;
2071                         }
2072                 }
2073                 
2074                 for(i = 0; i < 1000; i++)
2075                 {
2076                         if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
2077                         {
2078                                 //T(("Differnce in look up test\n"));
2079                         }
2080                         else
2081                         {
2082                                 // T(("Look up ok\n"));
2083                         }
2084                 }
2085                 
2086                 yaffs_CheckObjectHashSanity(dev);
2087         
2088                 for(i = 0; i < 1000; i+=3)
2089                 {
2090                         yaffs_FreeObject(in[i]);        
2091                         in[i] = NULL;
2092                 }
2093                 
2094         
2095                 yaffs_CheckObjectHashSanity(dev);
2096         }
2097                 
2098 }
2099
2100 #endif
2101
2102 /////////////////////////// Block Management and Page Allocation ///////////////////
2103
2104
2105 static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
2106 {
2107         dev->allocationBlock = -1; // force it to get a new one
2108         //Todo we're assuming the malloc will pass.
2109         dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
2110         // Set up dynamic blockinfo stuff.
2111         dev->chunkBitmapStride = (dev->nChunksPerBlock+7)/8;
2112         dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
2113         if(dev->blockInfo && dev->chunkBits)
2114         {
2115                 memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));
2116                 memset(dev->chunkBits,0,dev->chunkBitmapStride * nBlocks);
2117                 return YAFFS_OK;
2118         }
2119         
2120         return YAFFS_FAIL;
2121         
2122 }
2123
2124 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
2125 {
2126         YFREE(dev->blockInfo);
2127         dev->blockInfo = NULL;
2128         YFREE(dev->chunkBits);
2129         dev->chunkBits = NULL;
2130 }
2131
2132
2133 static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi)
2134 {
2135         int i;
2136         __u32 seq;
2137         yaffs_BlockInfo *b;
2138         
2139         if(!dev->isYaffs2) return 1; // disqualification only applies to yaffs2.
2140         
2141         if(!bi->hasShrinkHeader) return 1; // can gc
2142
2143
2144         // Find the oldest dirty sequence number if we don't know it and save it
2145         // so we don't have to keep recomputing it.
2146         if(!dev->oldestDirtySequence)
2147         {
2148                 seq = dev->sequenceNumber;
2149
2150                 for(i = dev->startBlock; i <= dev->endBlock; i++)
2151                 {
2152                         b = yaffs_GetBlockInfo(dev,i);
2153                         if(b->blockState == YAFFS_BLOCK_STATE_FULL &&
2154                         (b->pagesInUse - b->softDeletions )< dev->nChunksPerBlock &&
2155                         b->sequenceNumber < seq)
2156                         {
2157                                 seq = b->sequenceNumber;
2158                         }
2159                 }
2160                 dev->oldestDirtySequence = seq;
2161         }
2162
2163
2164         // Can't do gc of this block if there are any blocks older than this one that have
2165         // discarded pages.
2166         return (bi->sequenceNumber <= dev->oldestDirtySequence);
2167         
2168         
2169         return 1;
2170
2171 }
2172
2173 // FindDiretiestBlock is used to select the dirtiest block (or close enough)
2174 // for garbage collection.
2175 //
2176
2177
2178
2179 static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive)
2180 {
2181
2182         int b = dev->currentDirtyChecker;
2183         
2184         int i;
2185         int iterations;
2186         int dirtiest = -1;
2187         int pagesInUse; 
2188         yaffs_BlockInfo *bi;
2189         static int  nonAggressiveSkip = 0;
2190
2191         // If we're doing aggressive GC then we are happy to take a less-dirty block, and
2192         // search harder.
2193         // else (we're doing a leasurely gc), then we only bother to do this if the
2194         // block has only a few pages in use.
2195         
2196
2197         nonAggressiveSkip--;
2198
2199         if(!aggressive &&(nonAggressiveSkip > 0))
2200         {
2201                 return -1;
2202         }
2203
2204         pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
2205         if(aggressive)
2206         {
2207                 iterations = dev->endBlock - dev->startBlock + 1;
2208         }
2209         else
2210         {
2211                 iterations = dev->endBlock - dev->startBlock + 1;
2212                 iterations = iterations / 16; 
2213                 if(iterations > 200)
2214                 {
2215                         iterations = 200;
2216                 }
2217         }
2218         
2219         for(i = 0; i <= iterations && pagesInUse > 0 ; i++)
2220         {
2221                 b++;
2222                 if ( b < dev->startBlock || b > dev->endBlock)
2223                 {
2224                         b =  dev->startBlock;
2225                 }
2226
2227                 if(b < dev->startBlock || b > dev->endBlock)
2228                 {
2229                         T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b));
2230                         YBUG();
2231                 }
2232                 
2233                 bi = yaffs_GetBlockInfo(dev,b);
2234                 
2235                 if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
2236                    (bi->pagesInUse - bi->softDeletions )< pagesInUse &&
2237                    yaffs_BlockNotDisqualifiedFromGC(dev,bi))
2238                 {
2239                         dirtiest = b;
2240                         pagesInUse = (bi->pagesInUse - bi->softDeletions);
2241                 }
2242         }
2243         
2244         dev->currentDirtyChecker = b;
2245         
2246         if(dirtiest > 0)
2247         {
2248                 T(YAFFS_TRACE_GC,(TSTR("GC Selected block %d with %d free" TENDSTR),dirtiest,dev->nChunksPerBlock - pagesInUse));
2249         }
2250         
2251         dev->oldestDirtySequence = 0; // clear this
2252         
2253         if(dirtiest > 0)
2254         {
2255                 nonAggressiveSkip = 4;
2256         }
2257
2258         return dirtiest;
2259 }
2260
2261
2262 static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
2263 {
2264         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,blockNo);
2265         
2266         int erasedOk = 0;
2267         
2268         // If the block is still healthy erase it and mark as clean.
2269         // If the block has had a data failure, then retire it.
2270         bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
2271
2272         if(!bi->needsRetiring)
2273         {
2274                 erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);
2275                 if(!erasedOk)
2276                 {
2277                         dev->nErasureFailures++;
2278                         T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo));
2279                 }
2280         }
2281
2282         if(erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE))
2283         {
2284                         int i;
2285                         for(i = 0; i < dev->nChunksPerBlock; i++)
2286                         {
2287                                         if(!yaffs_CheckChunkErased(dev,blockNo * dev->nChunksPerBlock + i))
2288                                         {
2289                                                 T(YAFFS_TRACE_ERROR,(TSTR(">>Block %d erasure supposedly OK, but chunk %d not erased" TENDSTR),blockNo,i));
2290                                         }
2291                         }
2292         }
2293         
2294         if( erasedOk )
2295         {
2296                 // Clean it up...
2297                 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
2298                 dev->nErasedBlocks++;
2299                 bi->pagesInUse = 0;
2300                 bi->softDeletions = 0;
2301                 bi->hasShrinkHeader=0;
2302                 yaffs_ClearChunkBits(dev,blockNo);
2303         
2304                 T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo));
2305         }
2306         else
2307         {
2308                 yaffs_RetireBlock(dev,blockNo);
2309                 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
2310         }
2311 }
2312
2313 static void yaffs_DumpBlockStats(yaffs_Device *dev)
2314 {
2315         int i,j;
2316         yaffs_BlockInfo *bi;
2317         
2318         for(i= dev->startBlock; i <=dev->endBlock; i++)
2319         {
2320                 bi = yaffs_GetBlockInfo(dev,i);
2321                 T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i,
2322                 bi->blockState,bi->hasShrinkHeader,bi->pagesInUse,bi->softDeletions,bi->sequenceNumber));       
2323                 
2324                 for(j = 0; j < dev->nChunksPerBlock; j++)
2325                 {
2326                         if(yaffs_CheckChunkBit(dev,i,j))
2327                         {
2328                                 T(YAFFS_TRACE_ALLOCATE,(TSTR(" %d"),j));
2329
2330                         }
2331                 }
2332                 T(YAFFS_TRACE_ALLOCATE,(TSTR(" " TENDSTR)));
2333
2334         }
2335 }
2336
2337
2338 static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
2339 {
2340         int i;
2341         
2342         yaffs_BlockInfo *bi;
2343         
2344 #if 0
2345         static int j = 0;
2346         j++;
2347         if(j < 0 || j > 100)
2348         {
2349                 j = 0;
2350                 yaffs_DumpBlockStats(dev);
2351         }
2352         
2353 #endif
2354         
2355         if(dev->nErasedBlocks < 1)
2356         {
2357                 // Hoosterman we've got a problem.
2358                 // Can't get space to gc
2359                 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));
2360
2361                 return -1;
2362         }
2363         
2364         // Find an empty block.
2365         
2366         for(i = dev->startBlock; i <= dev->endBlock; i++)
2367         {
2368                 dev->allocationBlockFinder++;
2369                 if(dev->allocationBlockFinder < dev->startBlock || dev->allocationBlockFinder> dev->endBlock) 
2370                 {
2371                         dev->allocationBlockFinder = dev->startBlock;
2372                 }
2373                 
2374                 bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder);
2375
2376                 if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
2377                 {
2378                         bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
2379                         dev->sequenceNumber++;
2380                         bi->sequenceNumber = dev->sequenceNumber;
2381                         dev->nErasedBlocks--;           
2382                         T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocated block %d, seq  %d" TENDSTR),dev->allocationBlockFinder,dev->sequenceNumber));   
2383                         return dev->allocationBlockFinder;
2384                 }
2385         }
2386                 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks, but there should have been one" TENDSTR)));
2387
2388         
2389         return -1;      
2390 }
2391
2392
2393
2394 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
2395 {
2396         int retVal;
2397         yaffs_BlockInfo *bi;
2398         
2399         if(dev->allocationBlock < 0)
2400         {
2401                 // Get next block to allocate off
2402                 dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
2403                 dev->allocationPage = 0;
2404         }
2405         
2406         if(!useReserve &&  dev->nErasedBlocks </*=*/ dev->nReservedBlocks)
2407         {
2408                 // Not enough space to allocate unless we're allowed to use the reserve.
2409                 return -1;
2410         }
2411
2412         if(dev->nErasedBlocks < dev->nReservedBlocks && dev->allocationPage == 0)
2413         {
2414                 T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocating reserve" TENDSTR)));   
2415         }
2416
2417         
2418         // Next page please....
2419         if(dev->allocationBlock >= 0)
2420         {
2421                 bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);
2422                 
2423                 retVal = (dev->allocationBlock * dev->nChunksPerBlock) + 
2424                                   dev->allocationPage;
2425                 bi->pagesInUse++;
2426                 yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage);
2427
2428                 dev->allocationPage++;
2429                 
2430                 dev->nFreeChunks--;
2431                 
2432                 // If the block is full set the state to full
2433                 if(dev->allocationPage >= dev->nChunksPerBlock)
2434                 {
2435                         bi->blockState = YAFFS_BLOCK_STATE_FULL;
2436                         dev->allocationBlock = -1;
2437                 }
2438
2439
2440                 return retVal;
2441                 
2442         }
2443         T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
2444
2445         return -1;      
2446 }
2447
2448
2449 // To determine if we have enough space we just look at the 
2450 // number of erased blocks.
2451 // The cache is allowed to use reserved blocks.
2452
2453 static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)
2454 {
2455         return (dev->nErasedBlocks >= dev->nReservedBlocks);
2456 }
2457
2458
2459 static int yaffs_GetErasedChunks(yaffs_Device *dev)
2460 {
2461                 int n;
2462
2463                 n = dev->nErasedBlocks * dev->nChunksPerBlock;
2464
2465                 if(dev->allocationBlock> 0)
2466                 {
2467                         n += (dev->nChunksPerBlock - dev->allocationPage);
2468                 }
2469
2470                 return n;
2471
2472 }
2473
2474 int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
2475 {
2476         int oldChunk;
2477         int newChunk;
2478         int chunkInBlock;
2479         int markNAND;
2480         int retVal = YAFFS_OK;
2481         int cleanups = 0;
2482         int i;
2483
2484         int chunksBefore = yaffs_GetErasedChunks(dev);
2485         int chunksAfter;
2486
2487         yaffs_ExtendedTags  tags;
2488         
2489         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
2490         
2491         yaffs_Object *object;
2492         
2493         bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
2494
2495         T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
2496         //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));        
2497
2498         bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
2499
2500
2501         if(!yaffs_StillSomeChunkBits(dev,block))
2502         {
2503                 T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d that has no chunks in use" TENDSTR),block));
2504                 yaffs_BlockBecameDirty(dev,block);
2505         }
2506         else
2507         {
2508
2509                         __u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);
2510
2511         for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock; 
2512             chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
2513             chunkInBlock++, oldChunk++ )
2514         {
2515                 if(yaffs_CheckChunkBit(dev,block,chunkInBlock))
2516                 {
2517                         
2518                         // This page is in use and might need to be copied off
2519                         
2520                         markNAND = 1;
2521                         
2522                         //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
2523                         
2524                         yaffs_InitialiseTags(&tags);
2525                         
2526                         yaffs_ReadChunkWithTagsFromNAND(dev,oldChunk,buffer, &tags);
2527
2528                         object = yaffs_FindObjectByNumber(dev,tags.objectId);
2529                         
2530                         T(YAFFS_TRACE_GC_DETAIL,(TSTR("Collecting page %d, %d %d %d " TENDSTR),chunkInBlock,tags.objectId,tags.chunkId,tags.byteCount));
2531                         
2532                         if(!object)
2533                         {
2534                                 T(YAFFS_TRACE_ERROR,(TSTR("page %d in gc has no object " TENDSTR),oldChunk));
2535                         }
2536                         
2537                         if(object && object->deleted && tags.chunkId != 0)
2538                         {
2539                                 // Data chunk in a deleted file, throw it away
2540                                 // It's a deleted data chunk,
2541                                 // No need to copy this, just forget about it and fix up the
2542                                 // object.
2543                                 
2544                                 //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); 
2545                                 object->nDataChunks--;
2546                                 
2547                                 if(object->nDataChunks <= 0)
2548                                 {
2549                                         // remeber to clean up the object
2550                                         dev->gcCleanupList[cleanups] = tags.objectId;
2551                                         cleanups++;
2552                                 }
2553                                 markNAND = 0;
2554                         }
2555                         else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)
2556                         {
2557                                 // Deleted object header with no data chunks.
2558                                 // Can be discarded and the file deleted.
2559                                 object->chunkId = 0;
2560                                 yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
2561                                 object->variant.fileVariant.top = NULL;
2562                                 yaffs_DoGenericObjectDeletion(object);
2563                                 
2564                         }
2565                         else if(object)
2566                         {
2567                                 // It's either a data chunk in a live file or
2568                                 // an ObjectHeader, so we're interested in it.
2569                                 // NB Need to keep the ObjectHeaders of deleted files
2570                                 // until the whole file has been deleted off
2571                                 tags.serialNumber++;
2572
2573                                 dev->nGCCopies++;
2574
2575                                 newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
2576                         
2577                                 if(newChunk < 0)
2578                                 {
2579                                         retVal =  YAFFS_FAIL;
2580                                 }
2581                                 else
2582                                 {
2583                         
2584                                         // Ok, now fix up the Tnodes etc.
2585                         
2586                                         if(tags.chunkId == 0)
2587                                         {
2588                                                 // It's a header
2589                                                 object->chunkId = newChunk;
2590                                                 object->serial = tags.serialNumber;
2591                                         }
2592                                         else
2593                                         {
2594                                                 // It's a data chunk
2595                                                 yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
2596                                         }
2597                                 }
2598                         }
2599                         
2600                         yaffs_DeleteChunk(dev,oldChunk,markNAND,__LINE__);                      
2601                         
2602                 }
2603         }
2604
2605         yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
2606
2607
2608         // Do any required cleanups
2609         for(i = 0; i < cleanups; i++)
2610         {                                               
2611                 // Time to delete the file too
2612                 object =  yaffs_FindObjectByNumber(dev,dev->gcCleanupList[i]);
2613                 if(object)
2614                 {
2615                         yaffs_FreeTnode(dev,object->variant.fileVariant.top);
2616                         object->variant.fileVariant.top = NULL;
2617                         T(YAFFS_TRACE_GC,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId));
2618                         yaffs_DoGenericObjectDeletion(object);
2619                 }
2620
2621         }
2622
2623         }
2624
2625         if(chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev)))
2626         {
2627                         T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
2628         }
2629                         
2630         return YAFFS_OK;
2631 }
2632
2633 #if 0
2634 static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
2635 {
2636         // find a file to delete
2637         struct list_head *i;    
2638         yaffs_Object *l;
2639
2640
2641         //Scan the unlinked files looking for one to delete
2642         list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
2643         {
2644                 if(i)
2645                 {
2646                         l = list_entry(i, yaffs_Object,siblings);
2647                         if(l->deleted)
2648                         {
2649                                 return l;                       
2650                         }
2651                 }
2652         }       
2653         return NULL;
2654 }
2655
2656
2657 static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
2658 {
2659         // This does background deletion on unlinked files.. only deleted ones.
2660         // If we don't have a file we're working on then find one
2661         if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)
2662         {
2663                 dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);
2664         }
2665         
2666         // OK, we're working on a file...
2667         if(dev->unlinkedDeletion)
2668         {
2669                 yaffs_Object *obj = dev->unlinkedDeletion;
2670                 int delresult;
2671                 int limit; // Number of chunks to delete in a file.
2672                                    // NB this can be exceeded, but not by much.
2673                                    
2674                 limit = -1;
2675
2676                 delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
2677                 
2678                 if(obj->nDataChunks == 0)
2679                 {
2680                         // Done all the deleting of data chunks.
2681                         // Now dump the header and clean up
2682                         yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
2683                         obj->variant.fileVariant.top = NULL;
2684                         yaffs_DoGenericObjectDeletion(obj);
2685                         dev->nDeletedFiles--;
2686                         dev->nUnlinkedFiles--;
2687                         dev->nBackgroundDeletions++;
2688                         dev->unlinkedDeletion = NULL;   
2689                 }
2690         }
2691 }
2692
2693 #endif
2694
2695 #if 0
2696 #define YAFFS_GARBAGE_COLLECT_LOW_WATER 2
2697 static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
2698 {
2699         int block;
2700         int aggressive=0;
2701         
2702         //yaffs_DoUnlinkedFileDeletion(dev);
2703         
2704         if(dev->nErasedBlocks <= (dev->nReservedBlocks + YAFFS_GARBAGE_COLLECT_LOW_WATER))
2705         {
2706                 aggressive = 1;
2707         }               
2708         
2709         if(aggressive)
2710         {
2711                 block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
2712                 
2713                 if(block >= 0)
2714                 {
2715                         dev->garbageCollections++;
2716                         return yaffs_GarbageCollectBlock(dev,block);
2717                 }       
2718                 else
2719                 {
2720                         return YAFFS_FAIL;
2721                 }
2722         }
2723
2724         return YAFFS_OK;
2725 }
2726 #endif
2727
2728 // New garbage collector
2729 // If we're very low on erased blocks then we do aggressive garbage collection
2730 // otherwise we do "leasurely" garbage collection.
2731 // Aggressive gc looks further (whole array) and will accept dirtier blocks.
2732 // Passive gc only inspects smaller areas and will only accept cleaner blocks.
2733 //
2734 // The idea is to help clear out space in a more spread-out manner.
2735 // Dunno if it really does anything useful.
2736 //
2737 int yaffs_CheckGarbageCollection(yaffs_Device *dev)
2738 {
2739         int block;
2740         int aggressive; 
2741         int gcOk = YAFFS_OK;
2742         int maxTries = 0;
2743         
2744         //yaffs_DoUnlinkedFileDeletion(dev);
2745
2746         // This loop should pass the first time.
2747         // We'll only see looping here if the erase of the collected block fails.
2748         
2749         do{
2750                 maxTries++;
2751                 if(dev->nErasedBlocks <= (dev->nReservedBlocks + 2))
2752                 {
2753                         // We need a block soon...
2754                         aggressive = 1;
2755                 }
2756                 else 
2757                 {
2758                         // We're in no hurry
2759                         aggressive = 0;
2760                 }
2761         
2762                 block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
2763         
2764                 if(block > 0)
2765                 {
2766                         dev->garbageCollections++;
2767                         if(!aggressive)
2768                         {
2769                                 dev->passiveGarbageCollections++;
2770                         }
2771
2772                         T(YAFFS_TRACE_GC,(TSTR("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),dev->nErasedBlocks,aggressive));
2773
2774                         gcOk =  yaffs_GarbageCollectBlock(dev,block);
2775                 }
2776
2777                 if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) 
2778                 {
2779                         T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
2780                 }
2781         } while((dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) && (block > 0) && (maxTries < 5));
2782
2783         return aggressive ? gcOk: YAFFS_OK;
2784 }
2785
2786
2787 //////////////////////////// TAGS ///////////////////////////////////////
2788
2789
2790 void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
2791 {
2792         memset(tags,0,sizeof(yaffs_ExtendedTags));
2793         tags->validMarker0 = 0xAAAAAAAA;
2794         tags->validMarker1 = 0x55555555;
2795 }
2796
2797 static int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
2798 {
2799         return (tags->validMarker0 == 0xAAAAAAAA &&     tags->validMarker1 == 0x55555555);
2800
2801 }
2802
2803
2804 #if 0
2805
2806 void yaffs_CalcTagsECC(yaffs_Tags *tags)
2807 {
2808         // Calculate an ecc
2809         
2810         unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
2811         unsigned  i,j;
2812         unsigned  ecc = 0;
2813         unsigned bit = 0;
2814
2815         tags->ecc = 0;
2816         
2817         for(i = 0; i < 8; i++)
2818         {
2819                 for(j = 1; j &0xff; j<<=1)
2820                 {
2821                         bit++;
2822                         if(b[i] & j)
2823                         {
2824                                 ecc ^= bit;
2825                         }
2826                 }
2827         }
2828         
2829         tags->ecc = ecc;
2830         
2831         
2832 }
2833
2834 int  yaffs_CheckECCOnTags(yaffs_Tags *tags)
2835 {
2836         unsigned ecc = tags->ecc;
2837         
2838         yaffs_CalcTagsECC(tags);
2839         
2840         ecc ^= tags->ecc;
2841         
2842         if(ecc && ecc <= 64)
2843         {
2844                 // TODO: Handle the failure better. Retire?
2845                 unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
2846
2847                 ecc--;
2848                                 
2849                 b[ecc / 8] ^= (1 << (ecc & 7));
2850                 
2851                 // Now recvalc the ecc
2852                 yaffs_CalcTagsECC(tags);
2853                 
2854                 return 1; // recovered error
2855         }
2856         else if(ecc)
2857         {
2858                 // Wierd ecc failure value
2859                 // TODO Need to do somethiong here
2860                 return -1; //unrecovered error
2861         }
2862         
2863         return 0;
2864 }
2865
2866 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
2867 {
2868         yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
2869         
2870         yaffs_CalcTagsECC(tagsPtr);
2871         
2872         sparePtr->tagByte0 = tu->asBytes[0];
2873         sparePtr->tagByte1 = tu->asBytes[1];
2874         sparePtr->tagByte2 = tu->asBytes[2];
2875         sparePtr->tagByte3 = tu->asBytes[3];
2876         sparePtr->tagByte4 = tu->asBytes[4];
2877         sparePtr->tagByte5 = tu->asBytes[5];
2878         sparePtr->tagByte6 = tu->asBytes[6];
2879         sparePtr->tagByte7 = tu->asBytes[7];
2880 }
2881
2882 static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
2883 {
2884         yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
2885         int result;
2886
2887         tu->asBytes[0]= sparePtr->tagByte0;
2888         tu->asBytes[1]= sparePtr->tagByte1;
2889         tu->asBytes[2]= sparePtr->tagByte2;
2890         tu->asBytes[3]= sparePtr->tagByte3;
2891         tu->asBytes[4]= sparePtr->tagByte4;
2892         tu->asBytes[5]= sparePtr->tagByte5;
2893         tu->asBytes[6]= sparePtr->tagByte6;
2894         tu->asBytes[7]= sparePtr->tagByte7;
2895         
2896         result =  yaffs_CheckECCOnTags(tagsPtr);
2897         if(result> 0)
2898         {
2899                 dev->tagsEccFixed++;
2900         }
2901         else if(result <0)
2902         {
2903                 dev->tagsEccUnfixed++;
2904         }
2905 }
2906
2907 static void yaffs_SpareInitialise(yaffs_Spare *spare)
2908 {
2909         memset(spare,0xFF,sizeof(yaffs_Spare));
2910 }
2911
2912 #endif
2913
2914 #if 0
2915 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve)
2916 {
2917         // NB There must be tags, data is optional
2918         // If there is data, then an ECC is calculated on it.
2919         
2920         yaffs_Spare spare;
2921         
2922         if(!tags)
2923         {
2924                 return YAFFS_FAIL;
2925         }
2926         
2927         //yaffs_SpareInitialise(&spare);
2928         
2929         //if(!dev->useNANDECC && buffer)
2930         //{
2931         //      yaffs_CalcECC(buffer,&spare);
2932         //}
2933         
2934         //yaffs_LoadTagsIntoSpare(&spare,tags);
2935         
2936         return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
2937         
2938 }
2939 #endif
2940
2941 static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject)
2942 {
2943         return  (  tags->chunkId == chunkInObject &&
2944                            tags->objectId == objectId &&
2945                            !tags->chunkDeleted) ? 1 : 0;
2946         
2947 }
2948
2949
2950
2951 int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
2952 {
2953         //Get the Tnode, then get the level 0 offset chunk offset
2954     yaffs_Tnode *tn;     
2955     int theChunk = -1;
2956     yaffs_ExtendedTags localTags;
2957     int retVal = -1;
2958     
2959     yaffs_Device *dev = in->myDev;
2960     
2961     
2962     if(!tags)
2963     {
2964         // Passed a NULL, so use our own tags space
2965         tags = &localTags;
2966     }
2967     
2968     tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2969     
2970     if(tn)
2971     {
2972                 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
2973                 
2974                 retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
2975     }
2976     return retVal;
2977 }
2978
2979 int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
2980 {
2981         //Get the Tnode, then get the level 0 offset chunk offset
2982     yaffs_Tnode *tn;     
2983     int theChunk = -1;
2984     yaffs_ExtendedTags localTags;
2985
2986     yaffs_Device *dev = in->myDev;
2987     int retVal = -1;
2988     
2989     if(!tags)
2990     {
2991         // Passed a NULL, so use our own tags space
2992         tags = &localTags;
2993     }
2994     
2995     tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2996     
2997     if(tn)
2998     {
2999     
3000                 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
3001                 
3002                 retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
3003     
3004                 // Delete the entry in the filestructure (if found)
3005                 if(retVal != -1)
3006                 {
3007                         tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
3008                 }
3009     }
3010     else
3011     {
3012         //T(("No level 0 found for %d\n", chunkInInode));
3013     }
3014     
3015     if(retVal == -1)
3016     {
3017         //T(("Could not find %d to delete\n",chunkInInode));
3018     }
3019     return retVal;
3020 }
3021
3022
3023 #ifdef YAFFS_PARANOID
3024
3025 static int yaffs_CheckFileSanity(yaffs_Object *in)
3026 {
3027         int chunk;
3028         int nChunks;
3029         int fSize;
3030         int failed = 0;
3031         int objId;
3032         yaffs_Tnode *tn;
3033     yaffs_Tags localTags;
3034     yaffs_Tags *tags = &localTags;
3035     int theChunk;
3036     int chunkDeleted;
3037     
3038         
3039         if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
3040         {
3041                 //T(("Object not a file\n"));
3042                 return YAFFS_FAIL;
3043         }
3044         
3045         objId = in->objectId;
3046         fSize  = in->variant.fileVariant.fileSize;
3047         nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk;
3048         
3049         for(chunk = 1; chunk <= nChunks; chunk++)
3050         {
3051                 tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk);
3052     
3053                 if(tn)
3054                 {
3055     
3056                         theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits;
3057                         
3058                 if(yaffs_CheckChunkBits(dev,theChunk/dev->nChunksPerBlock,theChunk%dev->nChunksPerBlock))
3059                         {
3060
3061
3062                                 yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags,&chunkDeleted);
3063                                 if(yaffs_TagsMatch(tags,in->objectId,chunk,chunkDeleted))
3064                                 {
3065                                         // found it;
3066                                 
3067                                 }
3068                         }
3069                         else
3070                         {
3071                                 //T(("File problem file [%d,%d] NAND %d  tags[%d,%d]\n",
3072                                 //              objId,chunk,theChunk,tags->chunkId,tags->objectId);
3073                                                 
3074                                 failed = 1;
3075                                                         
3076                         }
3077     
3078                 }
3079                 else
3080                 {
3081                         //T(("No level 0 found for %d\n", chunk));
3082                 }
3083         }
3084         
3085         return failed ? YAFFS_FAIL : YAFFS_OK;
3086 }
3087
3088 #endif
3089
3090 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
3091 {
3092         yaffs_Tnode *tn;
3093         yaffs_Device *dev = in->myDev;
3094         int existingChunk;
3095         yaffs_ExtendedTags existingTags;
3096         yaffs_ExtendedTags newTags;
3097         unsigned existingSerial, newSerial;
3098                 
3099         tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
3100         if(!tn)
3101         {
3102                 return YAFFS_FAIL;
3103         }
3104
3105         existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];            
3106         
3107         if(inScan)
3108         {
3109                 // If we're scanning then we need to test for duplicates
3110                 // NB This does not need to be efficient since it should only ever 
3111                 // happen when the power fails during a write, then only one
3112                 // chunk should ever be affected.
3113         
3114                 
3115                 if(existingChunk != 0)
3116                 {
3117                         // NB Right now existing chunk will not be real chunkId if the device >= 32MB
3118                         //    thus we have to do a FindChunkInFile to get the real chunk id.
3119                         //
3120                         // We have a duplicate now we need to decide which one to use
3121                         // To do this we get both sets of tags and compare serial numbers.
3122                         yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND, NULL,&newTags);
3123                         
3124                         
3125                         // Do a proper find
3126                         existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags);
3127
3128                         if(existingChunk <=0)
3129                         {
3130                                 //Hoosterman - how did this happen?
3131                                 
3132                                 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: existing chunk < 0 in scan" TENDSTR)));
3133
3134                         }
3135
3136                         
3137                         // NB The deleted flags should be false, otherwise the chunks will 
3138                         // not be loaded during a scan
3139                         
3140                         newSerial = newTags.serialNumber;
3141                         existingSerial = existingTags.serialNumber;
3142                         
3143                         if( in->myDev->isYaffs2 ||
3144                             existingChunk <= 0 ||
3145                             ((existingSerial+1) & 3) == newSerial)
3146                         {
3147                                 // Use new
3148                                 // Delete the old one and drop through to update the tnode
3149                                 yaffs_DeleteChunk(dev,existingChunk,1,__LINE__);
3150                         }
3151                         else
3152                         {
3153                                 // Use existing.
3154                                 // Delete the new one and return early so that the tnode isn't changed
3155                                 yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
3156                                 return YAFFS_OK;
3157                         }
3158                 }
3159
3160         }
3161                 
3162         if(existingChunk == 0)
3163         {
3164                 in->nDataChunks++;
3165         }
3166         
3167         tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = (chunkInNAND >> dev->chunkGroupBits);
3168         
3169         return YAFFS_OK;
3170 }
3171
3172
3173
3174 int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
3175 {
3176     int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
3177     
3178     if(chunkInNAND >= 0)
3179     {
3180                 return yaffs_ReadChunkWithTagsFromNAND(in->myDev,chunkInNAND,buffer,NULL);
3181         }
3182         else
3183         {
3184                 T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not found zero instead" TENDSTR),chunkInNAND));
3185
3186                 memset(buffer,0,in->myDev->nBytesPerChunk); // get sane data if you read a hole
3187                 return 0;
3188         }
3189
3190 }
3191
3192
3193 void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn)
3194 {
3195         int block;
3196         int page;
3197         yaffs_ExtendedTags tags;
3198         yaffs_BlockInfo *bi;
3199         
3200         if(chunkId <= 0) return;        
3201         
3202         dev->nDeletions++;
3203         block = chunkId / dev->nChunksPerBlock;
3204         page = chunkId % dev->nChunksPerBlock;
3205         
3206         bi = yaffs_GetBlockInfo(dev,block);
3207         
3208         T(YAFFS_TRACE_DELETION,(TSTR("line %d delete of chunk %d" TENDSTR),lyn,chunkId));
3209         
3210         if(markNAND && 
3211           bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
3212           !dev->isYaffs2)
3213         {
3214 //              yaffs_SpareInitialise(&spare);
3215
3216 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
3217
3218                 //read data before write, to ensure correct ecc 
3219                 //if we're using MTD verification under Linux
3220                 yaffs_ReadChunkFromNAND(dev,chunkId,NULL,&spare,0);
3221 #endif
3222
3223                 yaffs_InitialiseTags(&tags);
3224
3225                 tags.chunkDeleted = 1;
3226
3227         
3228                 yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags);
3229                 yaffs_HandleUpdateChunk(dev,chunkId,&tags);
3230         }
3231         else
3232         {
3233                         dev->nUnmarkedDeletions++;
3234         }       
3235         
3236         
3237         // Pull out of the management area.
3238         // If the whole block became dirty, this will kick off an erasure.
3239         if(     bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
3240             bi->blockState == YAFFS_BLOCK_STATE_FULL ||     
3241             bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
3242             bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
3243         {
3244                 dev->nFreeChunks++;
3245
3246                 yaffs_ClearChunkBit(dev,block,page);
3247                 bi->pagesInUse--;
3248                 
3249                 if(bi->pagesInUse == 0 &&
3250                    !bi->hasShrinkHeader &&
3251                bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
3252                bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING)
3253             {
3254                 yaffs_BlockBecameDirty(dev,block);
3255             }
3256
3257         }
3258         else
3259         {
3260                 // T(("Bad news deleting chunk %d\n",chunkId));
3261         }
3262         
3263 }
3264
3265
3266
3267
3268 int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
3269 {
3270         // Find old chunk Need to do this to get serial number
3271         // Write new one and patch into tree.
3272         // Invalidate old tags.
3273
3274     int prevChunkId;
3275     yaffs_ExtendedTags prevTags;
3276     
3277     int newChunkId;
3278     yaffs_ExtendedTags newTags;
3279
3280     yaffs_Device *dev = in->myDev;    
3281
3282         yaffs_CheckGarbageCollection(dev);
3283
3284         // Get the previous chunk at this location in the file if it exists
3285     prevChunkId  = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
3286     
3287     // Set up new tags
3288     yaffs_InitialiseTags(&newTags);
3289     
3290         newTags.chunkId = chunkInInode;
3291         newTags.objectId = in->objectId;
3292         newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
3293         newTags.byteCount = nBytes;
3294                 
3295 //      yaffs_CalcTagsECC(&newTags);
3296
3297         newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
3298         
3299         if(newChunkId >= 0)
3300         {
3301                 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
3302                 
3303                 
3304                 if(prevChunkId >= 0)
3305                 {
3306                         yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
3307         
3308                 }
3309                 
3310                 yaffs_CheckFileSanity(in);
3311         }
3312         return newChunkId;
3313
3314
3315
3316
3317
3318 }
3319
3320
3321 // UpdateObjectHeader updates the header on NAND for an object.
3322 // If name is not NULL, then that new name is used.
3323 //
3324 int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink)
3325 {
3326
3327         yaffs_BlockInfo *bi;
3328         
3329         yaffs_Device *dev = in->myDev;
3330         
3331     int prevChunkId;
3332     int retVal = 0;
3333     
3334     int newChunkId;
3335     yaffs_ExtendedTags newTags;
3336     
3337     __u8 *buffer = NULL;
3338     YCHAR oldName[YAFFS_MAX_NAME_LENGTH+1];
3339     
3340    // __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
3341     
3342     yaffs_ObjectHeader *oh = NULL;
3343     // yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
3344
3345     
3346     if(!in->fake || force)
3347     {
3348   
3349                 yaffs_CheckGarbageCollection(dev);              
3350     
3351             buffer = yaffs_GetTempBuffer(in->myDev,__LINE__);
3352             oh  = (yaffs_ObjectHeader *)buffer;
3353     
3354                 prevChunkId = in->chunkId;
3355     
3356                 if(prevChunkId >= 0)
3357                 {
3358                         yaffs_ReadChunkWithTagsFromNAND(dev,prevChunkId,buffer,NULL);
3359                         memcpy(oldName,oh->name,sizeof(oh->name));      
3360                 }
3361
3362                 memset(buffer,0xFF,dev->nBytesPerChunk);
3363
3364                 // Header data
3365                 oh->type = in->variantType;
3366                 
3367                 oh->st_mode = in->st_mode;
3368
3369 #ifdef CONFIG_YAFFS_WINCE
3370                 oh->win_atime[0] = in->win_atime[0];
3371                 oh->win_ctime[0] = in->win_ctime[0];
3372                 oh->win_mtime[0] = in->win_mtime[0];
3373                 oh->win_atime[1] = in->win_atime[1];
3374                 oh->win_ctime[1] = in->win_ctime[1];
3375                 oh->win_mtime[1] = in->win_mtime[1];
3376 #else
3377                 oh->st_uid = in->st_uid;
3378                 oh->st_gid = in->st_gid;
3379                 oh->st_atime = in->st_atime;
3380                 oh->st_mtime = in->st_mtime;
3381                 oh->st_ctime = in->st_ctime;
3382                 oh->st_rdev = in->st_rdev;
3383 #endif  
3384                 if(in->parent)
3385                 {
3386                         oh->parentObjectId = in->parent->objectId;
3387                 }
3388                 else
3389                 {
3390                         oh->parentObjectId = 0;
3391                 }
3392                 
3393                 //oh->sum = in->sum;
3394                 if(name && *name)
3395                 {
3396                         memset(oh->name,0,sizeof(oh->name));
3397                         yaffs_strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
3398                 }
3399                 else if(prevChunkId)
3400                 {       
3401                         memcpy(oh->name, oldName,sizeof(oh->name));
3402                 }
3403                 else
3404                 {
3405                         memset(oh->name,0,sizeof(oh->name));    
3406                 }
3407                 
3408                 oh->isShrink = isShrink;
3409         
3410                 switch(in->variantType)
3411                 {
3412                         case YAFFS_OBJECT_TYPE_UNKNOWN:         
3413                                 // Should not happen
3414                                 break;
3415                         case YAFFS_OBJECT_TYPE_FILE:
3416                                 oh->fileSize = in->variant.fileVariant.fileSize;
3417                                 break;
3418                         case YAFFS_OBJECT_TYPE_HARDLINK:
3419                                 oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
3420                                 break;
3421                         case YAFFS_OBJECT_TYPE_SPECIAL: 
3422                                 // Do nothing
3423                                 break;
3424                         case YAFFS_OBJECT_TYPE_DIRECTORY:       
3425                                 // Do nothing
3426                                 break;
3427                         case YAFFS_OBJECT_TYPE_SYMLINK:
3428                                 yaffs_strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
3429                                 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
3430                                 break;
3431                 }
3432
3433                 // Tags
3434                 yaffs_InitialiseTags(&newTags);
3435                 in->serial++;
3436                 newTags.chunkId = 0;
3437                 newTags.objectId = in->objectId;
3438                 newTags.serialNumber = in->serial;
3439         
3440
3441                 // Create new chunk in NAND
3442                 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags, (prevChunkId >= 0) ? 1 : 0 );
3443     
3444                 if(newChunkId >= 0)
3445                 {
3446                 
3447                         in->chunkId = newChunkId;       
3448                 
3449                         if(prevChunkId >= 0)
3450                         {
3451                                 yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
3452                         }
3453                 
3454                         in->dirty = 0;
3455                         
3456                         // If this was a shrink, then mark the block that the chunk lives on
3457                         if(isShrink)
3458                         {
3459                                 bi = yaffs_GetBlockInfo(in->myDev,newChunkId / in->myDev->nChunksPerBlock);
3460                                 bi->hasShrinkHeader = 1;
3461                         }
3462                         
3463                 }
3464                 
3465                 retVal =  newChunkId;
3466
3467     }
3468     
3469         if(buffer) 
3470                 yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
3471         
3472     return retVal;
3473 }
3474
3475
3476 /////////////////////// Short Operations Cache ////////////////////////////////
3477 //      In many siturations where there is no high level buffering (eg WinCE) a lot of
3478 //      reads might be short sequential reads, and a lot of writes may be short 
3479 //  sequential writes. eg. scanning/writing a jpeg file.
3480 //      In these cases, a short read/write cache can provide a huge perfomance benefit 
3481 //  with dumb-as-a-rock code.
3482 //  There are a limited number (~10) of cache chunks per device so that we don't
3483 //  need a very intelligent search.
3484
3485
3486
3487
3488
3489 static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
3490 {
3491         yaffs_Device *dev = obj->myDev;
3492         int lowest;
3493         int i;
3494         yaffs_ChunkCache *cache;
3495         int chunkWritten;
3496         //int nBytes;
3497         int nCaches = obj->myDev->nShortOpCaches;
3498         
3499         if  (nCaches > 0)
3500         {
3501                 do{
3502                         cache = NULL;
3503                 
3504                         // Find the dirty cache for this object with the lowest chunk id.
3505                         for(i = 0; i < nCaches; i++)
3506                         {
3507                                 if(dev->srCache[i].object == obj &&
3508                                    dev->srCache[i].dirty)
3509                                 {
3510                                         if(!cache ||  dev->srCache[i].chunkId < lowest)
3511                                         {
3512                                                 cache = &dev->srCache[i];
3513                                                 lowest = cache->chunkId;
3514                                         }
3515                                 }
3516                         }
3517                 
3518                         if(cache && !cache->locked)
3519                         {
3520                                 //Write it out and free it up
3521
3522 #if 0
3523                                 nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);
3524                         
3525                                 if(nBytes > YAFFS_BYTES_PER_CHUNK)
3526                                 {
3527                                         nBytes= YAFFS_BYTES_PER_CHUNK;
3528                                 }
3529 #endif                  
3530                                 chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
3531                                                                                                                         cache->chunkId,
3532                                                                                                                         cache->data,
3533                                                                                                                         cache->nBytes,1);
3534
3535                                 cache->dirty = 0;
3536                                 cache->object = NULL;
3537                         }
3538                 
3539                 } while(cache && chunkWritten > 0);
3540         
3541                 if(cache)
3542                 {
3543                         //Hoosterman, disk full while writing cache out.
3544                         T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
3545
3546                 }
3547         }       
3548                 
3549 }
3550
3551
3552 // Grab us a chunk for use.
3553 // First look for an empty one. 
3554 // Then look for the least recently used non-dirty one.
3555 // Then look for the least recently used dirty one...., flush and look again.
3556 static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
3557 {
3558         int i;
3559         int usage;
3560         int theOne;
3561         
3562         if(dev->nShortOpCaches > 0)
3563         {
3564                 for(i = 0; i < dev->nShortOpCaches; i++)
3565                 {
3566                         if(!dev->srCache[i].object)
3567                         {
3568                                 //T(("Grabbing empty %d\n",i));
3569                                 
3570                                 //printf("Grabbing empty %d\n",i);
3571                         
3572                                 return &dev->srCache[i];
3573                         }
3574                 }
3575                 
3576                 return NULL;
3577         
3578                 theOne = -1; 
3579                 usage = 0; // just to stop the compiler grizzling
3580         
3581                 for(i = 0; i < dev->nShortOpCaches; i++)
3582                 {
3583                         if(!dev->srCache[i].dirty &&
3584                         ((dev->srCache[i].lastUse < usage  && theOne >= 0)|| 
3585                                 theOne < 0))
3586                         {
3587                                 usage = dev->srCache[i].lastUse;
3588                                 theOne = i;
3589                         }
3590                 }
3591         
3592                 //T(("Grabbing non-empty %d\n",theOne));
3593                 
3594                 //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
3595                 
3596                 return  theOne >= 0 ?  &dev->srCache[theOne] : NULL;
3597         }
3598         else
3599         {
3600                 return NULL;
3601         }
3602         
3603 }
3604
3605
3606 static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
3607 {
3608         yaffs_ChunkCache *cache;
3609         yaffs_Object *theObj;
3610         int usage;
3611         int i;
3612         int pushout;
3613         
3614         if(dev->nShortOpCaches > 0)
3615         {
3616                 // Try find a non-dirty one...
3617         
3618                 cache = yaffs_GrabChunkCacheWorker(dev);
3619         
3620                 if(!cache)
3621                 {
3622                         // They were all dirty, find the last recently used object and flush
3623                         // its cache, then  find again.
3624                         // NB what's here is not very accurate, we actually flush the object
3625                         // the last recently used page.
3626                 
3627                         theObj = NULL;
3628                         usage = 0;
3629                         cache = NULL;
3630                         pushout = 0;
3631         
3632                         for(i = 0; i < dev->nShortOpCaches; i++)
3633                         {
3634                                 if( dev->srCache[i].object && 
3635                                         !dev->srCache[i].locked &&
3636                                         (dev->srCache[i].lastUse < usage || !cache))
3637                                 {
3638                                         usage  = dev->srCache[i].lastUse;
3639                                         theObj = dev->srCache[i].object;
3640                                         cache = &dev->srCache[i];
3641                                         pushout = i;
3642                                 }
3643                         }
3644                 
3645                         if(!cache || cache->dirty)
3646                         {
3647                         
3648                                 //printf("Dirty ");
3649                                 yaffs_FlushFilesChunkCache(theObj);
3650                 
3651                                 // Try again
3652                                 cache = yaffs_GrabChunkCacheWorker(dev);
3653                         }
3654                         else
3655                         {
3656                                 //printf(" pushout %d\n",pushout);
3657                         }
3658                         
3659                 }
3660
3661                 return cache;
3662         }
3663         else
3664                 return NULL;
3665
3666 }
3667
3668
3669 // Find a cached chunk
3670 static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunkId)
3671 {
3672         yaffs_Device *dev = obj->myDev;
3673         int i;
3674         if(dev->nShortOpCaches > 0)
3675         {
3676                 for(i = 0; i < dev->nShortOpCaches; i++)
3677                 {
3678                         if(dev->srCache[i].object == obj && 
3679                         dev->srCache[i].chunkId == chunkId)
3680                         {
3681                                 dev->cacheHits++;
3682                         
3683                                 return &dev->srCache[i];
3684                         }
3685                 }
3686         }
3687         return NULL;
3688 }
3689
3690 // Mark the chunk for the least recently used algorithym
3691 static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite)
3692 {
3693
3694         if(dev->nShortOpCaches > 0)
3695         {
3696                 if( dev->srLastUse < 0 || 
3697                         dev->srLastUse > 100000000)
3698                 {
3699                         // Reset the cache usages
3700                         int i;
3701                         for(i = 1; i < dev->nShortOpCaches; i++)
3702                         {
3703                                 dev->srCache[i].lastUse = 0;
3704                         }
3705                         dev->srLastUse = 0;
3706                 }
3707
3708                 dev->srLastUse++;
3709         
3710                 cache->lastUse = dev->srLastUse;
3711
3712                 if(isAWrite)
3713                 {
3714                         cache->dirty = 1;
3715                 }
3716         }
3717 }
3718
3719 // Invalidate a single cache page.
3720 // Do this when a whole page gets written,
3721 // ie the short cache for this page is no longer valid.
3722 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
3723 {
3724         if(object->myDev->nShortOpCaches > 0)
3725         {
3726                 yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId);
3727
3728                 if(cache)
3729                 {
3730                         cache->object = NULL;
3731                 }
3732         }
3733 }
3734
3735
3736 // Invalidate all the cache pages associated with this object
3737 // Do this whenever ther file is deleted or resized.
3738 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
3739 {
3740         int i;
3741         yaffs_Device *dev = in->myDev;
3742         
3743         if(dev->nShortOpCaches > 0)
3744         { 
3745                 // Now invalidate it.
3746                 for(i = 0; i < dev->nShortOpCaches; i++)
3747                 {
3748                         if(dev->srCache[i].object == in)
3749                         {
3750                                 dev->srCache[i].object = NULL;
3751                         }
3752                 }
3753         }
3754 }
3755
3756
3757
3758
3759
3760 ///////////////////////// File read/write ///////////////////////////////
3761 // Read and write have very similar structures.
3762 // In general the read/write has three parts to it
3763 // * An incomplete chunk to start with (if the read/write is not chunk-aligned)
3764 // * Some complete chunks
3765 // * An incomplete chunk to end off with
3766 //
3767 // Curve-balls: the first chunk might also be the last chunk.
3768
3769 int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
3770 {
3771         
3772         
3773         int chunk;
3774         int start;
3775         int nToCopy;
3776         int n = nBytes;
3777         int nDone = 0;
3778         yaffs_ChunkCache *cache;
3779         
3780         yaffs_Device *dev;
3781         
3782         dev = in->myDev;
3783         
3784         while(n > 0)
3785         {
3786                 chunk = offset / dev->nBytesPerChunk + 1; // The first chunk is 1
3787                 start = offset % dev->nBytesPerChunk;
3788
3789                 // OK now check for the curveball where the start and end are in
3790                 // the same chunk.      
3791                 if(     (start + n) < dev->nBytesPerChunk)
3792                 {
3793                         nToCopy = n;
3794                 }
3795                 else
3796                 {
3797                         nToCopy = dev->nBytesPerChunk - start;
3798                 }
3799         
3800                 cache = yaffs_FindChunkCache(in,chunk);
3801                 
3802                 // If the chunk is already in the cache or it is less than a whole chunk
3803                 // then use the cache (if there is caching)
3804                 // else bypass the cache.
3805                 if( cache || nToCopy != dev->nBytesPerChunk)
3806                 {
3807                         if(dev->nShortOpCaches > 0)
3808                         {
3809                                 
3810                                 // If we can't find the data in the cache, then load it up.
3811                                 
3812                                 if(!cache)
3813                                 {
3814                                         cache = yaffs_GrabChunkCache(in->myDev);
3815                                         cache->object = in;
3816                                         cache->chunkId = chunk;
3817                                         cache->dirty = 0;
3818                                         cache->locked = 0;
3819                                         yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
3820                                         cache->nBytes = 0;      
3821                                 }
3822                         
3823                                 yaffs_UseChunkCache(dev,cache,0);
3824
3825                                 cache->locked = 1;
3826
3827 #ifdef CONFIG_YAFFS_WINCE
3828                                 yfsd_UnlockYAFFS(TRUE);
3829 #endif
3830                                 memcpy(buffer,&cache->data[start],nToCopy);
3831
3832 #ifdef CONFIG_YAFFS_WINCE
3833                                 yfsd_LockYAFFS(TRUE);
3834 #endif
3835                                 cache->locked = 0;
3836                         }
3837                         else
3838                         {
3839                                 // Read into the local buffer then copy...
3840                                 
3841                                 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3842                                 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);            
3843 #ifdef CONFIG_YAFFS_WINCE
3844                                 yfsd_UnlockYAFFS(TRUE);
3845 #endif
3846                                 memcpy(buffer,&localBuffer[start],nToCopy);
3847
3848 #ifdef CONFIG_YAFFS_WINCE
3849                                 yfsd_LockYAFFS(TRUE);
3850 #endif
3851                                 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3852                         }
3853
3854                 }
3855                 else
3856                 {
3857 #ifdef CONFIG_YAFFS_WINCE
3858                         __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3859                         
3860                         // Under WinCE can't do direct transfer. Need to use a local buffer.
3861                         // This is because we otherwise screw up WinCE's memory mapper
3862                         yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3863
3864 #ifdef CONFIG_YAFFS_WINCE
3865                                 yfsd_UnlockYAFFS(TRUE);
3866 #endif
3867                         memcpy(buffer,localBuffer,dev->nBytesPerChunk);
3868
3869 #ifdef CONFIG_YAFFS_WINCE
3870                                 yfsd_LockYAFFS(TRUE);
3871                                 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3872 #endif
3873
3874 #else
3875                         // A full chunk. Read directly into the supplied buffer.
3876                         yaffs_ReadChunkDataFromObject(in,chunk,buffer);
3877 #endif
3878                 }
3879                 
3880                 n -= nToCopy;
3881                 offset += nToCopy;
3882                 buffer += nToCopy;
3883                 nDone += nToCopy;
3884                 
3885         }
3886         
3887         return nDone;
3888 }
3889
3890
3891
3892 int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes)
3893 {       
3894         
3895         int chunk;
3896         int start;
3897         int nToCopy;
3898         int n = nBytes;
3899         int nDone = 0;
3900         int nToWriteBack;
3901         int startOfWrite = offset;
3902         int chunkWritten = 0;
3903         int nBytesRead;
3904         
3905         yaffs_Device *dev;
3906         
3907         dev = in->myDev;
3908         
3909         
3910         while(n > 0 && chunkWritten >= 0)
3911         {
3912                 chunk = offset / dev->nBytesPerChunk + 1;
3913                 start = offset % dev->nBytesPerChunk;
3914                 
3915
3916                 // OK now check for the curveball where the start and end are in
3917                 // the same chunk.
3918                 
3919                 if(     (start + n) < dev->nBytesPerChunk)
3920                 {
3921                         nToCopy = n;
3922                         
3923                         // Now folks, to calculate how many bytes to write back....
3924                         // If we're overwriting and not writing to then end of file then
3925                         // we need to write back as much as was there before.
3926                         
3927                         nBytesRead = in->variant.fileVariant.fileSize - ((chunk -1) * dev->nBytesPerChunk);
3928                         
3929                         if(nBytesRead > dev->nBytesPerChunk)
3930                         {
3931                                 nBytesRead = dev->nBytesPerChunk;
3932                         }
3933                         
3934                         nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start +n);
3935                         
3936                 }
3937                 else
3938                 {
3939                         nToCopy = dev->nBytesPerChunk - start;
3940                         nToWriteBack = dev->nBytesPerChunk;
3941                 }
3942         
3943                 if(nToCopy != dev->nBytesPerChunk)
3944                 {
3945                         // An incomplete start or end chunk (or maybe both start and end chunk)
3946                         if(dev->nShortOpCaches > 0)
3947                         {
3948                                 yaffs_ChunkCache *cache;
3949                                 // If we can't find the data in the cache, then load it up.
3950                                 cache = yaffs_FindChunkCache(in,chunk);
3951                                 if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))
3952                                 {
3953                                         cache = yaffs_GrabChunkCache(in->myDev);
3954                                         cache->object = in;
3955                                         cache->chunkId = chunk;
3956                                         cache->dirty = 0;
3957                                         cache->locked = 0;
3958                                         yaffs_ReadChunkDataFromObject(in,chunk,cache->data);            
3959                                 }
3960                         
3961                                 if(cache)
3962                                 {       
3963                                         yaffs_UseChunkCache(dev,cache,1);
3964                                         cache->locked = 1;
3965 #ifdef CONFIG_YAFFS_WINCE
3966                                 yfsd_UnlockYAFFS(TRUE);
3967 #endif
3968         
3969                                         memcpy(&cache->data[start],buffer,nToCopy);
3970
3971 #ifdef CONFIG_YAFFS_WINCE
3972                                 yfsd_LockYAFFS(TRUE);
3973 #endif
3974                                         cache->locked = 0;
3975                                         cache->nBytes = nToWriteBack;
3976                                 }
3977                                 else
3978                                 {
3979                                         chunkWritten = -1; // fail the write
3980                                 }
3981                         }
3982                         else
3983                         {
3984                                 // An incomplete start or end chunk (or maybe both start and end chunk)
3985                                 // Read into the local buffer then copy, then copy over and write back.
3986                                 
3987                                 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3988                 
3989                                 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3990                                 
3991 #ifdef CONFIG_YAFFS_WINCE
3992                                 yfsd_UnlockYAFFS(TRUE);
3993 #endif
3994                                         
3995                                 memcpy(&localBuffer[start],buffer,nToCopy);
3996                         
3997 #ifdef CONFIG_YAFFS_WINCE
3998                                 yfsd_LockYAFFS(TRUE);
3999 #endif
4000                                 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
4001                                 
4002                                 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
4003                         
4004                                 //T(("Write with readback to chunk %d %d  start %d  copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));
4005                         }
4006                         
4007                 }
4008                 else
4009                 {
4010                         
4011 #ifdef CONFIG_YAFFS_WINCE
4012                         // Under WinCE can't do direct transfer. Need to use a local buffer.
4013                         // This is because we otherwise screw up WinCE's memory mapper
4014                                 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
4015 #ifdef CONFIG_YAFFS_WINCE
4016                                 yfsd_UnlockYAFFS(TRUE);
4017 #endif
4018                         memcpy(localBuffer,buffer,dev->nBytesPerChunk);
4019 #ifdef CONFIG_YAFFS_WINCE
4020                                 yfsd_LockYAFFS(TRUE);
4021 #endif
4022                         chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,dev->nBytesPerChunk,0);
4023                         yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
4024 #else
4025                         // A full chunk. Write directly from the supplied buffer.
4026                         chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,dev->nBytesPerChunk,0);
4027 #endif
4028                         // Since we've overwritten the cached data, we better invalidate it.
4029                         yaffs_InvalidateChunkCache(in,chunk);
4030                         //T(("Write to chunk %d %d\n",chunk,chunkWritten));
4031                 }
4032                 
4033                 if(chunkWritten >= 0)
4034                 {
4035                         n -= nToCopy;
4036                         offset += nToCopy;
4037                         buffer += nToCopy;
4038                         nDone += nToCopy;
4039                 }
4040                 
4041         }
4042         
4043         // Update file object
4044         
4045         if((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
4046         {
4047                 in->variant.fileVariant.fileSize = (startOfWrite + nDone);
4048         }
4049         
4050         in->dirty = 1;
4051         
4052         return nDone;
4053 }
4054
4055 static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
4056 {
4057
4058         yaffs_Device *dev = in->myDev;
4059         int oldFileSize = in->variant.fileVariant.fileSize;
4060
4061         
4062         int lastDel = 1 + (oldFileSize-1)/dev->nBytesPerChunk;
4063                 
4064         int startDel = 1 + (newSize + dev->nBytesPerChunk - 1)/
4065                                                 dev->nBytesPerChunk;
4066         int i;
4067         int chunkId;
4068
4069         // Delete backwards so that we don't end up with holes if
4070         // power is lost part-way through the operation.
4071         for(i = lastDel; i >= startDel; i--)
4072         {
4073                 // NB this could be optimised somewhat,
4074                 // eg. could retrieve the tags and write them without
4075                 // using yaffs_DeleteChunk
4076
4077                 chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
4078                 if(chunkId > 0)
4079                 {
4080                         if(chunkId < (dev->startBlock * dev->nChunksPerBlock) || 
4081                        chunkId >= ((dev->endBlock+1) * dev->nChunksPerBlock))
4082                         {
4083                                 T(YAFFS_TRACE_ALWAYS,("Found daft chunkId %d for %d\n",chunkId,i));
4084                         }
4085                         else
4086                         {
4087                                 in->nDataChunks--;
4088                                 yaffs_DeleteChunk(dev,chunkId,1,__LINE__);
4089                         }
4090                 }
4091         }
4092                 
4093 }
4094
4095 int yaffs_ResizeFile(yaffs_Object *in, int newSize)
4096 {
4097
4098         int oldFileSize = in->variant.fileVariant.fileSize;
4099         int sizeOfPartialChunk;
4100         yaffs_Device *dev = in->myDev;
4101         
4102          sizeOfPartialChunk  = newSize % dev->nBytesPerChunk;
4103                 
4104
4105         yaffs_FlushFilesChunkCache(in); 
4106         yaffs_InvalidateWholeChunkCache(in);
4107
4108         yaffs_CheckGarbageCollection(dev);
4109         
4110         if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
4111         {
4112                 return yaffs_GetFileSize(in);
4113         }
4114         
4115         if(newSize < oldFileSize)
4116         {
4117
4118                 yaffs_PruneResizedChunks(in,newSize);
4119                 
4120                 if(sizeOfPartialChunk != 0)
4121                 {
4122                         int lastChunk = 1+ newSize/dev->nBytesPerChunk;
4123                         __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
4124                         
4125                         // Got to read and rewrite the last chunk with its new size and zero pad
4126                         yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
4127                         
4128                         memset(localBuffer + sizeOfPartialChunk,0, dev->nBytesPerChunk - sizeOfPartialChunk);
4129                         
4130                         yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfPartialChunk,1);
4131                                 
4132                         yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
4133                 }
4134                 
4135                 in->variant.fileVariant.fileSize = newSize;
4136                 
4137                 yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
4138                 
4139                 // TODO write a new object header to show we've shrunk the file
4140                 // Do this only if the file is not in the deleted directory.
4141                 if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED)
4142                 {
4143                         yaffs_UpdateObjectHeader(in,NULL, 0, 1);
4144                 }
4145
4146                 
4147                 return newSize;
4148                 
4149         }
4150         else
4151         {
4152                 return oldFileSize;
4153         }
4154 }
4155
4156
4157 loff_t yaffs_GetFileSize(yaffs_Object *obj)
4158 {
4159         obj = yaffs_GetEquivalentObject(obj);
4160         
4161         switch(obj->variantType)
4162         {
4163                 case YAFFS_OBJECT_TYPE_FILE: 
4164                         return obj->variant.fileVariant.fileSize;
4165                 case YAFFS_OBJECT_TYPE_SYMLINK:
4166                         return yaffs_strlen(obj->variant.symLinkVariant.alias);
4167                 default:
4168                         return 0;
4169         }
4170 }
4171
4172
4173
4174 // yaffs_FlushFile() updates the file's
4175 // objectId in NAND
4176
4177 int yaffs_FlushFile(yaffs_Object *in, int updateTime)
4178 {
4179         int retVal;
4180         if(in->dirty)
4181         {
4182                 //T(("flushing object header\n"));
4183                 
4184                 yaffs_FlushFilesChunkCache(in);
4185                 if(updateTime)
4186                 {
4187 #ifdef CONFIG_YAFFS_WINCE
4188                         yfsd_WinFileTimeNow(in->win_mtime);
4189 #else
4190
4191                         in->st_mtime = Y_CURRENT_TIME;
4192
4193 #endif
4194                 }
4195
4196                 retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
4197         }
4198         else
4199         {
4200                 retVal = YAFFS_OK;
4201         }
4202         
4203         return retVal;
4204         
4205 }
4206
4207
4208 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
4209 {
4210
4211         // First off, invalidate the file's data in the cache, without flushing.
4212         yaffs_InvalidateWholeChunkCache(in);
4213
4214         if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir))
4215         {
4216                 // Move to the unlinked directory so we have a record that it was deleted.
4217                 yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
4218
4219         }
4220
4221         
4222         yaffs_RemoveObjectFromDirectory(in);
4223         yaffs_DeleteChunk(in->myDev,in->chunkId,1,__LINE__);
4224         in->chunkId = -1;
4225
4226 #ifdef __KERNEL__
4227         if(in->myInode)
4228         {
4229                 in->myInode->u.generic_ip = NULL;
4230                 in->myInode = 0;
4231         }
4232 #endif
4233         yaffs_FreeObject(in);
4234         return YAFFS_OK;
4235
4236 }
4237
4238 // yaffs_DeleteFile deletes the whole file data
4239 // and the inode associated with the file.
4240 // It does not delete the links associated with the file.
4241 static int yaffs_UnlinkFile(yaffs_Object *in)
4242 {
4243
4244 #ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION
4245
4246         // Delete the file data & tnodes
4247
4248          yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);
4249          
4250
4251         yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
4252         
4253         return  yaffs_DoGenericObjectDeletion(in);
4254 #else
4255         int retVal;
4256         int immediateDeletion=0;
4257
4258         if(1)
4259         {
4260                 //in->unlinked = 1;
4261                 //in->myDev->nUnlinkedFiles++;
4262                 //in->renameAllowed = 0;
4263 #ifdef __KERNEL__
4264                 if(!in->myInode)
4265                 {
4266                         immediateDeletion = 1;
4267
4268                 }
4269 #else
4270                 if(in->inUse <= 0)
4271                 {
4272                         immediateDeletion = 1;
4273
4274                 }
4275 #endif
4276                 if(immediateDeletion)
4277                 {
4278                         retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
4279                         T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
4280                         in->deleted=1;
4281                         in->myDev->nDeletedFiles++;
4282                         yaffs_SoftDeleteFile(in);
4283                 }
4284                 else
4285                 {
4286                         retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0);
4287                 }
4288         
4289         }
4290         return retVal;
4291
4292         
4293 #endif
4294 }
4295
4296 int yaffs_DeleteFile(yaffs_Object *in)
4297 {
4298         int retVal = YAFFS_OK;
4299         
4300         if(in->nDataChunks > 0)
4301         {
4302                 // Use soft deletion
4303                 if(!in->unlinked)
4304                 {
4305                         retVal = yaffs_UnlinkFile(in);
4306                 }
4307                 if(retVal == YAFFS_OK && 
4308                 in->unlinked &&
4309                 !in->deleted)
4310                 {
4311                         in->deleted = 1;
4312                         in->myDev->nDeletedFiles++;
4313                         yaffs_SoftDeleteFile(in);
4314                 }
4315                 return in->deleted ? YAFFS_OK : YAFFS_FAIL;     
4316         }
4317         else
4318         {
4319                 // The file has no data chunks so we toss it immediately
4320                 yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
4321                 in->variant.fileVariant.top = NULL;
4322                 yaffs_DoGenericObjectDeletion(in);      
4323                 
4324                 return YAFFS_OK;        
4325         }
4326 }
4327
4328 static int yaffs_DeleteDirectory(yaffs_Object *in)
4329 {
4330         //First check that the directory is empty.
4331         if(list_empty(&in->variant.directoryVariant.children))
4332         {
4333                 return  yaffs_DoGenericObjectDeletion(in);
4334         }
4335         
4336         return YAFFS_FAIL;
4337         
4338 }
4339
4340 static int yaffs_DeleteSymLink(yaffs_Object *in)
4341 {
4342         YFREE(in->variant.symLinkVariant.alias);
4343
4344         return  yaffs_DoGenericObjectDeletion(in);
4345 }
4346
4347 static int yaffs_DeleteHardLink(yaffs_Object *in)
4348 {
4349         // remove this hardlink from the list assocaited with the equivalent
4350         // object
4351         list_del(&in->hardLinks);
4352         return  yaffs_DoGenericObjectDeletion(in);      
4353 }
4354
4355
4356 static void yaffs_DestroyObject(yaffs_Object *obj)
4357 {
4358         switch(obj->variantType)
4359         {
4360                 case YAFFS_OBJECT_TYPE_FILE: yaffs_DeleteFile(obj); break;
4361                 case YAFFS_OBJECT_TYPE_DIRECTORY: yaffs_DeleteDirectory(obj); break;
4362                 case YAFFS_OBJECT_TYPE_SYMLINK: yaffs_DeleteSymLink(obj); break;
4363                 case YAFFS_OBJECT_TYPE_HARDLINK: yaffs_DeleteHardLink(obj); break;
4364                 case YAFFS_OBJECT_TYPE_SPECIAL: yaffs_DoGenericObjectDeletion(obj); break;
4365                 case YAFFS_OBJECT_TYPE_UNKNOWN: break; // should not happen.
4366         }
4367 }
4368
4369
4370 static int yaffs_UnlinkWorker(yaffs_Object *obj)
4371 {
4372
4373         
4374         if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
4375         {
4376                 return  yaffs_DeleteHardLink(obj);
4377         }
4378         else if(!list_empty(&obj->hardLinks))
4379         {       
4380                 // Curve ball: We're unlinking an object that has a hardlink.
4381                 //
4382                 //      This problem arises because we are not strictly following
4383                 //  The Linux link/inode model.
4384                 //
4385                 // We can't really delete the object.
4386                 // Instead, we do the following:
4387                 // - Select a hardlink.
4388                 // - Unhook it from the hard links
4389                 // - Unhook it from its parent directory (so that the rename can work)
4390                 // - Rename the object to the hardlink's name.
4391                 // - Delete the hardlink
4392                 
4393                 
4394                 yaffs_Object *hl;
4395                 int retVal;
4396                 YCHAR name[YAFFS_MAX_NAME_LENGTH+1];
4397                 
4398                 hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
4399                 
4400                 list_del_init(&hl->hardLinks);
4401                 list_del_init(&hl->siblings);
4402                 
4403                 yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
4404                 
4405                 retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0);
4406                 
4407                 if(retVal == YAFFS_OK)
4408                 {
4409                         retVal = yaffs_DoGenericObjectDeletion(hl);
4410                 }
4411                 return retVal;
4412                                 
4413         }
4414         else
4415         {
4416                 switch(obj->variantType)
4417                 {
4418                         case YAFFS_OBJECT_TYPE_FILE:
4419                                 return yaffs_UnlinkFile(obj);
4420                                 break;
4421                         case YAFFS_OBJECT_TYPE_DIRECTORY:
4422                                 return yaffs_DeleteDirectory(obj);
4423                                 break;
4424                         case YAFFS_OBJECT_TYPE_SYMLINK:
4425                                 return yaffs_DeleteSymLink(obj);
4426                                 break;
4427                         case YAFFS_OBJECT_TYPE_HARDLINK:
4428                         case YAFFS_OBJECT_TYPE_UNKNOWN:
4429                         default:
4430                                 return YAFFS_FAIL;
4431                 }
4432         }
4433 }
4434
4435 int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
4436 {
4437         yaffs_Object *obj;
4438         
4439          obj = yaffs_FindObjectByName(dir,name);
4440          
4441          if(obj && obj->unlinkAllowed)
4442          {
4443                 return yaffs_UnlinkWorker(obj);
4444          }
4445          
4446          return YAFFS_FAIL;
4447         
4448 }
4449
4450 //////////////// Initialisation Scanning /////////////////
4451
4452
4453 #if 0
4454 // For now we use the SmartMedia check.
4455 // We look at the blockStatus byte in the first two chunks
4456 // These must be 0xFF to pass as OK.
4457 // todo: this function needs to be modifyable foir different NAND types
4458 // and different chunk sizes.  Suggest make this into a per-device configurable
4459 // function.
4460 static int yaffs_IsBlockBad(yaffs_Device *dev, int blk)
4461 {
4462         yaffsExtendedTags *tags;
4463         
4464         yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock,NULL,&tags,1);
4465 #if 1
4466         if(yaffs_CountBits(spare.blockStatus) < 7)
4467         {
4468                 return 1;
4469         }
4470 #else
4471         if(spare.blockStatus != 0xFF)
4472         {
4473                 return 1;
4474         }
4475 #endif
4476         yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock + 1,NULL,&spare,1);
4477
4478 #if 1
4479         if(yaffs_CountBits(spare.blockStatus) < 7)
4480         {
4481                 return 1;
4482         }
4483 #else
4484         if(spare.blockStatus != 0xFF)
4485         {
4486                 return 1;
4487         }
4488 #endif
4489         
4490         return 0;
4491         
4492 }
4493
4494 #endif
4495
4496
4497 typedef struct 
4498 {
4499         int seq;
4500         int block;
4501 } yaffs_BlockIndex;
4502
4503
4504
4505 static int yaffs_Scan(yaffs_Device *dev)
4506 {
4507         yaffs_ExtendedTags tags;
4508         int blk;
4509         int blockIterator;
4510         int startIterator;
4511         int endIterator;
4512         int nBlocksToScan = 0;
4513         
4514         int chunk;
4515         int c;
4516         int deleted;
4517         yaffs_BlockState state;
4518         yaffs_Object *hardList = NULL;
4519         yaffs_Object *hl;
4520         yaffs_BlockInfo *bi;
4521         int sequenceNumber;     
4522         yaffs_ObjectHeader *oh;
4523         yaffs_Object *in;
4524         yaffs_Object *parent;
4525         int nBlocks = dev->endBlock - dev->startBlock + 1;
4526         
4527         __u8 *chunkData;
4528
4529         yaffs_BlockIndex *blockIndex = NULL;
4530
4531         T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts  startblk %d endblk %d..." TENDSTR),dev->startBlock,dev->endBlock));
4532         
4533         chunkData = yaffs_GetTempBuffer(dev,__LINE__);
4534         
4535         
4536         dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
4537         
4538         if(dev->isYaffs2)
4539         {
4540                 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));               
4541         }
4542         
4543         
4544         // Scan all the blocks to determine their state
4545         for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
4546         {
4547                 bi = yaffs_GetBlockInfo(dev,blk);
4548                 yaffs_ClearChunkBits(dev,blk);
4549                 bi->pagesInUse = 0;
4550                 bi->softDeletions = 0;
4551                                 
4552                 yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
4553                 
4554                 bi->blockState = state;
4555                 bi->sequenceNumber = sequenceNumber;
4556
4557                 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
4558                 
4559                 if(state == YAFFS_BLOCK_STATE_DEAD)
4560                 {
4561                         T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
4562                 }
4563                 else if(state == YAFFS_BLOCK_STATE_EMPTY)
4564                 {
4565                         T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
4566                         dev->nErasedBlocks++;
4567                         dev->nFreeChunks += dev->nChunksPerBlock;
4568                 }
4569                 else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4570                 {
4571                                         
4572                         // Determine the highest sequence number
4573                         if( dev->isYaffs2 &&
4574                             sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
4575                             sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
4576                          {
4577                                 
4578                                 blockIndex[nBlocksToScan].seq = sequenceNumber;
4579                                 blockIndex[nBlocksToScan].block = blk;
4580                                 
4581                                 nBlocksToScan++;
4582
4583                                 if(sequenceNumber >= dev->sequenceNumber)
4584                                 {
4585                                         dev->sequenceNumber = sequenceNumber;
4586                                 }
4587                         }
4588                         else if(dev->isYaffs2)
4589                         {
4590                                 // TODO: Nasty sequence number!
4591                                 T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
4592
4593                         }
4594                 }
4595         }
4596         
4597         // Sort the blocks
4598         // Dungy old bubble sort for now...
4599         if(dev->isYaffs2)
4600         {
4601                 yaffs_BlockIndex temp;
4602                 int i;
4603                 int j;
4604                 
4605                 for(i = 0; i < nBlocksToScan; i++)
4606                         for(j = i+1; j < nBlocksToScan; j++)
4607                          if(blockIndex[i].seq > blockIndex[j].seq)
4608                          {
4609                                 temp = blockIndex[j];
4610                                 blockIndex[j] = blockIndex[i];
4611                                 blockIndex[i] = temp;
4612                          }
4613         }
4614         
4615         
4616         // Now scan the blocks looking at the data.
4617         if(dev->isYaffs2)
4618         {
4619                 startIterator = 0;
4620                 endIterator = nBlocksToScan-1;
4621                 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
4622         }
4623         else
4624         {
4625                 startIterator = dev->startBlock;
4626                 endIterator = dev->endBlock;
4627         }
4628         
4629         for(blockIterator = startIterator; blockIterator <= endIterator; blockIterator++)
4630         {
4631         
4632                 if(dev->isYaffs2)
4633                 {
4634                         // get the block to scan in the correct order
4635                         blk = blockIndex[blockIterator].block;
4636                 }
4637                 else
4638                 {
4639                         blk = blockIterator;
4640                 }
4641
4642
4643                 bi = yaffs_GetBlockInfo(dev,blk);
4644                 state = bi->blockState;
4645                 
4646                 deleted = 0;
4647                 
4648                 for(c = 0; c < dev->nChunksPerBlock && 
4649                                    state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++)
4650                 {
4651                         // Read the tags and decide what to do
4652                         chunk = blk * dev->nChunksPerBlock + c;
4653                         
4654                         yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
4655
4656                         // Let's have a good look at this chunk...
4657         
4658                         
4659                         if(!dev->isYaffs2 && tags.chunkDeleted)
4660                         {
4661                                 // A deleted chunk
4662                                 deleted++;
4663                                 dev->nFreeChunks ++;
4664                                 //T((" %d %d deleted\n",blk,c));
4665                         }
4666                         else if(!tags.chunkUsed)
4667                         {
4668                                 // An unassigned chunk in the block
4669                                 // This means that either the block is empty or 
4670                                 // this is the one being allocated from
4671                                 
4672                                 if(c == 0)
4673                                 {
4674                                         // We're looking at the first chunk in the block so the block is unused
4675                                         state = YAFFS_BLOCK_STATE_EMPTY;
4676                                         dev->nErasedBlocks++;
4677                                 }
4678                                 else
4679                                 {
4680                                         // this is the block being allocated from
4681                                         T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
4682                                         state = YAFFS_BLOCK_STATE_ALLOCATING;
4683                                         dev->allocationBlock = blk;
4684                                         dev->allocationPage = c;
4685                                         dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
4686                                                                                                           // go forth from here.
4687                                         //Yaffs2 sanity check:
4688                                         // This should be the one with the highest sequence number
4689                                         if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
4690                                         {
4691                                                 T(YAFFS_TRACE_ALWAYS,
4692                                                                 (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
4693                                                                 blk,bi->sequenceNumber,dev->sequenceNumber));
4694                                         }
4695                                 }
4696
4697                                 dev->nFreeChunks += (dev->nChunksPerBlock - c);
4698                         }
4699                         else if(tags.chunkId > 0)
4700                         {
4701                                 int endpos;
4702                                 // A data chunk.
4703                                 yaffs_SetChunkBit(dev,blk,c);
4704                                 bi->pagesInUse++;
4705                                                                 
4706                                 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
4707                                 // PutChunkIntoFIle checks for a clash (two data chunks with
4708                                 // the same chunkId).
4709                                 yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
4710                                 endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
4711                                 if(in->variant.fileVariant.scannedFileSize <endpos)
4712                                 {
4713                                         in->variant.fileVariant.scannedFileSize = endpos;
4714                                         if(!dev->useHeaderFileSize)
4715                                         {
4716                                                 in->variant.fileVariant.fileSize =      
4717                                                         in->variant.fileVariant.scannedFileSize;
4718                                         }
4719
4720                                 }
4721                                 //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));  
4722                         }
4723                         else
4724                         {
4725                                 // chunkId == 0, so it is an ObjectHeader.
4726                                 // Thus, we read in the object header and make the object
4727                                 yaffs_SetChunkBit(dev,blk,c);
4728                                 bi->pagesInUse++;
4729                                                         
4730                                 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
4731                                 
4732                                 oh = (yaffs_ObjectHeader *)chunkData;
4733                                 
4734                                 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
4735                                 
4736                                 if(in->valid)
4737                                 {
4738                                         // We have already filled this one. We have a duplicate and need to resolve it.
4739                                         
4740                                         unsigned existingSerial = in->serial;
4741                                         unsigned newSerial = tags.serialNumber;
4742                                         
4743                                         if( dev->isYaffs2 ||
4744                                             ((existingSerial+1) & 3) == newSerial)
4745                                         {
4746                                                 // Use new one - destroy the exisiting one
4747                                                 yaffs_DeleteChunk(dev,in->chunkId,1,__LINE__);
4748                                                 in->valid = 0;
4749                                         }
4750                                         else
4751                                         {
4752                                                 // Use existing - destroy this one.
4753                                                 yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4754                                         }
4755                                 }
4756                                 
4757                                 if(!in->valid &&
4758                                    (tags.objectId == YAFFS_OBJECTID_ROOT ||
4759                                     tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
4760                                 {
4761                                         // We only load some info, don't fiddle with directory structure
4762                                         in->valid = 1;
4763                                         in->variantType = oh->type;
4764         
4765                                         in->st_mode  = oh->st_mode;
4766 #ifdef CONFIG_YAFFS_WINCE
4767                                         in->win_atime[0] = oh->win_atime[0];
4768                                         in->win_ctime[0] = oh->win_ctime[0];
4769                                         in->win_mtime[0] = oh->win_mtime[0];
4770                                         in->win_atime[1] = oh->win_atime[1];
4771                                         in->win_ctime[1] = oh->win_ctime[1];
4772                                         in->win_mtime[1] = oh->win_mtime[1];
4773 #else
4774                                         in->st_uid   = oh->st_uid;
4775                                         in->st_gid   = oh->st_gid;
4776                                         in->st_atime = oh->st_atime;
4777                                         in->st_mtime = oh->st_mtime;
4778                                         in->st_ctime = oh->st_ctime;
4779                                         in->st_rdev = oh->st_rdev;
4780 #endif
4781                                         in->chunkId  = chunk;
4782
4783                                 }
4784                                 else if(!in->valid)
4785                                 {
4786                                         // we need to load this info
4787                                 
4788                                         in->valid = 1;
4789                                         in->variantType = oh->type;
4790         
4791                                         in->st_mode  = oh->st_mode;
4792 #ifdef CONFIG_YAFFS_WINCE
4793                                         in->win_atime[0] = oh->win_atime[0];
4794                                         in->win_ctime[0] = oh->win_ctime[0];
4795                                         in->win_mtime[0] = oh->win_mtime[0];
4796                                         in->win_atime[1] = oh->win_atime[1];
4797                                         in->win_ctime[1] = oh->win_ctime[1];
4798                                         in->win_mtime[1] = oh->win_mtime[1];
4799 #else
4800                                         in->st_uid   = oh->st_uid;
4801                                         in->st_gid   = oh->st_gid;
4802                                         in->st_atime = oh->st_atime;
4803                                         in->st_mtime = oh->st_mtime;
4804                                         in->st_ctime = oh->st_ctime;
4805                                         in->st_rdev = oh->st_rdev;
4806 #endif
4807                                         in->chunkId  = chunk;
4808
4809                                         yaffs_SetObjectName(in,oh->name);
4810                                         in->dirty = 0;
4811                                                         
4812                                         // directory stuff...
4813                                         // hook up to parent
4814         
4815                                         parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
4816                                         if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
4817                                         {
4818                                                 // Set up as a directory
4819                                                 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
4820                                                 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
4821                                         }
4822                                         else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
4823                                         {
4824                                                 // Hoosterman, another problem....
4825                                                 // We're trying to use a non-directory as a directory
4826
4827                                                 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
4828                                                 parent = dev->lostNFoundDir;
4829                                         }
4830                                 
4831                                         yaffs_AddObjectToDirectory(parent,in);
4832
4833                                         if(0 && (parent == dev->deletedDir ||
4834                                            parent == dev->unlinkedDir))
4835                                         {
4836                                                 in->deleted = 1; // If it is unlinked at start up then it wants deleting
4837                                                 dev->nDeletedFiles++;
4838                                         }
4839                                 
4840                                         // Note re hardlinks.
4841                                         // Since we might scan a hardlink before its equivalent object is scanned
4842                                         // we put them all in a list.
4843                                         // After scanning is complete, we should have all the objects, so we run through this
4844                                         // list and fix up all the chains.              
4845         
4846                                         switch(in->variantType)
4847                                         {
4848                                                 case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem
4849                                                         break;
4850                                                 case YAFFS_OBJECT_TYPE_FILE:
4851                                                         if(dev->isYaffs2 && oh->isShrink)
4852                                                         {
4853                                                                 // Prune back the shrunken chunks
4854                                                                 yaffs_PruneResizedChunks(in,oh->fileSize);
4855                                                                 // Mark the block as having a shrinkHeader
4856                                                                 bi->hasShrinkHeader = 1;
4857                                                         }
4858                                                         
4859                                                         if(dev->useHeaderFileSize)
4860                                                                 in->variant.fileVariant.fileSize = oh->fileSize;
4861                                                                 
4862                                                         break;
4863                                                 case YAFFS_OBJECT_TYPE_HARDLINK:
4864                                                         in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
4865                                                         in->hardLinks.next = (struct list_head *)hardList;
4866                                                         hardList = in;
4867                                                         break;
4868                                                 case YAFFS_OBJECT_TYPE_DIRECTORY:       // Do nothing
4869                                                         break;
4870                                                 case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
4871                                                         break;
4872                                                 case YAFFS_OBJECT_TYPE_SYMLINK:         // Do nothing
4873                                                         in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
4874                                                         break;
4875                                         }
4876
4877                                         if(parent == dev->deletedDir)
4878                                         {
4879                                                 yaffs_DestroyObject(in);
4880                                                 bi->hasShrinkHeader = 1;
4881                                         }
4882                                         //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));        
4883                                 }
4884                         }
4885                 }
4886                 
4887                 if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4888                 {
4889                         // If we got this far while scanning, then the block is fully allocated.
4890                         state = YAFFS_BLOCK_STATE_FULL; 
4891                 }
4892                 
4893                 bi->blockState = state;
4894                 
4895                 // Now let's see if it was dirty
4896                 if(     bi->pagesInUse == 0 &&
4897                         !bi->hasShrinkHeader &&
4898                 bi->blockState == YAFFS_BLOCK_STATE_FULL)
4899             {
4900                 yaffs_BlockBecameDirty(dev,blk);
4901             }
4902
4903         }
4904         
4905         if(blockIndex)
4906         {
4907                 YFREE(blockIndex);
4908         }
4909         
4910         // Ok, we've done all the scanning.
4911         
4912         // Fix up the hard link chains.
4913         // We should now have scanned all the objects, now it's time to add these 
4914         // hardlinks.
4915         while(hardList)
4916         {
4917                 hl = hardList;
4918                 hardList = (yaffs_Object *)(hardList->hardLinks.next);
4919                 
4920                 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
4921                 
4922                 if(in)
4923                 {
4924                         // Add the hardlink pointers
4925                         hl->variant.hardLinkVariant.equivalentObject=in;
4926                         list_add(&hl->hardLinks,&in->hardLinks);
4927                 }
4928                 else
4929                 {
4930                         //Todo Need to report/handle this better.
4931                         // Got a problem... hardlink to a non-existant object
4932                         hl->variant.hardLinkVariant.equivalentObject=NULL;
4933                         INIT_LIST_HEAD(&hl->hardLinks);
4934                         
4935                 }
4936                 
4937         }
4938         
4939         {
4940                 struct list_head *i;    
4941                 struct list_head *n;
4942                         
4943                 yaffs_Object *l;
4944                 // Soft delete all the unlinked files
4945                 list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
4946                 {
4947                         if(i)
4948                         {
4949                                 l = list_entry(i, yaffs_Object,siblings);
4950                                 if(l->deleted)
4951                                 {
4952                                         yaffs_DestroyObject(l);         
4953                                 }
4954                         }
4955                 }       
4956         }
4957         
4958         yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
4959
4960         T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan ends" TENDSTR)));
4961
4962         return YAFFS_OK;
4963 }
4964
4965
4966
4967 ////////////////////////// Directory Functions /////////////////////////
4968
4969
4970 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
4971 {
4972
4973         if(obj->siblings.prev == NULL)
4974         {
4975                 // Not initialised
4976                 INIT_LIST_HEAD(&obj->siblings);
4977                 
4978         }
4979         else if(!list_empty(&obj->siblings))
4980         {
4981                 // If it is holed up somewhere else, un hook it
4982                 list_del_init(&obj->siblings);
4983         }
4984         // Now add it
4985         list_add(&obj->siblings,&directory->variant.directoryVariant.children);
4986         obj->parent = directory;
4987         
4988         if(directory == obj->myDev->unlinkedDir || directory == obj->myDev->deletedDir)
4989         {
4990                 obj->unlinked = 1;
4991                 obj->myDev->nUnlinkedFiles++;
4992                 obj->renameAllowed = 0;
4993         }
4994 }
4995
4996 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
4997 {
4998         list_del_init(&obj->siblings);
4999         obj->parent = NULL;
5000 }
5001
5002 yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const YCHAR *name)
5003 {
5004         int sum;
5005         
5006         struct list_head *i;
5007         YCHAR buffer[YAFFS_MAX_NAME_LENGTH+1];
5008         
5009         yaffs_Object *l;
5010         
5011         sum = yaffs_CalcNameSum(name);
5012         
5013         list_for_each(i,&directory->variant.directoryVariant.children)
5014         {
5015                 if(i)
5016                 {
5017                         l = list_entry(i, yaffs_Object,siblings);
5018                 
5019                         // Special case for lost-n-found
5020                         if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
5021                         {
5022                                 if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
5023                                 {
5024                                         return l;
5025                                 }
5026                         }
5027                         else if(yaffs_SumCompare(l->sum, sum)||
5028                                     l->chunkId <= 0) //LostnFound cunk called Objxxx
5029                         {
5030                                 // Do a real check
5031                                 yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH);
5032                                 if(yaffs_strcmp(name,buffer) == 0)
5033                                 {
5034                                         return l;
5035                                 }
5036                         
5037                         }                       
5038                 }
5039         }
5040         
5041         return NULL;
5042 }
5043
5044
5045 int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
5046 {
5047         struct list_head *i;    
5048         yaffs_Object *l;
5049         
5050         
5051         list_for_each(i,&theDir->variant.directoryVariant.children)
5052         {
5053                 if(i)
5054                 {
5055                         l = list_entry(i, yaffs_Object,siblings);
5056                         if(l && !fn(l))
5057                         {
5058                                 return YAFFS_FAIL;
5059                         }
5060                 }
5061         }
5062         
5063         return YAFFS_OK;
5064
5065 }
5066
5067
5068 // GetEquivalentObject dereferences any hard links to get to the
5069 // actual object.
5070
5071 yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
5072 {
5073         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
5074         {
5075                 // We want the object id of the equivalent object, not this one
5076                 obj = obj->variant.hardLinkVariant.equivalentObject;
5077         }
5078         return obj;
5079
5080 }
5081
5082 int yaffs_GetObjectName(yaffs_Object *obj,YCHAR *name,int buffSize)
5083 {
5084         memset(name,0,buffSize * sizeof(YCHAR));
5085         
5086         if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
5087         {
5088                 yaffs_strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
5089         }
5090         else if(obj->chunkId <= 0)
5091         {
5092                 YCHAR locName[20];
5093                 // make up a name
5094                 yaffs_sprintf(locName,_Y("%s%d"),YAFFS_LOSTNFOUND_PREFIX,obj->objectId);
5095                 yaffs_strncpy(name,locName,buffSize - 1);
5096
5097         }
5098 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5099         else if(obj->shortName[0])
5100         {
5101                 yaffs_strcpy(name,obj->shortName);
5102         }
5103 #endif
5104         else
5105         {
5106                 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev,__LINE__);
5107                 
5108                 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
5109
5110                 memset(buffer,0,obj->myDev->nBytesPerChunk);
5111         
5112                 if(obj->chunkId >= 0)
5113                 {
5114                         yaffs_ReadChunkWithTagsFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
5115                 }
5116                 yaffs_strncpy(name,oh->name,buffSize - 1);
5117
5118                 yaffs_ReleaseTempBuffer(obj->myDev,buffer,__LINE__);
5119         }
5120         
5121         return yaffs_strlen(name);
5122 }
5123
5124 int yaffs_GetObjectFileLength(yaffs_Object *obj)
5125 {
5126         
5127         // Dereference any hard linking
5128         obj = yaffs_GetEquivalentObject(obj);
5129         
5130         if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
5131         {
5132                 return obj->variant.fileVariant.fileSize;
5133         }
5134         if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
5135         {
5136                 return yaffs_strlen(obj->variant.symLinkVariant.alias);
5137         }
5138         else
5139         {
5140                 // Only a directory should drop through to here
5141                 return obj->myDev->nBytesPerChunk;
5142         }       
5143 }
5144
5145 int yaffs_GetObjectLinkCount(yaffs_Object *obj)
5146 {
5147         int count = 0; 
5148         struct list_head *i;
5149         
5150         if(!obj->unlinked)
5151         {
5152                 count++;        // the object itself
5153         }
5154         list_for_each(i,&obj->hardLinks)
5155         {
5156                 count++;        // add the hard links;
5157         }
5158         return count;
5159         
5160 }
5161
5162
5163 int yaffs_GetObjectInode(yaffs_Object *obj)
5164 {
5165         obj = yaffs_GetEquivalentObject(obj);
5166         
5167         return obj->objectId;
5168 }
5169
5170 unsigned yaffs_GetObjectType(yaffs_Object *obj)
5171 {
5172         obj = yaffs_GetEquivalentObject(obj);
5173         
5174         switch(obj->variantType)
5175         {
5176                 case YAFFS_OBJECT_TYPE_FILE:            return DT_REG; break;
5177                 case YAFFS_OBJECT_TYPE_DIRECTORY:       return DT_DIR; break;
5178                 case YAFFS_OBJECT_TYPE_SYMLINK:         return DT_LNK; break;
5179                 case YAFFS_OBJECT_TYPE_HARDLINK:        return DT_REG; break;
5180                 case YAFFS_OBJECT_TYPE_SPECIAL:         
5181                         if(S_ISFIFO(obj->st_mode)) return DT_FIFO;
5182                         if(S_ISCHR(obj->st_mode)) return DT_CHR;
5183                         if(S_ISBLK(obj->st_mode)) return DT_BLK;
5184                         if(S_ISSOCK(obj->st_mode)) return DT_SOCK;
5185                 default: return DT_REG; break;
5186         }
5187 }
5188
5189 YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
5190 {
5191         obj = yaffs_GetEquivalentObject(obj);
5192         if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
5193         {
5194                 return yaffs_CloneString(obj->variant.symLinkVariant.alias);
5195         }
5196         else
5197         {
5198                 return yaffs_CloneString(_Y(""));
5199         }
5200 }
5201
5202 #ifndef CONFIG_YAFFS_WINCE
5203
5204 int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
5205 {
5206         unsigned int valid = attr->ia_valid;
5207         
5208         if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
5209         if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
5210         if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
5211         
5212         if(valid & ATTR_ATIME) obj->st_atime = Y_TIME_CONVERT(attr->ia_atime);
5213         if(valid & ATTR_CTIME) obj->st_ctime = Y_TIME_CONVERT(attr->ia_ctime);
5214         if(valid & ATTR_MTIME) obj->st_mtime = Y_TIME_CONVERT(attr->ia_mtime);
5215         
5216         if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
5217         
5218         yaffs_UpdateObjectHeader(obj,NULL,1,0);
5219         
5220         return YAFFS_OK;
5221         
5222 }
5223 int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
5224 {
5225         unsigned int valid = 0;
5226         
5227         attr->ia_mode = obj->st_mode;   valid |= ATTR_MODE;
5228         attr->ia_uid = obj->st_uid;             valid |= ATTR_UID;
5229         attr->ia_gid = obj->st_gid;             valid |= ATTR_GID;
5230         
5231         Y_TIME_CONVERT(attr->ia_atime)= obj->st_atime;  valid |= ATTR_ATIME;
5232         Y_TIME_CONVERT(attr->ia_ctime) = obj->st_ctime; valid |= ATTR_CTIME;
5233         Y_TIME_CONVERT(attr->ia_mtime) = obj->st_mtime; valid |= ATTR_MTIME;
5234
5235         attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
5236         
5237         attr->ia_valid = valid;
5238         
5239         return YAFFS_OK;
5240         
5241 }
5242
5243 #endif
5244
5245 int yaffs_DumpObject(yaffs_Object *obj)
5246 {
5247 //      __u8 buffer[YAFFS_BYTES_PER_CHUNK];
5248         YCHAR name[257];
5249 //      yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
5250
5251 //      memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
5252         
5253 //      if(obj->chunkId >= 0)
5254 //      {
5255 //              yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
5256 //      }
5257         
5258         yaffs_GetObjectName(obj,name,256);
5259         
5260         T(YAFFS_TRACE_ALWAYS,(TSTR("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n" TENDSTR),
5261                         obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, 
5262                         obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
5263
5264 #if 0
5265         YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
5266                         obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial, 
5267                         obj->sum, obj->chunkId));
5268                 switch(obj->variantType)
5269         {
5270                 case YAFFS_OBJECT_TYPE_FILE: 
5271                         YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
5272                         break;
5273                 case YAFFS_OBJECT_TYPE_DIRECTORY:
5274                         YPRINTF((" DIRECTORY\n"));
5275                         break;
5276                 case YAFFS_OBJECT_TYPE_HARDLINK: //todo
5277                 case YAFFS_OBJECT_TYPE_SYMLINK:
5278                 case YAFFS_OBJECT_TYPE_UNKNOWN:
5279                 default:
5280         }
5281 #endif
5282         
5283         return YAFFS_OK;
5284 }
5285
5286
5287 ///////////////////////// Initialisation code ///////////////////////////
5288
5289
5290 int yaffs_CheckDevFunctions(const yaffs_Device *dev)
5291 {
5292
5293         // Common functions, gotta have
5294         if(!dev->eraseBlockInNAND ||
5295            !dev->initialiseNAND) return 0;
5296
5297 #ifdef CONFIG_YAFFS_YAFFS2
5298
5299         // Can use the "with tags" style interface for yaffs1 or yaffs2
5300         if(dev->writeChunkWithTagsToNAND &&
5301            dev->readChunkWithTagsFromNAND &&
5302            !dev->writeChunkToNAND &&
5303            !dev->readChunkFromNAND &&
5304            dev->markNANDBlockBad &&
5305            dev->queryNANDBlock) return 1;
5306 #endif
5307
5308         // Can use the "spare" style interface for yaffs1
5309         if(!dev->isYaffs2 &&
5310            !dev->writeChunkWithTagsToNAND &&
5311            !dev->readChunkWithTagsFromNAND &&
5312            dev->writeChunkToNAND &&
5313            dev->readChunkFromNAND &&
5314            !dev->markNANDBlockBad &&
5315            !dev->queryNANDBlock) return 1;
5316
5317         return 0; // bad
5318 }
5319
5320
5321 int yaffs_GutsInitialise(yaffs_Device *dev)
5322 {
5323         unsigned x;
5324         int bits;
5325         int extraBits;
5326         int nBlocks;
5327
5328         T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
5329         // Check stuff that must be set
5330
5331         if(!dev)
5332         {
5333                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Need a device" TENDSTR)));
5334                 return YAFFS_FAIL;
5335         }
5336
5337         // Check geometry parameters.
5338
5339         if(     (dev->isYaffs2 && dev->nBytesPerChunk <1024)  ||
5340                 (!dev->isYaffs2 && dev->nBytesPerChunk !=512)  ||
5341                 dev->nChunksPerBlock < 2 ||
5342                 dev->nReservedBlocks < 2 ||
5343                 dev->startBlock <= 0 ||
5344                 dev->endBlock <= 0 ||
5345                 dev->endBlock <= (dev->startBlock + dev->nReservedBlocks + 2) // otherwise it is too small
5346           )
5347         {
5348                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " TENDSTR),
5349                    dev->nBytesPerChunk, dev->isYaffs2 ? "2" : ""));
5350                 return YAFFS_FAIL;
5351         }
5352
5353         if(yaffs_InitialiseNAND(dev) != YAFFS_OK)
5354         {
5355                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
5356                 return YAFFS_FAIL;
5357         }
5358
5359         // Got the right mix of functions?
5360         //
5361         if(!yaffs_CheckDevFunctions(dev))
5362         {
5363                 //Function missing
5364                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device function(s) missing or wrong\n" TENDSTR)));
5365
5366                 return YAFFS_FAIL;
5367         }
5368
5369         // This is really a compilation check.
5370         if(!yaffs_CheckStructures())
5371         {
5372                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
5373                 return YAFFS_FAIL;
5374         }
5375
5376         if(dev->isMounted)
5377         {
5378                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device already mounted\n" TENDSTR)));
5379                 return YAFFS_FAIL;
5380         }
5381
5382         //
5383         //
5384         // Finished with most checks. One or two more checks happen later on too.
5385         //
5386
5387         dev->isMounted = 1;
5388
5389
5390         nBlocks = dev->endBlock - dev->startBlock + 1;
5391
5392
5393
5394         // OK now calculate a few things for the device
5395         // Calculate chunkGroupBits.
5396         // We need to find the next power of 2 > than endBlock
5397         
5398         x = dev->nChunksPerBlock * (dev->endBlock+1);
5399         
5400         for(bits = extraBits = 0; x > 1; bits++)
5401         {
5402                 if(x & 1) extraBits++;
5403                 x >>= 1;
5404         }
5405
5406         if(extraBits > 0) bits++;
5407         
5408         
5409         // Level0 Tnodes are 16 bits, so if the bitwidth of the
5410         // chunk range we're using is greater than 16 we need
5411         // to figure out chunk shift and chunkGroupSize
5412         if(bits <= 16) 
5413         {
5414                 dev->chunkGroupBits = 0;
5415         }
5416         else
5417         {
5418                 dev->chunkGroupBits = bits - 16;
5419         }
5420         
5421         dev->chunkGroupSize = 1 << dev->chunkGroupBits;
5422
5423         if(dev->nChunksPerBlock < dev->chunkGroupSize)
5424         {
5425                 // We have a problem because the soft delete won't work if
5426                 // the chunk group size > chunks per block.
5427                 // This can be remedied by using larger "virtual blocks".
5428                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: chunk group too large\n" TENDSTR)));
5429                 
5430                 return YAFFS_FAIL;
5431         }
5432
5433         
5434         // OK, we've finished verifying the device, lets continue with initialisation
5435         
5436         // More device initialisation
5437         dev->garbageCollections = 0;
5438         dev->passiveGarbageCollections = 0;
5439         dev->currentDirtyChecker = 0;
5440         dev->bufferedBlock = -1;
5441         dev->doingBufferedBlockRewrite = 0;
5442         dev->nDeletedFiles = 0;
5443         dev->nBackgroundDeletions=0;
5444         dev->nUnlinkedFiles = 0;
5445         dev->eccFixed=0;
5446         dev->eccUnfixed=0;
5447         dev->tagsEccFixed=0;
5448         dev->tagsEccUnfixed=0;
5449         dev->nErasureFailures = 0;
5450         
5451         //dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
5452         // Initialise temporary buffers
5453         {
5454                 int i;
5455                 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
5456                 {
5457                         dev->tempBuffer[i].line = 0; // not in use
5458                         dev->tempBuffer[i].buffer = YMALLOC(dev->nBytesPerChunk);
5459                 }
5460         }
5461         
5462
5463         
5464         yaffs_InitialiseBlocks(dev,nBlocks);
5465         
5466         yaffs_InitialiseTnodes(dev);
5467
5468         yaffs_InitialiseObjects(dev);
5469         
5470         dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
5471         
5472         if(dev->nShortOpCaches > 0)
5473         { 
5474                 int i;
5475                 
5476                 if(dev->nShortOpCaches >  YAFFS_MAX_SHORT_OP_CACHES)
5477                 {
5478                         dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
5479                 }
5480                 
5481                 dev->srCache = YMALLOC( dev->nShortOpCaches * sizeof(yaffs_ChunkCache));
5482                 
5483                 for(i=0; i < dev->nShortOpCaches; i++)
5484                 {
5485                         dev->srCache[i].object = NULL;
5486                         dev->srCache[i].lastUse = 0;
5487                         dev->srCache[i].dirty = 0;
5488                         dev->srCache[i].data = YMALLOC(dev->nBytesPerChunk);
5489                 }
5490                 dev->srLastUse = 0;
5491         }
5492
5493         dev->cacheHits = 0;
5494         
5495         
5496         // Initialise the unlinked, root and lost and found directories
5497         dev->lostNFoundDir = dev->rootDir = dev->unlinkedDir = dev->deletedDir = NULL;
5498         
5499         dev->unlinkedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
5500         dev->deletedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
5501
5502         dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
5503         dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_LOSTNFOUND_MODE | S_IFDIR);
5504         yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
5505         
5506         if(dev->isYaffs2) 
5507         {
5508                 dev->useHeaderFileSize = 1;
5509         }
5510                 
5511         // Now scan the flash.  
5512         yaffs_Scan(dev);
5513         
5514         // Zero out stats
5515         dev->nPageReads = 0;
5516     dev->nPageWrites =  0;
5517         dev->nBlockErasures = 0;
5518         dev->nGCCopies = 0;
5519         dev->nRetriedWrites = 0;
5520
5521         dev->nRetiredBlocks = 0;
5522
5523         T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
5524         return YAFFS_OK;
5525                 
5526 }
5527
5528 void yaffs_Deinitialise(yaffs_Device *dev)
5529 {
5530         if(dev->isMounted)
5531         {
5532                 int i;
5533         
5534                 yaffs_DeinitialiseBlocks(dev);
5535                 yaffs_DeinitialiseTnodes(dev);
5536                 yaffs_DeinitialiseObjects(dev);
5537                 if(dev->nShortOpCaches > 0)
5538                 {
5539                                 
5540                         for(i=0; i < dev->nShortOpCaches; i++)
5541                         {
5542                                 YFREE(dev->srCache[i].data);
5543                         }
5544
5545                         YFREE(dev->srCache);
5546                 }
5547
5548                 YFREE(dev->gcCleanupList);
5549
5550                 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
5551                 {
5552                         YFREE(dev->tempBuffer[i].buffer);
5553                 }
5554                 
5555                 dev->isMounted = 0;
5556         }
5557         
5558 }
5559
5560 #if 0
5561
5562 int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
5563 {
5564         int nFree = dev->nFreeChunks - (dev->nChunksPerBlock * YAFFS_RESERVED_BLOCKS);
5565         
5566         struct list_head *i;    
5567         yaffs_Object *l;
5568         
5569         
5570         // To the free chunks add the chunks that are in the deleted unlinked files.
5571         list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
5572         {
5573                 l = list_entry(i, yaffs_Object,siblings);
5574                 if(l->deleted)
5575                 {
5576                         nFree++;
5577                         nFree += l->nDataChunks;
5578                 }
5579         }
5580         
5581         
5582         // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);        
5583
5584         if(nFree < 0) nFree = 0;
5585
5586         return nFree;   
5587         
5588 }
5589
5590 #endif
5591
5592 int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
5593 {
5594         int nFree;
5595         int pending;
5596         int b;
5597         int nDirtyCacheChunks=0;
5598         
5599         yaffs_BlockInfo *blk;
5600         
5601         struct list_head *i;    
5602         yaffs_Object *l;
5603         
5604         for(nFree = 0, b = dev->startBlock; b <= dev->endBlock; b++)
5605         {
5606                 blk = yaffs_GetBlockInfo(dev,b);
5607                 
5608                 switch(blk->blockState)
5609                 {
5610                         case YAFFS_BLOCK_STATE_EMPTY:
5611                         case YAFFS_BLOCK_STATE_ALLOCATING: 
5612                         case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break;
5613                         default: break;
5614                 }
5615         }
5616         
5617         
5618         pending = 0;
5619         
5620         // To the free chunks add the chunks that are in the deleted unlinked files.
5621         list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
5622         {
5623                 if(i)
5624                 {
5625                         l = list_entry(i, yaffs_Object,siblings);
5626                         if(l->deleted)
5627                         {
5628                                 pending++;
5629                                 pending += l->nDataChunks;
5630                         }
5631                 }
5632         }
5633         
5634         
5635         
5636         //printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending);
5637         
5638         if(nFree != dev->nFreeChunks) 
5639         {
5640         //      printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks);
5641         }
5642
5643         nFree += pending;
5644         
5645         // Now count the number of dirty chunks in the cache and subtract those
5646         
5647         {
5648                 int i;
5649                 for(i = 0; i < dev->nShortOpCaches; i++)
5650                 {
5651                         if(dev->srCache[i].dirty) nDirtyCacheChunks++;
5652                 }
5653         }
5654         
5655         nFree -= nDirtyCacheChunks;
5656         
5657         nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
5658         
5659         if(nFree < 0) nFree = 0;
5660
5661         return nFree;   
5662         
5663 }
5664
5665
5666
5667 /////////////////// YAFFS test code //////////////////////////////////
5668
5669 #define yaffs_CheckStruct(structure,syze, name) \
5670            if(sizeof(structure) != syze) \
5671                { \
5672                  T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),name,syze,sizeof(structure))); \
5673                  return YAFFS_FAIL; \
5674                    }
5675                  
5676                  
5677 static int yaffs_CheckStructures(void)
5678 {
5679 //      yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
5680 //      yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
5681 //      yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
5682 #ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
5683         yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
5684 #endif
5685         yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
5686         
5687         
5688         return YAFFS_OK;
5689 }
5690
5691 #if 0
5692 void yaffs_GutsTest(yaffs_Device *dev)
5693 {
5694         
5695         if(yaffs_CheckStructures() != YAFFS_OK)
5696         {
5697                 T(YAFFS_TRACE_ALWAYS,(TSTR("One or more structures malformed-- aborting\n" TENDSTR)));
5698                 return;
5699         }
5700         
5701         yaffs_TnodeTest(dev);
5702         yaffs_ObjectTest(dev);  
5703 }
5704 #endif
5705
5706