Add patches from Nick Banes for compatability
[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&n