2f899f3ec516e21eca987ce8e2e064404cf1701b
[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);
3969
3970 #ifdef CONFIG_YAFFS_WINCE
3971                                 yfsd_LockYAFFS(TRUE);
3972 #endif
3973                                         cache->locked = 0;
3974                                         cache->nBytes = nToWriteBack;
3975                                 }
3976                                 else
3977                                 {
3978                                         chunkWritten = -1; // fail the write
3979                                 }
3980                         }
3981                         else
3982                         {
3983                                 // An incomplete start or end chunk (or maybe both start and end chunk)
3984                                 // Read into the local buffer then copy, then copy over and write back.
3985                                 
3986                                 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
3987                 
3988                                 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3989                                 
3990 #ifdef CONFIG_YAFFS_WINCE
3991                                 yfsd_UnlockYAFFS(TRUE);
3992 #endif
3993                                         
3994                                 memcpy(&localBuffer[start],buffer,nToCopy);
3995                         
3996 #ifdef CONFIG_YAFFS_WINCE
3997                                 yfsd_LockYAFFS(TRUE);
3998 #endif
3999                                 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
4000                                 
4001                                 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
4002                         
4003                                 //T(("Write with readback to chunk %d %d  start %d  copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));
4004                         }
4005                         
4006                 }
4007                 else
4008                 {
4009                         
4010 #ifdef CONFIG_YAFFS_WINCE
4011                         // Under WinCE can't do direct transfer. Need to use a local buffer.
4012                         // This is because we otherwise screw up WinCE's memory mapper
4013                                 __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
4014 #ifdef CONFIG_YAFFS_WINCE
4015                                 yfsd_UnlockYAFFS(TRUE);
4016 #endif
4017                         memcpy(localBuffer,buffer,dev->nBytesPerChunk);
4018 #ifdef CONFIG_YAFFS_WINCE
4019                                 yfsd_LockYAFFS(TRUE);
4020 #endif
4021                         chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,dev->nBytesPerChunk,0);
4022                         yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
4023 #else
4024                         // A full chunk. Write directly from the supplied buffer.
4025                         chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,dev->nBytesPerChunk,0);
4026 #endif
4027                         // Since we've overwritten the cached data, we better invalidate it.
4028                         yaffs_InvalidateChunkCache(in,chunk);
4029                         //T(("Write to chunk %d %d\n",chunk,chunkWritten));
4030                 }
4031                 
4032                 if(chunkWritten >= 0)
4033                 {
4034                         n -= nToCopy;
4035                         offset += nToCopy;
4036                         buffer += nToCopy;
4037                         nDone += nToCopy;
4038                 }
4039                 
4040         }
4041         
4042         // Update file object
4043         
4044         if((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
4045         {
4046                 in->variant.fileVariant.fileSize = (startOfWrite + nDone);
4047         }
4048         
4049         in->dirty = 1;
4050         
4051         return nDone;
4052 }
4053
4054 static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
4055 {
4056
4057         yaffs_Device *dev = in->myDev;
4058         int oldFileSize = in->variant.fileVariant.fileSize;
4059
4060         
4061         int lastDel = 1 + (oldFileSize-1)/dev->nBytesPerChunk;
4062                 
4063         int startDel = 1 + (newSize + dev->nBytesPerChunk - 1)/
4064                                                 dev->nBytesPerChunk;
4065         int i;
4066         int chunkId;
4067
4068         // Delete backwards so that we don't end up with holes if
4069         // power is lost part-way through the operation.
4070         for(i = lastDel; i >= startDel; i--)
4071         {
4072                 // NB this could be optimised somewhat,
4073                 // eg. could retrieve the tags and write them without
4074                 // using yaffs_DeleteChunk
4075
4076                 chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
4077                 if(chunkId > 0)
4078                 {
4079                         if(chunkId < (dev->startBlock * dev->nChunksPerBlock) || 
4080                        chunkId >= ((dev->endBlock+1) * dev->nChunksPerBlock))
4081                         {
4082                                 T(YAFFS_TRACE_ALWAYS,("Found daft chunkId %d for %d\n",chunkId,i));
4083                         }
4084                         else
4085                         {
4086                                 in->nDataChunks--;
4087                                 yaffs_DeleteChunk(dev,chunkId,1,__LINE__);
4088                         }
4089                 }
4090         }
4091                 
4092 }
4093
4094 int yaffs_ResizeFile(yaffs_Object *in, int newSize)
4095 {
4096
4097         int oldFileSize = in->variant.fileVariant.fileSize;
4098         int sizeOfPartialChunk;
4099         yaffs_Device *dev = in->myDev;
4100         
4101          sizeOfPartialChunk  = newSize % dev->nBytesPerChunk;
4102                 
4103
4104         yaffs_FlushFilesChunkCache(in); 
4105         yaffs_InvalidateWholeChunkCache(in);
4106
4107         yaffs_CheckGarbageCollection(dev);
4108         
4109         if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
4110         {
4111                 return yaffs_GetFileSize(in);
4112         }
4113         
4114         if(newSize < oldFileSize)
4115         {
4116
4117                 yaffs_PruneResizedChunks(in,newSize);
4118                 
4119                 if(sizeOfPartialChunk != 0)
4120                 {
4121                         int lastChunk = 1+ newSize/dev->nBytesPerChunk;
4122                         __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
4123                         
4124                         // Got to read and rewrite the last chunk with its new size and zero pad
4125                         yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
4126                         
4127                         memset(localBuffer + sizeOfPartialChunk,0, dev->nBytesPerChunk - sizeOfPartialChunk);
4128                         
4129                         yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfPartialChunk,1);
4130                                 
4131                         yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
4132                 }
4133                 
4134                 in->variant.fileVariant.fileSize = newSize;
4135                 
4136                 yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
4137                 
4138                 // TODO write a new object header to show we've shrunk the file
4139                 // Do this only if the file is not in the deleted directory.
4140                 if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED)
4141                 {
4142                         yaffs_UpdateObjectHeader(in,NULL, 0, 1);
4143                 }
4144
4145                 
4146                 return newSize;
4147                 
4148         }
4149         else
4150         {
4151                 return oldFileSize;
4152         }
4153 }
4154
4155
4156 loff_t yaffs_GetFileSize(yaffs_Object *obj)
4157 {
4158         obj = yaffs_GetEquivalentObject(obj);
4159         
4160         switch(obj->variantType)
4161         {
4162                 case YAFFS_OBJECT_TYPE_FILE: 
4163                         return obj->variant.fileVariant.fileSize;
4164                 case YAFFS_OBJECT_TYPE_SYMLINK:
4165                         return yaffs_strlen(obj->variant.symLinkVariant.alias);
4166                 default:
4167                         return 0;
4168         }
4169 }
4170
4171
4172
4173 // yaffs_FlushFile() updates the file's
4174 // objectId in NAND
4175
4176 int yaffs_FlushFile(yaffs_Object *in, int updateTime)
4177 {
4178         int retVal;
4179         if(in->dirty)
4180         {
4181                 //T(("flushing object header\n"));
4182                 
4183                 yaffs_FlushFilesChunkCache(in);
4184                 if(updateTime)
4185                 {
4186 #ifdef CONFIG_YAFFS_WINCE
4187                         yfsd_WinFileTimeNow(in->win_mtime);
4188 #else
4189
4190                         in->st_mtime = Y_CURRENT_TIME;
4191
4192 #endif
4193                 }
4194
4195                 retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
4196         }
4197         else
4198         {
4199                 retVal = YAFFS_OK;
4200         }
4201         
4202         return retVal;
4203         
4204 }
4205
4206
4207 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
4208 {
4209
4210         // First off, invalidate the file's data in the cache, without flushing.
4211         yaffs_InvalidateWholeChunkCache(in);
4212
4213         if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir))
4214         {
4215                 // Move to the unlinked directory so we have a record that it was deleted.
4216                 yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
4217
4218         }
4219
4220         
4221         yaffs_RemoveObjectFromDirectory(in);
4222         yaffs_DeleteChunk(in->myDev,in->chunkId,1,__LINE__);
4223         in->chunkId = -1;
4224
4225 #ifdef __KERNEL__
4226         if(in->myInode)
4227         {
4228                 in->myInode->u.generic_ip = NULL;
4229                 in->myInode = 0;
4230         }
4231 #endif
4232         yaffs_FreeObject(in);
4233         return YAFFS_OK;
4234
4235 }
4236
4237 // yaffs_DeleteFile deletes the whole file data
4238 // and the inode associated with the file.
4239 // It does not delete the links associated with the file.
4240 static int yaffs_UnlinkFile(yaffs_Object *in)
4241 {
4242
4243 #ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION
4244
4245         // Delete the file data & tnodes
4246
4247          yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);
4248          
4249
4250         yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
4251         
4252         return  yaffs_DoGenericObjectDeletion(in);
4253 #else
4254         int retVal;
4255         int immediateDeletion=0;
4256
4257         if(1)
4258         {
4259                 //in->unlinked = 1;
4260                 //in->myDev->nUnlinkedFiles++;
4261                 //in->renameAllowed = 0;
4262 #ifdef __KERNEL__
4263                 if(!in->myInode)
4264                 {
4265                         immediateDeletion = 1;
4266
4267                 }
4268 #else
4269                 if(in->inUse <= 0)
4270                 {
4271                         immediateDeletion = 1;
4272
4273                 }
4274 #endif
4275                 if(immediateDeletion)
4276                 {
4277                         retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
4278                         T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
4279                         in->deleted=1;
4280                         in->myDev->nDeletedFiles++;
4281                         yaffs_SoftDeleteFile(in);
4282                 }
4283                 else
4284                 {
4285                         retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0);
4286                 }
4287         
4288         }
4289         return retVal;
4290
4291         
4292 #endif
4293 }
4294
4295 int yaffs_DeleteFile(yaffs_Object *in)
4296 {
4297         int retVal = YAFFS_OK;
4298         
4299         if(in->nDataChunks > 0)
4300         {
4301                 // Use soft deletion
4302                 if(!in->unlinked)
4303                 {
4304                         retVal = yaffs_UnlinkFile(in);
4305                 }
4306                 if(retVal == YAFFS_OK && 
4307                 in->unlinked &&
4308                 !in->deleted)
4309                 {
4310                         in->deleted = 1;
4311                         in->myDev->nDeletedFiles++;
4312                         yaffs_SoftDeleteFile(in);
4313                 }
4314                 return in->deleted ? YAFFS_OK : YAFFS_FAIL;     
4315         }
4316         else
4317         {
4318                 // The file has no data chunks so we toss it immediately
4319                 yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
4320                 in->variant.fileVariant.top = NULL;
4321                 yaffs_DoGenericObjectDeletion(in);      
4322                 
4323                 return YAFFS_OK;        
4324         }
4325 }
4326
4327 static int yaffs_DeleteDirectory(yaffs_Object *in)
4328 {
4329         //First check that the directory is empty.
4330         if(list_empty(&in->variant.directoryVariant.children))
4331         {
4332                 return  yaffs_DoGenericObjectDeletion(in);
4333         }
4334         
4335         return YAFFS_FAIL;
4336         
4337 }
4338
4339 static int yaffs_DeleteSymLink(yaffs_Object *in)
4340 {
4341         YFREE(in->variant.symLinkVariant.alias);
4342
4343         return  yaffs_DoGenericObjectDeletion(in);
4344 }
4345
4346 static int yaffs_DeleteHardLink(yaffs_Object *in)
4347 {
4348         // remove this hardlink from the list assocaited with the equivalent
4349         // object
4350         list_del(&in->hardLinks);
4351         return  yaffs_DoGenericObjectDeletion(in);      
4352 }
4353
4354
4355 static void yaffs_DestroyObject(yaffs_Object *obj)
4356 {
4357         switch(obj->variantType)
4358         {
4359                 case YAFFS_OBJECT_TYPE_FILE: yaffs_DeleteFile(obj); break;
4360                 case YAFFS_OBJECT_TYPE_DIRECTORY: yaffs_DeleteDirectory(obj); break;
4361                 case YAFFS_OBJECT_TYPE_SYMLINK: yaffs_DeleteSymLink(obj); break;
4362                 case YAFFS_OBJECT_TYPE_HARDLINK: yaffs_DeleteHardLink(obj); break;
4363                 case YAFFS_OBJECT_TYPE_SPECIAL: yaffs_DoGenericObjectDeletion(obj); break;
4364                 case YAFFS_OBJECT_TYPE_UNKNOWN: break; // should not happen.
4365         }
4366 }
4367
4368
4369 static int yaffs_UnlinkWorker(yaffs_Object *obj)
4370 {
4371
4372         
4373         if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
4374         {
4375                 return  yaffs_DeleteHardLink(obj);
4376         }
4377         else if(!list_empty(&obj->hardLinks))
4378         {       
4379                 // Curve ball: We're unlinking an object that has a hardlink.
4380                 //
4381                 //      This problem arises because we are not strictly following
4382                 //  The Linux link/inode model.
4383                 //
4384                 // We can't really delete the object.
4385                 // Instead, we do the following:
4386                 // - Select a hardlink.
4387                 // - Unhook it from the hard links
4388                 // - Unhook it from its parent directory (so that the rename can work)
4389                 // - Rename the object to the hardlink's name.
4390                 // - Delete the hardlink
4391                 
4392                 
4393                 yaffs_Object *hl;
4394                 int retVal;
4395                 YCHAR name[YAFFS_MAX_NAME_LENGTH+1];
4396                 
4397                 hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
4398                 
4399                 list_del_init(&hl->hardLinks);
4400                 list_del_init(&hl->siblings);
4401                 
4402                 yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
4403                 
4404                 retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0);
4405                 
4406                 if(retVal == YAFFS_OK)
4407                 {
4408                         retVal = yaffs_DoGenericObjectDeletion(hl);
4409                 }
4410                 return retVal;
4411                                 
4412         }
4413         else
4414         {
4415                 switch(obj->variantType)
4416                 {
4417                         case YAFFS_OBJECT_TYPE_FILE:
4418                                 return yaffs_UnlinkFile(obj);
4419                                 break;
4420                         case YAFFS_OBJECT_TYPE_DIRECTORY:
4421                                 return yaffs_DeleteDirectory(obj);
4422                                 break;
4423                         case YAFFS_OBJECT_TYPE_SYMLINK:
4424                                 return yaffs_DeleteSymLink(obj);
4425                                 break;
4426                         case YAFFS_OBJECT_TYPE_HARDLINK:
4427                         case YAFFS_OBJECT_TYPE_UNKNOWN:
4428                         default:
4429                                 return YAFFS_FAIL;
4430                 }
4431         }
4432 }
4433
4434 int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
4435 {
4436         yaffs_Object *obj;
4437         
4438          obj = yaffs_FindObjectByName(dir,name);
4439          
4440          if(obj && obj->unlinkAllowed)
4441          {
4442                 return yaffs_UnlinkWorker(obj);
4443          }
4444          
4445          return YAFFS_FAIL;
4446         
4447 }
4448
4449 //////////////// Initialisation Scanning /////////////////
4450
4451
4452 #if 0
4453 // For now we use the SmartMedia check.
4454 // We look at the blockStatus byte in the first two chunks
4455 // These must be 0xFF to pass as OK.
4456 // todo: this function needs to be modifyable foir different NAND types
4457 // and different chunk sizes.  Suggest make this into a per-device configurable
4458 // function.
4459 static int yaffs_IsBlockBad(yaffs_Device *dev, int blk)
4460 {
4461         yaffsExtendedTags *tags;
4462         
4463         yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock,NULL,&tags,1);
4464 #if 1
4465         if(yaffs_CountBits(spare.blockStatus) < 7)
4466         {
4467                 return 1;
4468         }
4469 #else
4470         if(spare.blockStatus != 0xFF)
4471         {
4472                 return 1;
4473         }
4474 #endif
4475         yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock + 1,NULL,&spare,1);
4476
4477 #if 1
4478         if(yaffs_CountBits(spare.blockStatus) < 7)
4479         {
4480                 return 1;
4481         }
4482 #else
4483         if(spare.blockStatus != 0xFF)
4484         {
4485                 return 1;
4486         }
4487 #endif
4488         
4489         return 0;
4490         
4491 }
4492
4493 #endif
4494
4495
4496 typedef struct 
4497 {
4498         int seq;
4499         int block;
4500 } yaffs_BlockIndex;
4501
4502
4503
4504 static int yaffs_Scan(yaffs_Device *dev)
4505 {
4506         yaffs_ExtendedTags tags;
4507         int blk;
4508         int blockIterator;
4509         int startIterator;
4510         int endIterator;
4511         int nBlocksToScan = 0;
4512         
4513         int chunk;
4514         int c;
4515         int deleted;
4516         yaffs_BlockState state;
4517         yaffs_Object *hardList = NULL;
4518         yaffs_Object *hl;
4519         yaffs_BlockInfo *bi;
4520         int sequenceNumber;     
4521         yaffs_ObjectHeader *oh;
4522         yaffs_Object *in;
4523         yaffs_Object *parent;
4524         int nBlocks = dev->endBlock - dev->startBlock + 1;
4525         
4526         __u8 *chunkData;
4527
4528         yaffs_BlockIndex *blockIndex = NULL;
4529
4530         T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts  startblk %d endblk %d..." TENDSTR),dev->startBlock,dev->endBlock));
4531         
4532         chunkData = yaffs_GetTempBuffer(dev,__LINE__);
4533         
4534         
4535         dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
4536         
4537         if(dev->isYaffs2)
4538         {
4539                 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));               
4540         }
4541         
4542         
4543         // Scan all the blocks to determine their state
4544         for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
4545         {
4546                 bi = yaffs_GetBlockInfo(dev,blk);
4547                 yaffs_ClearChunkBits(dev,blk);
4548                 bi->pagesInUse = 0;
4549                 bi->softDeletions = 0;
4550                                 
4551                 yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
4552                 
4553                 bi->blockState = state;
4554                 bi->sequenceNumber = sequenceNumber;
4555
4556                 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
4557                 
4558                 if(state == YAFFS_BLOCK_STATE_DEAD)
4559                 {
4560                         T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
4561                 }
4562                 else if(state == YAFFS_BLOCK_STATE_EMPTY)
4563                 {
4564                         T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
4565                         dev->nErasedBlocks++;
4566                         dev->nFreeChunks += dev->nChunksPerBlock;
4567                 }
4568                 else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4569                 {
4570                                         
4571                         // Determine the highest sequence number
4572                         if( dev->isYaffs2 &&
4573                             sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
4574                             sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
4575                          {
4576                                 
4577                                 blockIndex[nBlocksToScan].seq = sequenceNumber;
4578                                 blockIndex[nBlocksToScan].block = blk;
4579                                 
4580                                 nBlocksToScan++;
4581
4582                                 if(sequenceNumber >= dev->sequenceNumber)
4583                                 {
4584                                         dev->sequenceNumber = sequenceNumber;
4585                                 }
4586                         }
4587                         else if(dev->isYaffs2)
4588                         {
4589                                 // TODO: Nasty sequence number!
4590                                 T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
4591
4592                         }
4593                 }
4594         }
4595         
4596         // Sort the blocks
4597         // Dungy old bubble sort for now...
4598         if(dev->isYaffs2)
4599         {
4600                 yaffs_BlockIndex temp;
4601                 int i;
4602                 int j;
4603                 
4604                 for(i = 0; i < nBlocksToScan; i++)
4605                         for(j = i+1; j < nBlocksToScan; j++)
4606                          if(blockIndex[i].seq > blockIndex[j].seq)
4607                          {
4608                                 temp = blockIndex[j];
4609                                 blockIndex[j] = blockIndex[i];
4610                                 blockIndex[i] = temp;
4611                          }
4612         }
4613         
4614         
4615         // Now scan the blocks looking at the data.
4616         if(dev->isYaffs2)
4617         {
4618                 startIterator = 0;
4619                 endIterator = nBlocksToScan-1;
4620                 T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
4621         }
4622         else
4623         {
4624                 startIterator = dev->startBlock;
4625                 endIterator = dev->endBlock;
4626         }
4627         
4628         for(blockIterator = startIterator; blockIterator <= endIterator; blockIterator++)
4629         {
4630         
4631                 if(dev->isYaffs2)
4632                 {
4633                         // get the block to scan in the correct order
4634                         blk = blockIndex[blockIterator].block;
4635                 }
4636                 else
4637                 {
4638                         blk = blockIterator;
4639                 }
4640
4641
4642                 bi = yaffs_GetBlockInfo(dev,blk);
4643                 state = bi->blockState;
4644                 
4645                 deleted = 0;
4646                 
4647                 for(c = 0; c < dev->nChunksPerBlock && 
4648                                    state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++)
4649                 {
4650                         // Read the tags and decide what to do
4651                         chunk = blk * dev->nChunksPerBlock + c;
4652                         
4653                         yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
4654
4655                         // Let's have a good look at this chunk...
4656         
4657                         
4658                         if(!dev->isYaffs2 && tags.chunkDeleted)
4659                         {
4660                                 // A deleted chunk
4661                                 deleted++;
4662                                 dev->nFreeChunks ++;
4663                                 //T((" %d %d deleted\n",blk,c));
4664                         }
4665                         else if(!tags.chunkUsed)
4666                         {
4667                                 // An unassigned chunk in the block
4668                                 // This means that either the block is empty or 
4669                                 // this is the one being allocated from
4670                                 
4671                                 if(c == 0)
4672                                 {
4673                                         // We're looking at the first chunk in the block so the block is unused
4674                                         state = YAFFS_BLOCK_STATE_EMPTY;
4675                                         dev->nErasedBlocks++;
4676                                 }
4677                                 else
4678                                 {
4679                                         // this is the block being allocated from
4680                                         T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
4681                                         state = YAFFS_BLOCK_STATE_ALLOCATING;
4682                                         dev->allocationBlock = blk;
4683                                         dev->allocationPage = c;
4684                                         dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
4685                                                                                                           // go forth from here.
4686                                         //Yaffs2 sanity check:
4687                                         // This should be the one with the highest sequence number
4688                                         if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
4689                                         {
4690                                                 T(YAFFS_TRACE_ALWAYS,
4691                                                                 (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
4692                                                                 blk,bi->sequenceNumber,dev->sequenceNumber));
4693                                         }
4694                                 }
4695
4696                                 dev->nFreeChunks += (dev->nChunksPerBlock - c);
4697                         }
4698                         else if(tags.chunkId > 0)
4699                         {
4700                                 int endpos;
4701                                 // A data chunk.
4702                                 yaffs_SetChunkBit(dev,blk,c);
4703                                 bi->pagesInUse++;
4704                                                                 
4705                                 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
4706                                 // PutChunkIntoFIle checks for a clash (two data chunks with
4707                                 // the same chunkId).
4708                                 yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
4709                                 endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
4710                                 if(in->variant.fileVariant.scannedFileSize <endpos)
4711                                 {
4712                                         in->variant.fileVariant.scannedFileSize = endpos;
4713                                         if(!dev->useHeaderFileSize)
4714                                         {
4715                                                 in->variant.fileVariant.fileSize =      
4716                                                         in->variant.fileVariant.scannedFileSize;
4717                                         }
4718
4719                                 }
4720                                 //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));  
4721                         }
4722                         else
4723                         {
4724                                 // chunkId == 0, so it is an ObjectHeader.
4725                                 // Thus, we read in the object header and make the object
4726                                 yaffs_SetChunkBit(dev,blk,c);
4727                                 bi->pagesInUse++;
4728                                                         
4729                                 yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
4730                                 
4731                                 oh = (yaffs_ObjectHeader *)chunkData;
4732                                 
4733                                 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
4734                                 
4735                                 if(in->valid)
4736                                 {
4737                                         // We have already filled this one. We have a duplicate and need to resolve it.
4738                                         
4739                                         unsigned existingSerial = in->serial;
4740                                         unsigned newSerial = tags.serialNumber;
4741                                         
4742                                         if( dev->isYaffs2 ||
4743                                             ((existingSerial+1) & 3) == newSerial)
4744                                         {
4745                                                 // Use new one - destroy the exisiting one
4746                                                 yaffs_DeleteChunk(dev,in->chunkId,1,__LINE__);
4747                                                 in->valid = 0;
4748                                         }
4749                                         else
4750                                         {
4751                                                 // Use existing - destroy this one.
4752                                                 yaffs_DeleteChunk(dev,chunk,1,__LINE__);
4753                                         }
4754                                 }
4755                                 
4756                                 if(!in->valid &&
4757                                    (tags.objectId == YAFFS_OBJECTID_ROOT ||
4758                                     tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
4759                                 {
4760                                         // We only load some info, don't fiddle with directory structure
4761                                         in->valid = 1;
4762                                         in->variantType = oh->type;
4763         
4764                                         in->st_mode  = oh->st_mode;
4765 #ifdef CONFIG_YAFFS_WINCE
4766                                         in->win_atime[0] = oh->win_atime[0];
4767                                         in->win_ctime[0] = oh->win_ctime[0];
4768                                         in->win_mtime[0] = oh->win_mtime[0];
4769                                         in->win_atime[1] = oh->win_atime[1];
4770                                         in->win_ctime[1] = oh->win_ctime[1];
4771                                         in->win_mtime[1] = oh->win_mtime[1];
4772 #else
4773                                         in->st_uid   = oh->st_uid;
4774                                         in->st_gid   = oh->st_gid;
4775                                         in->st_atime = oh->st_atime;
4776                                         in->st_mtime = oh->st_mtime;
4777                                         in->st_ctime = oh->st_ctime;
4778                                         in->st_rdev = oh->st_rdev;
4779 #endif
4780                                         in->chunkId  = chunk;
4781
4782                                 }
4783                                 else if(!in->valid)
4784                                 {
4785                                         // we need to load this info
4786                                 
4787                                         in->valid = 1;
4788                                         in->variantType = oh->type;
4789         
4790                                         in->st_mode  = oh->st_mode;
4791 #ifdef CONFIG_YAFFS_WINCE
4792                                         in->win_atime[0] = oh->win_atime[0];
4793                                         in->win_ctime[0] = oh->win_ctime[0];
4794                                         in->win_mtime[0] = oh->win_mtime[0];
4795                                         in->win_atime[1] = oh->win_atime[1];
4796                                         in->win_ctime[1] = oh->win_ctime[1];
4797                                         in->win_mtime[1] = oh->win_mtime[1];
4798 #else
4799                                         in->st_uid   = oh->st_uid;
4800                                         in->st_gid   = oh->st_gid;
4801                                         in->st_atime = oh->st_atime;
4802                                         in->st_mtime = oh->st_mtime;
4803                                         in->st_ctime = oh->st_ctime;
4804                                         in->st_rdev = oh->st_rdev;
4805 #endif
4806                                         in->chunkId  = chunk;
4807
4808                                         yaffs_SetObjectName(in,oh->name);
4809                                         in->dirty = 0;
4810                                                         
4811                                         // directory stuff...
4812                                         // hook up to parent
4813         
4814                                         parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
4815                                         if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
4816                                         {
4817                                                 // Set up as a directory
4818                                                 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
4819                                                 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
4820                                         }
4821                                         else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
4822                                         {
4823                                                 // Hoosterman, another problem....
4824                                                 // We're trying to use a non-directory as a directory
4825
4826                                                 T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
4827                                                 parent = dev->lostNFoundDir;
4828                                         }
4829                                 
4830                                         yaffs_AddObjectToDirectory(parent,in);
4831
4832                                         if(0 && (parent == dev->deletedDir ||
4833                                            parent == dev->unlinkedDir))
4834                                         {
4835                                                 in->deleted = 1; // If it is unlinked at start up then it wants deleting
4836                                                 dev->nDeletedFiles++;
4837                                         }
4838                                 
4839                                         // Note re hardlinks.
4840                                         // Since we might scan a hardlink before its equivalent object is scanned
4841                                         // we put them all in a list.
4842                                         // After scanning is complete, we should have all the objects, so we run through this
4843                                         // list and fix up all the chains.              
4844         
4845                                         switch(in->variantType)
4846                                         {
4847                                                 case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem
4848                                                         break;
4849                                                 case YAFFS_OBJECT_TYPE_FILE:
4850                                                         if(dev->isYaffs2 && oh->isShrink)
4851                                                         {
4852                                                                 // Prune back the shrunken chunks
4853                                                                 yaffs_PruneResizedChunks(in,oh->fileSize);
4854                                                                 // Mark the block as having a shrinkHeader
4855                                                                 bi->hasShrinkHeader = 1;
4856                                                         }
4857                                                         
4858                                                         if(dev->useHeaderFileSize)
4859                                                                 in->variant.fileVariant.fileSize = oh->fileSize;
4860                                                                 
4861                                                         break;
4862                                                 case YAFFS_OBJECT_TYPE_HARDLINK:
4863                                                         in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
4864                                                         in->hardLinks.next = (struct list_head *)hardList;
4865                                                         hardList = in;
4866                                                         break;
4867                                                 case YAFFS_OBJECT_TYPE_DIRECTORY:       // Do nothing
4868                                                         break;
4869                                                 case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
4870                                                         break;
4871                                                 case YAFFS_OBJECT_TYPE_SYMLINK:         // Do nothing
4872                                                         in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
4873                                                         break;
4874                                         }
4875
4876                                         if(parent == dev->deletedDir)
4877                                         {
4878                                                 yaffs_DestroyObject(in);
4879                                                 bi->hasShrinkHeader = 1;
4880                                         }
4881                                         //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));        
4882                                 }
4883                         }
4884                 }
4885                 
4886                 if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
4887                 {
4888                         // If we got this far while scanning, then the block is fully allocated.
4889                         state = YAFFS_BLOCK_STATE_FULL; 
4890                 }
4891                 
4892                 bi->blockState = state;
4893                 
4894                 // Now let's see if it was dirty
4895                 if(     bi->pagesInUse == 0 &&
4896                         !bi->hasShrinkHeader &&
4897                 bi->blockState == YAFFS_BLOCK_STATE_FULL)
4898             {
4899                 yaffs_BlockBecameDirty(dev,blk);
4900             }
4901
4902         }
4903         
4904         if(blockIndex)
4905         {
4906                 YFREE(blockIndex);
4907         }
4908         
4909         // Ok, we've done all the scanning.
4910         
4911         // Fix up the hard link chains.
4912         // We should now have scanned all the objects, now it's time to add these 
4913         // hardlinks.
4914         while(hardList)
4915         {
4916                 hl = hardList;
4917                 hardList = (yaffs_Object *)(hardList->hardLinks.next);
4918                 
4919                 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
4920                 
4921                 if(in)
4922                 {
4923                         // Add the hardlink pointers
4924                         hl->variant.hardLinkVariant.equivalentObject=in;
4925                         list_add(&hl->hardLinks,&in->hardLinks);
4926                 }
4927                 else
4928                 {
4929                         //Todo Need to report/handle this better.
4930                         // Got a problem... hardlink to a non-existant object
4931                         hl->variant.hardLinkVariant.equivalentObject=NULL;
4932                         INIT_LIST_HEAD(&hl->hardLinks);
4933                         
4934                 }
4935                 
4936         }
4937         
4938         {
4939                 struct list_head *i;    
4940                 struct list_head *n;
4941                         
4942                 yaffs_Object *l;
4943                 // Soft delete all the unlinked files
4944                 list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
4945                 {
4946                         if(i)
4947                         {
4948                                 l = list_entry(i, yaffs_Object,siblings);
4949                                 if(l->deleted)
4950                                 {
4951                                         yaffs_DestroyObject(l);         
4952                                 }
4953                         }
4954                 }       
4955         }
4956         
4957         yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
4958
4959         T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan ends" TENDSTR)));
4960
4961         return YAFFS_OK;
4962 }
4963
4964
4965
4966 ////////////////////////// Directory Functions /////////////////////////
4967
4968
4969 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
4970 {
4971
4972         if(obj->siblings.prev == NULL)
4973         {
4974                 // Not initialised
4975                 INIT_LIST_HEAD(&obj->siblings);
4976                 
4977         }
4978         else if(!list_empty(&obj->siblings))
4979         {
4980                 // If it is holed up somewhere else, un hook it
4981                 list_del_init(&obj->siblings);
4982         }
4983         // Now add it
4984         list_add(&obj->siblings,&directory->variant.directoryVariant.children);
4985         obj->parent = directory;
4986         
4987         if(directory == obj->myDev->unlinkedDir || directory == obj->myDev->deletedDir)
4988         {
4989                 obj->unlinked = 1;
4990                 obj->myDev->nUnlinkedFiles++;
4991                 obj->renameAllowed = 0;
4992         }
4993 }
4994
4995 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
4996 {
4997         list_del_init(&obj->siblings);
4998         obj->parent = NULL;
4999 }
5000
5001 yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const YCHAR *name)
5002 {
5003         int sum;
5004         
5005         struct list_head *i;
5006         YCHAR buffer[YAFFS_MAX_NAME_LENGTH+1];
5007         
5008         yaffs_Object *l;
5009         
5010         sum = yaffs_CalcNameSum(name);
5011         
5012         list_for_each(i,&directory->variant.directoryVariant.children)
5013         {
5014                 if(i)
5015                 {
5016                         l = list_entry(i, yaffs_Object,siblings);
5017                 
5018                         // Special case for lost-n-found
5019                         if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
5020                         {
5021                                 if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
5022                                 {
5023                                         return l;
5024                                 }
5025                         }
5026                         else if(yaffs_SumCompare(l->sum, sum)||
5027                                     l->chunkId <= 0) //LostnFound cunk called Objxxx
5028                         {
5029                                 // Do a real check
5030                                 yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH);
5031                                 if(yaffs_strcmp(name,buffer) == 0)
5032                                 {
5033                                         return l;
5034                                 }
5035                         
5036                         }                       
5037                 }
5038         }
5039         
5040         return NULL;
5041 }
5042
5043
5044 int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
5045 {
5046         struct list_head *i;    
5047         yaffs_Object *l;
5048         
5049         
5050         list_for_each(i,&theDir->variant.directoryVariant.children)
5051         {
5052                 if(i)
5053                 {
5054                         l = list_entry(i, yaffs_Object,siblings);
5055                         if(l && !fn(l))
5056                         {
5057                                 return YAFFS_FAIL;
5058                         }
5059                 }
5060         }
5061         
5062         return YAFFS_OK;
5063
5064 }
5065
5066
5067 // GetEquivalentObject dereferences any hard links to get to the
5068 // actual object.
5069
5070 yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
5071 {
5072         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
5073         {
5074                 // We want the object id of the equivalent object, not this one
5075                 obj = obj->variant.hardLinkVariant.equivalentObject;
5076         }
5077         return obj;
5078
5079 }
5080
5081 int yaffs_GetObjectName(yaffs_Object *obj,YCHAR *name,int buffSize)
5082 {
5083         memset(name,0,buffSize * sizeof(YCHAR));
5084         
5085         if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
5086         {
5087                 yaffs_strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
5088         }
5089         else if(obj->chunkId <= 0)
5090         {
5091                 YCHAR locName[20];
5092                 // make up a name
5093                 yaffs_sprintf(locName,_Y("%s%d"),YAFFS_LOSTNFOUND_PREFIX,obj->objectId);
5094                 yaffs_strncpy(name,locName,buffSize - 1);
5095
5096         }
5097 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
5098         else if(obj->shortName[0])
5099         {
5100                 yaffs_strcpy(name,obj->shortName);
5101         }
5102 #endif
5103         else
5104         {
5105                 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev,__LINE__);
5106                 
5107                 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
5108
5109                 memset(buffer,0,obj->myDev->nBytesPerChunk);
5110         
5111                 if(obj->chunkId >= 0)
5112                 {
5113                         yaffs_ReadChunkWithTagsFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
5114                 }
5115                 yaffs_strncpy(name,oh->name,buffSize - 1);
5116
5117                 yaffs_ReleaseTempBuffer(obj->myDev,buffer,__LINE__);
5118         }
5119         
5120         return yaffs_strlen(name);
5121 }
5122
5123 int yaffs_GetObjectFileLength(yaffs_Object *obj)
5124 {
5125         
5126         // Dereference any hard linking
5127         obj = yaffs_GetEquivalentObject(obj);
5128         
5129         if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
5130         {
5131                 return obj->variant.fileVariant.fileSize;
5132         }
5133         if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
5134         {
5135                 return yaffs_strlen(obj->variant.symLinkVariant.alias);
5136         }
5137         else
5138         {
5139                 // Only a directory should drop through to here
5140                 return obj->myDev->nBytesPerChunk;
5141         }       
5142 }
5143
5144 int yaffs_GetObjectLinkCount(yaffs_Object *obj)
5145 {
5146         int count = 0; 
5147         struct list_head *i;
5148         
5149         if(!obj->unlinked)
5150         {
5151                 count++;        // the object itself
5152         }
5153         list_for_each(i,&obj->hardLinks)
5154         {
5155                 count++;        // add the hard links;
5156         }
5157         return count;
5158         
5159 }
5160
5161
5162 int yaffs_GetObjectInode(yaffs_Object *obj)
5163 {
5164         obj = yaffs_GetEquivalentObject(obj);
5165         
5166         return obj->objectId;
5167 }
5168
5169 unsigned yaffs_GetObjectType(yaffs_Object *obj)
5170 {
5171         obj = yaffs_GetEquivalentObject(obj);
5172         
5173         switch(obj->variantType)
5174         {
5175                 case YAFFS_OBJECT_TYPE_FILE:            return DT_REG; break;
5176                 case YAFFS_OBJECT_TYPE_DIRECTORY:       return DT_DIR; break;
5177                 case YAFFS_OBJECT_TYPE_SYMLINK:         return DT_LNK; break;
5178                 case YAFFS_OBJECT_TYPE_HARDLINK:        return DT_REG; break;
5179                 case YAFFS_OBJECT_TYPE_SPECIAL:         
5180                         if(S_ISFIFO(obj->st_mode)) return DT_FIFO;
5181                         if(S_ISCHR(obj->st_mode)) return DT_CHR;
5182                         if(S_ISBLK(obj->st_mode)) return DT_BLK;
5183                         if(S_ISSOCK(obj->st_mode)) return DT_SOCK;
5184                 default: return DT_REG; break;
5185         }
5186 }
5187
5188 YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
5189 {
5190         obj = yaffs_GetEquivalentObject(obj);
5191         if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
5192         {
5193                 return yaffs_CloneString(obj->variant.symLinkVariant.alias);
5194         }
5195         else
5196         {
5197                 return yaffs_CloneString(_Y(""));
5198         }
5199 }
5200
5201 #ifndef CONFIG_YAFFS_WINCE
5202
5203 int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
5204 {
5205         unsigned int valid = attr->ia_valid;
5206         
5207         if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
5208         if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
5209         if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
5210         
5211         if(valid & ATTR_ATIME) obj->st_atime = Y_TIME_CONVERT(attr->ia_atime);
5212         if(valid & ATTR_CTIME) obj->st_ctime = Y_TIME_CONVERT(attr->ia_ctime);
5213         if(valid & ATTR_MTIME) obj->st_mtime = Y_TIME_CONVERT(attr->ia_mtime);
5214         
5215         if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
5216         
5217         yaffs_UpdateObjectHeader(obj,NULL,1,0);
5218         
5219         return YAFFS_OK;
5220         
5221 }
5222 int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
5223 {
5224         unsigned int valid = 0;
5225         
5226         attr->ia_mode = obj->st_mode;   valid |= ATTR_MODE;
5227         attr->ia_uid = obj->st_uid;             valid |= ATTR_UID;
5228         attr->ia_gid = obj->st_gid;             valid |= ATTR_GID;
5229         
5230         Y_TIME_CONVERT(attr->ia_atime)= obj->st_atime;  valid |= ATTR_ATIME;
5231         Y_TIME_CONVERT(attr->ia_ctime) = obj->st_ctime; valid |= ATTR_CTIME;
5232         Y_TIME_CONVERT(attr->ia_mtime) = obj->st_mtime; valid |= ATTR_MTIME;
5233
5234         attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
5235         
5236         attr->ia_valid = valid;
5237         
5238         return YAFFS_OK;
5239         
5240 }
5241
5242 #endif
5243
5244 int yaffs_DumpObject(yaffs_Object *obj)
5245 {
5246 //      __u8 buffer[YAFFS_BYTES_PER_CHUNK];
5247         YCHAR name[257];
5248 //      yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
5249
5250 //      memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
5251         
5252 //      if(obj->chunkId >= 0)
5253 //      {
5254 //              yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
5255 //      }
5256         
5257         yaffs_GetObjectName(obj,name,256);
5258         
5259         T(YAFFS_TRACE_ALWAYS,(TSTR("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n" TENDSTR),
5260                         obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, 
5261                         obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
5262
5263 #if 0
5264         YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
5265                         obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial, 
5266                         obj->sum, obj->chunkId));
5267                 switch(obj->variantType)
5268         {
5269                 case YAFFS_OBJECT_TYPE_FILE: 
5270                         YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
5271                         break;
5272                 case YAFFS_OBJECT_TYPE_DIRECTORY:
5273                         YPRINTF((" DIRECTORY\n"));
5274                         break;
5275                 case YAFFS_OBJECT_TYPE_HARDLINK: //todo
5276                 case YAFFS_OBJECT_TYPE_SYMLINK:
5277                 case YAFFS_OBJECT_TYPE_UNKNOWN:
5278                 default:
5279         }
5280 #endif
5281         
5282         return YAFFS_OK;
5283 }
5284
5285
5286 ///////////////////////// Initialisation code ///////////////////////////
5287
5288
5289 int yaffs_CheckDevFunctions(const yaffs_Device *dev)
5290 {
5291
5292         // Common functions, gotta have
5293         if(!dev->eraseBlockInNAND ||
5294            !dev->initialiseNAND) return 0;
5295
5296 #ifdef CONFIG_YAFFS_YAFFS2
5297
5298         // Can use the "with tags" style interface for yaffs1 or yaffs2
5299         if(dev->writeChunkWithTagsToNAND &&
5300            dev->readChunkWithTagsFromNAND &&
5301            !dev->writeChunkToNAND &&
5302            !dev->readChunkFromNAND &&
5303            dev->markNANDBlockBad &&
5304            dev->queryNANDBlock) return 1;
5305 #endif
5306
5307         // Can use the "spare" style interface for yaffs1
5308         if(!dev->isYaffs2 &&
5309            !dev->writeChunkWithTagsToNAND &&
5310            !dev->readChunkWithTagsFromNAND &&
5311            dev->writeChunkToNAND &&
5312            dev->readChunkFromNAND &&
5313            !dev->markNANDBlockBad &&
5314            !dev->queryNANDBlock) return 1;
5315
5316         return 0; // bad
5317 }
5318
5319
5320 int yaffs_GutsInitialise(yaffs_Device *dev)
5321 {
5322         unsigned x;
5323         int bits;
5324         int extraBits;
5325         int nBlocks;
5326
5327         T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
5328         // Check stuff that must be set
5329
5330         if(!dev)
5331         {
5332                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Need a device" TENDSTR)));
5333                 return YAFFS_FAIL;
5334         }
5335
5336         // Check geometry parameters.
5337
5338         if(     (dev->isYaffs2 && dev->nBytesPerChunk <1024)  ||
5339                 (!dev->isYaffs2 && dev->nBytesPerChunk !=512)  ||
5340                 dev->nChunksPerBlock < 2 ||
5341                 dev->nReservedBlocks < 2 ||
5342                 dev->startBlock <= 0 ||
5343                 dev->endBlock <= 0 ||
5344                 dev->endBlock <= (dev->startBlock + dev->nReservedBlocks + 2) // otherwise it is too small
5345           )
5346         {
5347                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " TENDSTR),
5348                    dev->nBytesPerChunk, dev->isYaffs2 ? "2" : ""));
5349                 return YAFFS_FAIL;
5350         }
5351
5352         if(yaffs_InitialiseNAND(dev) != YAFFS_OK)
5353         {
5354                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
5355                 return YAFFS_FAIL;
5356         }
5357
5358         // Got the right mix of functions?
5359         //
5360         if(!yaffs_CheckDevFunctions(dev))
5361         {
5362                 //Function missing
5363                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device function(s) missing or wrong\n" TENDSTR)));
5364
5365                 return YAFFS_FAIL;
5366         }
5367
5368         // This is really a compilation check.
5369         if(!yaffs_CheckStructures())
5370         {
5371                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
5372                 return YAFFS_FAIL;
5373         }
5374
5375         if(dev->isMounted)
5376         {
5377                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device already mounted\n" TENDSTR)));
5378                 return YAFFS_FAIL;
5379         }
5380
5381         //
5382         //
5383         // Finished with most checks. One or two more checks happen later on too.
5384         //
5385
5386         dev->isMounted = 1;
5387
5388
5389         nBlocks = dev->endBlock - dev->startBlock + 1;
5390
5391
5392
5393         // OK now calculate a few things for the device
5394         // Calculate chunkGroupBits.
5395         // We need to find the next power of 2 > than endBlock
5396         
5397         x = dev->nChunksPerBlock * (dev->endBlock+1);
5398         
5399         for(bits = extraBits = 0; x > 1; bits++)
5400         {
5401                 if(x & 1) extraBits++;
5402                 x >>= 1;
5403         }
5404
5405         if(extraBits > 0) bits++;
5406         
5407         
5408         // Level0 Tnodes are 16 bits, so if the bitwidth of the
5409         // chunk range we're using is greater than 16 we need
5410         // to figure out chunk shift and chunkGroupSize
5411         if(bits <= 16) 
5412         {
5413                 dev->chunkGroupBits = 0;
5414         }
5415         else
5416         {
5417                 dev->chunkGroupBits = bits - 16;
5418         }
5419         
5420         dev->chunkGroupSize = 1 << dev->chunkGroupBits;
5421
5422         if(dev->nChunksPerBlock < dev->chunkGroupSize)
5423         {
5424                 // We have a problem because the soft delete won't work if
5425                 // the chunk group size > chunks per block.
5426                 // This can be remedied by using larger "virtual blocks".
5427                 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: chunk group too large\n" TENDSTR)));
5428                 
5429                 return YAFFS_FAIL;
5430         }
5431
5432         
5433         // OK, we've finished verifying the device, lets continue with initialisation
5434         
5435         // More device initialisation
5436         dev->garbageCollections = 0;
5437         dev->passiveGarbageCollections = 0;
5438         dev->currentDirtyChecker = 0;
5439         dev->bufferedBlock = -1;
5440         dev->doingBufferedBlockRewrite = 0;
5441         dev->nDeletedFiles = 0;
5442         dev->nBackgroundDeletions=0;
5443         dev->nUnlinkedFiles = 0;
5444         dev->eccFixed=0;
5445         dev->eccUnfixed=0;
5446         dev->tagsEccFixed=0;
5447         dev->tagsEccUnfixed=0;
5448         dev->nErasureFailures = 0;
5449         
5450         //dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
5451         // Initialise temporary buffers
5452         {
5453                 int i;
5454                 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
5455                 {
5456                         dev->tempBuffer[i].line = 0; // not in use
5457                         dev->tempBuffer[i].buffer = YMALLOC(dev->nBytesPerChunk);
5458                 }
5459         }
5460         
5461
5462         
5463         yaffs_InitialiseBlocks(dev,nBlocks);
5464         
5465         yaffs_InitialiseTnodes(dev);
5466
5467         yaffs_InitialiseObjects(dev);
5468         
5469         dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
5470         
5471         if(dev->nShortOpCaches > 0)
5472         { 
5473                 int i;
5474                 
5475                 if(dev->nShortOpCaches >  YAFFS_MAX_SHORT_OP_CACHES)
5476                 {
5477                         dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
5478                 }
5479                 
5480                 dev->srCache = YMALLOC( dev->nShortOpCaches * sizeof(yaffs_ChunkCache));
5481                 
5482                 for(i=0; i < dev->nShortOpCaches; i++)
5483                 {
5484                         dev->srCache[i].object = NULL;
5485                         dev->srCache[i].lastUse = 0;
5486                         dev->srCache[i].dirty = 0;
5487                         dev->srCache[i].data = YMALLOC(dev->nBytesPerChunk);
5488                 }
5489                 dev->srLastUse = 0;
5490         }
5491
5492         dev->cacheHits = 0;
5493         
5494         
5495         // Initialise the unlinked, root and lost and found directories
5496         dev->lostNFoundDir = dev->rootDir = dev->unlinkedDir = dev->deletedDir = NULL;
5497         
5498         dev->unlinkedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
5499         dev->deletedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
5500
5501         dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
5502         dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_LOSTNFOUND_MODE | S_IFDIR);
5503         yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
5504         
5505         if(dev->isYaffs2) 
5506         {
5507                 dev->useHeaderFileSize = 1;
5508         }
5509                 
5510         // Now scan the flash.  
5511         yaffs_Scan(dev);
5512         
5513         // Zero out stats
5514         dev->nPageReads = 0;
5515     dev->nPageWrites =  0;
5516         dev->nBlockErasures = 0;
5517         dev->nGCCopies = 0;
5518         dev->nRetriedWrites = 0;
5519
5520         dev->nRetiredBlocks = 0;
5521
5522         T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
5523         return YAFFS_OK;
5524                 
5525 }
5526
5527 void yaffs_Deinitialise(yaffs_Device *dev)
5528 {
5529         if(dev->isMounted)
5530         {
5531                 int i;
5532         
5533                 yaffs_DeinitialiseBlocks(dev);
5534                 yaffs_DeinitialiseTnodes(dev);
5535                 yaffs_DeinitialiseObjects(dev);
5536                 if(dev->nShortOpCaches > 0)
5537                 {
5538                                 
5539                         for(i=0; i < dev->nShortOpCaches; i++)
5540                         {
5541                                 YFREE(dev->srCache[i].data);
5542                         }
5543
5544                         YFREE(dev->srCache);
5545                 }
5546
5547                 YFREE(dev->gcCleanupList);
5548
5549                 for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
5550                 {
5551                         YFREE(dev->tempBuffer[i].buffer);
5552                 }
5553                 
5554                 dev->isMounted = 0;
5555         }
5556         
5557 }
5558
5559 #if 0
5560
5561 int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
5562 {
5563         int nFree = dev->nFreeChunks - (dev->nChunksPerBlock * YAFFS_RESERVED_BLOCKS);
5564         
5565         struct list_head *i;    
5566         yaffs_Object *l;
5567         
5568         
5569         // To the free chunks add the chunks that are in the deleted unlinked files.
5570         list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
5571         {
5572                 l = list_entry(i, yaffs_Object,siblings);
5573                 if(l->deleted)
5574                 {
5575                         nFree++;
5576                         nFree += l->nDataChunks;
5577                 }
5578         }
5579         
5580         
5581         // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);        
5582
5583         if(nFree < 0) nFree = 0;
5584
5585         return nFree;   
5586         
5587 }
5588
5589 #endif
5590
5591 int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
5592 {
5593         int nFree;
5594         int pending;
5595         int b;
5596         int nDirtyCacheChunks=0;
5597         
5598         yaffs_BlockInfo *blk;
5599         
5600         struct list_head *i;    
5601         yaffs_Object *l;
5602         
5603         for(nFree = 0, b = dev->startBlock; b <= dev->endBlock; b++)
5604         {
5605                 blk = yaffs_GetBlockInfo(dev,b);
5606                 
5607                 switch(blk->blockState)
5608                 {
5609                         case YAFFS_BLOCK_STATE_EMPTY:
5610                         case YAFFS_BLOCK_STATE_ALLOCATING: 
5611                         case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break;
5612                         default: break;
5613                 }
5614         }
5615         
5616         
5617         pending = 0;
5618         
5619         // To the free chunks add the chunks that are in the deleted unlinked files.
5620         list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
5621         {
5622                 if(i)
5623                 {
5624                         l = list_entry(i, yaffs_Object,siblings);
5625                         if(l->deleted)
5626                         {
5627                                 pending++;
5628                                 pending += l->nDataChunks;
5629                         }
5630                 }
5631         }
5632         
5633         
5634         
5635         //printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending);
5636         
5637         if(nFree != dev->nFreeChunks) 
5638         {
5639         //      printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks);
5640         }
5641
5642         nFree += pending;
5643         
5644         // Now count the number of dirty chunks in the cache and subtract those
5645         
5646         {
5647                 int i;
5648                 for(i = 0; i < dev->nShortOpCaches; i++)
5649                 {
5650                         if(dev->srCache[i].dirty) nDirtyCacheChunks++;
5651                 }
5652         }
5653         
5654         nFree -= nDirtyCacheChunks;
5655         
5656         nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
5657         
5658         if(nFree < 0) nFree = 0;
5659
5660         return nFree;   
5661         
5662 }
5663
5664
5665
5666 /////////////////// YAFFS test code //////////////////////////////////
5667
5668 #define yaffs_CheckStruct(structure,syze, name) \
5669            if(sizeof(structure) != syze) \
5670                { \
5671                  T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),name,syze,sizeof(structure))); \
5672                  return YAFFS_FAIL; \
5673                    }
5674                  
5675                  
5676 static int yaffs_CheckStructures(void)
5677 {
5678 //      yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
5679 //      yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
5680 //      yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
5681 #ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
5682         yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
5683 #endif
5684         yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
5685         
5686         
5687         return YAFFS_OK;
5688 }
5689
5690 #if 0
5691 void yaffs_GutsTest(yaffs_Device *dev)
5692 {
5693         
5694         if(yaffs_CheckStructures() != YAFFS_OK)
5695         {
5696                 T(YAFFS_TRACE_ALWAYS,(TSTR("One or more structures malformed-- aborting\n" TENDSTR)));
5697                 return;
5698         }
5699         
5700         yaffs_TnodeTest(dev);
5701         yaffs_ObjectTest(dev);  
5702 }
5703 #endif
5704
5705