*** empty log message ***
[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.4 2004-12-17 04:39:04 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         dev->readChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
493         
494         if(!yaffs_CheckFF(data,dev->nBytesPerChunk) || tags.chunkUsed)
495         {
496                 T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not erased" TENDSTR),chunkInNAND));
497                 retval = YAFFS_FAIL;
498         }
499
500         yaffs_ReleaseTempBuffer(dev,data,__LINE__);
501         
502         return retval;
503         
504 }
505
506
507
508 #if 1
509 static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_ExtendedTags *tags,int useReserve)
510 {
511         int chunk;
512         
513         int writeOk = 1;
514         int attempts = 0;
515         
516
517         
518         do{
519                 chunk = yaffs_AllocateChunk(dev,useReserve);
520         
521                 if(chunk >= 0)
522                 {
523
524                         // First check this chunk is erased...
525 #ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
526                         writeOk = yaffs_CheckChunkErased(dev,chunk);
527 #endif          
528                         if(!writeOk)
529                         {
530                                 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));
531                         }
532                         else
533                         {
534                                 writeOk =  yaffs_WriteChunkWithTagsToNAND(dev,chunk,data,tags);
535                         }
536                         attempts++;
537
538                         if(writeOk)
539                         {
540                                 // Copy the data into the robustification buffer.
541                                 // NB We do this at the end to prevent duplicates in the case of a write error.
542                                 //Todo
543                                 yaffs_HandleWriteChunkOk(dev,chunk,data,tags);
544                         }
545                         else
546                         {
547                                 yaffs_HandleWriteChunkError(dev,chunk);
548                         }
549                 }
550                 
551         } while(chunk >= 0 && ! writeOk);
552         
553         if(attempts > 1)
554         {
555                 T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));
556                 dev->nRetriedWrites+= (attempts - 1);   
557         }
558         
559
560         
561         return chunk;
562 }
563 #endif
564
565
566 ///
567 // Functions for robustisizing
568 //
569 //
570
571 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
572 {
573         
574         yaffs_MarkBlockBad(dev,blockInNAND);
575         
576         yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
577
578         dev->nRetiredBlocks++;
579 }
580
581
582
583 static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
584 {
585         dev->doingBufferedBlockRewrite = 1;
586         //
587         //      Remove erased chunks
588         //  Rewrite existing chunks to a new block
589         //      Set current write block to the new block
590         
591         dev->doingBufferedBlockRewrite = 0;
592         
593         return 1;
594 }
595
596
597 static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
598 {
599         int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
600
601         // Mark the block for retirement
602         yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
603         T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));
604
605
606         //TODO  
607         // Just do a garbage collection on the affected block then retire the block
608         // NB recursion
609 }
610
611
612 static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
613 {
614 }
615
616 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
617 {
618 }
619
620 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_ExtendedTags *tags)
621 {
622 }
623
624 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
625 {
626         int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
627
628         // Mark the block for retirement
629         yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
630         // Delete the chunk
631         yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
632 }
633
634
635
636 #if 0
637 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize)
638 {
639
640
641         if( memcmp(d0,d1,dataSize) != 0 ||
642                 s0->tagByte0 != s1->tagByte0 ||
643                 s0->tagByte1 != s1->tagByte1 ||
644                 s0->tagByte2 != s1->tagByte2 ||
645                 s0->tagByte3 != s1->tagByte3 ||
646                 s0->tagByte4 != s1->tagByte4 ||
647                 s0->tagByte5 != s1->tagByte5 ||
648                 s0->tagByte6 != s1->tagByte6 ||
649                 s0->tagByte7 != s1->tagByte7 ||
650                 s0->ecc1[0]  != s1->ecc1[0]  ||
651                 s0->ecc1[1]  != s1->ecc1[1]  ||
652                 s0->ecc1[2]  != s1->ecc1[2]  ||
653                 s0->ecc2[0]  != s1->ecc2[0]  ||
654                 s0->ecc2[1]  != s1->ecc2[1]  ||
655                 s0->ecc2[2]  != s1->ecc2[2] )
656                 {
657                         return 0;
658                 }
659         
660         return 1;
661 }
662 #endif
663
664
665 ///////////////////////// Object management //////////////////
666 // List of spare objects
667 // The list is hooked together using the first pointer
668 // in the object
669
670 // static yaffs_Object *yaffs_freeObjects = NULL;
671
672 // static int yaffs_nFreeObjects;
673
674 // static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
675
676 // static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
677
678
679 static __u16 yaffs_CalcNameSum(const YCHAR *name)
680 {
681         __u16 sum = 0;
682         __u16 i = 1;
683         
684         YUCHAR *bname = (YUCHAR *)name;
685         if(bname)
686         {
687                 while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH))
688                 {
689
690 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
691                         sum += yaffs_toupper(*bname) * i;
692 #else
693                         sum += (*bname) * i;
694 #endif
695                         i++;
696                         bname++;
697                 }
698         }
699         return sum;
700 }
701
702 void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
703 {
704 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
705                                         if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
706                                         {
707                                                 yaffs_strcpy(obj->shortName,name);
708                                         }
709                                         else
710                                         {
711                                                 obj->shortName[0]=_Y('\0');
712                                         }
713 #endif
714                                         obj->sum = yaffs_CalcNameSum(name);
715 }
716
717 #if 0
718 void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
719 {
720         yaffs_ECCCalculate(data , spare->ecc1);
721         yaffs_ECCCalculate(&data[256] , spare->ecc2);
722 }
723 #endif
724
725
726 ///////////////////////// TNODES ///////////////////////
727
728 // List of spare tnodes
729 // The list is hooked together using the first pointer
730 // in the tnode.
731
732 //static yaffs_Tnode *yaffs_freeTnodes = NULL;
733
734 // static int yaffs_nFreeTnodes;
735
736 //static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
737
738
739
740 // yaffs_CreateTnodes creates a bunch more tnodes and
741 // adds them to the tnode free list.
742 // Don't use this function directly
743
744 static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
745 {
746     int i;
747     yaffs_Tnode *newTnodes;
748     yaffs_TnodeList *tnl;
749     
750     if(nTnodes < 1) return YAFFS_OK;
751    
752         // make these things
753         
754     newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
755    
756     if (!newTnodes)
757     {
758                 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not allocate Tnodes"TENDSTR)));
759                 return YAFFS_FAIL;
760     }
761     
762     // Hook them into the free list
763     for(i = 0; i < nTnodes - 1; i++)
764     {
765         newTnodes[i].internal[0] = &newTnodes[i+1];
766 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
767         newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = 1;
768 #endif
769     }
770         
771         newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
772 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
773         newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = 1;
774 #endif
775         dev->freeTnodes = newTnodes;
776         dev->nFreeTnodes+= nTnodes;
777         dev->nTnodesCreated += nTnodes;
778
779         // Now add this bunch of tnodes to a list for freeing up.
780         // NB If we can't add this to the management list it isn't fatal
781         // but it just means we can't free this bunch of tnodes later.
782         tnl = YMALLOC(sizeof(yaffs_TnodeList));
783         if(!tnl)
784         {
785                 T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not add tnodes to management list" TENDSTR)));
786                 
787         }
788         else
789         {
790                 tnl->tnodes = newTnodes;
791                 tnl->next = dev->allocatedTnodeList;
792                 dev->allocatedTnodeList = tnl;
793         }
794
795
796         T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Tnodes added" TENDSTR)));
797
798
799         return YAFFS_OK;
800 }
801
802
803 // GetTnode gets us a clean tnode. Tries to make allocate more if we run out
804 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
805 {
806         yaffs_Tnode *tn = NULL;
807         
808         // If there are none left make more
809         if(!dev->freeTnodes)
810         {
811                 yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
812         }
813         
814         if(dev->freeTnodes)
815         {
816                 tn = dev->freeTnodes;
817 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
818         if(tn->internal[YAFFS_NTNODES_INTERNAL] != 1)
819                 {
820                         // Hoosterman, this thing looks like it isn't in the list
821                                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
822                 }
823 #endif
824                 dev->freeTnodes = dev->freeTnodes->internal[0];
825                 dev->nFreeTnodes--;
826                 // zero out
827                 memset(tn,0,sizeof(yaffs_Tnode));
828         }
829         
830
831         return tn;
832 }
833
834
835 // FreeTnode frees up a tnode and puts it back on the free list
836 static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
837 {
838         if(tn)
839         {
840 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
841         if(tn->internal[YAFFS_NTNODES_INTERNAL] != 0)
842                 {
843                         // Hoosterman, this thing looks like it is already in the list
844                                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
845                 }
846                 tn->internal[YAFFS_NTNODES_INTERNAL] = 1;
847 #endif
848                 tn->internal[0] = dev->freeTnodes;
849                 dev->freeTnodes = tn;
850                 dev->nFreeTnodes++;
851         }
852 }
853
854
855 static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
856 {
857         // Free the list of allocated tnodes
858         yaffs_TnodeList *tmp;
859                 
860         while(dev->allocatedTnodeList)
861         {
862                 tmp =  dev->allocatedTnodeList->next;
863
864                 YFREE(dev->allocatedTnodeList->tnodes);
865                 YFREE(dev->allocatedTnodeList);
866                 dev->allocatedTnodeList = tmp;
867                 
868         }
869         
870         dev->freeTnodes = NULL;
871         dev->nFreeTnodes = 0;
872 }
873
874 static void yaffs_InitialiseTnodes(yaffs_Device*dev)
875 {
876         dev->allocatedTnodeList = NULL;
877         dev->freeTnodes = NULL;
878         dev->nFreeTnodes = 0;
879         dev->nTnodesCreated = 0;
880
881 }
882
883 #if 0
884 void yaffs_TnodeTest(yaffs_Device *dev)
885 {
886
887         int i;
888         int j;
889         yaffs_Tnode *tn[1000];
890         
891         YINFO("Testing TNodes");
892         
893         for(j = 0; j < 50; j++)
894         {
895                 for(i = 0; i < 1000; i++)
896                 {
897                         tn[i] = yaffs_GetTnode(dev);
898                         if(!tn[i])
899                         {
900                                 YALERT("Getting tnode failed");
901                         }
902                 }
903                 for(i = 0; i < 1000; i+=3)
904                 {
905                         yaffs_FreeTnode(dev,tn[i]);
906                         tn[i] = NULL;
907                 }
908                 
909         }
910 }
911 #endif
912
913
914 ////////////////// END OF TNODE MANIPULATION ///////////////////////////
915
916 /////////////// Functions to manipulate the look-up tree (made up of tnodes)
917 // The look up tree is represented by the top tnode and the number of topLevel
918 // in the tree. 0 means only the level 0 tnode is in the tree.
919
920
921 // FindLevel0Tnode finds the level 0 tnode, if one exists.
922 // Used when reading.....
923 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure *fStruct, __u32 chunkId)
924 {
925         
926         yaffs_Tnode *tn = fStruct->top;
927         __u32 i;
928         int requiredTallness;   
929         int level = fStruct->topLevel;
930         
931         // Check sane level and chunk Id
932         if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
933         {
934 //              char str[50];
935 //              sprintf(str,"Bad level %d",level);
936 //              YALERT(str);
937                 return NULL;
938         }
939         
940         if(chunkId > YAFFS_MAX_CHUNK_ID)
941         {
942 //              char str[50];
943 //              sprintf(str,"Bad chunkId %d",chunkId);
944 //              YALERT(str);
945                 return NULL;
946         }
947
948         // First check we're tall enough (ie enough topLevel)
949         
950         i = chunkId >> (/*dev->chunkGroupBits  + */YAFFS_TNODES_LEVEL0_BITS);
951         requiredTallness = 0;
952         while(i)
953         {
954                 i >>= YAFFS_TNODES_INTERNAL_BITS;
955                 requiredTallness++;
956         }
957         
958         
959         if(requiredTallness > fStruct->topLevel)
960         {
961                 // Not tall enough, so we can't find it, return NULL.
962                 return NULL;
963         }
964                 
965         
966         // Traverse down to level 0
967         while (level > 0 && tn)
968         {
969             tn = tn->internal[(chunkId >>(/* dev->chunkGroupBits + */ YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
970                                YAFFS_TNODES_INTERNAL_MASK]; 
971                 level--;
972         
973         }
974         
975         return tn;              
976 }
977
978 // AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
979 // This happens in two steps:
980 //  1. If the tree isn't tall enough, then make it taller.
981 //  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
982 //
983 // Used when modifying the tree.
984 //
985 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
986 {
987         
988         yaffs_Tnode *tn; 
989         
990         int requiredTallness;
991         int i;
992         int l;
993         
994         __u32 x;
995                 
996         
997         //T((TSTR("AddOrFind topLevel=%d, chunk=%d"),fStruct->topLevel,chunkId));
998         
999         // Check sane level and page Id
1000         if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
1001         {
1002 //              char str[50];
1003 //              sprintf(str,"Bad level %d",fStruct->topLevel);
1004 //              YALERT(str);
1005                 return NULL;
1006         }
1007         
1008         if(chunkId > YAFFS_MAX_CHUNK_ID)
1009         {
1010 //              char str[50];
1011 //              sprintf(str,"Bad chunkId %d",chunkId);
1012 //              YALERT(str);
1013                 return NULL;
1014         }
1015         
1016         // First check we're tall enough (ie enough topLevel)
1017         
1018         x = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
1019         requiredTallness = 0;
1020         while(x)
1021         {
1022                 x >>= YAFFS_TNODES_INTERNAL_BITS;
1023                 requiredTallness++;
1024         }
1025         
1026         //T((TSTR(" required=%d"),requiredTallness));
1027         
1028         
1029         if(requiredTallness > fStruct->topLevel)
1030         {
1031                 // Not tall enough,gotta make the tree taller
1032                 for(i = fStruct->topLevel; i < requiredTallness; i++)
1033                 {
1034                         //T((TSTR(" add new top")));
1035                         
1036                         tn = yaffs_GetTnode(dev);
1037                         
1038                         if(tn)
1039                         {
1040                                 tn->internal[0] = fStruct->top;
1041                                 fStruct->top = tn;
1042                         }
1043                         else
1044                         {
1045                                         T(YAFFS_TRACE_ERROR,(TSTR("yaffs: no more tnodes" TENDSTR)));
1046                         }
1047                 }
1048                 
1049                 fStruct->topLevel = requiredTallness;
1050         }
1051         
1052         
1053         // Traverse down to level 0, adding anything we need
1054         
1055         l = fStruct->topLevel;
1056         tn = fStruct->top;
1057         while (l > 0 && tn)
1058         {
1059                 x = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
1060                                YAFFS_TNODES_INTERNAL_MASK;
1061                                
1062                 //T((TSTR(" [%d:%d]"),l,i));
1063                 
1064             if(!tn->internal[x])
1065             {
1066                 //T((TSTR(" added")));
1067                 
1068                 tn->internal[x] = yaffs_GetTnode(dev);
1069             }
1070             
1071             tn =        tn->internal[x];
1072                 l--;
1073         
1074         }
1075         
1076         //TSTR(TENDSTR)));
1077         
1078         return tn;              
1079 }
1080
1081
1082 int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
1083 {
1084         int j;
1085         
1086                                         
1087         for(j = 0; theChunk && j < dev->chunkGroupSize; j++)
1088         {
1089                 if(yaffs_CheckChunkBit(dev,theChunk / dev->nChunksPerBlock,theChunk % dev->nChunksPerBlock))
1090                 {
1091                         yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL,tags);
1092                         if(yaffs_TagsMatch(tags,objectId,chunkInInode))
1093                         {
1094                                 // found it;
1095                                 return theChunk;
1096                                         
1097                         }
1098                 }
1099                 theChunk++;
1100         }
1101         return -1;
1102 }
1103
1104 // DeleteWorker scans backwards through the tnode tree and deletes all the
1105 // chunks and tnodes in the file
1106 // Returns 1 if the tree was deleted. Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
1107
1108 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
1109 {
1110         int i;
1111         int chunkInInode;
1112         int theChunk;
1113         yaffs_ExtendedTags tags;
1114         int foundChunk;
1115         yaffs_Device *dev = in->myDev;
1116
1117         int allDone = 1;
1118         
1119         
1120         if(tn)
1121         {
1122                 if(level > 0)
1123                 {
1124                 
1125                         for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
1126                         {
1127                             if(tn->internal[i])
1128                         {
1129                                         if(limit && (*limit) < 0)
1130                                         {
1131                                                 allDone = 0;
1132                                         }
1133                                         else
1134                                         {
1135                                                 allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,
1136                                                                                 (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);
1137                                         }
1138                                         if(allDone)
1139                                         {
1140                                                 yaffs_FreeTnode(dev,tn->internal[i]);
1141                                         tn->internal[i] = NULL;
1142                                         }
1143                             }
1144                     
1145                         }
1146                         return (allDone) ? 1 : 0;
1147                 }
1148                 else if(level == 0)
1149                 {
1150                         int hitLimit = 0;
1151                         
1152                         for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0 && !hitLimit; i--)
1153                         {
1154                             if(tn->level0[i])
1155                         {
1156                                         
1157                                         chunkInInode = (chunkOffset << YAFFS_TNODES_LEVEL0_BITS ) + i;
1158                                         
1159                                         theChunk =  tn->level0[i] << dev->chunkGroupBits;
1160                                         
1161                                         foundChunk = yaffs_FindChunkInGroup(dev,theChunk,&tags,in->objectId,chunkInInode);
1162                                         
1163                                         if(foundChunk > 0)
1164                                         {
1165                                                 yaffs_DeleteChunk(dev,foundChunk,1,__LINE__);
1166                                                 in->nDataChunks--;
1167                                                 if(limit)
1168                                                 { 
1169                                                         *limit = *limit-1;
1170                                                         if(*limit <= 0) 
1171                                                         { 
1172                                                                 hitLimit = 1;
1173                                                         }
1174                                                 }
1175                                         
1176                                         }
1177                                         
1178                                 tn->level0[i] = 0;
1179                             }
1180                     
1181                         }
1182                         return (i < 0) ? 1 : 0;
1183
1184                         
1185                 }
1186                 
1187         }
1188         
1189         return 1;
1190         
1191 }
1192
1193
1194 static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
1195 {
1196
1197         yaffs_BlockInfo *theBlock;                                      
1198         
1199         T(YAFFS_TRACE_DELETION,(TSTR("soft delete chunk %d" TENDSTR),chunk));
1200                                                 
1201         theBlock =      yaffs_GetBlockInfo(dev,  chunk/dev->nChunksPerBlock);
1202         if(theBlock)
1203         {
1204                 theBlock->softDeletions++;
1205         }
1206 }
1207
1208 // SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
1209 // All soft deleting does is increment the block's softdelete count and pulls the chunk out
1210 // of the tnode.
1211 // THus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
1212 //
1213 static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset)
1214 {
1215         int i;
1216         int theChunk;
1217         int allDone = 1;
1218         yaffs_Device *dev = in->myDev;
1219         
1220         
1221         if(tn)
1222         {
1223                 if(level > 0)
1224                 {
1225                 
1226                         for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
1227                         {
1228                             if(tn->internal[i])
1229                         {
1230                                                 allDone = yaffs_SoftDeleteWorker(in,tn->internal[i],level - 1,
1231                                                                                 (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i);
1232                                         if(allDone)
1233                                         {
1234                                                 yaffs_FreeTnode(dev,tn->internal[i]);
1235                                         tn->internal[i] = NULL;
1236                                         }
1237                                         else
1238                                         {
1239                                                 //Hoosterman... how could this happen.
1240                                         }                           
1241                                 }                   
1242                         }
1243                         return (allDone) ? 1 : 0;
1244                 }
1245                 else if(level == 0)
1246                 {
1247                         
1248                         for(i = YAFFS_NTNODES_LEVEL0 -1; i >=0; i--)
1249                         {
1250                             if(tn->level0[i])
1251                         {
1252                                         // Note this does not find the real chunk, only the chunk group.
1253                                         // We make an assumption that a chunk group is niot larger than a block.
1254                                         theChunk =  (tn->level0[i] << dev->chunkGroupBits);
1255                                         
1256                                         yaffs_SoftDeleteChunk(dev,theChunk);
1257                                 tn->level0[i] = 0;
1258                             }
1259                     
1260                         }
1261                         return 1;
1262                         
1263                 }
1264                 
1265         }
1266         
1267         return 1;
1268                 
1269 }
1270
1271
1272
1273 static void yaffs_SoftDeleteFile(yaffs_Object *obj)
1274 {
1275         if(obj->deleted &&
1276            obj->variantType == YAFFS_OBJECT_TYPE_FILE &&
1277            !obj->softDeleted)
1278         {
1279                 if(obj->nDataChunks <= 0)
1280                 {
1281                                 // Empty file with no duplicate object headers, just delete it immediately
1282                                 yaffs_FreeTnode(obj->myDev,obj->variant.fileVariant.top);
1283                                 obj->variant.fileVariant.top = NULL;
1284                                 T(YAFFS_TRACE_TRACING,(TSTR("yaffs: Deleting empty file %d" TENDSTR),obj->objectId));
1285                                 yaffs_DoGenericObjectDeletion(obj);     
1286                 }
1287                 else
1288                 {
1289                         yaffs_SoftDeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0);
1290                         obj->softDeleted = 1;
1291                 }
1292         }
1293 }
1294
1295
1296
1297
1298
1299 // Pruning removes any part of the file structure tree that is beyond the
1300 // bounds of the file (ie that does not point to chunks).
1301 //
1302 // A file should only get pruned when its size is reduced.
1303 //
1304 // Before pruning, the chunks must be pulled from the tree and the
1305 // level 0 tnode entries must be zeroed out.
1306 // Could also use this for file deletion, but that's probably better handled
1307 // by a special case.
1308
1309 // yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
1310
1311 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
1312 {
1313         int i;
1314         int hasData;
1315         
1316         if(tn)
1317         {
1318                 hasData = 0;
1319                 
1320                 for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
1321                 {
1322                     if(tn->internal[i] && level > 0)
1323                     {
1324                         tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
1325                     }
1326                     
1327                     if(tn->internal[i])
1328                     {
1329                         hasData++;
1330                         }
1331                 }
1332                 
1333                 if(hasData == 0 && del0)
1334                 {
1335                         // Free and return NULL
1336                         
1337                         yaffs_FreeTnode(dev,tn);
1338                         tn = NULL;
1339                 }
1340                 
1341         }
1342
1343         return tn;
1344         
1345 }
1346
1347 static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
1348 {
1349         int i;
1350         int hasData;
1351         int done = 0;
1352         yaffs_Tnode *tn;
1353         
1354         if(fStruct->topLevel > 0)
1355         {
1356                 fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
1357                 
1358                 // Now we have a tree with all the non-zero branches NULL but the height
1359                 // is the same as it was.
1360                 // Let's see if we can trim internal tnodes to shorten the tree.
1361                 // We can do this if only the 0th element in the tnode is in use 
1362                 // (ie all the non-zero are NULL)
1363                 
1364                 while(fStruct->topLevel && !done)
1365                 {
1366                         tn = fStruct->top;
1367                         
1368                         hasData = 0;
1369                         for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
1370                         {
1371                                 if(tn->internal[i])
1372                         {
1373                                 hasData++;
1374                                 }
1375                         }
1376                         
1377                         if(!hasData)
1378                         {
1379                                 fStruct->top = tn->internal[0];
1380                                 fStruct->topLevel--;
1381                                 yaffs_FreeTnode(dev,tn);
1382                         }
1383                         else
1384                         {
1385                                 done = 1;
1386                         }
1387                 }
1388         }
1389         
1390         return YAFFS_OK;
1391 }
1392
1393
1394
1395
1396
1397 /////////////////////// End of File Structure functions. /////////////////
1398
1399 // yaffs_CreateFreeObjects creates a bunch more objects and
1400 // adds them to the object free list.
1401 static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
1402 {
1403     int i;
1404     yaffs_Object *newObjects;
1405     yaffs_ObjectList *list;
1406     
1407     if(nObjects < 1) return YAFFS_OK;
1408    
1409         // make these things
1410         
1411     newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
1412    
1413     if (!newObjects)
1414     {
1415                 T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
1416                 return YAFFS_FAIL;
1417     }
1418     
1419     // Hook them into the free list
1420     for(i = 0; i < nObjects - 1; i++)
1421     {
1422         newObjects[i].siblings.next = (struct list_head *)(&newObjects[i+1]);
1423     }
1424         
1425         newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
1426         dev->freeObjects = newObjects;
1427         dev->nFreeObjects+= nObjects;
1428         dev->nObjectsCreated+= nObjects;
1429         
1430         // Now add this bunch of Objects to a list for freeing up.
1431         
1432         list = YMALLOC(sizeof(yaffs_ObjectList));
1433         if(!list)
1434         {
1435                 T(YAFFS_TRACE_ALLOCATE,(TSTR("Could not add objects to management list" TENDSTR)));
1436         }
1437         else
1438         {
1439                 list->objects = newObjects;
1440                 list->next = dev->allocatedObjectList;
1441                 dev->allocatedObjectList = list;
1442         }
1443         
1444         
1445         
1446         return YAFFS_OK;
1447 }
1448
1449
1450 // AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
1451 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
1452 {
1453         yaffs_Object *tn = NULL;
1454         
1455         // If there are none left make more
1456         if(!dev->freeObjects)
1457         {
1458                 yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
1459         }
1460         
1461         if(dev->freeObjects)
1462         {
1463                 tn = dev->freeObjects;
1464                 dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
1465                 dev->nFreeObjects--;
1466                 
1467                 // Now sweeten it up...
1468         
1469                 memset(tn,0,sizeof(yaffs_Object));
1470                 tn->myDev = dev;
1471                 tn->chunkId = -1;
1472                 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
1473                 INIT_LIST_HEAD(&(tn->hardLinks));
1474                 INIT_LIST_HEAD(&(tn->hashLink));
1475                 INIT_LIST_HEAD(&tn->siblings);
1476                 
1477                 // Add it to the lost and found directory.
1478                 // NB Can't put root or lostNFound in lostNFound so
1479                 // check if lostNFound exists first
1480                 if(dev->lostNFoundDir)
1481                 {
1482                         yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);      
1483                 }
1484         }
1485         
1486
1487         return tn;
1488 }
1489
1490 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
1491 {
1492
1493         yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);              
1494         if(obj)
1495         {
1496                 obj->fake = 1;                  // it is fake so it has no NAND presence...
1497                 obj->renameAllowed= 0;  // ... and we're not allowed to rename it...
1498                 obj->unlinkAllowed= 0;  // ... or unlink it
1499                 obj->deleted = 0;
1500                 obj->unlinked = 0;
1501                 obj->st_mode = mode;
1502                 obj->myDev = dev;
1503                 obj->chunkId = 0; // Not a valid chunk.
1504         }
1505         
1506         return obj;
1507         
1508 }
1509
1510
1511 static void yaffs_UnhashObject(yaffs_Object *tn)
1512 {
1513         int bucket;
1514         yaffs_Device *dev = tn->myDev;
1515         
1516         
1517         // If it is still linked into the bucket list, free from the list
1518         if(!list_empty(&tn->hashLink))
1519         {
1520                 list_del_init(&tn->hashLink);
1521                 bucket =  yaffs_HashFunction(tn->objectId);
1522                 dev->objectBucket[bucket].count--;
1523         }
1524         
1525 }
1526
1527
1528 // FreeObject frees up a Object and puts it back on the free list
1529 static void yaffs_FreeObject(yaffs_Object *tn)
1530 {
1531
1532         yaffs_Device *dev = tn->myDev;
1533         
1534 #ifdef  __KERNEL__
1535         if(tn->myInode)
1536         {
1537                 // We're still hooked up to a cached inode.
1538                 // Don't delete now, but mark for later deletion
1539                 tn->deferedFree = 1;
1540                 return;
1541         }
1542 #endif
1543         
1544         yaffs_UnhashObject(tn);
1545         
1546         // Link into the free list.
1547         tn->siblings.next = (struct list_head *)(dev->freeObjects);
1548         dev->freeObjects = tn;
1549         dev->nFreeObjects++;
1550 }
1551
1552
1553
1554 #ifdef __KERNEL__
1555
1556 void yaffs_HandleDeferedFree(yaffs_Object *obj)
1557 {
1558         if(obj->deferedFree)
1559         {
1560            yaffs_FreeObject(obj);
1561         }
1562 }
1563
1564 #endif
1565
1566
1567
1568 static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
1569 {
1570         // Free the list of allocated Objects
1571         
1572         yaffs_ObjectList *tmp;
1573         
1574         while( dev->allocatedObjectList)
1575         {
1576                 tmp =  dev->allocatedObjectList->next;
1577                 YFREE(dev->allocatedObjectList->objects);
1578                 YFREE(dev->allocatedObjectList);
1579                 
1580                 dev->allocatedObjectList =  tmp;
1581         }
1582         
1583         dev->freeObjects = NULL;
1584         dev->nFreeObjects = 0;
1585 }
1586
1587 static void yaffs_InitialiseObjects(yaffs_Device *dev)
1588 {
1589         int i;
1590         
1591         dev->allocatedObjectList = NULL;
1592         dev->freeObjects = NULL;
1593         dev->nFreeObjects = 0;
1594         
1595         for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
1596         {
1597                 INIT_LIST_HEAD(&dev->objectBucket[i].list);
1598                 dev->objectBucket[i].count = 0; 
1599         }
1600
1601 }
1602
1603
1604
1605
1606
1607
1608 int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
1609 {
1610         static int x = 0;
1611         int i;
1612         int l = 999;
1613         int lowest = 999999;
1614
1615                 
1616         // First let's see if we can find one that's empty.
1617         
1618         for(i = 0; i < 10 && lowest > 0; i++)
1619          {
1620                 x++;
1621                 x %=  YAFFS_NOBJECT_BUCKETS;
1622                 if(dev->objectBucket[x].count < lowest)
1623                 {
1624                         lowest = dev->objectBucket[x].count;
1625                         l = x;
1626                 }
1627                 
1628         }
1629         
1630         // If we didn't find an empty list, then try
1631         // looking a bit further for a short one
1632         
1633         for(i = 0; i < 10 && lowest > 3; i++)
1634          {
1635                 x++;
1636                 x %=  YAFFS_NOBJECT_BUCKETS;
1637                 if(dev->objectBucket[x].count < lowest)
1638                 {
1639                         lowest = dev->objectBucket[x].count;
1640                         l = x;
1641                 }
1642                 
1643         }
1644         
1645         return l;
1646 }
1647
1648 static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
1649 {
1650         int bucket = yaffs_FindNiceObjectBucket(dev);
1651         
1652         // Now find an object value that has not already been taken
1653         // by scanning the list.
1654         
1655         int found = 0;
1656         struct list_head *i;
1657         
1658         __u32 n = (__u32)bucket;
1659
1660         //yaffs_CheckObjectHashSanity();        
1661         
1662         while(!found)
1663         {
1664                 found = 1;
1665                 n +=  YAFFS_NOBJECT_BUCKETS;
1666                 if(1 ||dev->objectBucket[bucket].count > 0)
1667                 {
1668                         list_for_each(i,&dev->objectBucket[bucket].list)
1669                         {
1670                                 // If there is already one in the list
1671                                 if(i && list_entry(i, yaffs_Object,hashLink)->objectId == n)
1672                                 {
1673                                         found = 0;
1674                                 }
1675                         }
1676                 }
1677         }
1678         
1679         //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
1680         
1681         return n;       
1682 }
1683
1684 void yaffs_HashObject(yaffs_Object *in)
1685 {
1686         int bucket = yaffs_HashFunction(in->objectId);
1687         yaffs_Device *dev = in->myDev;
1688         
1689         if(!list_empty(&in->hashLink))
1690         {
1691                 //YINFO("!!!");
1692         }
1693
1694         
1695         list_add(&in->hashLink,&dev->objectBucket[bucket].list);
1696         dev->objectBucket[bucket].count++;
1697
1698 }
1699
1700 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number)
1701 {
1702         int bucket = yaffs_HashFunction(number);
1703         struct list_head *i;
1704         yaffs_Object *in;
1705         
1706         list_for_each(i,&dev->objectBucket[bucket].list)
1707         {
1708                 // Look if it is in the list
1709                 if(i)
1710                 {
1711                         in = list_entry(i, yaffs_Object,hashLink);
1712                         if(in->objectId == number)
1713                         {
1714                                 return in;
1715                         }
1716                 }
1717         }
1718         
1719         return NULL;
1720 }
1721
1722
1723
1724 yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
1725 {
1726                 
1727         yaffs_Object *theObject;
1728
1729         if(number < 0)
1730         {
1731                 number = yaffs_CreateNewObjectNumber(dev);
1732         }
1733         
1734         theObject = yaffs_AllocateEmptyObject(dev);
1735         
1736         if(theObject)
1737         {
1738                 theObject->fake = 0;
1739                 theObject->renameAllowed = 1;
1740                 theObject->unlinkAllowed = 1;
1741                 theObject->objectId = number;
1742                 yaffs_HashObject(theObject);
1743                 theObject->variantType = type;
1744 #ifdef CONFIG_YAFFS_WINCE
1745                 yfsd_WinFileTimeNow(theObject->win_atime);
1746                 theObject->win_ctime[0] = theObject->win_mtime[0] = theObject->win_atime[0];
1747                 theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];
1748
1749 #else
1750
1751                 theObject->st_atime = theObject->st_mtime = theObject->st_ctime = Y_CURRENT_TIME;               
1752 #endif
1753                 switch(type)
1754                 {
1755                         case YAFFS_OBJECT_TYPE_FILE: 
1756                                 theObject->variant.fileVariant.fileSize = 0;
1757                                 theObject->variant.fileVariant.scannedFileSize = 0;
1758                                 theObject->variant.fileVariant.topLevel = 0;
1759                                 theObject->variant.fileVariant.top  = yaffs_GetTnode(dev);
1760                                 break;
1761                         case YAFFS_OBJECT_TYPE_DIRECTORY:
1762                                 INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
1763                                 break;
1764                         case YAFFS_OBJECT_TYPE_SYMLINK:
1765                                 // No action required
1766                                 break;
1767                         case YAFFS_OBJECT_TYPE_HARDLINK:
1768                                 // No action required
1769                                 break;
1770                         case YAFFS_OBJECT_TYPE_SPECIAL:
1771                                 // No action required
1772                                 break;
1773                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1774                                 // todo this should not happen
1775                                 break;
1776                 }
1777         }
1778         
1779         return theObject;
1780 }
1781
1782 yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
1783 {
1784         yaffs_Object *theObject = NULL;
1785         
1786         if(number > 0)
1787         {
1788                 theObject = yaffs_FindObjectByNumber(dev,number);
1789         }
1790         
1791         if(!theObject)
1792         {
1793                 theObject = yaffs_CreateNewObject(dev,number,type);
1794         }
1795         
1796         return theObject;
1797
1798 }
1799
1800 YCHAR *yaffs_CloneString(const YCHAR *str)
1801 {
1802         YCHAR *newStr = NULL;
1803         
1804         if(str && *str)
1805         {
1806                 newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
1807                 yaffs_strcpy(newStr,str);
1808         }
1809
1810         return newStr;
1811         
1812 }
1813
1814 //
1815 // Mknod (create) a new object.
1816 // equivalentObject only has meaning for a hard link;
1817 // aliasString only has meaning for a sumlink.
1818 // rdev only has meaning for devices (a subset of special objects)
1819 yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
1820                                                                  yaffs_Object *parent,
1821                                                                  const YCHAR *name, 
1822                                                                  __u32 mode,
1823                                                                  __u32 uid,
1824                                                                  __u32 gid,
1825                                                                  yaffs_Object *equivalentObject,
1826                                                                  const YCHAR *aliasString,
1827                                                                  __u32 rdev)
1828 {
1829         yaffs_Object *in;
1830
1831         yaffs_Device *dev = parent->myDev;
1832         
1833         // Check if the entry exists. If it does then fail the call since we don't want a dup.
1834         if(yaffs_FindObjectByName(parent,name))
1835         {
1836                 return NULL;
1837         }
1838         
1839         in = yaffs_CreateNewObject(dev,-1,type);
1840         
1841         if(in)
1842         {
1843                 in->chunkId = -1;
1844                 in->valid = 1;
1845                 in->variantType = type;
1846
1847                 in->st_mode  = mode;
1848                 
1849 #ifdef CONFIG_YAFFS_WINCE
1850                 yfsd_WinFileTimeNow(in->win_atime);
1851                 in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
1852                 in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
1853                 
1854 #else
1855                 in->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME;
1856
1857                 in->st_rdev  = rdev;
1858                 in->st_uid   = uid;
1859                 in->st_gid   = gid;
1860 #endif          
1861                 in->nDataChunks = 0;
1862
1863                 yaffs_SetObjectName(in,name);
1864                 in->dirty = 1;
1865                 
1866                 yaffs_AddObjectToDirectory(parent,in);
1867                 
1868                 in->myDev = parent->myDev;
1869                 
1870                                 
1871                 switch(type)
1872                 {
1873                         case YAFFS_OBJECT_TYPE_SYMLINK:
1874                                 in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
1875                                 break;
1876                         case YAFFS_OBJECT_TYPE_HARDLINK:
1877                                 in->variant.hardLinkVariant.equivalentObject = equivalentObject;
1878                                 in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
1879                                 list_add(&in->hardLinks,&equivalentObject->hardLinks);
1880                                 break;
1881                         case YAFFS_OBJECT_TYPE_FILE: // do nothing
1882                         case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
1883                         case YAFFS_OBJECT_TYPE_SPECIAL: // do nothing
1884                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1885                                 break;
1886                 }
1887
1888                 if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
1889                    yaffs_UpdateObjectHeader(in,name,0,0) < 0)
1890                 {
1891                         // Could not create the object header, fail the creation
1892                         yaffs_DestroyObject(in);
1893                         in = NULL;
1894                 }
1895
1896         }
1897         
1898         return in;
1899 }
1900
1901 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
1902 {
1903         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL,0);
1904 }
1905
1906 yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
1907 {
1908         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,0);
1909 }
1910
1911 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
1912 {
1913         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,rdev);
1914 }
1915
1916 yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid,const YCHAR *alias)
1917 {
1918         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias,0);
1919 }
1920
1921 // NB yaffs_Link returns the object id of the equivalent object.
1922 yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object *equivalentObject)
1923 {
1924         // Get the real object in case we were fed a hard link as an equivalent object
1925         equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
1926         
1927         if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL,0))
1928         {
1929                 return equivalentObject;
1930         }
1931         else
1932         {
1933                 return NULL;
1934         }
1935         
1936 }
1937
1938
1939 static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force)
1940 {
1941         int unlinkOp;
1942         int deleteOp;
1943
1944         if(newDir == NULL)
1945         {
1946                 newDir = obj->parent; // use the old directory
1947         }
1948
1949         // TODO: Do we need this different handling for YAFFS2 and YAFFS1??
1950         if(obj->myDev->isYaffs2)
1951         {
1952                 unlinkOp = (newDir == obj->myDev->unlinkedDir);
1953         }
1954         else
1955         {
1956                 unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
1957         }
1958
1959         deleteOp = (newDir == obj->myDev->deletedDir);
1960         
1961         // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
1962         // duplicate names are allowed.
1963         // Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
1964         if( (unlinkOp|| 
1965                  deleteOp ||
1966                  force || 
1967                  !yaffs_FindObjectByName(newDir,newName))  &&
1968              newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1969         {
1970                 yaffs_SetObjectName(obj,newName);
1971                 obj->dirty = 1;
1972                 
1973                 yaffs_AddObjectToDirectory(newDir,obj);
1974                 
1975                 if(unlinkOp) obj->unlinked = 1;
1976                 
1977                 // If it is a dletion then we mark it as a shrink for gc purposes.
1978                 if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp) >= 0)
1979                 {
1980                         return YAFFS_OK;
1981                 }
1982         }
1983         
1984         return YAFFS_FAIL;
1985 }
1986
1987
1988
1989 int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName)
1990 {
1991         yaffs_Object *obj;
1992         int force = 0;
1993         
1994 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
1995         // Special case for case insemsitive systems (eg. WinCE).
1996         // While look-up is case insensitive, the name isn't.
1997         // THerefore we might want to change x.txt to X.txt
1998         if(oldDir == newDir && yaffs_strcmp(oldName,newName) == 0)
1999         {
2000                 force = 1;
2001         }       
2002 #endif
2003         
2004         obj = yaffs_FindObjectByName(oldDir,oldName);
2005         if(obj && obj->renameAllowed)
2006         {
2007                 return yaffs_ChangeObjectName(obj,newDir,newName,force);
2008         }
2009         return YAFFS_FAIL;
2010 }
2011
2012
2013
2014 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
2015 {
2016         // Scan the buckets and check that the lists 
2017         // have as many members as the count says there are
2018         int bucket;
2019         int countEm;
2020         struct list_head *j;
2021         int ok = YAFFS_OK;
2022         
2023         for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
2024         {
2025                 countEm = 0;
2026                 
2027                 list_for_each(j,&dev->objectBucket[bucket].list)
2028                 {
2029                         countEm++;
2030                 }
2031                 
2032                 if(countEm != dev->objectBucket[bucket].count)
2033                 {
2034                         T(YAFFS_TRACE_ERROR,(TSTR("Inode hash inconsistency" TENDSTR)));
2035                         ok = YAFFS_FAIL;
2036                 }
2037         }
2038
2039         return ok;
2040 }
2041
2042 #if 0
2043 void yaffs_ObjectTest(yaffs_Device *dev)
2044 {
2045         yaffs_Object *in[1000];
2046         int inNo[1000];
2047         yaffs_Object *inold[1000];
2048         int i;
2049         int j;
2050         
2051         memset(in,0,1000*sizeof(yaffs_Object *));
2052         memset(inold,0,1000*sizeof(yaffs_Object *));
2053         
2054         yaffs_CheckObjectHashSanity(dev);
2055         
2056         for(j = 0; j < 10; j++)
2057         {
2058                 //T(("%d\n",j));
2059                 
2060                 for(i = 0; i < 1000; i++)
2061                 {
2062                         in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
2063                         if(!in[i])
2064                         {
2065                                 YINFO("No more inodes");
2066                         }
2067                         else
2068                         {
2069                                 inNo[i] = in[i]->objectId;
2070                         }
2071                 }
2072                 
2073                 for(i = 0; i < 1000; i++)
2074                 {
2075                         if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
2076                         {
2077                                 //T(("Differnce in look up test\n"));
2078                         }
2079                         else
2080                         {
2081                                 // T(("Look up ok\n"));
2082                         }
2083                 }
2084                 
2085                 yaffs_CheckObjectHashSanity(dev);
2086         
2087                 for(i = 0; i < 1000; i+=3)
2088                 {
2089                         yaffs_FreeObject(in[i]);        
2090                         in[i] = NULL;
2091                 }
2092                 
2093         
2094                 yaffs_CheckObjectHashSanity(dev);
2095         }
2096                 
2097 }
2098
2099 #endif
2100
2101 /////////////////////////// Block Management and Page Allocation ///////////////////
2102
2103
2104 static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
2105 {
2106         dev->allocationBlock = -1; // force it to get a new one
2107         //Todo we're assuming the malloc will pass.
2108         dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
2109         // Set up dynamic blockinfo stuff.
2110         dev->chunkBitmapStride = (dev->nChunksPerBlock+7)/8;
2111         dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
2112         if(dev->blockInfo && dev->chunkBits)
2113         {
2114                 memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));
2115                 memset(dev->chunkBits,0,dev->chunkBitmapStride * nBlocks);
2116                 return YAFFS_OK;
2117         }
2118         
2119         return YAFFS_FAIL;
2120         
2121 }
2122
2123 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
2124 {
2125         YFREE(dev->blockInfo);
2126         dev->blockInfo = NULL;
2127         YFREE(dev->chunkBits);
2128         dev->chunkBits = NULL;
2129 }
2130
2131
2132 static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi)
2133 {
2134         int i;
2135         __u32 seq;
2136         yaffs_BlockInfo *b;
2137         
2138         if(!dev->isYaffs2) return 1; // disqualification only applies to yaffs2.
2139         
2140         if(!bi->hasShrinkHeader) return 1; // can gc
2141
2142
2143         // Find the oldest dirty sequence number if we don't know it and save it
2144         // so we don't have to keep recomputing it.
2145         if(!dev->oldestDirtySequence)
2146         {
2147                 seq = dev->sequenceNumber;
2148
2149                 for(i = dev->startBlock; i <= dev->endBlock; i++)
2150                 {
2151                         b = yaffs_GetBlockInfo(dev,i);
2152                         if(b->blockState == YAFFS_BLOCK_STATE_FULL &&
2153                         (b->pagesInUse - b->softDeletions )< dev->nChunksPerBlock &&
2154                         b->sequenceNumber < seq)
2155                         {
2156                                 seq = b->sequenceNumber;
2157                         }
2158                 }
2159                 dev->oldestDirtySequence = seq;
2160         }
2161
2162
2163         // Can't do gc of this block if there are any blocks older than this one that have
2164         // discarded pages.
2165         return (bi->sequenceNumber <= dev->oldestDirtySequence);
2166         
2167         
2168         return 1;
2169
2170 }
2171
2172 // FindDiretiestBlock is used to select the dirtiest block (or close enough)
2173 // for garbage collection.
2174 //
2175
2176
2177
2178 static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive)
2179 {
2180
2181         int b = dev->currentDirtyChecker;
2182         
2183         int i;
2184         int iterations;
2185         int dirtiest = -1;
2186         int pagesInUse; 
2187         yaffs_BlockInfo *bi;
2188         static int  nonAggressiveSkip = 0;
2189
2190         // If we're doing aggressive GC then we are happy to take a less-dirty block, and
2191         // search harder.
2192         // else (we're doing a leasurely gc), then we only bother to do this if the
2193         // block has only a few pages in use.
2194         
2195
2196         nonAggressiveSkip--;
2197
2198         if(!aggressive &&(nonAggressiveSkip > 0))
2199         {
2200                 return -1;
2201         }
2202
2203         pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
2204         if(aggressive)
2205         {
2206                 iterations = dev->endBlock - dev->startBlock + 1;
2207         }
2208         else
2209         {
2210                 iterations = dev->endBlock - dev->startBlock + 1;
2211                 iterations = iterations / 16; 
2212                 if(iterations > 200)
2213                 {
2214                         iterations = 200;
2215                 }
2216         }
2217         
2218         for(i = 0; i <= iterations && pagesInUse > 0 ; i++)
2219         {
2220                 b++;
2221                 if ( b < dev->startBlock || b > dev->endBlock)
2222                 {
2223                         b =  dev->startBlock;
2224                 }
2225
2226                 if(b < dev->startBlock || b > dev->endBlock)
2227                 {
2228                         T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b));
2229                         YBUG();
2230                 }
2231                 
2232                 bi = yaffs_GetBlockInfo(dev,b);
2233                 
2234                 if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
2235                    (bi->pagesInUse - bi->softDeletions )< pagesInUse &&
2236                    yaffs_BlockNotDisqualifiedFromGC(dev,bi))
2237                 {
2238                         dirtiest = b;
2239                         pagesInUse = (bi->pagesInUse - bi->softDeletions);
2240                 }
2241         }
2242         
2243         dev->currentDirtyChecker = b;
2244         
2245         if(dirtiest > 0)
2246         {
2247                 T(YAFFS_TRACE_GC,(TSTR("GC Selected block %d with %d free" TENDSTR),dirtiest,dev->nChunksPerBlock - pagesInUse));
2248         }
2249         
2250         dev->oldestDirtySequence = 0; // clear this
2251         
2252         if(dirtiest > 0)
2253         {
2254                 nonAggressiveSkip = 4;
2255         }
2256
2257         return dirtiest;
2258 }
2259
2260
2261 static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
2262 {
2263         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,blockNo);
2264         
2265         int erasedOk = 0;
2266         
2267         // If the block is still healthy erase it and mark as clean.
2268         // If the block has had a data failure, then retire it.
2269         bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
2270
2271         if(!bi->needsRetiring)
2272         {
2273                 erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);
2274                 if(!erasedOk)
2275                 {
2276                         dev->nErasureFailures++;
2277                         T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo));
2278                 }
2279         }
2280
2281         if(erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE))
2282         {
2283                         int i;
2284                         for(i = 0; i < dev->nChunksPerBlock; i++)
2285                         {
2286                                         if(!yaffs_CheckChunkErased(dev,blockNo * dev->nChunksPerBlock + i))
2287                                         {
2288                                                 T(YAFFS_TRACE_ERROR,(TSTR(">>Block %d erasure supposedly OK, but chunk %d not erased" TENDSTR),blockNo,i));
2289                                         }
2290                         }
2291         }
2292         
2293         if( erasedOk )
2294         {
2295                 // Clean it up...
2296                 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
2297                 dev->nErasedBlocks++;
2298                 bi->pagesInUse = 0;
2299                 bi->softDeletions = 0;
2300                 bi->hasShrinkHeader=0;
2301                 yaffs_ClearChunkBits(dev,blockNo);
2302         
2303                 T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo));
2304         }
2305         else
2306         {
2307                 yaffs_RetireBlock(dev,blockNo);
2308                 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
2309         }
2310 }
2311
2312 static void yaffs_DumpBlockStats(yaffs_Device *dev)
2313 {
2314         int i,j;
2315         yaffs_BlockInfo *bi;
2316         
2317         for(i= dev->startBlock; i <=dev->endBlock; i++)
2318         {
2319                 bi = yaffs_GetBlockInfo(dev,i);
2320                 T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i,
2321                 bi->blockState,bi->hasShrinkHeader,bi->pagesInUse,bi->softDeletions,bi->sequenceNumber));       
2322                 
2323                 for(j = 0; j < dev->nChunksPerBlock; j++)
2324                 {
2325                         if(yaffs_CheckChunkBit(dev,i,j))
2326                         {
2327                                 T(YAFFS_TRACE_ALLOCATE,(TSTR(" %d"),j));
2328
2329                         }
2330                 }
2331                 T(YAFFS_TRACE_ALLOCATE,(TSTR(" " TENDSTR)));
2332
2333         }
2334 }
2335
2336
2337 static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
2338 {
2339         int i;
2340         
2341         yaffs_BlockInfo *bi;
2342         
2343 #if 0
2344         static int j = 0;
2345         j++;
2346         if(j < 0 || j > 100)
2347         {
2348                 j = 0;
2349                 yaffs_DumpBlockStats(dev);
2350         }
2351         
2352 #endif
2353         
2354         if(dev->nErasedBlocks < 1)
2355         {
2356                 // Hoosterman we've got a problem.
2357                 // Can't get space to gc
2358                 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));
2359
2360                 return -1;
2361         }
2362         
2363         // Find an empty block.
2364         
2365         for(i = dev->startBlock; i <= dev->endBlock; i++)
2366         {
2367                 dev->allocationBlockFinder++;
2368                 if(dev->allocationBlockFinder < dev->startBlock || dev->allocationBlockFinder> dev->endBlock) 
2369                 {
2370                         dev->allocationBlockFinder = dev->startBlock;
2371                 }
2372                 
2373                 bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder);
2374
2375                 if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
2376                 {
2377                         bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
2378                         dev->sequenceNumber++;
2379                         bi->sequenceNumber = dev->sequenceNumber;
2380                         dev->nErasedBlocks--;           
2381                         T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocated block %d, seq  %d" TENDSTR),dev->allocationBlockFinder,dev->sequenceNumber));   
2382                         return dev->allocationBlockFinder;
2383                 }
2384         }
2385                 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks, but there should have been one" TENDSTR)));
2386
2387         
2388         return -1;      
2389 }
2390
2391
2392
2393 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
2394 {
2395         int retVal;
2396         yaffs_BlockInfo *bi;
2397         
2398         if(dev->allocationBlock < 0)
2399         {
2400                 // Get next block to allocate off
2401                 dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
2402                 dev->allocationPage = 0;
2403         }
2404         
2405         if(!useReserve &&  dev->nErasedBlocks </*=*/ dev->nReservedBlocks)
2406         {
2407                 // Not enough space to allocate unless we're allowed to use the reserve.
2408                 return -1;
2409         }
2410
2411         if(dev->nErasedBlocks < dev->nReservedBlocks && dev->allocationPage == 0)
2412         {
2413                 T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocating reserve" TENDSTR)));   
2414         }
2415
2416         
2417         // Next page please....
2418         if(dev->allocationBlock >= 0)
2419         {
2420                 bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);
2421                 
2422                 retVal = (dev->allocationBlock * dev->nChunksPerBlock) + 
2423                                   dev->allocationPage;
2424                 bi->pagesInUse++;
2425                 yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage);
2426
2427                 dev->allocationPage++;
2428                 
2429                 dev->nFreeChunks--;
2430                 
2431                 // If the block is full set the state to full
2432                 if(dev->allocationPage >= dev->nChunksPerBlock)
2433                 {
2434                         bi->blockState = YAFFS_BLOCK_STATE_FULL;
2435                         dev->allocationBlock = -1;
2436                 }
2437
2438
2439                 return retVal;
2440                 
2441         }
2442         T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
2443
2444         return -1;      
2445 }
2446
2447
2448 // To determine if we have enough space we just look at the 
2449 // number of erased blocks.
2450 // The cache is allowed to use reserved blocks.
2451
2452 static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)
2453 {
2454         return (dev->nErasedBlocks >= dev->nReservedBlocks);
2455 }
2456
2457
2458 static int yaffs_GetErasedChunks(yaffs_Device *dev)
2459 {
2460                 int n;
2461
2462                 n = dev->nErasedBlocks * dev->nChunksPerBlock;
2463
2464                 if(dev->allocationBlock> 0)
2465                 {
2466                         n += (dev->nChunksPerBlock - dev->allocationPage);
2467                 }
2468
2469                 return n;
2470
2471 }
2472
2473 int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
2474 {
2475         int oldChunk;
2476         int newChunk;
2477         int chunkInBlock;
2478         int markNAND;
2479         int retVal = YAFFS_OK;
2480         int cleanups = 0;
2481         int i;
2482
2483         int chunksBefore = yaffs_GetErasedChunks(dev);
2484         int chunksAfter;
2485
2486         yaffs_ExtendedTags  tags;
2487         
2488         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
2489         
2490         yaffs_Object *object;
2491         
2492         bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
2493
2494         T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
2495         //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));        
2496
2497         bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
2498
2499
2500         if(!yaffs_StillSomeChunkBits(dev,block))
2501         {
2502                 T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d that has no chunks in use" TENDSTR),block));
2503                 yaffs_BlockBecameDirty(dev,block);
2504         }
2505         else
2506         {
2507
2508                         __u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);
2509
2510         for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock; 
2511             chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
2512             chunkInBlock++, oldChunk++ )
2513         {
2514                 if(yaffs_CheckChunkBit(dev,block,chunkInBlock))
2515                 {
2516                         
2517                         // This page is in use and might need to be copied off
2518                         
2519                         markNAND = 1;
2520                         
2521                         //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
2522                         
2523                         yaffs_InitialiseTags(&tags);
2524                         
2525                         yaffs_ReadChunkWithTagsFromNAND(dev,oldChunk,buffer, &tags);
2526
2527                         object = yaffs_FindObjectByNumber(dev,tags.objectId);
2528                         
2529                         T(YAFFS_TRACE_GC_DETAIL,(TSTR("Collecting page %d, %d %d %d " TENDSTR),chunkInBlock,tags.objectId,tags.chunkId,tags.byteCount));
2530                         
2531                         if(!object)
2532                         {
2533                                 T(YAFFS_TRACE_ERROR,(TSTR("page %d in gc has no object " TENDSTR),oldChunk));
2534                         }
2535                         
2536                         if(object && object->deleted && tags.chunkId != 0)
2537                         {
2538                                 // Data chunk in a deleted file, throw it away
2539                                 // It's a deleted data chunk,
2540                                 // No need to copy this, just forget about it and fix up the
2541                                 // object.
2542                                 
2543                                 //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); 
2544                                 object->nDataChunks--;
2545                                 
2546                                 if(object->nDataChunks <= 0)
2547                                 {
2548                                         // remeber to clean up the object
2549                                         dev->gcCleanupList[cleanups] = tags.objectId;
2550                                         cleanups++;
2551                                 }
2552                                 markNAND = 0;
2553                         }
2554                         else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)
2555                         {
2556                                 // Deleted object header with no data chunks.
2557                                 // Can be discarded and the file deleted.
2558                                 object->chunkId = 0;
2559                                 yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
2560                                 object->variant.fileVariant.top = NULL;
2561                                 yaffs_DoGenericObjectDeletion(object);
2562                                 
2563                         }
2564                         else if(object)
2565                         {
2566                                 // It's either a data chunk in a live file or
2567                                 // an ObjectHeader, so we're interested in it.
2568                                 // NB Need to keep the ObjectHeaders of deleted files
2569                                 // until the whole file has been deleted off
2570                                 tags.serialNumber++;
2571
2572                                 dev->nGCCopies++;
2573
2574                                 newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
2575                         
2576                                 if(newChunk < 0)
2577                                 {
2578                                         retVal =  YAFFS_FAIL;
2579                                 }
2580                                 else
2581                                 {
2582                         
2583                                         // Ok, now fix up the Tnodes etc.
2584                         
2585                                         if(tags.chunkId == 0)
2586                                         {
2587                                                 // It's a header
2588                                                 object->chunkId = newChunk;
2589                                                 object->serial = tags.serialNumber;
2590                                         }
2591                                         else
2592                                         {
2593                                                 // It's a data chunk
2594                                                 yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
2595                                         }
2596                                 }
2597                         }
2598                         
2599                         yaffs_DeleteChunk(dev,oldChunk,markNAND,__LINE__);                      
2600                         
2601                 }
2602         }
2603
2604         yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
2605
2606
2607         // Do any required cleanups
2608         for(i = 0; i < cleanups; i++)
2609         {                                               
2610                 // Time to delete the file too
2611                 object =  yaffs_FindObjectByNumber(dev,dev->gcCleanupList[i]);
2612                 if(object)
2613                 {
2614                         yaffs_FreeTnode(dev,object->variant.fileVariant.top);
2615                         object->variant.fileVariant.top = NULL;
2616                         T(YAFFS_TRACE_GC,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId));
2617                         yaffs_DoGenericObjectDeletion(object);
2618                 }
2619
2620         }
2621
2622         }
2623
2624         if(chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev)))
2625         {
2626                         T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
2627         }
2628                         
2629         return YAFFS_OK;
2630 }
2631
2632 #if 0
2633 static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
2634 {
2635         // find a file to delete
2636         struct list_head *i;    
2637         yaffs_Object *l;
2638
2639
2640         //Scan the unlinked files looking for one to delete
2641         list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
2642         {
2643                 if(i)
2644                 {
2645                         l = list_entry(i, yaffs_Object,siblings);
2646                         if(l->deleted)
2647                         {
2648                                 return l;                       
2649                         }
2650                 }
2651         }       
2652         return NULL;
2653 }
2654
2655
2656 static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
2657 {
2658         // This does background deletion on unlinked files.. only deleted ones.
2659         // If we don't have a file we're working on then find one
2660         if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)
2661         {
2662                 dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);
2663         }
2664         
2665         // OK, we're working on a file...
2666         if(dev->unlinkedDeletion)
2667         {
2668                 yaffs_Object *obj = dev->unlinkedDeletion;
2669                 int delresult;
2670                 int limit; // Number of chunks to delete in a file.
2671                                    // NB this can be exceeded, but not by much.
2672                                    
2673                 limit = -1;
2674
2675                 delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
2676                 
2677                 if(obj->nDataChunks == 0)
2678                 {
2679                         // Done all the deleting of data chunks.
2680                         // Now dump the header and clean up
2681                         yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
2682                         obj->variant.fileVariant.top = NULL;
2683                         yaffs_DoGenericObjectDeletion(obj);
2684                         dev->nDeletedFiles--;
2685                         dev->nUnlinkedFiles--;
2686                         dev->nBackgroundDeletions++;
2687                         dev->unlinkedDeletion = NULL;   
2688                 }
2689         }
2690 }
2691
2692 #endif
2693
2694 #if 0
2695 #define YAFFS_GARBAGE_COLLECT_LOW_WATER 2
2696 static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
2697 {
2698         int block;
2699         int aggressive=0;
2700         
2701         //yaffs_DoUnlinkedFileDeletion(dev);
2702         
2703         if(dev->nErasedBlocks <= (dev->nReservedBlocks + YAFFS_GARBAGE_COLLECT_LOW_WATER))
2704         {
2705                 aggressive = 1;
2706         }               
2707         
2708         if(aggressive)
2709         {
2710                 block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
2711                 
2712                 if(block >= 0)
2713                 {
2714                         dev->garbageCollections++;
2715                         return yaffs_GarbageCollectBlock(dev,block);
2716                 }       
2717                 else
2718                 {
2719                         return YAFFS_FAIL;
2720                 }
2721         }
2722
2723         return YAFFS_OK;
2724 }
2725 #endif
2726
2727 // New garbage collector
2728 // If we're very low on erased blocks then we do aggressive garbage collection
2729 // otherwise we do "leasurely" garbage collection.
2730 // Aggressive gc looks further (whole array) and will accept dirtier blocks.
2731 // Passive gc only inspects smaller areas and will only accept cleaner blocks.
2732 //
2733 // The idea is to help clear out space in a more spread-out manner.
2734 // Dunno if it really does anything useful.
2735 //
2736 int yaffs_CheckGarbageCollection(yaffs_Device *dev)
2737 {
2738         int block;
2739         int aggressive; 
2740         int gcOk = YAFFS_OK;
2741         int maxTries = 0;
2742         
2743         //yaffs_DoUnlinkedFileDeletion(dev);
2744
2745         // This loop should pass the first time.
2746         // We'll only see looping here if the erase of the collected block fails.
2747         
2748         do{
2749                 maxTries++;
2750                 if(dev->nErasedBlocks <= (dev->nReservedBlocks + 2))
2751                 {
2752                         // We need a block soon...
2753                         aggressive = 1;
2754                 }
2755                 else 
2756                 {
2757                         // We're in no hurry
2758                         aggressive = 0;
2759                 }
2760         
2761                 block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
2762         
2763                 if(block > 0)
2764                 {
2765                         dev->garbageCollections++;
2766                         if(!aggressive)
2767                         {
2768                                 dev->passiveGarbageCollections++;
2769                         }
2770
2771                         T(YAFFS_TRACE_GC,(TSTR("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),dev->nErasedBlocks,aggressive));
2772
2773                         gcOk =  yaffs_GarbageCollectBlock(dev,block);
2774                 }
2775
2776                 if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) 
2777                 {
2778                         T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
2779                 }
2780         } while((dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) && (block > 0) && (maxTries < 5));
2781
2782         return aggressive ? gcOk: YAFFS_OK;
2783 }
2784
2785
2786 //////////////////////////// TAGS ///////////////////////////////////////
2787
2788
2789 void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
2790 {
2791         memset(tags,0,sizeof(yaffs_ExtendedTags));
2792         tags->validMarker0 = 0xAAAAAAAA;
2793         tags->validMarker1 = 0x55555555;
2794 }
2795
2796 static int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
2797 {
2798         return (tags->validMarker0 == 0xAAAAAAAA &&     tags->validMarker1 == 0x55555555);
2799
2800 }
2801
2802
2803 #if 0
2804
2805 void yaffs_CalcTagsECC(yaffs_Tags *tags)
2806 {
2807         // Calculate an ecc
2808         
2809         unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
2810         unsigned  i,j;
2811         unsigned  ecc = 0;
2812         unsigned bit = 0;
2813
2814         tags->ecc = 0;
2815         
2816         for(i = 0; i < 8; i++)
2817         {
2818                 for(j = 1; j &0xff; j<<=1)
2819                 {
2820                         bit++;
2821                         if(b[i] & j)
2822                         {
2823                                 ecc ^= bit;
2824                         }
2825                 }
2826         }
2827         
2828         tags->ecc = ecc;
2829         
2830         
2831 }
2832
2833 int  yaffs_CheckECCOnTags(yaffs_Tags *tags)
2834 {
2835         unsigned ecc = tags->ecc;
2836         
2837         yaffs_CalcTagsECC(tags);
2838         
2839         ecc ^= tags->ecc;
2840         
2841         if(ecc && ecc <= 64)
2842         {
2843                 // TODO: Handle the failure better. Retire?
2844                 unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
2845
2846                 ecc--;
2847                                 
2848                 b[ecc / 8] ^= (1 << (ecc & 7));
2849                 
2850                 // Now recvalc the ecc
2851                 yaffs_CalcTagsECC(tags);
2852                 
2853                 return 1; // recovered error
2854         }
2855         else if(ecc)
2856         {
2857                 // Wierd ecc failure value
2858                 // TODO Need to do somethiong here
2859                 return -1; //unrecovered error
2860         }
2861         
2862         return 0;
2863 }
2864
2865 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
2866 {
2867         yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
2868         
2869         yaffs_CalcTagsECC(tagsPtr);
2870         
2871         sparePtr->tagByte0 = tu->asBytes[0];
2872         sparePtr->tagByte1 = tu->asBytes[1];
2873         sparePtr->tagByte2 = tu->asBytes[2];
2874         sparePtr->tagByte3 = tu->asBytes[3];
2875         sparePtr->tagByte4 = tu->asBytes[4];
2876         sparePtr->tagByte5 = tu->asBytes[5];
2877         sparePtr->tagByte6 = tu->asBytes[6];
2878         sparePtr->tagByte7 = tu->asBytes[7];
2879 }
2880
2881 static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
2882 {
2883         yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
2884         int result;
2885
2886         tu->asBytes[0]= sparePtr->tagByte0;
2887         tu->asBytes[1]= sparePtr->tagByte1;
2888         tu->asBytes[2]= sparePtr->tagByte2;
2889         tu->asBytes[3]= sparePtr->tagByte3;
2890         tu->asBytes[4]= sparePtr->tagByte4;
2891         tu->asBytes[5]= sparePtr->tagByte5;
2892         tu->asBytes[6]= sparePtr->tagByte6;
2893         tu->asBytes[7]= sparePtr->tagByte7;
2894         
2895         result =  yaffs_CheckECCOnTags(tagsPtr);
2896         if(result> 0)
2897         {
2898                 dev->tagsEccFixed++;
2899         }
2900         else if(result <0)
2901         {
2902                 dev->tagsEccUnfixed++;
2903         }
2904 }
2905
2906 static void yaffs_SpareInitialise(yaffs_Spare *spare)
2907 {
2908         memset(spare,0xFF,sizeof(yaffs_Spare));
2909 }
2910
2911 #endif
2912
2913 #if 0
2914 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve)
2915 {
2916         // NB There must be tags, data is optional
2917         // If there is data, then an ECC is calculated on it.
2918         
2919         yaffs_Spare spare;
2920         
2921         if(!tags)
2922         {
2923                 return YAFFS_FAIL;
2924         }
2925         
2926         //yaffs_SpareInitialise(&spare);
2927         
2928         //if(!dev->useNANDECC && buffer)
2929         //{
2930         //      yaffs_CalcECC(buffer,&spare);
2931         //}
2932         
2933         //yaffs_LoadTagsIntoSpare(&spare,tags);
2934         
2935         return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
2936         
2937 }
2938 #endif
2939
2940 static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject)
2941 {
2942         return  (  tags->chunkId == chunkInObject &&
2943                            tags->objectId == objectId &&
2944                            !tags->chunkDeleted) ? 1 : 0;
2945         
2946 }
2947
2948
2949
2950 int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
2951 {
2952         //Get the Tnode, then get the level 0 offset chunk offset
2953     yaffs_Tnode *tn;     
2954     int theChunk = -1;
2955     yaffs_ExtendedTags localTags;
2956     int retVal = -1;
2957     
2958     yaffs_Device *dev = in->myDev;
2959     
2960     
2961     if(!tags)
2962     {
2963         // Passed a NULL, so use our own tags space
2964         tags = &localTags;
2965     }
2966     
2967     tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2968     
2969     if(tn)
2970     {
2971                 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
2972                 
2973                 retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
2974     }
2975     return retVal;
2976 }
2977
2978 int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
2979 {
2980         //Get the Tnode, then get the level 0 offset chunk offset
2981     yaffs_Tnode *tn;     
2982     int theChunk = -1;
2983     yaffs_ExtendedTags localTags;
2984
2985     yaffs_Device *dev = in->myDev;
2986     int retVal = -1;
2987     
2988     if(!tags)
2989     {
2990         // Passed a NULL, so use our own tags space
2991         tags = &localTags;
2992     }
2993     
2994     tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2995     
2996     if(tn)
2997     {
2998     
2999                 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
3000                 
3001                 retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
3002     
3003                 // Delete the entry in the filestructure (if found)
3004                 if(retVal != -1)
3005                 {
3006                         tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
3007                 }
3008     }
3009     else
3010     {
3011         //T(("No level 0 found for %d\n", chunkInInode));
3012     }
3013     
3014     if(retVal == -1)
3015     {
3016         //T(("Could not find %d to delete\n",chunkInInode));
3017     }
3018     return retVal;
3019 }
3020
3021
3022 #ifdef YAFFS_PARANOID
3023
3024 static int yaffs_CheckFileSanity(yaffs_Object *in)
3025 {
3026         int chunk;
3027         int nChunks;
3028         int fSize;
3029         int failed = 0;
3030         int objId;
3031         yaffs_Tnode *tn;
3032     yaffs_Tags localTags;
3033     yaffs_Tags *tags = &localTags;
3034     int theChunk;
3035     int chunkDeleted;
3036     
3037         
3038         if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
3039         {
3040                 //T(("Object not a file\n"));
3041                 return YAFFS_FAIL;
3042         }
3043         
3044         objId = in->objectId;
3045         fSize  = in->variant.fileVariant.fileSize;
3046         nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk;
3047         
3048         for(chunk = 1; chunk <= nChunks; chunk++)
3049         {
3050                 tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk);
3051     
3052                 if(tn)
3053                 {
3054     
3055                         theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits;
3056                         
3057                 if(yaffs_CheckChunkBits(dev,theChunk/dev->nChunksPerBlock,theChunk%dev->nChunksPerBlock))
3058                         {
3059
3060
3061                                 yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags,&chunkDeleted);
3062                                 if(yaffs_TagsMatch(tags,in->objectId,chunk,chunkDeleted))
3063                                 {
3064                                         // found it;
3065                                 
3066                                 }
3067                         }
3068                         else
3069                         {
3070                                 //T(("File problem file [%d,%d] NAND %d  tags[%d,%d]\n",
3071                                 //              objId,chunk,theChunk,tags->chunkId,tags->objectId);
3072                                                 
3073                                 failed = 1;
3074                                                         
3075                         }
3076     
3077                 }
3078                 else
3079                 {
3080                         //T(("No level 0 found for %d\n", chunk));
3081                 }
3082         }
3083         
3084         return failed ? YAFFS_FAIL : YAFFS_OK;
3085 }
3086
3087 #endif
3088
3089 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
3090 {
3091         yaffs_Tnode *tn;
3092         yaffs_Device *dev = in->myDev;
3093         int existingChunk;
3094         yaffs_ExtendedTags existingTags;
3095         yaffs_ExtendedTags newTags;
3096         unsigned existingSerial, newSerial;
3097                 
3098         tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
3099         if(!tn)
3100         {
3101                 return YAFFS_FAIL;
3102         }
3103
3104         existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];            
3105         
3106         if(inScan)
3107         {
3108                 // If we're scanning then we need to test for duplicates
3109                 // NB This does not need to be efficient since it should only ever 
3110                 // happen when the power fails during a write, then only one
3111                 // chunk should ever be affected.
3112         
3113                 
3114                 if(existingChunk != 0)
3115                 {
3116                         // NB Right now existing chunk will not be real chunkId if the device >= 32MB
3117                         //    thus we have to do a FindChunkInFile to get the real chunk id.
3118                         //
3119                         // We have a duplicate now we need to decide which one to use
3120                         // To do this we get both sets of tags and compare serial numbers.
3121                         yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND, NULL,&newTags);
3122                         
3123                         
3124                         // Do a proper find
3125                         existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags);
3126
3127                         if(existingChunk <=0)
3128                         {
3129                                 //Hoosterman - how did this happen?
3130                                 
3131                                 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: existing chunk < 0 in scan" TENDSTR)));
3132
3133                         }
3134
3135                         
3136                         // NB The deleted flags should be false, otherwise the chunks will 
3137                         // not be loaded during a scan
3138                         
3139                         newSerial = newTags.serialNumber;
3140                         existingSerial = existingTags.serialNumber;
3141                         
3142                         if( in->myDev->isYaffs2 ||
3143                             existingChunk <= 0 ||
3144                             ((existingSerial+1) & 3) == newSerial)
3145                         {
3146                                 // Use new
3147                                 // Delete the old one and drop through to update the tnode
3148                                 yaffs_DeleteChunk(dev,existingChunk,1,__LINE__);
3149                         }
3150                         else
3151                         {
3152                                 // Use existing.
3153                                 // Delete the new one and return early so that the tnode isn't changed
3154                                 yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
3155                                 return YAFFS_OK;
3156                         }
3157                 }
3158
3159         }
3160                 
3161         if(existingChunk == 0)
3162         {
3163                 in->nDataChunks++;
3164         }
3165         
3166         tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = (chunkInNAND >> dev->chunkGroupBits);
3167         
3168         return YAFFS_OK;
3169 }
3170
3171
3172
3173 int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
3174 {
3175     int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
3176     
3177     if(chunkInNAND >= 0)
3178     {
3179                 return yaffs_ReadChunkWithTagsFromNAND(in->myDev,chunkInNAND,buffer,NULL);
3180         }
3181         else
3182         {
3183                 T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not found zero instead" TENDSTR),chunkInNAND));
3184
3185                 memset(buffer,0,in->myDev->nBytesPerChunk); // get sane data if you read a hole
3186                 return 0;
3187         }
3188
3189 }
3190
3191
3192 void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn)
3193 {
3194         int block;
3195         int page;
3196         yaffs_ExtendedTags tags;
3197         yaffs_BlockInfo *bi;
3198         
3199         if(chunkId <= 0) return;        
3200         
3201         dev->nDeletions++;
3202         block = chunkId / dev->nChunksPerBlock;
3203         page = chunkId % dev->nChunksPerBlock;
3204         
3205         bi = yaffs_GetBlockInfo(dev,block);
3206         
3207         T(YAFFS_TRACE_DELETION,(TSTR("line %d delete of chunk %d" TENDSTR),lyn,chunkId));
3208         
3209         if(markNAND && 
3210           bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
3211           !dev->isYaffs2)
3212         {
3213 //              yaffs_SpareInitialise(&spare);
3214
3215 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
3216
3217                 //read data before write, to ensure correct ecc 
3218                 //if we're using MTD verification under Linux
3219                 yaffs_ReadChunkFromNAND(dev,chunkId,NULL,&spare,0);
3220 #endif
3221
3222                 yaffs_InitialiseTags(&tags);
3223
3224                 tags.chunkDeleted = 1;
3225
3226         
3227                 yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags);
3228                 yaffs_HandleUpdateChunk(dev,chunkId,&tags);
3229         }
3230         else
3231         {
3232                         dev->nUnmarkedDeletions++;
3233         }       
3234         
3235         
3236         // Pull out of the management area.
3237         // If the whole block became dirty, this will kick off an erasure.
3238         if(     bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
3239             bi->blockState == YAFFS_BLOCK_STATE_FULL ||     
3240             bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
3241             bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
3242         {
3243                 dev->nFreeChunks++;
3244
3245                 yaffs_ClearChunkBit(dev,block,page);
3246                 bi->pagesInUse--;
3247                 
3248                 if(bi->pagesInUse == 0 &&
3249                    !bi->hasShrinkHeader &&
3250                bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
3251                bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING)
3252             {
3253                 yaffs_BlockBecameDirty(dev,block);
3254             }
3255
3256         }
3257         else
3258         {
3259                 // T(("Bad news deleting chunk %d\n",chunkId));
3260         }
3261         
3262 }
3263
3264
3265
3266
3267 int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
3268 {
3269         // Find old chunk Need to do this to get serial number
3270         // Write new one and patch into tree.
3271         // Invalidate old tags.
3272
3273     int prevChunkId;
3274     yaffs_ExtendedTags prevTags;
3275     
3276     int newChunkId;
3277     yaffs_ExtendedTags newTags;
3278
3279     yaffs_Device *dev = in->myDev;    
3280
3281         yaffs_CheckGarbageCollection(dev);
3282
3283         // Get the previous chunk at this location in the file if it exists
3284     prevChunkId  = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
3285     
3286     // Set up new tags
3287     yaffs_InitialiseTags(&newTags);
3288     
3289         newTags.chunkId = chunkInInode;
3290         newTags.objectId = in->objectId;
3291         newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
3292         newTags.byteCount = nBytes;
3293                 
3294 //      yaffs_CalcTagsECC(&newTags);
3295
3296         newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
3297         
3298         if(newChunkId >= 0)
3299         {
3300                 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
3301                 
3302                 
3303                 if(prevChunkId >= 0)
3304                 {
3305                         yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
3306         
3307                 }
3308                 
3309                 yaffs_CheckFileSanity(in);
3310         }
3311         return newChunkId;
3312
3313
3314
3315
3316
3317 }
3318
3319
3320 // UpdateObjectHeader updates the header on NAND for an object.
3321 // If name is not NULL, then that new name is used.
3322 //
3323 int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink)
3324 {
3325
3326         yaffs_BlockInfo *bi;
3327         
3328         yaffs_Device *dev = in->myDev;
3329         
3330     int prevChunkId;
3331     int retVal = 0;
3332     
3333     int newChunkId;
3334     yaffs_ExtendedTags newTags;
3335     
3336     __u8 *buffer = NULL;
3337     YCHAR oldName[YAFFS_MAX_NAME_LENGTH+1];
3338     
3339    // __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
3340     
3341     yaffs_ObjectHeader *oh = NULL;
3342     // yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
3343
3344     
3345     if(!in->fake || force)
3346     {
3347   
3348                 yaffs_CheckGarbageCollection(dev);              
3349     
3350             buffer = yaffs_GetTempBuffer(in->myDev,__LINE__);
3351             oh  = (yaffs_ObjectHeader *)buffer;
3352     
3353                 prevChunkId = in->chunkId;
3354     
3355                 if(prevChunkId >= 0)
3356                 {
3357                         yaffs_ReadChunkWithTagsFromNAND(dev,prevChunkId,buffer,NULL);
3358                         memcpy(oldName,oh->name,sizeof(oh->name));      
3359                 }
3360
3361                 memset(buffer,0xFF,dev->nBytesPerChunk);
3362
3363                 // Header data
3364                 oh->type = in->variantType;
3365                 
3366                 oh->st_mode = in->st_mode;
3367
3368 #ifdef CONFIG_YAFFS_WINCE
3369                 oh->win_atime[0] = in->win_atime[0];
3370                 oh->win_ctime[0] = in->win_ctime[0];
3371                 oh->win_mtime[0] = in->win_mtime[0];
3372                 oh->win_atime[1] = in->win_atime[1];
3373                 oh->win_ctime[1] = in->win_ctime[1];
3374                 oh->win_mtime[1] = in->win_mtime[1];
3375 #else
3376                 oh->st_uid = in->st_uid;
3377                 oh->st_gid = in->st_gid;
3378                 oh->st_atime = in->st_atime;
3379                 oh->st_mtime = in->st_mtime;
3380                 oh->st_ctime = in->st_ctime;
3381                 oh->st_rdev = in->st_rdev;
3382 #endif  
3383                 if(in->parent)
3384                 {
3385                         oh->parentObjectId = in->parent->objectId;
3386                 }
3387                 else
3388                 {
3389                         oh->parentObjectId = 0;
3390                 }
3391                 
3392                 //oh->sum = in->sum;
3393                 if(name && *name)
3394                 {
3395                         memset(oh->name,0,sizeof(oh->name));
3396                         yaffs_strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
3397                 }
3398                 else if(prevChunkId)
3399                 {       
3400                         memcpy(oh->name, oldName,sizeof(oh->name));
3401                 }
3402                 else
3403                 {
3404                         memset(oh->name,0,sizeof(oh->name));    
3405                 }
3406                 
3407                 oh->isShrink = isShrink;
3408         
3409                 switch(in->variantType)
3410                 {
3411                         case YAFFS_OBJECT_TYPE_UNKNOWN:         
3412                                 // Should not happen
3413                                 break;
3414                         case YAFFS_OBJECT_TYPE_FILE:
3415                                 oh->fileSize = in->variant.fileVariant.fileSize;
3416                                 break;
3417                         case YAFFS_OBJECT_TYPE_HARDLINK:
3418                                 oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
3419                                 break;
3420                         case YAFFS_OBJECT_TYPE_SPECIAL: 
3421                                 // Do nothing
3422                                 break;
3423                         case YAFFS_OBJECT_TYPE_DIRECTORY:       
3424                                 // Do nothing
3425                                 break;
3426                         case YAFFS_OBJECT_TYPE_SYMLINK:
3427                                 yaffs_strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
3428                                 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
3429                                 break;
3430                 }
3431
3432                 // Tags
3433                 yaffs_InitialiseTags(&newTags);
3434                 in->serial++;
3435                 newTags.chunkId = 0;
3436                 newTags.objectId = in->objectId;
3437                 newTags.serialNumber = in->serial;
3438         
3439
3440                 // Create new chunk in NAND
3441                 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags, (prevChunkId >= 0) ? 1 : 0 );
3442     
3443                 if(newChunkId >= 0)
3444                 {
3445                 
3446                         in->chunkId = newChunkId;       
3447                 
3448                         if(prevChunkId >= 0)
3449                         {
3450                                 yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
3451                         }
3452                 
3453                         in->dirty = 0;
3454                         
3455                         // If this was a shrink, then mark the block that the chunk lives on
3456                         if(isShrink)
3457                         {
3458                                 bi = yaffs_GetBlockInfo(in->myDev,newChunkId / in->myDev->nChunksPerBlock);
3459                                 bi->hasShrinkHeader = 1;
3460                         }
3461                         
3462                 }
3463                 
3464                 retVal =  newChunkId;
3465
3466     }
3467     
3468         if(buffer) 
3469                 yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
3470         
3471     return retVal;
3472 }
3473
3474
3475 /////////////////////// Short Operations Cache ////////////////////////////////
3476 //      In many siturations where there is no high level buffering (eg WinCE) a lot of
3477 //      reads might be short sequential reads, and a lot of writes may be short 
3478 //  sequential writes. eg. scanning/writing a jpeg file.
3479 //      In these cases, a short read/write cache can provide a huge perfomance benefit 
3480 //  with dumb-as-a-rock code.
3481 //  There are a limited number (~10) of cache chunks per device so that we don't
3482 //  need a very intelligent search.
3483
3484
3485
3486
3487
3488 static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
3489 {
3490         yaffs_Device *dev = obj->myDev;
3491         int lowest;
3492         int i;
3493         yaffs_ChunkCache *cache;
3494         int chunkWritten;
3495         //int nBytes;
3496         int nCaches = obj->myDev->nShortOpCaches;
3497         
3498         if  (nCaches > 0)
3499         {
3500                 do{
3501                         cache = NULL;
3502                 
3503                         // Find the dirty cache for this object with the lowest chunk id.
3504                         for(i = 0; i < nCaches; i++)
3505                         {
3506                                 if(dev->srCache[i].object == obj &&
3507                                    dev->srCache[i].dirty)
3508                                 {
3509                                         if(!cache ||  dev->srCache[i].chunkId < lowest)
3510                                         {
3511                                                 cache = &dev->srCache[i];
3512                                                 lowest = cache->chunkId;
3513                                         }
3514                                 }
3515                         }
3516                 
3517                         if(cache && !cache->locked)
3518                         {
3519                                 //Write it out and free it up
3520
3521 #if 0
3522                                 nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);
3523                         
3524                                 if(nBytes > YAFFS_BYTES_PER_CHUNK)
3525                                 {
3526                                         nBytes= YAFFS_BYTES_PER_CHUNK;
3527                                 }
3528 #endif                  
3529                                 chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
3530                                                                                                                         cache->chunkId,
3531                                                                                                                         cache->data,
3532                                                                                                                         cache->nBytes,1);
3533
3534                                 cache->dirty = 0;
3535                                 cache->object = NULL;
3536                         }
3537                 
3538                 } while(cache && chunkWritten > 0);
3539         
3540                 if(cache)
3541                 {
3542                         //Hoosterman, disk full while writing cache out.
3543                         T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
3544
3545                 }
3546         }       
3547                 
3548 }
3549
3550
3551 // Grab us a chunk for use.
3552 // First look for an empty one. 
3553 // Then look for the least recently used non-dirty one.
3554 // Then look for the least recently used dirty one...., flush and look again.
3555 static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
3556 {
3557         int i;
3558         int usage;
3559         int theOne;
3560         
3561         if(dev->nShortOpCaches > 0)
3562         {
3563                 for(i = 0; i < dev->nShortOpCaches; i++)
3564                 {
3565                         if(!dev->srCache[i].object)
3566                         {
3567                                 //T(("Grabbing empty %d\n",i));
3568                                 
3569                                 //printf("Grabbing empty %d\n",i);
3570                         
3571                                 return &dev->srCache[i];
3572                         }
3573                 }
3574                 
3575                 return NULL;
3576         
3577                 theOne = -1; 
3578                 usage = 0; // just to stop the compiler grizzling
3579         
3580                 for(i = 0; i < dev->nShortOpCaches; i++)
3581                 {
3582                         if(!dev->srCache[i].dirty &&
3583                         ((dev->srCache[i].lastUse < usage  && theOne >= 0)|| 
3584                                 theOne < 0))
3585                         {
3586                                 usage = dev->srCache[i].lastUse;
3587                                 theOne = i;
3588                         }
3589                 }
3590         
3591                 //T(("Grabbing non-empty %d\n",theOne));
3592                 
3593                 //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
3594                 
3595                 return  theOne >= 0 ?  &dev->srCache[theOne] : NULL;
3596         }
3597         else
3598         {
3599                 return NULL;
3600         }
3601         
3602 }
3603
3604
3605 static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
3606 {
3607         yaffs_ChunkCache *cache;
3608         yaffs_Object *theObj;
3609         int usage;
3610         int i;
3611         int pushout;
3612         
3613         if(dev->nShortOpCaches > 0)
3614         {
3615                 // Try find a non-dirty one...
3616         
3617                 cache = yaffs_GrabChunkCacheWorker(dev);
3618         
3619                 if(!cache)
3620                 {
3621                         // They were all dirty, find the last recently used object and flush
3622                         // its cache, then  find again.
3623                         // NB what's here is not very accurate, we actually flush the object
3624                         // the last recently used page.
3625                 
3626                         theObj = NULL;
3627                         usage = 0;
3628                         cache = NULL;
3629                         pushout = 0;
3630         
3631                         for(i = 0; i < dev->nShortOpCaches; i++)
3632                         {
3633                                 if( dev->srCache[i].object && 
3634                                         !dev->srCache[i].locked &&
3635                                         (dev->srCache[i].lastUse < usage || !cache))
3636                                 {
3637                                         usage  = dev->srCache[i].lastUse;
3638                                         theObj = dev->srCache[i].object;
3639                                         cache = &dev->srCache[i];
3640                                         pushout = i;
3641                                 }
3642                         }
3643                 
3644                         if(!cache || cache->dirty)
3645                         {
3646                         
3647                                 //printf("Dirty ");
3648                                 yaffs_FlushFilesChunkCache(theObj);
3649                 
3650                                 // Try again
3651                                 cache = yaffs_GrabChunkCacheWorker(dev);
3652                         }
3653                         else
3654                         {
3655                                 //printf(" pushout %d\n",pushout);
3656                         }
3657                         
3658                 }
3659
3660                 return cache;
3661         }
3662         else
3663                 return NULL;
3664
3665 }
3666
3667
3668 // Find a cached chunk
3669 static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunkId)
3670 {
3671         yaffs_Device *dev = obj->myDev;
3672         int i;
3673         if(dev->nShortOpCaches > 0)
3674         {
3675                 for(i = 0; i < dev->nShortOpCaches; i++)
3676                 {
3677                         if(dev->srCache[i].object == obj && 
3678                         dev->srCache[i].chunkId == chunkId)
3679                         {
3680                                 dev->cacheHits++;
3681                         
3682                                 return &dev->srCache[i];
3683                         }
3684                 }
3685         }
3686         return NULL;
3687 }
3688
3689 // Mark the chunk for the least recently used algorithym
3690 static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite)
3691 {
3692
3693         if(dev->nShortOpCaches > 0)
3694         {
3695                 if( dev->srLastUse < 0 || 
3696                         dev->srLastUse > 100000000)
3697                 {
3698                         // Reset the cache usages
3699                         int i;
3700                         for(i = 1; i < dev->nShortOpCaches; i++)
3701                         {
3702                                 dev->srCache[i].lastUse = 0;
3703                         }
3704                         dev->srLastUse = 0;
3705                 }
3706
3707                 dev->srLastUse++;
3708         
3709                 cache->lastUse = dev->srLastUse;
3710
3711                 if(isAWrite)
3712                 {
3713                         cache->dirty = 1;
3714                 }
3715         }
3716 }
3717
3718 // Invalidate a single cache page.
3719 // Do this when a whole page gets written,
3720 // ie the short cache for this page is no longer valid.
3721 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
3722 {
3723         if(object->myDev->nShortOpCaches > 0)
3724         {
3725                 yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId);
3726
3727                 if(cache)
3728                 {
3729                         cache->object = NULL;
3730                 }
3731         }
3732 }
3733
3734
3735 // Invalidate all the cache pages associated with this object
3736 // Do this whenever ther file is deleted or resized.
3737 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
3738 {
3739         int i;
3740         yaffs_Device *dev = in->myDev;
3741         
3742         if(dev->nShortOpCaches > 0)
3743         { 
3744                 // Now invalidate it.
3745                 for(i = 0; i < dev->nShortOpCaches; i++)
3746                 {
3747                         if(dev->srCache[i].object == in)
3748                         {
3749                                 dev->srCache[i].object = NULL;
3750                         }
3751                 }
3752         }
3753 }
3754
3755
3756
3757
3758
3759 ///////////////////////// File read/write ///////////////////////////////
3760 // Read and write have very similar structures.
3761 // In general the read/write has three parts to it
3762 // * An incomplete chunk to start with (if the read/write is not chunk-aligned)
3763 // * Some complete chunks
3764 // * An incomplete chunk to end off with
3765 //
3766 // Curve-balls: the first chunk might also be the last chunk.
3767
3768 int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
3769 {
3770         
3771         
3772         int chunk;
3773         int start;
3774         int nToCopy;
3775         int n = nBytes;
3776         int nDone = 0;
3777         yaffs_ChunkCache *cache;
3778         
3779         yaffs_Device *dev;
3780         
3781         dev = in->myDev;
3782         
3783         while(n > 0)
3784         {
3785                 chunk = offset / dev->nBytesPerChunk + 1; // The first chunk is 1
3786                 start = offset % dev->nBytesPerChunk;
3787
3788                 // OK now check for the curveball where the start and end are in
3789                 // the same chunk.      
3790                 if(     (start + n) < dev->nBytesPerChunk)
3791                 {
3792                         nToCopy = n;
3793                 }
3794                 else
3795                 {
3796                         nToCopy = dev->nBytesPerChunk - start;
3797                 }
3798         
3799                 cache = yaffs_FindChunkCache(in,chunk);
3800                 
3801                 // If the chunk is already in the cache or it is less than a whole chunk
3802                 // then use the cache (if there is caching)
3803                 // else bypass the cache.
3804                 if( cache || nToCopy != dev->nBytesPerChunk)
3805                 {
3806                         if(dev->nShortOpCaches > 0)
3807                         {
3808                                 
3809                                 // If we can't find the data in the cache, then load it up.
3810                                 
3811                                 if(!cache)
3812                                 {
3813                                         cache = yaffs_GrabChunkCache(in->myDev);
3814                                         cache->object = in;
3815                                         cache->chunkId = chunk;
3816                                         cache->dirty = 0;
3817                                         cache->locked = 0;
3818                                         yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
3819                                         cache->nBytes = 0;      
3820                                 }
3821                         
3822                                 yaffs_UseChunkCache(dev,cache,0);
3823
3824                                 cache->locked = 1;
3825
3826 #ifdef CONFIG_YAFFS_WINCE
3827                                 yfsd_UnlockYAFFS(TRUE);
3828 #endif
3829                                 memcpy(buffer,&cache->data[start],nToCopy);
3830
3831 #ifdef CONFIG_YAFFS_WINCE
3832                                 yfsd_LockYAFFS(TRUE);
3833 #endif
3834                                 cache->locked = 0;
3835                         }
3836                         else
3837                         {
3838                                 // Read into the local buffer then copy...
3839                                 
3840                                 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3841                                 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);            
3842 #ifdef CONFIG_YAFFS_WINCE
3843                                 yfsd_UnlockYAFFS(TRUE);
3844 #endif
3845                                 memcpy(buffer,&localBuffer[start],nToCopy);
3846
3847 #ifdef CONFIG_YAFFS_WINCE
3848                                 yfsd_LockYAFFS(TRUE);
3849 #endif
3850                                 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3851                         }
3852
3853                 }
3854                 else
3855                 {
3856 #ifdef CONFIG_YAFFS_WINCE
3857                         __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3858                         
3859                         // Under WinCE can't do direct transfer. Need to use a local buffer.
3860                         // This is because we otherwise screw up WinCE's memory mapper
3861                         yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3862
3863 #ifdef CONFIG_YAFFS_WINCE
3864                                 yfsd_UnlockYAFFS(TRUE);
3865 #endif
3866                         memcpy(buffer,localBuffer,dev->nBytesPerChunk);
3867
3868 #ifdef CONFIG_YAFFS_WINCE
3869                                 yfsd_LockYAFFS(TRUE);
3870                                 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
3871 #endif
3872
3873 #else
3874                         // A full chunk. Read directly into the supplied buffer.
3875                         yaffs_ReadChunkDataFromObject(in,chunk,buffer);
3876 #endif
3877                 }
3878                 
3879                 n -= nToCopy;
3880                 offset += nToCopy;
3881                 buffer += nToCopy;
3882                 nDone += nToCopy;
3883                 
3884         }
3885         
3886         return nDone;
3887 }
3888
3889
3890
3891 int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes)
3892 {       
3893         
3894         int chunk;
3895         int start;
3896         int nToCopy;
3897         int n = nBytes;
3898         int nDone = 0;
3899         int nToWriteBack;
3900         int startOfWrite = offset;
3901         int chunkWritten = 0;
3902         int nBytesRead;
3903         
3904         yaffs_Device *dev;
3905         
3906         dev = in->myDev;
3907         
3908         
3909         while(n > 0 && chunkWritten >= 0)
3910         {
3911                 chunk = offset / dev->nBytesPerChunk + 1;
3912                 start = offset % dev->nBytesPerChunk;
3913                 
3914
3915                 // OK now check for the curveball where the start and end are in
3916                 // the same chunk.
3917                 
3918                 if(     (start + n) < dev->nBytesPerChunk)
3919                 {
3920                         nToCopy = n;
3921                         
3922                         // Now folks, to calculate how many bytes to write back....
3923                         // If we're overwriting and not writing to then end of file then
3924                         // we need to write back as much as was there before.
3925                         
3926                         nBytesRead = in->variant.fileVariant.fileSize - ((chunk -1) * dev->nBytesPerChunk);
3927                         
3928                         if(nBytesRead > dev->nBytesPerChunk)
3929                         {
3930                                 nBytesRead = dev->nBytesPerChunk;
3931                         }
3932                         
3933                         nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start +n);
3934                         
3935                 }
3936                 else
3937                 {
3938                         nToCopy = dev->nBytesPerChunk - start;
3939                         nToWriteBack = dev->nBytesPerChunk;
3940                 }
3941         
3942                 if(nToCopy != dev->nBytesPerChunk)
3943                 {
3944                         // An incomplete start or end chunk (or maybe both start and end chunk)
3945                         if(dev->nShortOpCaches > 0)
3946                         {
3947                                 yaffs_ChunkCache *cache;
3948                                 // If we can't find the data in the cache, then load it up.
3949                                 cache = yaffs_FindChunkCache(in,chunk);
3950                                 if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))
3951                                 {
3952                                         cache = yaffs_GrabChunkCache(in->myDev);
3953                                         cache->object = in;
3954                                         cache->chunkId = chunk;
3955                                         cache->dirty = 0;
3956                                         cache->locked = 0;
3957                                         yaffs_ReadChunkDataFromObject(in,chunk,cache->data);            
3958                                 }
3959                         
3960                                 if(cache)
3961                                 {       
3962                                         yaffs_UseChunkCache(dev,cache,1);
3963                                         cache->locked = 1;
3964 #ifdef CONFIG_YAFFS_WINCE
3965                                 yfsd_UnlockYAFFS(TRUE);
3966 #endif
3967         
3968                                         memcpy(&cache->data[start],buffer,nToCopy);