gc part of the block at a time to reduce latency
[yaffs2.git] / yaffs_guts.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2007 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 const char *yaffs_guts_c_version =
15     "$Id: yaffs_guts.c,v 1.67 2008-11-27 02:46:45 charles Exp $";
16
17 #include "yportenv.h"
18
19 #include "yaffsinterface.h"
20 #include "yaffs_guts.h"
21 #include "yaffs_tagsvalidity.h"
22 #include "yaffs_getblockinfo.h"
23
24 #include "yaffs_tagscompat.h"
25 #ifndef  CONFIG_YAFFS_USE_OWN_SORT
26 #include "yaffs_qsort.h"
27 #endif
28 #include "yaffs_nand.h"
29
30 #include "yaffs_checkptrw.h"
31
32 #include "yaffs_nand.h"
33 #include "yaffs_packedtags2.h"
34
35
36 #ifdef CONFIG_YAFFS_WINCE
37 void yfsd_LockYAFFS(BOOL fsLockOnly);
38 void yfsd_UnlockYAFFS(BOOL fsLockOnly);
39 #endif
40
41 #define YAFFS_PASSIVE_GC_CHUNKS 2
42
43 #include "yaffs_ecc.h"
44
45
46 /* Robustification (if it ever comes about...) */
47 static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND);
48 static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk);
49 static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
50                                      const __u8 * data,
51                                      const yaffs_ExtendedTags * tags);
52 static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
53                                     const yaffs_ExtendedTags * tags);
54
55 /* Other local prototypes */
56 static int yaffs_UnlinkObject( yaffs_Object *obj);
57 static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
58
59 static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
60
61 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device * dev,
62                                              const __u8 * buffer,
63                                              yaffs_ExtendedTags * tags,
64                                              int useReserve);
65 static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode,
66                                   int chunkInNAND, int inScan);
67
68 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,
69                                            yaffs_ObjectType type);
70 static void yaffs_AddObjectToDirectory(yaffs_Object * directory,
71                                        yaffs_Object * obj);
72 static int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name,
73                                     int force, int isShrink, int shadows);
74 static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj);
75 static int yaffs_CheckStructures(void);
76 static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level,
77                               int chunkOffset, int *limit);
78 static int yaffs_DoGenericObjectDeletion(yaffs_Object * in);
79
80 static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo);
81
82
83 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
84                                   int chunkInNAND);
85
86 static int yaffs_UnlinkWorker(yaffs_Object * obj);
87 static void yaffs_DestroyObject(yaffs_Object * obj);
88
89 static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,
90                            int chunkInObject);
91
92 loff_t yaffs_GetFileSize(yaffs_Object * obj);
93
94 static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr);
95
96 static void yaffs_VerifyFreeChunks(yaffs_Device * dev);
97
98 static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
99
100 static void yaffs_VerifyDirectory(yaffs_Object *directory);
101 #ifdef YAFFS_PARANOID
102 static int yaffs_CheckFileSanity(yaffs_Object * in);
103 #else
104 #define yaffs_CheckFileSanity(in)
105 #endif
106
107 static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in);
108 static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId);
109
110 static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
111
112 static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,
113                                  yaffs_ExtendedTags * tags);
114
115 static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);
116 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev,
117                                           yaffs_FileStructure * fStruct,
118                                           __u32 chunkId);
119
120
121 /* Function to calculate chunk and offset */
122
123 static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, __u32 *offsetOut)
124 {
125         int chunk;
126         __u32 offset;
127         
128         chunk  = (__u32)(addr >> dev->chunkShift);
129                 
130         if(dev->chunkDiv == 1)
131         {
132                 /* easy power of 2 case */
133                 offset = (__u32)(addr & dev->chunkMask);
134         }
135         else
136         {
137                 /* Non power-of-2 case */
138                 
139                 loff_t chunkBase;
140                 
141                 chunk /= dev->chunkDiv;
142                 
143                 chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk;
144                 offset = (__u32)(addr - chunkBase);
145         }
146
147         *chunkOut = chunk;
148         *offsetOut = offset;
149 }
150
151 /* Function to return the number of shifts for a power of 2 greater than or equal 
152  * to the given number
153  * Note we don't try to cater for all possible numbers and this does not have to
154  * be hellishly efficient.
155  */
156  
157 static __u32 ShiftsGE(__u32 x)
158 {
159         int extraBits;
160         int nShifts;
161         
162         nShifts = extraBits = 0;
163         
164         while(x>1){
165                 if(x & 1) extraBits++;
166                 x>>=1;
167                 nShifts++;
168         }
169
170         if(extraBits) 
171                 nShifts++;
172                 
173         return nShifts;
174 }
175
176 /* Function to return the number of shifts to get a 1 in bit 0
177  */
178  
179 static __u32 Shifts(__u32 x)
180 {
181         int nShifts;
182         
183         nShifts =  0;
184         
185         if(!x) return 0;
186         
187         while( !(x&1)){
188                 x>>=1;
189                 nShifts++;
190         }
191                 
192         return nShifts;
193 }
194
195
196
197 /* 
198  * Temporary buffer manipulations.
199  */
200
201 static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)       
202 {
203         int i;
204         __u8 *buf = (__u8 *)1;
205                 
206         memset(dev->tempBuffer,0,sizeof(dev->tempBuffer));
207                 
208         for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
209                 dev->tempBuffer[i].line = 0;    /* not in use */
210                 dev->tempBuffer[i].buffer = buf =
211                     YMALLOC_DMA(dev->totalBytesPerChunk);
212         }
213                 
214         return buf ? YAFFS_OK : YAFFS_FAIL;
215         
216 }
217
218 __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo)
219 {
220         int i, j;
221
222         dev->tempInUse++;
223         if(dev->tempInUse > dev->maxTemp)
224                 dev->maxTemp = dev->tempInUse;
225
226         for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
227                 if (dev->tempBuffer[i].line == 0) {
228                         dev->tempBuffer[i].line = lineNo;
229                         if ((i + 1) > dev->maxTemp) {
230                                 dev->maxTemp = i + 1;
231                                 for (j = 0; j <= i; j++)
232                                         dev->tempBuffer[j].maxLine =
233                                             dev->tempBuffer[j].line;
234                         }
235
236                         return dev->tempBuffer[i].buffer;
237                 }
238         }
239
240         T(YAFFS_TRACE_BUFFERS,
241           (TSTR("Out of temp buffers at line %d, other held by lines:"),
242            lineNo));
243         for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
244                 T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));
245         }
246         T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
247
248         /*
249          * If we got here then we have to allocate an unmanaged one
250          * This is not good.
251          */
252
253         dev->unmanagedTempAllocations++;
254         return YMALLOC(dev->nDataBytesPerChunk);
255
256 }
257
258 void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer,
259                                     int lineNo)
260 {
261         int i;
262         
263         dev->tempInUse--;
264         
265         for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
266                 if (dev->tempBuffer[i].buffer == buffer) {
267                         dev->tempBuffer[i].line = 0;
268                         return;
269                 }
270         }
271
272         if (buffer) {
273                 /* assume it is an unmanaged one. */
274                 T(YAFFS_TRACE_BUFFERS,
275                   (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
276                    lineNo));
277                 YFREE(buffer);
278                 dev->unmanagedTempDeallocations++;
279         }
280
281 }
282
283 /*
284  * Determine if we have a managed buffer.
285  */
286 int yaffs_IsManagedTempBuffer(yaffs_Device * dev, const __u8 * buffer)
287 {
288         int i;
289         for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
290                 if (dev->tempBuffer[i].buffer == buffer)
291                         return 1;
292
293         }
294
295     for (i = 0; i < dev->nShortOpCaches; i++) {
296         if( dev->srCache[i].data == buffer )
297             return 1;
298
299     }
300
301     if (buffer == dev->checkpointBuffer)
302       return 1;
303
304     T(YAFFS_TRACE_ALWAYS,
305           (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR)));
306     return 0;
307 }
308
309
310
311 /*
312  * Chunk bitmap manipulations
313  */
314
315 static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device * dev, int blk)
316 {
317         if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
318                 T(YAFFS_TRACE_ERROR,
319                   (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
320                    blk));
321                 YBUG();
322         }
323         return dev->chunkBits +
324             (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
325 }
326
327 static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
328 {
329         if(blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
330            chunk < 0 || chunk >= dev->nChunksPerBlock) {
331            T(YAFFS_TRACE_ERROR,
332             (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),blk,chunk));
333             YBUG();
334         }
335 }
336
337 static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk)
338 {
339         __u8 *blkBits = yaffs_BlockBits(dev, blk);
340
341         memset(blkBits, 0, dev->chunkBitmapStride);
342 }
343
344 static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device * dev, int blk, int chunk)
345 {
346         __u8 *blkBits = yaffs_BlockBits(dev, blk);
347
348         yaffs_VerifyChunkBitId(dev,blk,chunk);
349
350         blkBits[chunk / 8] &= ~(1 << (chunk & 7));
351 }
352
353 static Y_INLINE void yaffs_SetChunkBit(yaffs_Device * dev, int blk, int chunk)
354 {
355         __u8 *blkBits = yaffs_BlockBits(dev, blk);
356         
357         yaffs_VerifyChunkBitId(dev,blk,chunk);
358
359         blkBits[chunk / 8] |= (1 << (chunk & 7));
360 }
361
362 static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk)
363 {
364         __u8 *blkBits = yaffs_BlockBits(dev, blk);
365         yaffs_VerifyChunkBitId(dev,blk,chunk);
366
367         return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
368 }
369
370 static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device * dev, int blk)
371 {
372         __u8 *blkBits = yaffs_BlockBits(dev, blk);
373         int i;
374         for (i = 0; i < dev->chunkBitmapStride; i++) {
375                 if (*blkBits)
376                         return 1;
377                 blkBits++;
378         }
379         return 0;
380 }
381
382 static int yaffs_CountChunkBits(yaffs_Device * dev, int blk)
383 {
384         __u8 *blkBits = yaffs_BlockBits(dev, blk);
385         int i;
386         int n = 0;
387         for (i = 0; i < dev->chunkBitmapStride; i++) {
388                 __u8 x = *blkBits;
389                 while(x){
390                         if(x & 1)
391                                 n++;
392                         x >>=1;
393                 }
394                         
395                 blkBits++;
396         }
397         return n;
398 }
399
400 /* 
401  * Verification code
402  */
403  
404 static int yaffs_SkipVerification(yaffs_Device *dev)
405 {
406         return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
407 }
408
409 #if 0
410 static int yaffs_SkipFullVerification(yaffs_Device *dev)
411 {
412         return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
413 }
414
415 #endif
416
417 static int yaffs_SkipNANDVerification(yaffs_Device *dev)
418 {
419         return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
420 }
421
422 static const char * blockStateName[] = {
423 "Unknown",
424 "Needs scanning",
425 "Scanning",
426 "Empty",
427 "Allocating",
428 "Full",
429 "Dirty",
430 "Checkpoint",
431 "Collecting",
432 "Dead"
433 };
434
435 static void yaffs_VerifyBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n)
436 {
437         int actuallyUsed;
438         int inUse;
439         
440         if(yaffs_SkipVerification(dev))
441                 return;
442                 
443         /* Report illegal runtime states */
444         if(bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
445                 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState));
446                 
447         switch(bi->blockState){
448          case YAFFS_BLOCK_STATE_UNKNOWN:
449          case YAFFS_BLOCK_STATE_SCANNING:
450          case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
451                 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has bad run-state %s"TENDSTR),
452                 n,blockStateName[bi->blockState]));
453         }
454         
455         /* Check pages in use and soft deletions are legal */
456         
457         actuallyUsed = bi->pagesInUse - bi->softDeletions;
458         
459         if(bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
460            bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
461            actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
462                 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
463                 n,bi->pagesInUse,bi->softDeletions));
464         
465                 
466         /* Check chunk bitmap legal */
467         inUse = yaffs_CountChunkBits(dev,n);
468         if(inUse != bi->pagesInUse)
469                 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
470                         n,bi->pagesInUse,inUse));
471         
472         /* Check that the sequence number is valid.
473          * Ten million is legal, but is very unlikely 
474          */
475         if(dev->isYaffs2 && 
476            (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
477            (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000 ))
478                 T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has suspect sequence number of %d"TENDSTR),
479                 n,bi->sequenceNumber));
480                 
481 }
482
483 static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n)
484 {
485         yaffs_VerifyBlock(dev,bi,n);
486         
487         /* After collection the block should be in the erased state */
488         /* TODO: This will need to change if we do partial gc */
489         
490         if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){
491                 T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
492                         n,bi->blockState));
493         }
494 }
495
496 static void yaffs_VerifyBlocks(yaffs_Device *dev)
497 {
498         int i;
499         int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
500         int nIllegalBlockStates = 0;
501         
502
503         if(yaffs_SkipVerification(dev))
504                 return;
505
506         memset(nBlocksPerState,0,sizeof(nBlocksPerState));
507
508                 
509         for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++){
510                 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
511                 yaffs_VerifyBlock(dev,bi,i);
512
513                 if(bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
514                         nBlocksPerState[bi->blockState]++;
515                 else
516                         nIllegalBlockStates++;
517                                         
518         }
519         
520         T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR)));
521         T(YAFFS_TRACE_VERIFY,(TSTR("Block summary"TENDSTR)));
522         
523         T(YAFFS_TRACE_VERIFY,(TSTR("%d blocks have illegal states"TENDSTR),nIllegalBlockStates));
524         if(nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
525                 T(YAFFS_TRACE_VERIFY,(TSTR("Too many allocating blocks"TENDSTR)));
526
527         for(i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
528                 T(YAFFS_TRACE_VERIFY,
529                   (TSTR("%s %d blocks"TENDSTR),
530                   blockStateName[i],nBlocksPerState[i]));
531         
532         if(dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
533                 T(YAFFS_TRACE_VERIFY,
534                  (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
535                  dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
536                  
537         if(dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
538                 T(YAFFS_TRACE_VERIFY,
539                  (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
540                  dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
541                  
542         if(nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
543                 T(YAFFS_TRACE_VERIFY,
544                  (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
545                  nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
546
547         T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR)));
548
549 }
550
551 /*
552  * Verify the object header. oh must be valid, but obj and tags may be NULL in which
553  * case those tests will not be performed.
554  */
555 static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
556 {
557         if(obj && yaffs_SkipVerification(obj->myDev))
558                 return;
559                 
560         if(!(tags && obj && oh)){
561                 T(YAFFS_TRACE_VERIFY,
562                                 (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
563                                 (__u32)tags,(__u32)obj,(__u32)oh));
564                 return;
565         }
566         
567         if(oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
568            oh->type > YAFFS_OBJECT_TYPE_MAX)
569                 T(YAFFS_TRACE_VERIFY,
570                  (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
571                  tags->objectId, oh->type));
572
573         if(tags->objectId != obj->objectId)
574                 T(YAFFS_TRACE_VERIFY,
575                  (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
576                  tags->objectId, obj->objectId));
577
578
579         /*
580          * Check that the object's parent ids match if parentCheck requested.
581          * 
582          * Tests do not apply to the root object.
583          */
584         
585         if(parentCheck && tags->objectId > 1 && !obj->parent)
586                 T(YAFFS_TRACE_VERIFY,
587                  (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
588                  tags->objectId, oh->parentObjectId));
589                 
590         
591         if(parentCheck && obj->parent &&
592            oh->parentObjectId != obj->parent->objectId && 
593            (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
594             obj->parent->objectId != YAFFS_OBJECTID_DELETED))
595                 T(YAFFS_TRACE_VERIFY,
596                  (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
597                  tags->objectId, oh->parentObjectId, obj->parent->objectId));
598                 
599         
600         if(tags->objectId > 1 && oh->name[0] == 0) /* Null name */
601                 T(YAFFS_TRACE_VERIFY,
602                 (TSTR("Obj %d header name is NULL"TENDSTR),
603                  obj->objectId));
604
605         if(tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
606                 T(YAFFS_TRACE_VERIFY,
607                 (TSTR("Obj %d header name is 0xFF"TENDSTR),
608                  obj->objectId));
609 }
610
611
612
613 static int yaffs_VerifyTnodeWorker(yaffs_Object * obj, yaffs_Tnode * tn,
614                                         __u32 level, int chunkOffset)
615 {
616         int i;
617         yaffs_Device *dev = obj->myDev;
618         int ok = 1;
619
620         if (tn) {
621                 if (level > 0) {
622
623                         for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){
624                                 if (tn->internal[i]) {
625                                         ok = yaffs_VerifyTnodeWorker(obj,
626                                                         tn->internal[i],
627                                                         level - 1,
628                                                         (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
629                                 }
630                         }
631                 } else if (level == 0) {
632                         yaffs_ExtendedTags tags;
633                         __u32 objectId = obj->objectId;
634                         
635                         chunkOffset <<=  YAFFS_TNODES_LEVEL0_BITS;
636                         
637                         for(i = 0; i < YAFFS_NTNODES_LEVEL0; i++){
638                                 __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i);
639                                 
640                                 if(theChunk > 0){
641                                         /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
642                                         yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags);
643                                         if(tags.objectId != objectId || tags.chunkId != chunkOffset){
644                                                 T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
645                                                         objectId, chunkOffset, theChunk,
646                                                         tags.objectId, tags.chunkId));
647                                         }
648                                 }
649                                 chunkOffset++;
650                         }
651                 }
652         }
653
654         return ok;
655
656 }
657
658
659 static void yaffs_VerifyFile(yaffs_Object *obj)
660 {
661         int requiredTallness;
662         int actualTallness;
663         __u32 lastChunk;
664         __u32 x;
665         __u32 i;
666         yaffs_Device *dev;
667         yaffs_ExtendedTags tags;
668         yaffs_Tnode *tn;
669         __u32 objectId;
670         
671         if(!obj)
672                 return;
673
674         if(yaffs_SkipVerification(obj->myDev))
675                 return;
676         
677         dev = obj->myDev;
678         objectId = obj->objectId;
679         
680         /* Check file size is consistent with tnode depth */
681         lastChunk =  obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
682         x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
683         requiredTallness = 0;
684         while (x> 0) {
685                 x >>= YAFFS_TNODES_INTERNAL_BITS;
686                 requiredTallness++;
687         }
688         
689         actualTallness = obj->variant.fileVariant.topLevel;
690         
691         if(requiredTallness > actualTallness )
692                 T(YAFFS_TRACE_VERIFY,
693                 (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
694                  obj->objectId,actualTallness, requiredTallness));
695         
696         
697         /* Check that the chunks in the tnode tree are all correct. 
698          * We do this by scanning through the tnode tree and
699          * checking the tags for every chunk match.
700          */
701
702         if(yaffs_SkipNANDVerification(dev))
703                 return;
704                 
705         for(i = 1; i <= lastChunk; i++){
706                 tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant,i);
707
708                 if (tn) {
709                         __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i);
710                         if(theChunk > 0){
711                                 /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
712                                 yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags);
713                                 if(tags.objectId != objectId || tags.chunkId != i){
714                                         T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
715                                                 objectId, i, theChunk,
716                                                 tags.objectId, tags.chunkId));
717                                 }
718                         }
719                 }
720
721         }
722
723 }
724
725
726 static void yaffs_VerifyHardLink(yaffs_Object *obj)
727 {
728         if(obj && yaffs_SkipVerification(obj->myDev))
729                 return;
730                 
731         /* Verify sane equivalent object */
732 }
733
734 static void yaffs_VerifySymlink(yaffs_Object *obj)
735 {
736         if(obj && yaffs_SkipVerification(obj->myDev))
737                 return;
738                 
739         /* Verify symlink string */
740 }
741
742 static void yaffs_VerifySpecial(yaffs_Object *obj)
743 {
744         if(obj && yaffs_SkipVerification(obj->myDev))
745                 return;
746 }
747
748 static void yaffs_VerifyObject(yaffs_Object *obj)
749 {
750         yaffs_Device *dev;
751         
752         __u32 chunkMin;
753         __u32 chunkMax;
754         
755         __u32 chunkIdOk;
756         __u32 chunkIsLive;
757         
758         if(!obj)
759                 return;
760         
761         dev = obj->myDev;
762         
763         if(yaffs_SkipVerification(dev))
764                 return;
765                 
766         /* Check sane object header chunk */
767
768         chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
769         chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
770
771         chunkIdOk = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
772         chunkIsLive = chunkIdOk &&
773                         yaffs_CheckChunkBit(dev,
774                                             obj->hdrChunk / dev->nChunksPerBlock,
775                                             obj->hdrChunk % dev->nChunksPerBlock);
776         if(!obj->fake &&
777             (!chunkIdOk || !chunkIsLive)) {
778            T(YAFFS_TRACE_VERIFY,
779            (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
780            obj->objectId,obj->hdrChunk,
781            chunkIdOk ? "" : ",out of range",
782            chunkIsLive || !chunkIdOk ? "" : ",marked as deleted"));
783         }
784         
785         if(chunkIdOk && chunkIsLive &&!yaffs_SkipNANDVerification(dev)) {
786                 yaffs_ExtendedTags tags;
787                 yaffs_ObjectHeader *oh;
788                 __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
789                 
790                 oh = (yaffs_ObjectHeader *)buffer;
791
792                 yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk,buffer, &tags);
793
794                 yaffs_VerifyObjectHeader(obj,oh,&tags,1);
795                 
796                 yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
797         }
798         
799         /* Verify it has a parent */
800         if(obj && !obj->fake &&
801            (!obj->parent || obj->parent->myDev != dev)){
802            T(YAFFS_TRACE_VERIFY,
803            (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
804            obj->objectId,obj->parent));    
805         }
806         
807         /* Verify parent is a directory */
808         if(obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){
809            T(YAFFS_TRACE_VERIFY,
810            (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
811            obj->objectId,obj->parent->variantType));       
812         }
813         
814         switch(obj->variantType){
815         case YAFFS_OBJECT_TYPE_FILE:
816                 yaffs_VerifyFile(obj);
817                 break;
818         case YAFFS_OBJECT_TYPE_SYMLINK:
819                 yaffs_VerifySymlink(obj);
820                 break;
821         case YAFFS_OBJECT_TYPE_DIRECTORY:
822                 yaffs_VerifyDirectory(obj);
823                 break;
824         case YAFFS_OBJECT_TYPE_HARDLINK:
825                 yaffs_VerifyHardLink(obj);
826                 break;
827         case YAFFS_OBJECT_TYPE_SPECIAL:
828                 yaffs_VerifySpecial(obj);
829                 break;
830         case YAFFS_OBJECT_TYPE_UNKNOWN:
831         default:
832                 T(YAFFS_TRACE_VERIFY,
833                 (TSTR("Obj %d has illegaltype %d"TENDSTR),
834                 obj->objectId,obj->variantType));          
835                 break;
836         }
837         
838         
839 }
840
841 static void yaffs_VerifyObjects(yaffs_Device *dev)
842 {
843         yaffs_Object *obj;
844         int i;
845         struct ylist_head *lh;
846
847         if(yaffs_SkipVerification(dev))
848                 return;
849         
850         /* Iterate through the objects in each hash entry */
851          
852          for(i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++){
853                 ylist_for_each(lh, &dev->objectBucket[i].list) {
854                         if (lh) {
855                                 obj = ylist_entry(lh, yaffs_Object, hashLink);
856                                 yaffs_VerifyObject(obj);
857                         }
858                 }
859          }
860
861 }
862
863
864 /*
865  *  Simple hash function. Needs to have a reasonable spread
866  */
867  
868 static Y_INLINE int yaffs_HashFunction(int n)
869 {
870         n = abs(n);
871         return (n % YAFFS_NOBJECT_BUCKETS);
872 }
873
874 /*
875  * Access functions to useful fake objects.
876  * Note that root might have a presence in NAND if permissions are set.
877  */
878  
879 yaffs_Object *yaffs_Root(yaffs_Device * dev)
880 {
881         return dev->rootDir;
882 }
883
884 yaffs_Object *yaffs_LostNFound(yaffs_Device * dev)
885 {
886         return dev->lostNFoundDir;
887 }
888
889
890 /*
891  *  Erased NAND checking functions
892  */
893  
894 int yaffs_CheckFF(__u8 * buffer, int nBytes)
895 {
896         /* Horrible, slow implementation */
897         while (nBytes--) {
898                 if (*buffer != 0xFF)
899                         return 0;
900                 buffer++;
901         }
902         return 1;
903 }
904
905 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
906                                   int chunkInNAND)
907 {
908
909         int retval = YAFFS_OK;
910         __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
911         yaffs_ExtendedTags tags;
912         int result;
913
914         result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
915         
916         if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
917                 retval = YAFFS_FAIL;
918                 
919
920         if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
921                 T(YAFFS_TRACE_NANDACCESS,
922                   (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
923                 retval = YAFFS_FAIL;
924         }
925
926         yaffs_ReleaseTempBuffer(dev, data, __LINE__);
927
928         return retval;
929
930 }
931
932 static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
933                                              const __u8 * data,
934                                              yaffs_ExtendedTags * tags,
935                                              int useReserve)
936 {
937         int attempts = 0;
938         int writeOk = 0;
939         int chunk;
940
941         yaffs_InvalidateCheckpoint(dev);
942
943         do {
944                 yaffs_BlockInfo *bi = 0;
945                 int erasedOk = 0;
946
947                 chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
948                 if (chunk < 0) {
949                         /* no space */
950                         break;
951                 }
952
953                 /* First check this chunk is erased, if it needs
954                  * checking.  The checking policy (unless forced
955                  * always on) is as follows:
956                  *
957                  * Check the first page we try to write in a block.
958                  * If the check passes then we don't need to check any
959                  * more.        If the check fails, we check again...
960                  * If the block has been erased, we don't need to check.
961                  *
962                  * However, if the block has been prioritised for gc,
963                  * then we think there might be something odd about
964                  * this block and stop using it.
965                  *
966                  * Rationale: We should only ever see chunks that have
967                  * not been erased if there was a partially written
968                  * chunk due to power loss.  This checking policy should
969                  * catch that case with very few checks and thus save a
970                  * lot of checks that are most likely not needed.
971                  */
972                 if (bi->gcPrioritise) {
973                         yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
974                         /* try another chunk */
975                         continue;
976                 }
977
978                 /* let's give it a try */
979                 attempts++;
980
981 #ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
982                 bi->skipErasedCheck = 0;
983 #endif
984                 if (!bi->skipErasedCheck) {
985                         erasedOk = yaffs_CheckChunkErased(dev, chunk);
986                         if (erasedOk != YAFFS_OK) {
987                                 T(YAFFS_TRACE_ERROR,
988                                 (TSTR ("**>> yaffs chunk %d was not erased"
989                                 TENDSTR), chunk));
990
991                                 /* try another chunk */
992                                 continue;
993                         }
994                         bi->skipErasedCheck = 1;
995                 }
996
997                 writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
998                                 data, tags);
999                 if (writeOk != YAFFS_OK) {
1000                         yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
1001                         /* try another chunk */
1002                         continue;
1003                 }
1004
1005                 /* Copy the data into the robustification buffer */
1006                 yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
1007
1008         } while (writeOk != YAFFS_OK && 
1009                 (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
1010         
1011         if(!writeOk)
1012                 chunk = -1;
1013
1014         if (attempts > 1) {
1015                 T(YAFFS_TRACE_ERROR,
1016                         (TSTR("**>> yaffs write required %d attempts" TENDSTR),
1017                         attempts));
1018
1019                 dev->nRetriedWrites += (attempts - 1);
1020         }
1021
1022         return chunk;
1023 }
1024
1025 /*
1026  * Block retiring for handling a broken block.
1027  */
1028  
1029 static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND)
1030 {
1031         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
1032
1033         yaffs_InvalidateCheckpoint(dev);
1034         
1035         yaffs_MarkBlockBad(dev, blockInNAND);
1036
1037         bi->blockState = YAFFS_BLOCK_STATE_DEAD;
1038         bi->gcPrioritise = 0;
1039         bi->needsRetiring = 0;
1040
1041         dev->nRetiredBlocks++;
1042 }
1043
1044 /*
1045  * Functions for robustisizing TODO
1046  *
1047  */
1048  
1049 static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
1050                                      const __u8 * data,
1051                                      const yaffs_ExtendedTags * tags)
1052 {
1053 }
1054
1055 static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
1056                                     const yaffs_ExtendedTags * tags)
1057 {
1058 }
1059
1060 void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
1061 {
1062         if(!bi->gcPrioritise){
1063                 bi->gcPrioritise = 1;
1064                 dev->hasPendingPrioritisedGCs = 1;
1065                 bi->chunkErrorStrikes ++;
1066                 
1067                 if(bi->chunkErrorStrikes > 3){
1068                         bi->needsRetiring = 1; /* Too many stikes, so retire this */
1069                         T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
1070
1071                 }
1072                 
1073         }
1074 }
1075
1076 static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk)
1077 {
1078
1079         int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
1080         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
1081
1082         yaffs_HandleChunkError(dev,bi);
1083                 
1084         
1085         if(erasedOk ) {
1086                 /* Was an actual write failure, so mark the block for retirement  */
1087                 bi->needsRetiring = 1;
1088                 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
1089                   (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
1090
1091                 
1092         }
1093         
1094         /* Delete the chunk */
1095         yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
1096 }
1097
1098
1099 /*---------------- Name handling functions ------------*/ 
1100
1101 static __u16 yaffs_CalcNameSum(const YCHAR * name)
1102 {
1103         __u16 sum = 0;
1104         __u16 i = 1;
1105
1106         const YUCHAR *bname = (const YUCHAR *) name;
1107         if (bname) {
1108                 while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
1109
1110 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
1111                         sum += yaffs_toupper(*bname) * i;
1112 #else
1113                         sum += (*bname) * i;
1114 #endif
1115                         i++;
1116                         bname++;
1117                 }
1118         }
1119         
1120         return sum;
1121 }
1122
1123 static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name)
1124 {
1125 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
1126         memset(obj->shortName,0,sizeof (YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1)); 
1127         if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) {
1128                 yaffs_strcpy(obj->shortName, name);
1129         } else {
1130                 obj->shortName[0] = _Y('\0');
1131         }
1132 #endif
1133         obj->sum = yaffs_CalcNameSum(name);
1134 }
1135
1136 /*-------------------- TNODES -------------------
1137
1138  * List of spare tnodes
1139  * The list is hooked together using the first pointer
1140  * in the tnode.
1141  */
1142  
1143 /* yaffs_CreateTnodes creates a bunch more tnodes and
1144  * adds them to the tnode free list.
1145  * Don't use this function directly
1146  */
1147
1148 static int yaffs_CreateTnodes(yaffs_Device * dev, int nTnodes)
1149 {
1150         int i;
1151         int tnodeSize;
1152         yaffs_Tnode *newTnodes;
1153         __u8 *mem;
1154         yaffs_Tnode *curr;
1155         yaffs_Tnode *next;
1156         yaffs_TnodeList *tnl;
1157
1158         if (nTnodes < 1)
1159                 return YAFFS_OK;
1160                 
1161         /* Calculate the tnode size in bytes for variable width tnode support.
1162          * Must be a multiple of 32-bits  */
1163         tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
1164
1165         if(tnodeSize < sizeof(yaffs_Tnode))
1166                 tnodeSize = sizeof(yaffs_Tnode);
1167                 
1168
1169         /* make these things */
1170
1171         newTnodes = YMALLOC(nTnodes * tnodeSize);
1172         mem = (__u8 *)newTnodes;
1173
1174         if (!newTnodes) {
1175                 T(YAFFS_TRACE_ERROR,
1176                   (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
1177                 return YAFFS_FAIL;
1178         }
1179
1180         /* Hook them into the free list */
1181 #if 0
1182         for (i = 0; i < nTnodes - 1; i++) {
1183                 newTnodes[i].internal[0] = &newTnodes[i + 1];
1184 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
1185                 newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
1186 #endif
1187         }
1188
1189         newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
1190 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
1191         newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
1192 #endif
1193         dev->freeTnodes = newTnodes;
1194 #else
1195         /* New hookup for wide tnodes */
1196         for(i = 0; i < nTnodes -1; i++) {
1197                 curr = (yaffs_Tnode *) &mem[i * tnodeSize];
1198                 next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
1199                 curr->internal[0] = next;
1200         }
1201         
1202         curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
1203         curr->internal[0] = dev->freeTnodes;
1204         dev->freeTnodes = (yaffs_Tnode *)mem;
1205
1206 #endif
1207
1208
1209         dev->nFreeTnodes += nTnodes;
1210         dev->nTnodesCreated += nTnodes;
1211
1212         /* Now add this bunch of tnodes to a list for freeing up.
1213          * NB If we can't add this to the management list it isn't fatal
1214          * but it just means we can't free this bunch of tnodes later.
1215          */
1216          
1217         tnl = YMALLOC(sizeof(yaffs_TnodeList));
1218         if (!tnl) {
1219                 T(YAFFS_TRACE_ERROR,
1220                   (TSTR
1221                    ("yaffs: Could not add tnodes to management list" TENDSTR)));
1222                    return YAFFS_FAIL;
1223
1224         } else {
1225                 tnl->tnodes = newTnodes;
1226                 tnl->next = dev->allocatedTnodeList;
1227                 dev->allocatedTnodeList = tnl;
1228         }
1229
1230         T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
1231
1232         return YAFFS_OK;
1233 }
1234
1235 /* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
1236
1237 static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device * dev)
1238 {
1239         yaffs_Tnode *tn = NULL;
1240
1241         /* If there are none left make more */
1242         if (!dev->freeTnodes) {
1243                 yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
1244         }
1245
1246         if (dev->freeTnodes) {
1247                 tn = dev->freeTnodes;
1248 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
1249                 if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
1250                         /* Hoosterman, this thing looks like it isn't in the list */
1251                         T(YAFFS_TRACE_ALWAYS,
1252                           (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
1253                 }
1254 #endif
1255                 dev->freeTnodes = dev->freeTnodes->internal[0];
1256                 dev->nFreeTnodes--;
1257         }
1258
1259         dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
1260
1261         return tn;
1262 }
1263
1264 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device * dev)
1265 {
1266         yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
1267         int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
1268
1269         if(tnodeSize < sizeof(yaffs_Tnode))
1270                 tnodeSize = sizeof(yaffs_Tnode);
1271         
1272         if(tn)
1273                 memset(tn, 0, tnodeSize);
1274
1275         return tn;      
1276 }
1277
1278 /* FreeTnode frees up a tnode and puts it back on the free list */
1279 static void yaffs_FreeTnode(yaffs_Device * dev, yaffs_Tnode * tn)
1280 {
1281         if (tn) {
1282 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
1283                 if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
1284                         /* Hoosterman, this thing looks like it is already in the list */
1285                         T(YAFFS_TRACE_ALWAYS,
1286                           (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
1287                 }
1288                 tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
1289 #endif
1290                 tn->internal[0] = dev->freeTnodes;
1291                 dev->freeTnodes = tn;
1292                 dev->nFreeTnodes++;
1293         }
1294         dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
1295         
1296 }
1297
1298 static void yaffs_DeinitialiseTnodes(yaffs_Device * dev)
1299 {
1300         /* Free the list of allocated tnodes */
1301         yaffs_TnodeList *tmp;
1302
1303         while (dev->allocatedTnodeList) {
1304                 tmp = dev->allocatedTnodeList->next;
1305
1306                 YFREE(dev->allocatedTnodeList->tnodes);
1307                 YFREE(dev->allocatedTnodeList);
1308                 dev->allocatedTnodeList = tmp;
1309
1310         }
1311
1312         dev->freeTnodes = NULL;
1313         dev->nFreeTnodes = 0;
1314 }
1315
1316 static void yaffs_InitialiseTnodes(yaffs_Device * dev)
1317 {
1318         dev->allocatedTnodeList = NULL;
1319         dev->freeTnodes = NULL;
1320         dev->nFreeTnodes = 0;
1321         dev->nTnodesCreated = 0;
1322
1323 }
1324
1325
1326 void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, unsigned val)
1327 {
1328   __u32 *map = (__u32 *)tn;
1329   __u32 bitInMap;
1330   __u32 bitInWord;
1331   __u32 wordInMap;
1332   __u32 mask;
1333   
1334   pos &= YAFFS_TNODES_LEVEL0_MASK;
1335   val >>= dev->chunkGroupBits;
1336   
1337   bitInMap = pos * dev->tnodeWidth;
1338   wordInMap = bitInMap /32;
1339   bitInWord = bitInMap & (32 -1);
1340   
1341   mask = dev->tnodeMask << bitInWord;
1342   
1343   map[wordInMap] &= ~mask;
1344   map[wordInMap] |= (mask & (val << bitInWord));
1345   
1346   if(dev->tnodeWidth > (32-bitInWord)) {
1347     bitInWord = (32 - bitInWord);
1348     wordInMap++;;
1349     mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
1350     map[wordInMap] &= ~mask;
1351     map[wordInMap] |= (mask & (val >> bitInWord));
1352   }
1353 }
1354
1355 static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos)
1356 {
1357   __u32 *map = (__u32 *)tn;
1358   __u32 bitInMap;
1359   __u32 bitInWord;
1360   __u32 wordInMap;
1361   __u32 val;
1362   
1363   pos &= YAFFS_TNODES_LEVEL0_MASK;
1364   
1365   bitInMap = pos * dev->tnodeWidth;
1366   wordInMap = bitInMap /32;
1367   bitInWord = bitInMap & (32 -1);
1368   
1369   val = map[wordInMap] >> bitInWord;
1370   
1371   if(dev->tnodeWidth > (32-bitInWord)) {
1372     bitInWord = (32 - bitInWord);
1373     wordInMap++;;
1374     val |= (map[wordInMap] << bitInWord);
1375   }
1376   
1377   val &= dev->tnodeMask;
1378   val <<= dev->chunkGroupBits;
1379   
1380   return val;
1381 }
1382
1383 /* ------------------- End of individual tnode manipulation -----------------*/
1384
1385 /* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
1386  * The look up tree is represented by the top tnode and the number of topLevel
1387  * in the tree. 0 means only the level 0 tnode is in the tree.
1388  */
1389
1390 /* FindLevel0Tnode finds the level 0 tnode, if one exists. */
1391 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev,
1392                                           yaffs_FileStructure * fStruct,
1393                                           __u32 chunkId)
1394 {
1395
1396         yaffs_Tnode *tn = fStruct->top;
1397         __u32 i;
1398         int requiredTallness;
1399         int level = fStruct->topLevel;
1400
1401         /* Check sane level and chunk Id */
1402         if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) {
1403                 return NULL;
1404         }
1405
1406         if (chunkId > YAFFS_MAX_CHUNK_ID) {
1407                 return NULL;
1408         }
1409
1410         /* First check we're tall enough (ie enough topLevel) */
1411
1412         i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
1413         requiredTallness = 0;
1414         while (i) {
1415                 i >>= YAFFS_TNODES_INTERNAL_BITS;
1416                 requiredTallness++;
1417         }
1418
1419         if (requiredTallness > fStruct->topLevel) {
1420                 /* Not tall enough, so we can't find it, return NULL. */
1421                 return NULL;
1422         }
1423
1424         /* Traverse down to level 0 */
1425         while (level > 0 && tn) {
1426                 tn = tn->
1427                     internal[(chunkId >>
1428                                ( YAFFS_TNODES_LEVEL0_BITS + 
1429                                  (level - 1) *
1430                                  YAFFS_TNODES_INTERNAL_BITS)
1431                               ) &
1432                              YAFFS_TNODES_INTERNAL_MASK];
1433                 level--;
1434
1435         }
1436
1437         return tn;
1438 }
1439
1440 /* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
1441  * This happens in two steps:
1442  *  1. If the tree isn't tall enough, then make it taller.
1443  *  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
1444  *
1445  * Used when modifying the tree.
1446  *
1447  *  If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
1448  *  be plugged into the ttree.
1449  */
1450  
1451 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device * dev,
1452                                                yaffs_FileStructure * fStruct,
1453                                                __u32 chunkId,
1454                                                yaffs_Tnode *passedTn)
1455 {
1456
1457         int requiredTallness;
1458         int i;
1459         int l;
1460         yaffs_Tnode *tn;
1461
1462         __u32 x;
1463
1464
1465         /* Check sane level and page Id */
1466         if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) {
1467                 return NULL;
1468         }
1469
1470         if (chunkId > YAFFS_MAX_CHUNK_ID) {
1471                 return NULL;
1472         }
1473
1474         /* First check we're tall enough (ie enough topLevel) */
1475
1476         x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
1477         requiredTallness = 0;
1478         while (x) {
1479                 x >>= YAFFS_TNODES_INTERNAL_BITS;
1480                 requiredTallness++;
1481         }
1482
1483
1484         if (requiredTallness > fStruct->topLevel) {
1485                 /* Not tall enough,gotta make the tree taller */
1486                 for (i = fStruct->topLevel; i < requiredTallness; i++) {
1487                 
1488                         tn = yaffs_GetTnode(dev);
1489
1490                         if (tn) {
1491                                 tn->internal[0] = fStruct->top;
1492                                 fStruct->top = tn;
1493                         } else {
1494                                 T(YAFFS_TRACE_ERROR,
1495                                   (TSTR("yaffs: no more tnodes" TENDSTR)));
1496                         }
1497                 }
1498
1499                 fStruct->topLevel = requiredTallness;
1500         }
1501
1502         /* Traverse down to level 0, adding anything we need */
1503
1504         l = fStruct->topLevel;
1505         tn = fStruct->top;
1506         
1507         if(l > 0) {
1508                 while (l > 0 && tn) {
1509                         x = (chunkId >>
1510                              ( YAFFS_TNODES_LEVEL0_BITS +
1511                               (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
1512                             YAFFS_TNODES_INTERNAL_MASK;
1513
1514
1515                         if((l>1) && !tn->internal[x]){
1516                                 /* Add missing non-level-zero tnode */
1517                                 tn->internal[x] = yaffs_GetTnode(dev);
1518
1519                         } else if(l == 1) {
1520                                 /* Looking from level 1 at level 0 */
1521                                 if (passedTn) {
1522                                         /* If we already have one, then release it.*/
1523                                         if(tn->internal[x])
1524                                                 yaffs_FreeTnode(dev,tn->internal[x]);
1525                                         tn->internal[x] = passedTn;
1526                         
1527                                 } else if(!tn->internal[x]) {
1528                                         /* Don't have one, none passed in */
1529                                         tn->internal[x] = yaffs_GetTnode(dev);
1530                                 }
1531                         }
1532                 
1533                         tn = tn->internal[x];
1534                         l--;
1535                 }
1536         } else {
1537                 /* top is level 0 */
1538                 if(passedTn) {
1539                         memcpy(tn,passedTn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
1540                         yaffs_FreeTnode(dev,passedTn);
1541                 }
1542         }
1543
1544         return tn;
1545 }
1546
1547 static int yaffs_FindChunkInGroup(yaffs_Device * dev, int theChunk,
1548                                   yaffs_ExtendedTags * tags, int objectId,
1549                                   int chunkInInode)
1550 {
1551         int j;
1552
1553         for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
1554                 if (yaffs_CheckChunkBit
1555                     (dev, theChunk / dev->nChunksPerBlock,
1556                      theChunk % dev->nChunksPerBlock)) {
1557                         yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
1558                                                         tags);
1559                         if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
1560                                 /* found it; */
1561                                 return theChunk;
1562
1563                         }
1564                 }
1565                 theChunk++;
1566         }
1567         return -1;
1568 }
1569
1570
1571 /* DeleteWorker scans backwards through the tnode tree and deletes all the
1572  * chunks and tnodes in the file
1573  * Returns 1 if the tree was deleted. 
1574  * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
1575  */
1576
1577 static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level,
1578                               int chunkOffset, int *limit)
1579 {
1580         int i;
1581         int chunkInInode;
1582         int theChunk;
1583         yaffs_ExtendedTags tags;
1584         int foundChunk;
1585         yaffs_Device *dev = in->myDev;
1586
1587         int allDone = 1;
1588
1589         if (tn) {
1590                 if (level > 0) {
1591
1592                         for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
1593                              i--) {
1594                                 if (tn->internal[i]) {
1595                                         if (limit && (*limit) < 0) {
1596                                                 allDone = 0;
1597                                         } else {
1598                                                 allDone =
1599                                                     yaffs_DeleteWorker(in,
1600                                                                        tn->
1601                                                                        internal
1602                                                                        [i],
1603                                                                        level -
1604                                                                        1,
1605                                                                        (chunkOffset
1606                                                                         <<
1607                                                                         YAFFS_TNODES_INTERNAL_BITS)
1608                                                                        + i,
1609                                                                        limit);
1610                                         }
1611                                         if (allDone) {
1612                                                 yaffs_FreeTnode(dev,
1613                                                                 tn->
1614                                                                 internal[i]);
1615                                                 tn->internal[i] = NULL;
1616                                         }
1617                                 }
1618
1619                         }
1620                         return (allDone) ? 1 : 0;
1621                 } else if (level == 0) {
1622                         int hitLimit = 0;
1623
1624                         for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
1625                              i--) {
1626                                 theChunk = yaffs_GetChunkGroupBase(dev,tn,i);
1627                                 if (theChunk) {
1628
1629                                         chunkInInode =
1630                                             (chunkOffset <<
1631                                              YAFFS_TNODES_LEVEL0_BITS) + i;
1632
1633                                         foundChunk =
1634                                             yaffs_FindChunkInGroup(dev,
1635                                                                    theChunk,
1636                                                                    &tags,
1637                                                                    in->objectId,
1638                                                                    chunkInInode);
1639
1640                                         if (foundChunk > 0) {
1641                                                 yaffs_DeleteChunk(dev,
1642                                                                   foundChunk, 1,
1643                                                                   __LINE__);
1644                                                 in->nDataChunks--;
1645                                                 if (limit) {
1646                                                         *limit = *limit - 1;
1647                                                         if (*limit <= 0) {
1648                                                                 hitLimit = 1;
1649                                                         }
1650                                                 }
1651
1652                                         }
1653
1654                                         yaffs_PutLevel0Tnode(dev,tn,i,0);
1655                                 }
1656
1657                         }
1658                         return (i < 0) ? 1 : 0;
1659
1660                 }
1661
1662         }
1663
1664         return 1;
1665
1666 }
1667
1668 static void yaffs_SoftDeleteChunk(yaffs_Device * dev, int chunk)
1669 {
1670
1671         yaffs_BlockInfo *theBlock;
1672
1673         T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
1674
1675         theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
1676         if (theBlock) {
1677                 theBlock->softDeletions++;
1678                 dev->nFreeChunks++;
1679         }
1680 }
1681
1682 /* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
1683  * All soft deleting does is increment the block's softdelete count and pulls the chunk out
1684  * of the tnode.
1685  * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
1686  */
1687  
1688 static int yaffs_SoftDeleteWorker(yaffs_Object * in, yaffs_Tnode * tn,
1689                                   __u32 level, int chunkOffset)
1690 {
1691         int i;
1692         int theChunk;
1693         int allDone = 1;
1694         yaffs_Device *dev = in->myDev;
1695
1696         if (tn) {
1697                 if (level > 0) {
1698
1699                         for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
1700                              i--) {
1701                                 if (tn->internal[i]) {
1702                                         allDone =
1703                                             yaffs_SoftDeleteWorker(in,
1704                                                                    tn->
1705                                                                    internal[i],
1706                                                                    level - 1,
1707                                                                    (chunkOffset
1708                                                                     <<
1709                                                                     YAFFS_TNODES_INTERNAL_BITS)
1710                                                                    + i);
1711                                         if (allDone) {
1712                                                 yaffs_FreeTnode(dev,
1713                                                                 tn->
1714                                                                 internal[i]);
1715                                                 tn->internal[i] = NULL;
1716                                         } else {
1717                                                 /* Hoosterman... how could this happen? */
1718                                         }
1719                                 }
1720                         }
1721                         return (allDone) ? 1 : 0;
1722                 } else if (level == 0) {
1723
1724                         for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
1725                                 theChunk = yaffs_GetChunkGroupBase(dev,tn,i);
1726                                 if (theChunk) {
1727                                         /* Note this does not find the real chunk, only the chunk group.
1728                                          * We make an assumption that a chunk group is not larger than 
1729                                          * a block.
1730                                          */
1731                                         yaffs_SoftDeleteChunk(dev, theChunk);
1732                                         yaffs_PutLevel0Tnode(dev,tn,i,0);
1733                                 }
1734
1735                         }
1736                         return 1;
1737
1738                 }
1739
1740         }
1741
1742         return 1;
1743
1744 }
1745
1746 static void yaffs_SoftDeleteFile(yaffs_Object * obj)
1747 {
1748         if (obj->deleted &&
1749             obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
1750                 if (obj->nDataChunks <= 0) {
1751                         /* Empty file with no duplicate object headers, just delete it immediately */
1752                         yaffs_FreeTnode(obj->myDev,
1753                                         obj->variant.fileVariant.top);
1754                         obj->variant.fileVariant.top = NULL;
1755                         T(YAFFS_TRACE_TRACING,
1756                           (TSTR("yaffs: Deleting empty file %d" TENDSTR),
1757                            obj->objectId));
1758                         yaffs_DoGenericObjectDeletion(obj);
1759                 } else {
1760                         yaffs_SoftDeleteWorker(obj,
1761                                                obj->variant.fileVariant.top,
1762                                                obj->variant.fileVariant.
1763                                                topLevel, 0);
1764                         obj->softDeleted = 1;
1765                 }
1766         }
1767 }
1768
1769 /* Pruning removes any part of the file structure tree that is beyond the
1770  * bounds of the file (ie that does not point to chunks).
1771  *
1772  * A file should only get pruned when its size is reduced.
1773  *
1774  * Before pruning, the chunks must be pulled from the tree and the
1775  * level 0 tnode entries must be zeroed out.
1776  * Could also use this for file deletion, but that's probably better handled
1777  * by a special case.
1778  */
1779
1780 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device * dev, yaffs_Tnode * tn,
1781                                       __u32 level, int del0)
1782 {
1783         int i;
1784         int hasData;
1785
1786         if (tn) {
1787                 hasData = 0;
1788
1789                 for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
1790                         if (tn->internal[i] && level > 0) {
1791                                 tn->internal[i] =
1792                                     yaffs_PruneWorker(dev, tn->internal[i],
1793                                                       level - 1,
1794                                                       (i == 0) ? del0 : 1);
1795                         }
1796
1797                         if (tn->internal[i]) {
1798                                 hasData++;
1799                         }
1800                 }
1801
1802                 if (hasData == 0 && del0) {
1803                         /* Free and return NULL */
1804
1805                         yaffs_FreeTnode(dev, tn);
1806                         tn = NULL;
1807                 }
1808
1809         }
1810
1811         return tn;
1812
1813 }
1814
1815 static int yaffs_PruneFileStructure(yaffs_Device * dev,
1816                                     yaffs_FileStructure * fStruct)
1817 {
1818         int i;
1819         int hasData;
1820         int done = 0;
1821         yaffs_Tnode *tn;
1822
1823         if (fStruct->topLevel > 0) {
1824                 fStruct->top =
1825                     yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
1826
1827                 /* Now we have a tree with all the non-zero branches NULL but the height
1828                  * is the same as it was.
1829                  * Let's see if we can trim internal tnodes to shorten the tree.
1830                  * We can do this if only the 0th element in the tnode is in use 
1831                  * (ie all the non-zero are NULL)
1832                  */
1833
1834                 while (fStruct->topLevel && !done) {
1835                         tn = fStruct->top;
1836
1837                         hasData = 0;
1838                         for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
1839                                 if (tn->internal[i]) {
1840                                         hasData++;
1841                                 }
1842                         }
1843
1844                         if (!hasData) {
1845                                 fStruct->top = tn->internal[0];
1846                                 fStruct->topLevel--;
1847                                 yaffs_FreeTnode(dev, tn);
1848                         } else {
1849                                 done = 1;
1850                         }
1851                 }
1852         }
1853
1854         return YAFFS_OK;
1855 }
1856
1857 /*-------------------- End of File Structure functions.-------------------*/
1858
1859 /* yaffs_CreateFreeObjects creates a bunch more objects and
1860  * adds them to the object free list.
1861  */
1862 static int yaffs_CreateFreeObjects(yaffs_Device * dev, int nObjects)
1863 {
1864         int i;
1865         yaffs_Object *newObjects;
1866         yaffs_ObjectList *list;
1867
1868         if (nObjects < 1)
1869                 return YAFFS_OK;
1870
1871         /* make these things */
1872         newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
1873         list = YMALLOC(sizeof(yaffs_ObjectList));
1874
1875         if (!newObjects || !list) {
1876                 if(newObjects)
1877                         YFREE(newObjects);
1878                 if(list)
1879                         YFREE(list);
1880                 T(YAFFS_TRACE_ALLOCATE,
1881                   (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
1882                 return YAFFS_FAIL;
1883         }
1884         
1885         /* Hook them into the free list */
1886         for (i = 0; i < nObjects - 1; i++) {
1887                 newObjects[i].siblings.next =
1888                     (struct ylist_head *)(&newObjects[i + 1]);
1889         }
1890
1891         newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
1892         dev->freeObjects = newObjects;
1893         dev->nFreeObjects += nObjects;
1894         dev->nObjectsCreated += nObjects;
1895
1896         /* Now add this bunch of Objects to a list for freeing up. */
1897
1898         list->objects = newObjects;
1899         list->next = dev->allocatedObjectList;
1900         dev->allocatedObjectList = list;
1901
1902         return YAFFS_OK;
1903 }
1904
1905
1906 /* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
1907 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev)
1908 {
1909         yaffs_Object *tn = NULL;
1910
1911 #ifdef VALGRIND_TEST
1912         tn = YMALLOC(sizeof(yaffs_Object));
1913 #else
1914         /* If there are none left make more */
1915         if (!dev->freeObjects) {
1916                 yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
1917         }
1918
1919         if (dev->freeObjects) {
1920                 tn = dev->freeObjects;
1921                 dev->freeObjects =
1922                     (yaffs_Object *) (dev->freeObjects->siblings.next);
1923                 dev->nFreeObjects--;
1924         }
1925 #endif
1926         if(tn){
1927                 /* Now sweeten it up... */
1928
1929                 memset(tn, 0, sizeof(yaffs_Object));
1930                 tn->myDev = dev;
1931                 tn->hdrChunk = 0;
1932                 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
1933                 YINIT_LIST_HEAD(&(tn->hardLinks));
1934                 YINIT_LIST_HEAD(&(tn->hashLink));
1935                 YINIT_LIST_HEAD(&tn->siblings);
1936                 
1937
1938                 /* Now make the directory sane */
1939                 if(dev->rootDir){
1940                         tn->parent = dev->rootDir;
1941                         ylist_add(&(tn->siblings),&dev->rootDir->variant.directoryVariant.children);
1942                 }
1943
1944                 /* Add it to the lost and found directory.
1945                  * NB Can't put root or lostNFound in lostNFound so
1946                  * check if lostNFound exists first
1947                  */
1948                 if (dev->lostNFoundDir) {
1949                         yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
1950                 }
1951         }
1952         
1953         dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
1954
1955         return tn;
1956 }
1957
1958 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device * dev, int number,
1959                                                __u32 mode)
1960 {
1961
1962         yaffs_Object *obj =
1963             yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
1964         if (obj) {
1965                 obj->fake = 1;          /* it is fake so it might have no NAND presence... */
1966                 obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
1967                 obj->unlinkAllowed = 0; /* ... or unlink it */
1968                 obj->deleted = 0;
1969                 obj->unlinked = 0;
1970                 obj->yst_mode = mode;
1971                 obj->myDev = dev;
1972                 obj->hdrChunk = 0;      /* Not a valid chunk. */
1973         }
1974
1975         return obj;
1976
1977 }
1978
1979 static void yaffs_UnhashObject(yaffs_Object * tn)
1980 {
1981         int bucket;
1982         yaffs_Device *dev = tn->myDev;
1983
1984         /* If it is still linked into the bucket list, free from the list */
1985         if (!ylist_empty(&tn->hashLink)) {
1986                 ylist_del_init(&tn->hashLink);
1987                 bucket = yaffs_HashFunction(tn->objectId);
1988                 dev->objectBucket[bucket].count--;
1989         }
1990
1991 }
1992
1993 /*  FreeObject frees up a Object and puts it back on the free list */
1994 static void yaffs_FreeObject(yaffs_Object * tn)
1995 {
1996
1997         yaffs_Device *dev = tn->myDev;
1998
1999         
2000         if(tn->parent)
2001                 YBUG();
2002         if(!ylist_empty(&tn->siblings))
2003                 YBUG();
2004
2005
2006 #ifdef  __KERNEL__
2007         if (tn->myInode) {
2008                 /* We're still hooked up to a cached inode.
2009                  * Don't delete now, but mark for later deletion
2010                  */
2011                 tn->deferedFree = 1;
2012                 return;
2013         }
2014 #endif
2015
2016         yaffs_UnhashObject(tn);
2017
2018 #ifdef VALGRIND_TEST
2019         YFREE(tn);
2020 #else
2021         /* Link into the free list. */
2022         tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
2023         dev->freeObjects = tn;
2024         dev->nFreeObjects++;
2025 #endif
2026         dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
2027
2028 }
2029
2030 #ifdef __KERNEL__
2031
2032 void yaffs_HandleDeferedFree(yaffs_Object * obj)
2033 {
2034         if (obj->deferedFree) {
2035                 yaffs_FreeObject(obj);
2036         }
2037 }
2038
2039 #endif
2040
2041 static void yaffs_DeinitialiseObjects(yaffs_Device * dev)
2042 {
2043         /* Free the list of allocated Objects */
2044
2045         yaffs_ObjectList *tmp;
2046
2047         while (dev->allocatedObjectList) {
2048                 tmp = dev->allocatedObjectList->next;
2049                 YFREE(dev->allocatedObjectList->objects);
2050                 YFREE(dev->allocatedObjectList);
2051
2052                 dev->allocatedObjectList = tmp;
2053         }
2054
2055         dev->freeObjects = NULL;
2056         dev->nFreeObjects = 0;
2057 }
2058
2059 static void yaffs_InitialiseObjects(yaffs_Device * dev)
2060 {
2061         int i;
2062
2063         dev->allocatedObjectList = NULL;
2064         dev->freeObjects = NULL;
2065         dev->nFreeObjects = 0;
2066
2067         for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
2068                 YINIT_LIST_HEAD(&dev->objectBucket[i].list);
2069                 dev->objectBucket[i].count = 0;
2070         }
2071
2072 }
2073
2074 static int yaffs_FindNiceObjectBucket(yaffs_Device * dev)
2075 {
2076         static int x = 0;
2077         int i;
2078         int l = 999;
2079         int lowest = 999999;
2080
2081         /* First let's see if we can find one that's empty. */
2082
2083         for (i = 0; i < 10 && lowest > 0; i++) {
2084                 x++;
2085                 x %= YAFFS_NOBJECT_BUCKETS;
2086                 if (dev->objectBucket[x].count < lowest) {
2087                         lowest = dev->objectBucket[x].count;
2088                         l = x;
2089                 }
2090
2091         }
2092
2093         /* If we didn't find an empty list, then try
2094          * looking a bit further for a short one
2095          */
2096
2097         for (i = 0; i < 10 && lowest > 3; i++) {
2098                 x++;
2099                 x %= YAFFS_NOBJECT_BUCKETS;
2100                 if (dev->objectBucket[x].count < lowest) {
2101                         lowest = dev->objectBucket[x].count;
2102                         l = x;
2103                 }
2104
2105         }
2106
2107         return l;
2108 }
2109
2110 static int yaffs_CreateNewObjectNumber(yaffs_Device * dev)
2111 {
2112         int bucket = yaffs_FindNiceObjectBucket(dev);
2113
2114         /* Now find an object value that has not already been taken
2115          * by scanning the list.
2116          */
2117
2118         int found = 0;
2119         struct ylist_head *i;
2120
2121         __u32 n = (__u32) bucket;
2122
2123         /* yaffs_CheckObjectHashSanity();  */
2124
2125         while (!found) {
2126                 found = 1;
2127                 n += YAFFS_NOBJECT_BUCKETS;
2128                 if (1 || dev->objectBucket[bucket].count > 0) {
2129                         ylist_for_each(i, &dev->objectBucket[bucket].list) {
2130                                 /* If there is already one in the list */
2131                                 if (i
2132                                     && ylist_entry(i, yaffs_Object,
2133                                                   hashLink)->objectId == n) {
2134                                         found = 0;
2135                                 }
2136                         }
2137                 }
2138         }
2139
2140
2141         return n;
2142 }
2143
2144 static void yaffs_HashObject(yaffs_Object * in)
2145 {
2146         int bucket = yaffs_HashFunction(in->objectId);
2147         yaffs_Device *dev = in->myDev;
2148
2149         ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
2150         dev->objectBucket[bucket].count++;
2151
2152 }
2153
2154 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number)
2155 {
2156         int bucket = yaffs_HashFunction(number);
2157         struct ylist_head *i;
2158         yaffs_Object *in;
2159
2160         ylist_for_each(i, &dev->objectBucket[bucket].list) {
2161                 /* Look if it is in the list */
2162                 if (i) {
2163                         in = ylist_entry(i, yaffs_Object, hashLink);
2164                         if (in->objectId == number) {
2165 #ifdef __KERNEL__
2166                                 /* Don't tell the VFS about this one if it is defered free */
2167                                 if (in->deferedFree)
2168                                         return NULL;
2169 #endif
2170
2171                                 return in;
2172                         }
2173                 }
2174         }
2175
2176         return NULL;
2177 }
2178
2179 yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,
2180                                     yaffs_ObjectType type)
2181 {
2182
2183         yaffs_Object *theObject;
2184         yaffs_Tnode *tn = NULL;
2185
2186         if (number < 0) {
2187                 number = yaffs_CreateNewObjectNumber(dev);
2188         }
2189
2190         theObject = yaffs_AllocateEmptyObject(dev);
2191         if(!theObject)
2192                 return NULL;
2193                 
2194         if(type == YAFFS_OBJECT_TYPE_FILE){
2195                 tn = yaffs_GetTnode(dev);
2196                 if(!tn){
2197                         yaffs_FreeObject(theObject);
2198                         return NULL;
2199                 }
2200         }
2201                 
2202         
2203
2204         if (theObject) {
2205                 theObject->fake = 0;
2206                 theObject->renameAllowed = 1;
2207                 theObject->unlinkAllowed = 1;
2208                 theObject->objectId = number;
2209                 yaffs_HashObject(theObject);
2210                 theObject->variantType = type;
2211 #ifdef CONFIG_YAFFS_WINCE
2212                 yfsd_WinFileTimeNow(theObject->win_atime);
2213                 theObject->win_ctime[0] = theObject->win_mtime[0] =
2214                     theObject->win_atime[0];
2215                 theObject->win_ctime[1] = theObject->win_mtime[1] =
2216                     theObject->win_atime[1];
2217
2218 #else
2219
2220                 theObject->yst_atime = theObject->yst_mtime =
2221                     theObject->yst_ctime = Y_CURRENT_TIME;
2222 #endif
2223
2224 #if 0
2225                 theObject->sum_prev = 12345;
2226                 theObject->sum_trailer = 6789;
2227 #endif
2228
2229                 switch (type) {
2230                 case YAFFS_OBJECT_TYPE_FILE:
2231                         theObject->variant.fileVariant.fileSize = 0;
2232                         theObject->variant.fileVariant.scannedFileSize = 0;
2233                         theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
2234                         theObject->variant.fileVariant.topLevel = 0;
2235                         theObject->variant.fileVariant.top = tn;
2236                         break;
2237                 case YAFFS_OBJECT_TYPE_DIRECTORY:
2238                         YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
2239                                        children);
2240                         break;
2241                 case YAFFS_OBJECT_TYPE_SYMLINK:
2242                 case YAFFS_OBJECT_TYPE_HARDLINK:
2243                 case YAFFS_OBJECT_TYPE_SPECIAL:
2244                         /* No action required */
2245                         break;
2246                 case YAFFS_OBJECT_TYPE_UNKNOWN:
2247                         /* todo this should not happen */
2248                         break;
2249                 }
2250         }
2251
2252         return theObject;
2253 }
2254
2255 static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device * dev,
2256                                                       int number,
2257                                                       yaffs_ObjectType type)
2258 {
2259         yaffs_Object *theObject = NULL;
2260
2261         if (number > 0) {
2262                 theObject = yaffs_FindObjectByNumber(dev, number);
2263         }
2264
2265         if (!theObject) {
2266                 theObject = yaffs_CreateNewObject(dev, number, type);
2267         }
2268
2269         return theObject;
2270
2271 }
2272                         
2273
2274 static YCHAR *yaffs_CloneString(const YCHAR * str)
2275 {
2276         YCHAR *newStr = NULL;
2277
2278         if (str && *str) {
2279                 newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
2280                 if(newStr)
2281                         yaffs_strcpy(newStr, str);
2282         }
2283
2284         return newStr;
2285
2286 }
2287
2288 /*
2289  * Mknod (create) a new object.
2290  * equivalentObject only has meaning for a hard link;
2291  * aliasString only has meaning for a sumlink.
2292  * rdev only has meaning for devices (a subset of special objects)
2293  */
2294  
2295 static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
2296                                        yaffs_Object * parent,
2297                                        const YCHAR * name,
2298                                        __u32 mode,
2299                                        __u32 uid,
2300                                        __u32 gid,
2301                                        yaffs_Object * equivalentObject,
2302                                        const YCHAR * aliasString, __u32 rdev)
2303 {
2304         yaffs_Object *in;
2305         YCHAR *str = NULL;
2306
2307         yaffs_Device *dev = parent->myDev;
2308
2309         /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
2310         if (yaffs_FindObjectByName(parent, name)) {
2311                 return NULL;
2312         }
2313
2314         in = yaffs_CreateNewObject(dev, -1, type);
2315
2316         if(!in)
2317                 return YAFFS_FAIL;
2318         
2319         if(type == YAFFS_OBJECT_TYPE_SYMLINK){
2320                 str = yaffs_CloneString(aliasString);
2321                 if(!str){
2322                         yaffs_FreeObject(in);
2323                         return NULL;
2324                 }
2325         }
2326         
2327         
2328
2329         if (in) {
2330                 in->hdrChunk = 0;
2331                 in->valid = 1;
2332                 in->variantType = type;
2333
2334                 in->yst_mode = mode;
2335
2336 #ifdef CONFIG_YAFFS_WINCE
2337                 yfsd_WinFileTimeNow(in->win_atime);
2338                 in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
2339                 in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
2340
2341 #else
2342                 in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
2343
2344                 in->yst_rdev = rdev;
2345                 in->yst_uid = uid;
2346                 in->yst_gid = gid;
2347 #endif
2348                 in->nDataChunks = 0;
2349
2350                 yaffs_SetObjectName(in, name);
2351                 in->dirty = 1;
2352
2353                 yaffs_AddObjectToDirectory(parent, in);
2354
2355                 in->myDev = parent->myDev;
2356
2357                 switch (type) {
2358                 case YAFFS_OBJECT_TYPE_SYMLINK:
2359                         in->variant.symLinkVariant.alias = str;
2360                         break;
2361                 case YAFFS_OBJECT_TYPE_HARDLINK:
2362                         in->variant.hardLinkVariant.equivalentObject =
2363                             equivalentObject;
2364                         in->variant.hardLinkVariant.equivalentObjectId =
2365                             equivalentObject->objectId;
2366                         ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
2367                         break;
2368                 case YAFFS_OBJECT_TYPE_FILE:    
2369                 case YAFFS_OBJECT_TYPE_DIRECTORY:
2370                 case YAFFS_OBJECT_TYPE_SPECIAL:
2371                 case YAFFS_OBJECT_TYPE_UNKNOWN:
2372                         /* do nothing */
2373                         break;
2374                 }
2375
2376                 if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
2377                         /* Could not create the object header, fail the creation */
2378                         yaffs_DestroyObject(in);
2379                         in = NULL;
2380                 }
2381
2382         }
2383
2384         return in;
2385 }
2386
2387 yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
2388                               __u32 mode, __u32 uid, __u32 gid)
2389 {
2390         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
2391                                  uid, gid, NULL, NULL, 0);
2392 }
2393
2394 yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
2395                                    __u32 mode, __u32 uid, __u32 gid)
2396 {
2397         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
2398                                  mode, uid, gid, NULL, NULL, 0);
2399 }
2400
2401 yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
2402                                  __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
2403 {
2404         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
2405                                  uid, gid, NULL, NULL, rdev);
2406 }
2407
2408 yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
2409                                  __u32 mode, __u32 uid, __u32 gid,
2410                                  const YCHAR * alias)
2411 {
2412         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
2413                                  uid, gid, NULL, alias, 0);
2414 }
2415
2416 /* yaffs_Link returns the object id of the equivalent object.*/
2417 yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
2418                          yaffs_Object * equivalentObject)
2419 {
2420         /* Get the real object in case we were fed a hard link as an equivalent object */
2421         equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
2422
2423         if (yaffs_MknodObject
2424             (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
2425              equivalentObject, NULL, 0)) {
2426                 return equivalentObject;
2427         } else {
2428                 return NULL;
2429         }
2430
2431 }
2432
2433 static int yaffs_ChangeObjectName(yaffs_Object * obj, yaffs_Object * newDir,
2434                                   const YCHAR * newName, int force, int shadows)
2435 {
2436         int unlinkOp;
2437         int deleteOp;
2438
2439         yaffs_Object *existingTarget;
2440
2441         if (newDir == NULL) {
2442                 newDir = obj->parent;   /* use the old directory */
2443         }
2444
2445         if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
2446                 T(YAFFS_TRACE_ALWAYS,
2447                   (TSTR
2448                    ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
2449                     TENDSTR)));
2450                 YBUG();
2451         }
2452         
2453         /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
2454         if (obj->myDev->isYaffs2) {
2455                 unlinkOp = (newDir == obj->myDev->unlinkedDir);
2456         } else {
2457                 unlinkOp = (newDir == obj->myDev->unlinkedDir
2458                             && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
2459         }
2460
2461         deleteOp = (newDir == obj->myDev->deletedDir);
2462
2463         existingTarget = yaffs_FindObjectByName(newDir, newName);
2464
2465         /* If the object is a file going into the unlinked directory, 
2466          *   then it is OK to just stuff it in since duplicate names are allowed.
2467          *   else only proceed if the new name does not exist and if we're putting 
2468          *   it into a directory.
2469          */
2470         if ((unlinkOp ||
2471              deleteOp ||
2472              force ||
2473              (shadows > 0) ||
2474              !existingTarget) &&
2475             newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
2476                 yaffs_SetObjectName(obj, newName);
2477                 obj->dirty = 1;
2478
2479                 yaffs_AddObjectToDirectory(newDir, obj);
2480
2481                 if (unlinkOp)
2482                         obj->unlinked = 1;
2483
2484                 /* If it is a deletion then we mark it as a shrink for gc purposes. */
2485                 if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows)>= 0)
2486                         return YAFFS_OK;
2487         }
2488
2489         return YAFFS_FAIL;
2490 }
2491
2492 int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
2493                        yaffs_Object * newDir, const YCHAR * newName)
2494 {
2495         yaffs_Object *obj=NULL;
2496         yaffs_Object *existingTarget=NULL;
2497         int force = 0;
2498         
2499         
2500         if(!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
2501                 YBUG();
2502         if(!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
2503                 YBUG();
2504
2505 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
2506         /* Special case for case insemsitive systems (eg. WinCE).
2507          * While look-up is case insensitive, the name isn't.
2508          * Therefore we might want to change x.txt to X.txt
2509         */
2510         if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) {
2511                 force = 1;
2512         }
2513 #endif
2514
2515         else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
2516           /* ENAMETOOLONG */
2517           return YAFFS_FAIL;
2518
2519         obj = yaffs_FindObjectByName(oldDir, oldName);
2520
2521         if (obj && obj->renameAllowed) {
2522
2523                 /* Now do the handling for an existing target, if there is one */
2524
2525                 existingTarget = yaffs_FindObjectByName(newDir, newName);
2526                 if (existingTarget &&
2527                     existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
2528                     !ylist_empty(&existingTarget->variant.directoryVariant.children)) {
2529                         /* There is a target that is a non-empty directory, so we fail */
2530                         return YAFFS_FAIL;      /* EEXIST or ENOTEMPTY */
2531                 } else if (existingTarget && existingTarget != obj) {
2532                         /* Nuke the target first, using shadowing, 
2533                          * but only if it isn't the same object
2534                          */
2535                         yaffs_ChangeObjectName(obj, newDir, newName, force,
2536                                                existingTarget->objectId);
2537                         yaffs_UnlinkObject(existingTarget);
2538                 }
2539
2540                 return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
2541         }
2542         return YAFFS_FAIL;
2543 }
2544
2545 /*------------------------- Block Management and Page Allocation ----------------*/
2546
2547 static int yaffs_InitialiseBlocks(yaffs_Device * dev)
2548 {
2549         int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
2550         
2551         dev->blockInfo = NULL;
2552         dev->chunkBits = NULL;
2553         
2554         dev->allocationBlock = -1;      /* force it to get a new one */
2555
2556         /* If the first allocation strategy fails, thry the alternate one */
2557         dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
2558         if(!dev->blockInfo){
2559                 dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
2560                 dev->blockInfoAlt = 1;
2561         }
2562         else
2563                 dev->blockInfoAlt = 0;
2564                 
2565         if(dev->blockInfo){
2566         
2567                 /* Set up dynamic blockinfo stuff. */
2568                 dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
2569                 dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
2570                 if(!dev->chunkBits){
2571                         dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
2572                         dev->chunkBitsAlt = 1;
2573                 }
2574                 else
2575                         dev->chunkBitsAlt = 0;
2576         }
2577         
2578         if (dev->blockInfo && dev->chunkBits) {
2579                 memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
2580                 memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
2581                 return YAFFS_OK;
2582         }
2583
2584         return YAFFS_FAIL;
2585
2586 }
2587
2588 static void yaffs_DeinitialiseBlocks(yaffs_Device * dev)
2589 {
2590         if(dev->blockInfoAlt && dev->blockInfo)
2591                 YFREE_ALT(dev->blockInfo);
2592         else if(dev->blockInfo)
2593                 YFREE(dev->blockInfo);
2594
2595         dev->blockInfoAlt = 0;
2596
2597         dev->blockInfo = NULL;
2598         
2599         if(dev->chunkBitsAlt && dev->chunkBits)
2600                 YFREE_ALT(dev->chunkBits);
2601         else if(dev->chunkBits)
2602                 YFREE(dev->chunkBits);
2603         dev->chunkBitsAlt = 0;
2604         dev->chunkBits = NULL;
2605 }
2606
2607 static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device * dev,
2608                                             yaffs_BlockInfo * bi)
2609 {
2610         int i;
2611         __u32 seq;
2612         yaffs_BlockInfo *b;
2613
2614         if (!dev->isYaffs2)
2615                 return 1;       /* disqualification only applies to yaffs2. */
2616
2617         if (!bi->hasShrinkHeader)
2618                 return 1;       /* can gc */
2619
2620         /* Find the oldest dirty sequence number if we don't know it and save it
2621          * so we don't have to keep recomputing it.
2622          */
2623         if (!dev->oldestDirtySequence) {
2624                 seq = dev->sequenceNumber;
2625
2626                 for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
2627                      i++) {
2628                         b = yaffs_GetBlockInfo(dev, i);
2629                         if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
2630                             (b->pagesInUse - b->softDeletions) <
2631                             dev->nChunksPerBlock && b->sequenceNumber < seq) {
2632                                 seq = b->sequenceNumber;
2633                         }
2634                 }
2635                 dev->oldestDirtySequence = seq;
2636         }
2637
2638         /* Can't do gc of this block if there are any blocks older than this one that have
2639          * discarded pages.
2640          */
2641         return (bi->sequenceNumber <= dev->oldestDirtySequence);
2642
2643 }
2644
2645 /* FindDiretiestBlock is used to select the dirtiest block (or close enough)
2646  * for garbage collection.
2647  */
2648
2649 static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev,
2650                                                int aggressive)
2651 {
2652
2653         int b = dev->currentDirtyChecker;
2654
2655         int i;
2656         int iterations;
2657         int dirtiest = -1;
2658         int pagesInUse = 0;
2659         int prioritised=0;
2660         yaffs_BlockInfo *bi;
2661         int pendingPrioritisedExist = 0;
2662         
2663         /* First let's see if we need to grab a prioritised block */
2664         if(dev->hasPendingPrioritisedGCs){
2665                 for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){
2666
2667                         bi = yaffs_GetBlockInfo(dev, i);
2668                         //yaffs_VerifyBlock(dev,bi,i);
2669                         
2670                         if(bi->gcPrioritise) {
2671                                 pendingPrioritisedExist = 1;
2672                                 if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
2673                                    yaffs_BlockNotDisqualifiedFromGC(dev, bi)){
2674                                         pagesInUse = (bi->pagesInUse - bi->softDeletions);
2675                                         dirtiest = i;
2676                                         prioritised = 1;
2677                                         aggressive = 1; /* Fool the non-aggressive skip logiv below */
2678                                 }
2679                         }
2680                 }
2681                 
2682                 if(!pendingPrioritisedExist) /* None found, so we can clear this */
2683                         dev->hasPendingPrioritisedGCs = 0;
2684         }
2685
2686         /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
2687          * search harder.
2688          * else (we're doing a leasurely gc), then we only bother to do this if the
2689          * block has only a few pages in use.
2690          */
2691
2692         dev->nonAggressiveSkip--;
2693
2694         if (!aggressive && (dev->nonAggressiveSkip > 0)) {
2695                 return -1;
2696         }
2697
2698         if(!prioritised)
2699                 pagesInUse =
2700                         (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
2701
2702         if (aggressive) {
2703                 iterations =
2704                     dev->internalEndBlock - dev->internalStartBlock + 1;
2705         } else {
2706                 iterations =
2707                     dev->internalEndBlock - dev->internalStartBlock + 1;
2708                 iterations = iterations / 16;
2709                 if (iterations > 200) {
2710                         iterations = 200;
2711                 }
2712         }
2713
2714         for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
2715                 b++;
2716                 if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
2717                         b = dev->internalStartBlock;
2718                 }
2719
2720                 if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
2721                         T(YAFFS_TRACE_ERROR,
2722                           (TSTR("**>> Block %d is not valid" TENDSTR), b));
2723                         YBUG();
2724                 }
2725
2726                 bi = yaffs_GetBlockInfo(dev, b);
2727
2728 #if 0
2729                 if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
2730                         dirtiest = b;
2731                         pagesInUse = 0;
2732                 }
2733                 else 
2734 #endif
2735
2736                 if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
2737                        (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
2738                         yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
2739                         dirtiest = b;
2740                         pagesInUse = (bi->pagesInUse - bi->softDeletions);
2741                 }
2742         }
2743
2744         dev->currentDirtyChecker = b;
2745
2746         if (dirtiest > 0) {
2747                 T(YAFFS_TRACE_GC,
2748                   (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
2749                    dev->nChunksPerBlock - pagesInUse,prioritised));
2750         }
2751
2752         dev->oldestDirtySequence = 0;
2753
2754         if (dirtiest > 0) {
2755                 dev->nonAggressiveSkip = 4;
2756         }
2757
2758         return dirtiest;
2759 }
2760
2761 static void yaffs_BlockBecameDirty(yaffs_Device * dev, int blockNo)
2762 {
2763         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
2764
2765         int erasedOk = 0;
2766
2767         /* If the block is still healthy erase it and mark as clean.
2768          * If the block has had a data failure, then retire it.
2769          */
2770          
2771         T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
2772                 (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
2773                 blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
2774                 
2775         bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
2776
2777         if (!bi->needsRetiring) {
2778                 yaffs_InvalidateCheckpoint(dev);
2779                 erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
2780                 if (!erasedOk) {
2781                         dev->nErasureFailures++;
2782                         T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
2783                           (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
2784                 }
2785         }
2786
2787         if (erasedOk && 
2788             ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
2789                 int i;
2790                 for (i = 0; i < dev->nChunksPerBlock; i++) {
2791                         if (!yaffs_CheckChunkErased
2792                             (dev, blockNo * dev->nChunksPerBlock + i)) {
2793                                 T(YAFFS_TRACE_ERROR,
2794                                   (TSTR
2795                                    (">>Block %d erasure supposedly OK, but chunk %d not erased"
2796                                     TENDSTR), blockNo, i));
2797                         }
2798                 }
2799         }
2800
2801         if (erasedOk) {
2802                 /* Clean it up... */
2803                 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
2804                 dev->nErasedBlocks++;
2805                 bi->pagesInUse = 0;
2806                 bi->softDeletions = 0;
2807                 bi->hasShrinkHeader = 0;
2808                 bi->skipErasedCheck = 1;  /* This is clean, so no need to check */
2809                 bi->gcPrioritise = 0;
2810                 yaffs_ClearChunkBits(dev, blockNo);
2811
2812                 T(YAFFS_TRACE_ERASE,
2813                   (TSTR("Erased block %d" TENDSTR), blockNo));
2814         } else {
2815                 dev->nFreeChunks -= dev->nChunksPerBlock;       /* We lost a block of free space */
2816
2817                 yaffs_RetireBlock(dev, blockNo);
2818                 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
2819                   (TSTR("**>> Block %d retired" TENDSTR), blockNo));
2820         }
2821 }
2822
2823 static int yaffs_FindBlockForAllocation(yaffs_Device * dev)
2824 {
2825         int i;
2826
2827         yaffs_BlockInfo *bi;
2828
2829         if (dev->nErasedBlocks < 1) {
2830                 /* Hoosterman we've got a problem.
2831                  * Can't get space to gc
2832                  */
2833                 T(YAFFS_TRACE_ERROR,
2834                   (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
2835
2836                 return -1;
2837         }
2838         
2839         /* Find an empty block. */
2840
2841         for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
2842                 dev->allocationBlockFinder++;
2843                 if (dev->allocationBlockFinder < dev->internalStartBlock
2844                     || dev->allocationBlockFinder > dev->internalEndBlock) {
2845                         dev->allocationBlockFinder = dev->internalStartBlock;
2846                 }
2847
2848                 bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
2849
2850                 if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
2851                         bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
2852                         dev->sequenceNumber++;
2853                         bi->sequenceNumber = dev->sequenceNumber;
2854                         dev->nErasedBlocks--;
2855                         T(YAFFS_TRACE_ALLOCATE,
2856                           (TSTR("Allocated block %d, seq  %d, %d left" TENDSTR),
2857                            dev->allocationBlockFinder, dev->sequenceNumber,
2858                            dev->nErasedBlocks));
2859                         return dev->allocationBlockFinder;
2860                 }
2861         }
2862
2863         T(YAFFS_TRACE_ALWAYS,
2864           (TSTR
2865            ("yaffs tragedy: no more erased blocks, but there should have been %d"
2866             TENDSTR), dev->nErasedBlocks));
2867
2868         return -1;
2869 }
2870
2871
2872
2873 static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
2874 {
2875         if(!dev->nCheckpointBlocksRequired &&
2876            dev->isYaffs2){
2877                 /* Not a valid value so recalculate */
2878                 int nBytes = 0;
2879                 int nBlocks;
2880                 int devBlocks = (dev->endBlock - dev->startBlock + 1);
2881                 int tnodeSize;
2882
2883                 tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
2884
2885                 if(tnodeSize < sizeof(yaffs_Tnode))
2886                         tnodeSize = sizeof(yaffs_Tnode);
2887                 
2888                 nBytes += sizeof(yaffs_CheckpointValidity);
2889                 nBytes += sizeof(yaffs_CheckpointDevice);
2890                 nBytes += devBlocks * sizeof(yaffs_BlockInfo);
2891                 nBytes += devBlocks * dev->chunkBitmapStride;
2892                 nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
2893                 nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
2894                 nBytes += sizeof(yaffs_CheckpointValidity);
2895                 nBytes += sizeof(__u32); /* checksum*/
2896         
2897                 /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
2898         
2899                 nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
2900         
2901                 dev->nCheckpointBlocksRequired = nBlocks;
2902         }
2903
2904         return dev->nCheckpointBlocksRequired;
2905 }
2906
2907 // Check if there's space to allocate...
2908 // Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
2909 static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev)
2910 {
2911         int reservedChunks;
2912         int reservedBlocks = dev->nReservedBlocks;
2913         int checkpointBlocks;
2914         
2915         if(dev->isYaffs2){
2916                 checkpointBlocks =  yaffs_CalcCheckpointBlocksRequired(dev) - 
2917                                     dev->blocksInCheckpoint;
2918                 if(checkpointBlocks < 0)
2919                         checkpointBlocks = 0;
2920         } else {
2921                 checkpointBlocks =0;
2922         }
2923         
2924         reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
2925         
2926         return (dev->nFreeChunks > reservedChunks);
2927 }
2928
2929 static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr)
2930 {
2931         int retVal;
2932         yaffs_BlockInfo *bi;
2933
2934         if (dev->allocationBlock < 0) {
2935                 /* Get next block to allocate off */
2936                 dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
2937                 dev->allocationPage = 0;
2938         }
2939
2940         if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
2941                 /* Not enough space to allocate unless we're allowed to use the reserve. */
2942                 return -1;
2943         }
2944
2945         if (dev->nErasedBlocks < dev->nReservedBlocks
2946             && dev->allocationPage == 0) {
2947                 T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
2948         }
2949
2950         /* Next page please.... */
2951         if (dev->allocationBlock >= 0) {
2952                 bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
2953
2954                 retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
2955                     dev->allocationPage;
2956                 bi->pagesInUse++;
2957                 yaffs_SetChunkBit(dev, dev->allocationBlock,
2958                                   dev->allocationPage);
2959
2960                 dev->allocationPage++;
2961
2962                 dev->nFreeChunks--;
2963
2964                 /* If the block is full set the state to full */
2965                 if (dev->allocationPage >= dev->nChunksPerBlock) {
2966                         bi->blockState = YAFFS_BLOCK_STATE_FULL;
2967                         dev->allocationBlock = -1;
2968                 }
2969
2970                 if(blockUsedPtr)
2971                         *blockUsedPtr = bi;
2972                         
2973                 return retVal;
2974         }
2975         
2976         T(YAFFS_TRACE_ERROR,
2977           (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
2978
2979         return -1;
2980 }
2981
2982 static int yaffs_GetErasedChunks(yaffs_Device * dev)
2983 {
2984         int n;
2985
2986         n = dev->nErasedBlocks * dev->nChunksPerBlock;
2987
2988         if (dev->allocationBlock > 0) {
2989                 n += (dev->nChunksPerBlock - dev->allocationPage);
2990         }
2991
2992         return n;
2993
2994 }
2995
2996 static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block, int wholeBlock)
2997 {
2998         int oldChunk;
2999         int newChunk;
3000         int markNAND;
3001         int retVal = YAFFS_OK;
3002         int cleanups = 0;
3003         int i;
3004         int isCheckpointBlock;
3005         int matchingChunk;
3006         int maxCopies;
3007
3008         int chunksBefore = yaffs_GetErasedChunks(dev);
3009         int chunksAfter;
3010
3011         yaffs_ExtendedTags tags;
3012
3013         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
3014
3015         yaffs_Object *object;
3016
3017         isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
3018         
3019         bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
3020
3021         T(YAFFS_TRACE_TRACING,
3022           (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR), 
3023           block,
3024           bi->pagesInUse,
3025           bi->hasShrinkHeader,
3026           wholeBlock));
3027
3028         /*yaffs_VerifyFreeChunks(dev); */
3029
3030         bi->hasShrinkHeader = 0;        /* clear the flag so that the block can erase */
3031
3032         /* Take off the number of soft deleted entries because
3033          * they're going to get really deleted during GC.
3034          */
3035         dev->nFreeChunks -= bi->softDeletions;
3036
3037         dev->isDoingGC = 1;
3038
3039         if (isCheckpointBlock ||
3040             !yaffs_StillSomeChunkBits(dev, block)) {
3041                 T(YAFFS_TRACE_TRACING,
3042                   (TSTR
3043                    ("Collecting block %d that has no chunks in use" TENDSTR),
3044                    block));
3045                 yaffs_BlockBecameDirty(dev, block);
3046         } else {
3047
3048                 __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
3049                 
3050                 yaffs_VerifyBlock(dev,bi,block);
3051
3052                 maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
3053                 oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
3054                 
3055                 for ( /* init already done */;
3056                      retVal == YAFFS_OK &&
3057                      dev->gcChunk < dev->nChunksPerBlock &&
3058                      (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)&&
3059                      maxCopies > 0;
3060                      dev->gcChunk++, oldChunk++) {
3061                         if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
3062
3063                                 /* This page is in use and might need to be copied off */
3064                                 
3065                                 maxCopies--;
3066
3067                                 markNAND = 1;
3068
3069                                 yaffs_InitialiseTags(&tags);
3070
3071                                 yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
3072                                                                 buffer, &tags);
3073
3074                                 object =
3075                                     yaffs_FindObjectByNumber(dev,
3076                                                              tags.objectId);
3077
3078                                 T(YAFFS_TRACE_GC_DETAIL,
3079                                   (TSTR
3080                                    ("Collecting chunk in block %d, %d %d %d " TENDSTR),
3081                                    dev->gcChunk, tags.objectId, tags.chunkId,
3082                                    tags.byteCount));
3083                                    
3084                                 if(object && !yaffs_SkipVerification(dev)){
3085                                         if(tags.chunkId == 0)
3086                                                 matchingChunk = object->hdrChunk;
3087                                         else if(object->softDeleted)
3088                                                 matchingChunk = oldChunk; /* Defeat the test */
3089                                         else
3090                                                 matchingChunk = yaffs_FindChunkInFile(object,tags.chunkId,NULL);
3091                                         
3092                                         if(oldChunk != matchingChunk)
3093                                                 T(YAFFS_TRACE_ERROR,
3094                                                   (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
3095                                                   oldChunk,matchingChunk,tags.objectId, tags.chunkId));
3096                                                 
3097                                 }
3098
3099                                 if (!object) {
3100                                         T(YAFFS_TRACE_ERROR,
3101                                           (TSTR
3102                                            ("page %d in gc has no object: %d %d %d "
3103                                             TENDSTR), oldChunk,
3104                                             tags.objectId, tags.chunkId, tags.byteCount));
3105                                 }
3106
3107                                 if (object && 
3108                                     object->deleted &&
3109                                     object->softDeleted &&
3110                                     tags.chunkId != 0) {
3111                                         /* Data chunk in a soft deleted file, throw it away
3112                                          * It's a soft deleted data chunk,
3113                                          * No need to copy this, just forget about it and 
3114                                          * fix up the object.
3115                                          */
3116
3117                                         object->nDataChunks--;
3118
3119                                         if (object->nDataChunks <= 0) {
3120                                                 /* remeber to clean up the object */
3121                                                 dev->gcCleanupList[cleanups] =
3122                                                     tags.objectId;
3123                                                 cleanups++;
3124                                         }
3125                                         markNAND = 0;
3126                                 } else if (0
3127                                            /* Todo object && object->deleted && object->nDataChunks == 0 */
3128                                            ) {
3129                                         /* Deleted object header with no data chunks.
3130                                          * Can be discarded and the file deleted.
3131                                          */
3132                                         object->hdrChunk = 0;
3133                                         yaffs_FreeTnode(object->myDev,
3134                                                         object->variant.
3135                                                         fileVariant.top);
3136                                         object->variant.fileVariant.top = NULL;
3137                                         yaffs_DoGenericObjectDeletion(object);
3138
3139                                 } else if (object) {
3140                                         /* It's either a data chunk in a live file or
3141                                          * an ObjectHeader, so we're interested in it.
3142                                          * NB Need to keep the ObjectHeaders of deleted files
3143                                          * until the whole file has been deleted off
3144                                          */
3145                                         tags.serialNumber++;
3146
3147                                         dev->nGCCopies++;
3148
3149                                         if (tags.chunkId == 0) {
3150                                                 /* It is an object Id,
3151                                                  * We need to nuke the shrinkheader flags first
3152                                                  * We no longer want the shrinkHeader flag since its work is done
3153                                                  * and if it is left in place it will mess up scanning.
3154                                                  * Also, clear out any shadowing stuff
3155                                                  */
3156
3157                                                 yaffs_ObjectHeader *oh;
3158                                                 oh = (yaffs_ObjectHeader *)buffer;
3159                                                 oh->isShrink = 0;
3160                                                 tags.extraShadows = 0;
3161                                                 tags.extraIsShrinkHeader = 0;
3162                                                 
3163                                                 yaffs_VerifyObjectHeader(object,oh,&tags,1);
3164                                         }
3165
3166                                         newChunk =
3167                                             yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
3168
3169                                         if (newChunk < 0) {
3170                                                 retVal = YAFFS_FAIL;
3171                                         } else {
3172
3173                                                 /* Ok, now fix up the Tnodes etc. */
3174
3175                                                 if (tags.chunkId == 0) {
3176                                                         /* It's a header */
3177                                                         object->hdrChunk =  newChunk;
3178                                                         object->serial =   tags.serialNumber;
3179                                                 } else {
3180                                                         /* It's a data chunk */
3181                                                         yaffs_PutChunkIntoFile
3182                                                             (object,
3183                                                              tags.chunkId,
3184                                                              newChunk, 0);
3185                                                 }
3186                                         }
3187                                 }
3188
3189                                 if(retVal == YAFFS_OK)
3190                                         yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
3191
3192                         }
3193                 }
3194
3195                 yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
3196                 
3197
3198
3199                 /* Do any required cleanups */
3200                 for (i = 0; i < cleanups; i++) {
3201                         /* Time to delete the file too */
3202                         object =
3203                             yaffs_FindObjectByNumber(dev,
3204                                                      dev->gcCleanupList[i]);
3205                         if (object) {
3206                                 yaffs_FreeTnode(dev,
3207                                                 object->variant.fileVariant.
3208                                                 top);
3209                                 object->variant.fileVariant.top = NULL;
3210                                 T(YAFFS_TRACE_GC,
3211                                   (TSTR
3212                                    ("yaffs: About to finally delete object %d"
3213                                     TENDSTR), object->objectId));
3214                                 yaffs_DoGenericObjectDeletion(object);
3215                                 object->myDev->nDeletedFiles--;
3216                         }
3217
3218                 }
3219
3220         }
3221
3222         yaffs_VerifyCollectedBlock(dev,bi,block);
3223           
3224         if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) {
3225                 T(YAFFS_TRACE_GC,
3226                   (TSTR
3227                    ("gc did not increase free chunks before %d after %d"
3228                     TENDSTR), chunksBefore, chunksAfter));
3229         }
3230
3231         /* If the gc completed then clear the current gcBlock so that we find another. */
3232         if(bi->blockState != YAFFS_BLOCK_STATE_COLLECTING){
3233                 dev->gcBlock = -1;
3234                 dev->gcChunk = 0;
3235         }
3236         
3237         dev->isDoingGC = 0;
3238
3239         return retVal;
3240 }
3241
3242 /* New garbage collector
3243  * If we're very low on erased blocks then we do aggressive garbage collection
3244  * otherwise we do "leasurely" garbage collection.
3245  * Aggressive gc looks further (whole array) and will accept less dirty blocks.
3246  * Passive gc only inspects smaller areas and will only accept more dirty blocks.
3247  *
3248  * The idea is to help clear out space in a more spread-out manner.
3249  * Dunno if it really does anything useful.
3250  */
3251 static int yaffs_CheckGarbageCollection(yaffs_Device * dev)
3252 {
3253         int block;
3254         int aggressive;
3255         int gcOk = YAFFS_OK;
3256         int maxTries = 0;
3257         
3258         int checkpointBlockAdjust;
3259
3260         if (dev->isDoingGC) {
3261                 /* Bail out so we don't get recursive gc */
3262                 return YAFFS_OK;
3263         }
3264         
3265         /* This loop should pass the first time.
3266          * We'll only see looping here if the erase of the collected block fails.
3267          */
3268
3269         do {
3270                 maxTries++;
3271                 
3272                 checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
3273                 if(checkpointBlockAdjust < 0)
3274                         checkpointBlockAdjust = 0;
3275
3276                 if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
3277                         /* We need a block soon...*/
3278                         aggressive = 1;
3279                 } else {
3280                         /* We're in no hurry */
3281                         aggressive = 0;
3282                 }
3283
3284                 if(dev->gcBlock <= 0){
3285                         dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
3286                         dev->gcChunk = 0;
3287                 }
3288                 
3289                 block = dev->gcBlock;
3290
3291                 if (block > 0) {
3292                         dev->garbageCollections++;
3293                         if (!aggressive) {
3294                                 dev->passiveGarbageCollections++;
3295                         }
3296
3297                         T(YAFFS_TRACE_GC,
3298                           (TSTR
3299                            ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
3300                            dev->nErasedBlocks, aggressive));
3301
3302                         gcOk = yaffs_GarbageCollectBlock(dev,block,aggressive);
3303                 }
3304
3305                 if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
3306                         T(YAFFS_TRACE_GC,
3307                           (TSTR
3308                            ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
3309                             TENDSTR), dev->nErasedBlocks, maxTries, block));
3310                 }
3311         } while ((dev->nErasedBlocks < dev->nReservedBlocks) && 
3312                  (block > 0) &&
3313                  (maxTries < 2));
3314
3315         return aggressive ? gcOk : YAFFS_OK;
3316 }
3317
3318 /*-------------------------  TAGS --------------------------------*/
3319
3320 static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,
3321                            int chunkInObject)
3322 {
3323         return (tags->chunkId == chunkInObject &&
3324                 tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
3325
3326 }
3327
3328
3329 /*-------------------- Data file manipulation -----------------*/
3330
3331 static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,
3332                                  yaffs_ExtendedTags * tags)
3333 {
3334         /*Get the Tnode, then get the level 0 offset chunk offset */
3335         yaffs_Tnode *tn;
3336         int theChunk = -1;
3337         yaffs_ExtendedTags localTags;
3338         int retVal = -1;
3339
3340         yaffs_Device *dev = in->myDev;
3341
3342         if (!tags) {
3343                 /* Passed a NULL, so use our own tags space */
3344                 tags = &localTags;
3345         }
3346
3347         tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
3348
3349         if (tn) {
3350                 theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
3351
3352                 retVal =
3353                     yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
3354                                            chunkInInode);
3355         }
3356         return retVal;
3357 }
3358
3359 static int yaffs_FindAndDeleteChunkInFile(yaffs_Object * in, int chunkInInode,
3360                                           yaffs_ExtendedTags * tags)
3361 {
3362         /* Get the Tnode, then get the level 0 offset chunk offset */
3363         yaffs_Tnode *tn;
3364         int theChunk = -1;
3365         yaffs_ExtendedTags localTags;
3366
3367         yaffs_Device *dev = in->myDev;
3368         int retVal = -1;
3369
3370         if (!tags) {
3371                 /* Passed a NULL, so use our own tags space */
3372                 tags = &localTags;
3373         }
3374
3375         tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
3376
3377         if (tn) {
3378
3379                 theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
3380
3381                 retVal =
3382                     yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
3383                                            chunkInInode);
3384
3385                 /* Delete the entry in the filestructure (if found) */
3386                 if (retVal != -1) {
3387                         yaffs_PutLevel0Tnode(dev,tn,chunkInInode,0);
3388                 }
3389         } else {
3390                 /*T(("No level 0 found for %d\n", chunkInInode)); */
3391         }
3392
3393         if (retVal == -1) {
3394                 /* T(("Could not find %d to delete\n",chunkInInode)); */
3395         }
3396         return retVal;
3397 }
3398
3399 #ifdef YAFFS_PARANOID
3400
3401 static int yaffs_CheckFileSanity(yaffs_Object * in)
3402 {
3403         int chunk;
3404         int nChunks;
3405         int fSize;
3406         int failed = 0;
3407         int objId;
3408         yaffs_Tnode *tn;
3409         yaffs_Tags localTags;
3410         yaffs_Tags *tags = &localTags;
3411         int theChunk;
3412         int chunkDeleted;
3413
3414         if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
3415                 /* T(("Object not a file\n")); */
3416                 return YAFFS_FAIL;
3417         }
3418
3419         objId = in->objectId;
3420         fSize = in->variant.fileVariant.fileSize;
3421         nChunks =
3422             (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
3423
3424         for (chunk = 1; chunk <= nChunks; chunk++) {
3425                 tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
3426                                            chunk);
3427
3428                 if (tn) {
3429
3430                         theChunk = yaffs_GetChunkGroupBase(dev,tn,chunk);
3431
3432                         if (yaffs_CheckChunkBits
3433                             (dev, theChunk / dev->nChunksPerBlock,
3434                              theChunk % dev->nChunksPerBlock)) {
3435
3436                                 yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
3437                                                             tags,
3438                                                             &chunkDeleted);
3439                                 if (yaffs_TagsMatch
3440                                     (tags, in->objectId, chunk, chunkDeleted)) {
3441                                         /* found it; */
3442
3443                                 }
3444                         } else {
3445
3446                                 failed = 1;
3447                         }
3448
3449                 } else {
3450                         /* T(("No level 0 found for %d\n", chunk)); */
3451                 }
3452         }
3453
3454         return failed ? YAFFS_FAIL : YAFFS_OK;
3455 }
3456
3457 #endif
3458
3459 static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode,
3460                                   int chunkInNAND, int inScan)
3461 {
3462         /* NB inScan is zero unless scanning. 
3463          * For forward scanning, inScan is > 0; 
3464          * for backward scanning inScan is < 0
3465          */
3466          
3467         yaffs_Tnode *tn;
3468         yaffs_Device *dev = in->myDev;
3469         int existingChunk;
3470         yaffs_ExtendedTags existingTags;
3471         yaffs_ExtendedTags newTags;
3472         unsigned existingSerial, newSerial;
3473
3474         if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
3475                 /* Just ignore an attempt at putting a chunk into a non-file during scanning
3476                  * If it is not during Scanning then something went wrong!
3477                  */
3478                 if (!inScan) {
3479                         T(YAFFS_TRACE_ERROR,
3480                           (TSTR
3481                            ("yaffs tragedy:attempt to put data chunk into a non-file"
3482                             TENDSTR)));
3483                         YBUG();
3484                 }
3485
3486                 yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
3487                 return YAFFS_OK;
3488         }
3489
3490         tn = yaffs_AddOrFindLevel0Tnode(dev, 
3491                                         &in->variant.fileVariant,
3492                                         chunkInInode,
3493                                         NULL);
3494         if (!tn) {
3495                 return YAFFS_FAIL;
3496         }
3497
3498         existingChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
3499
3500         if (inScan != 0) {
3501                 /* If we're scanning then we need to test for duplicates
3502                  * NB This does not need to be efficient since it should only ever 
3503                  * happen when the power fails during a write, then only one
3504                  * chunk should ever be affected.
3505                  *
3506                  * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
3507                  * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
3508                  */
3509
3510                 if (existingChunk > 0) {
3511                         /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
3512                          *    thus we have to do a FindChunkInFile to get the real chunk id.
3513                          *
3514                          * We have a duplicate now we need to decide which one to use:
3515                          *
3516                          * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
3517                          * Forward scanning YAFFS2: The new one is what we use, dump the old one.
3518                          * YAFFS1: Get both sets of tags and compare serial numbers.
3519                          */
3520
3521                         if (inScan > 0) {
3522                                 /* Only do this for forward scanning */
3523                                 yaffs_ReadChunkWithTagsFromNAND(dev,
3524                                                                 chunkInNAND,
3525                                                                 NULL, &newTags);
3526
3527                                 /* Do a proper find */
3528                                 existingChunk =
3529                                     yaffs_FindChunkInFile(in, chunkInInode,
3530                                                           &existingTags);
3531                         }
3532
3533                         if (existingChunk <= 0) {
3534                                 /*Hoosterman - how did this happen? */
3535
3536                                 T(YAFFS_TRACE_ERROR,
3537                                   (TSTR
3538                                    ("yaffs tragedy: existing chunk < 0 in scan"
3539                                     TENDSTR)));
3540
3541                         }
3542
3543                         /* NB The deleted flags should be false, otherwise the chunks will 
3544                          * not be loaded during a scan
3545                          */
3546
3547                         if(inScan > 0) {
3548                                 newSerial = newTags.serialNumber;
3549                                 existingSerial = existingTags.serialNumber;
3550                         }
3551
3552                         if ((inScan > 0) &&
3553                             (in->myDev->isYaffs2 ||
3554                              existingChunk <= 0 ||
3555                              ((existingSerial + 1) & 3) == newSerial)) {
3556                                 /* Forward scanning.                            
3557                                  * Use new
3558                                  * Delete the old one and drop through to update the tnode
3559                                  */
3560                                 yaffs_DeleteChunk(dev, existingChunk, 1,
3561                                                   __LINE__);
3562                         } else {
3563                                 /* Backward scanning or we want to use the existing one
3564                                  * Use existing.
3565                                  * Delete the new one and return early so that the tnode isn't changed
3566                                  */
3567                                 yaffs_DeleteChunk(dev, chunkInNAND, 1,
3568                                                   __LINE__);
3569                                 return YAFFS_OK;
3570                         }
3571                 }
3572
3573         }
3574
3575         if (existingChunk == 0) {
3576                 in->nDataChunks++;
3577         }
3578
3579         yaffs_PutLevel0Tnode(dev,tn,chunkInInode,chunkInNAND);
3580
3581         return YAFFS_OK;
3582 }
3583
3584 static int yaffs_ReadChunkDataFromObject(yaffs_Object * in, int chunkInInode,
3585                                          __u8 * buffer)
3586 {
3587         int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
3588
3589         if (chunkInNAND >= 0) {
3590                 return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
3591                                                        buffer,NULL);
3592         } else {
3593                 T(YAFFS_TRACE_NANDACCESS,
3594                   (TSTR("Chunk %d not found zero instead" TENDSTR),
3595                    chunkInNAND));
3596                 /* get sane (zero) data if you read a hole */
3597                 memset(buffer, 0, in->myDev->nDataBytesPerChunk);       
3598                 return 0;
3599         }
3600
3601 }
3602
3603 void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn)
3604 {
3605         int block;
3606         int page;
3607         yaffs_ExtendedTags tags;
3608         yaffs_BlockInfo *bi;
3609
3610         if (chunkId <= 0)
3611                 return;
3612                 
3613
3614         dev->nDeletions++;
3615         block = chunkId / dev->nChunksPerBlock;
3616         page = chunkId % dev->nChunksPerBlock;
3617
3618
3619         if(!yaffs_CheckChunkBit(dev,block,page))
3620                 T(YAFFS_TRACE_VERIFY,
3621                         (TSTR("Deleting invalid chunk %d"TENDSTR),
3622                          chunkId));
3623
3624         bi = yaffs_GetBlockInfo(dev, block);
3625
3626         T(YAFFS_TRACE_DELETION,
3627           (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
3628
3629         if (markNAND &&
3630             bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
3631
3632                 yaffs_InitialiseTags(&tags);
3633
3634                 tags.chunkDeleted = 1;
3635
3636                 yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
3637                 yaffs_HandleUpdateChunk(dev, chunkId, &tags);
3638         } else {
3639                 dev->nUnmarkedDeletions++;
3640         }
3641
3642         /* Pull out of the management area.
3643          * If the whole block became dirty, this will kick off an erasure.
3644          */
3645         if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
3646             bi->blockState == YAFFS_BLOCK_STATE_FULL ||
3647             bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
3648             bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
3649                 dev->nFreeChunks++;
3650
3651                 yaffs_ClearChunkBit(dev, block, page);
3652
3653                 bi->pagesInUse--;
3654
3655                 if (bi->pagesInUse == 0 &&
3656                     !bi->hasShrinkHeader &&
3657                     bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
3658                     bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
3659                         yaffs_BlockBecameDirty(dev, block);
3660                 }
3661
3662         } else {
3663                 /* T(("Bad news deleting chunk %d\n",chunkId)); */
3664         }
3665
3666 }
3667
3668 static int yaffs_WriteChunkDataToObject(yaffs_Object * in, int chunkInInode,
3669                                         const __u8 * buffer, int nBytes,
3670                                         int useReserve)
3671 {
3672         /* Find old chunk Need to do this to get serial number
3673          * Write new one and patch into tree.
3674          * Invalidate old tags.
3675          */
3676
3677         int prevChunkId;
3678         yaffs_ExtendedTags prevTags;
3679
3680         int newChunkId;
3681         yaffs_ExtendedTags newTags;
3682
3683         yaffs_Device *dev = in->myDev;
3684
3685         yaffs_CheckGarbageCollection(dev);
3686
3687         /* Get the previous chunk at this location in the file if it exists */
3688         prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
3689
3690         /* Set up new tags */
3691         yaffs_InitialiseTags(&newTags);
3692
3693         newTags.chunkId = chunkInInode;
3694         newTags.objectId = in->objectId;
3695         newTags.serialNumber =
3696             (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
3697         newTags.byteCount = nBytes;
3698         
3699         if(nBytes < 1 || nBytes > dev->totalBytesPerChunk){
3700           T(YAFFS_TRACE_ERROR,
3701           (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
3702           while(1){}
3703         }
3704         
3705         
3706
3707         newChunkId =
3708             yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
3709                                               useReserve);
3710
3711         if (newChunkId >= 0) {
3712                 yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
3713
3714                 if (prevChunkId >= 0) {
3715                         yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
3716
3717                 }
3718
3719                 yaffs_CheckFileSanity(in);
3720         }
3721         return newChunkId;
3722
3723 }
3724
3725 /* UpdateObjectHeader updates the header on NAND for an object.
3726  * If name is not NULL, then that new name is used.
3727  */
3728 int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, int force,
3729                              int isShrink, int shadows)
3730 {
3731
3732         yaffs_BlockInfo *bi;
3733
3734         yaffs_Device *dev = in->myDev;
3735
3736         int prevChunkId;
3737         int retVal = 0;
3738         int result = 0;
3739
3740         int newChunkId;
3741         yaffs_ExtendedTags newTags;
3742         yaffs_ExtendedTags oldTags;
3743
3744         __u8 *buffer = NULL;
3745         YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
3746
3747         yaffs_ObjectHeader *oh = NULL;
3748         
3749         yaffs_strcpy(oldName,_Y("silly old name"));
3750
3751
3752         if (!in->fake || 
3753             in == dev->rootDir || /* The rootDir should also be saved */
3754             force) {
3755
3756                 yaffs_CheckGarbageCollection(dev);
3757                 yaffs_CheckObjectDetailsLoaded(in);
3758
3759                 buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
3760                 oh = (yaffs_ObjectHeader *) buffer;
3761
3762                 prevChunkId = in->hdrChunk;
3763
3764                 if (prevChunkId > 0) {
3765                         result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
3766                                                         buffer, &oldTags);
3767                         
3768                         yaffs_VerifyObjectHeader(in,oh,&oldTags,0);
3769                                                                                 
3770                         memcpy(oldName, oh->name, sizeof(oh->name));
3771                 }
3772
3773                 memset(buffer, 0xFF, dev->nDataBytesPerChunk);
3774
3775                 oh->type = in->variantType;
3776                 oh->yst_mode = in->yst_mode;
3777                 oh->shadowsObject = oh->inbandShadowsObject = shadows;
3778
3779 #ifdef CONFIG_YAFFS_WINCE
3780                 oh->win_atime[0] = in->win_atime[0];
3781                 oh->win_ctime[0] = in->win_ctime[0];
3782                 oh->win_mtime[0] = in->win_mtime[0];
3783                 oh->win_atime[1] = in->win_atime[1];
3784                 oh->win_ctime[1] = in->win_ctime[1];
3785                 oh->win_mtime[1] = in->win_mtime[1];
3786 #else
3787                 oh->yst_uid = in->yst_uid;
3788                 oh->yst_gid = in->yst_gid;
3789                 oh->yst_atime = in->yst_atime;
3790                 oh->yst_mtime = in->yst_mtime;
3791                 oh->yst_ctime = in->yst_ctime;
3792                 oh->yst_rdev = in->yst_rdev;
3793 #endif
3794                 if (in->parent) {
3795                         oh->parentObjectId = in->parent->objectId;
3796                 } else {
3797                         oh->parentObjectId = 0;
3798                 }
3799
3800                 if (name && *name) {
3801                         memset(oh->name, 0, sizeof(oh->name));
3802                         yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
3803                 } else if (prevChunkId>=0) {
3804                         memcpy(oh->name, oldName, sizeof(oh->name));
3805                 } else {
3806                         memset(oh->name, 0, sizeof(oh->name));
3807                 }
3808
3809                 oh->isShrink = isShrink;
3810
3811                 switch (in->variantType) {
3812                 case YAFFS_OBJECT_TYPE_UNKNOWN:
3813                         /* Should not happen */
3814                         break;
3815                 case YAFFS_OBJECT_TYPE_FILE:
3816                         oh->fileSize =
3817                             (oh->parentObjectId == YAFFS_OBJECTID_DELETED
3818                              || oh->parentObjectId ==
3819                              YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
3820                             fileVariant.fileSize;
3821                         break;
3822                 case YAFFS_OBJECT_TYPE_HARDLINK:
3823                         oh->equivalentObjectId =
3824                             in->variant.hardLinkVariant.equivalentObjectId;
3825                         break;
3826                 case YAFFS_OBJECT_TYPE_SPECIAL:
3827                         /* Do nothing */
3828                         break;
3829                 case YAFFS_OBJECT_TYPE_DIRECTORY:
3830                         /* Do nothing */
3831                         break;
3832                 case YAFFS_OBJECT_TYPE_SYMLINK:
3833                         yaffs_strncpy(oh->alias,
3834                                       in->variant.symLinkVariant.alias,
3835                                       YAFFS_MAX_ALIAS_LENGTH);
3836                         oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
3837                         break;
3838                 }
3839
3840                 /* Tags */
3841                 yaffs_InitialiseTags(&newTags);
3842                 in->serial++;
3843                 newTags.chunkId = 0;
3844                 newTags.objectId = in->objectId;
3845                 newTags.serialNumber = in->serial;
3846
3847                 /* Add extra info for file header */
3848
3849                 newTags.extraHeaderInfoAvailable = 1;
3850                 newTags.extraParentObjectId = oh->parentObjectId;
3851                 newTags.extraFileLength = oh->fileSize;
3852                 newTags.extraIsShrinkHeader = oh->isShrink;
3853                 newTags.extraEquivalentObjectId = oh->equivalentObjectId;
3854                 newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
3855                 newTags.extraObjectType = in->variantType;
3856
3857                 yaffs_VerifyObjectHeader(in,oh,&newTags,1);
3858
3859                 /* Create new chunk in NAND */
3860                 newChunkId =
3861                     yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
3862                                                       (prevChunkId >= 0) ? 1 : 0);
3863
3864                 if (newChunkId >= 0) {
3865
3866                         in->hdrChunk = newChunkId;
3867
3868                         if (prevChunkId >= 0) {
3869                                 yaffs_DeleteChunk(dev, prevChunkId, 1,
3870                                                   __LINE__);
3871                         }
3872
3873                         if(!yaffs_ObjectHasCachedWriteData(in))
3874                                 in->dirty = 0;
3875
3876                         /* If this was a shrink, then mark the block that the chunk lives on */
3877                         if (isShrink) {
3878                                 bi = yaffs_GetBlockInfo(in->myDev,
3879                                                         newChunkId /in->myDev-> nChunksPerBlock);
3880                                 bi->hasShrinkHeader = 1;
3881                         }
3882
3883                 }
3884
3885                 retVal = newChunkId;
3886
3887         }
3888
3889         if (buffer)
3890                 yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
3891
3892         return retVal;
3893 }
3894
3895 /*------------------------ Short Operations Cache ----------------------------------------
3896  *   In many situations where there is no high level buffering (eg WinCE) a lot of
3897  *   reads might be short sequential reads, and a lot of writes may be short 
3898  *   sequential writes. eg. scanning/writing a jpeg file.
3899  *   In these cases, a short read/write cache can provide a huge perfomance benefit 
3900  *   with dumb-as-a-rock code.
3901  *   In Linux, the page cache provides read buffering aand the short op cache provides write 
3902  *   buffering.
3903  *
3904  *   There are a limited number (~10) of cache chunks per device so that we don't
3905  *   need a very intelligent search.
3906  */
3907
3908 static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
3909 {
3910         yaffs_Device *dev = obj->myDev;
3911         int i;
3912         yaffs_ChunkCache *cache;
3913         int nCaches = obj->myDev->nShortOpCaches;
3914         
3915         for(i = 0; i < nCaches; i++){
3916                 cache = &dev->srCache[i];
3917                 if (cache->object == obj &&
3918                     cache->dirty)
3919                         return 1;
3920         }
3921         
3922         return 0;
3923 }
3924
3925
3926 static void yaffs_FlushFilesChunkCache(yaffs_Object * obj)
3927 {
3928         yaffs_Device *dev = obj->myDev;
3929         int lowest = -99;       /* Stop compiler whining. */
3930         int i;
3931         yaffs_ChunkCache *cache;
3932         int chunkWritten = 0;
3933         int nCaches = obj->myDev->nShortOpCaches;
3934
3935         if (nCaches > 0) {
3936                 do {
3937                         cache = NULL;
3938
3939                         /* Find the dirty cache for this object with the lowest chunk id. */
3940                         for (i = 0; i < nCaches; i++) {
3941                                 if (dev->srCache[i].object == obj &&
3942                                     dev->srCache[i].dirty) {
3943                                         if (!cache
3944                                             || dev->srCache[i].chunkId <
3945                                             lowest) {
3946                                                 cache = &dev->srCache[i];
3947                                                 lowest = cache->chunkId;
3948                                         }
3949                                 }
3950                         }
3951
3952                         if (cache && !cache->locked) {
3953                                 /* Write it out and free it up */
3954
3955                                 chunkWritten =
3956                                     yaffs_WriteChunkDataToObject(cache->object,
3957                                                                  cache->chunkId,
3958                                                                  cache->data,
3959                                                                  cache->nBytes,
3960                                                                  1);
3961                                 cache->dirty = 0;
3962                                 cache->object = NULL;
3963                         }
3964
3965                 } while (cache && chunkWritten > 0);
3966
3967                 if (cache) {
3968                         /* Hoosterman, disk full while writing cache out. */
3969                         T(YAFFS_TRACE_ERROR,
3970                           (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
3971
3972                 }
3973         }
3974
3975 }
3976
3977 /*yaffs_FlushEntireDeviceCache(dev)
3978  *
3979  *
3980  */
3981
3982 void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
3983 {
3984         yaffs_Object *obj;
3985         int nCaches = dev->nShortOpCaches;
3986         int i;
3987         
3988         /* Find a dirty object in the cache and flush it...
3989          * until there are no further dirty objects.
3990          */
3991         do {
3992                 obj = NULL;
3993                 for( i = 0; i < nCaches && !obj; i++) {
3994                         if (dev->srCache[i].object &&
3995                             dev->srCache[i].dirty)
3996                                 obj = dev->srCache[i].object;
3997                             
3998                 }
3999                 if(obj)
4000                         yaffs_FlushFilesChunkCache(obj);
4001                         
4002         } while(obj);
4003         
4004 }
4005
4006
4007 /* Grab us a cache chunk for use.
4008  * First look for an empty one. 
4009  * Then look for the least recently used non-dirty one.
4010  * Then look for the least recently used dirty one...., flush and look again.
4011  */
4012 static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device * dev)
4013 {
4014         int i;
4015
4016         if (dev->nShortOpCaches > 0) {
4017                 for (i = 0; i < dev->nShortOpCaches; i++) {
4018                         if (!dev->srCache[i].object) 
4019                                 return &dev->srCache[i];
4020                 }
4021         }
4022
4023         return NULL;
4024 }
4025
4026 static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev)
4027 {
4028         yaffs_ChunkCache *cache;
4029         yaffs_Object *theObj;
4030         int usage;
4031         int i;
4032         int pushout;
4033
4034         if (dev->nShortOpCaches > 0) {
4035                 /* Try find a non-dirty one... */
4036
4037                 cache = yaffs_GrabChunkCacheWorker(dev);
4038
4039                 if (!cache) {
4040                         /* They were all dirty, find the last recently used object and flush
4041                          * its cache, then  find again.
4042                          * NB what's here is not very accurate, we actually flush the object
4043                          * the last recently used page.
4044                          */
4045
4046                         /* With locking we can't assume we can use entry zero */
4047
4048                         theObj = NULL;
4049                         usage = -1;
4050                         cache = NULL;
4051                         pushout = -1;
4052
4053                         for (i = 0; i < dev->nShortOpCaches; i++) {
4054                                 if (dev->srCache[i].object &&
4055                                     !dev->srCache[i].locked &&
4056                                     (dev->srCache[i].lastUse < usage || !cache))
4057                                 {
4058                                         usage = dev->srCache[i].lastUse;
4059                                         theObj = dev->srCache[i].object;
4060                                         cache = &dev->srCache[i];
4061                                         pushout = i;
4062                                 }
4063                         }
4064
4065                         if (!cache || cache->dirty) {
4066                                 /* Flush and try again */
4067                                 yaffs_FlushFilesChunkCache(theObj);
4068                                 cache = yaffs_GrabChunkCacheWorker(dev);
4069                         }
4070
4071                 }
4072                 return cache;
4073         } else
4074                 return NULL;
4075
4076 }
4077
4078 /* Find a cached chunk */
4079 static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object * obj,
4080                                               int chunkId)
4081 {
4082         yaffs_Device *dev = obj->myDev;
4083         int i;
4084         if (dev->nShortOpCaches > 0) {
4085                 for (i = 0; i < dev->nShortOpCaches; i++) {
4086                         if (dev->srCache[i].object == obj &&
4087                             dev->srCache[i].chunkId == chunkId) {
4088                                 dev->cacheHits++;
4089
4090                                 return &dev->srCache[i];
4091                         }
4092                 }
4093         }
4094         return NULL;
4095 }
4096
4097 /* Mark the chunk for the least recently used algorithym */
4098 static void yaffs_UseChunkCache(yaffs_Device * dev, yaffs_ChunkCache * cache,
4099                                 int isAWrite)
4100 {
4101
4102         if (dev->nShortOpCaches > 0) {
4103                 if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
4104                         /* Reset the cache usages */
4105                         int i;
4106                         for (i = 1; i < dev->nShortOpCaches; i++) {
4107                                 dev->srCache[i].lastUse = 0;
4108                         }
4109                         dev->srLastUse = 0;
4110                 }
4111
4112                 dev->srLastUse++;
4113
4114                 cache->lastUse = dev->srLastUse;
4115
4116                 if (isAWrite) {
4117                         cache->dirty = 1;
4118                 }
4119         }
4120 }
4121
4122 /* Invalidate a single cache page.
4123  * Do this when a whole page gets written,
4124  * ie the short cache for this page is no longer valid.
4125  */
4126 static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId)
4127 {
4128         if (object->myDev->nShortOpCaches > 0) {
4129                 yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
4130
4131                 if (cache) {
4132                         cache->object = NULL;
4133                 }
4134         }
4135 }
4136
4137 /* Invalidate all the cache pages associated with this object
4138  * Do this whenever ther file is deleted or resized.
4139  */
4140 static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in)
4141 {
4142         int i;
4143         yaffs_Device *dev = in->myDev;
4144
4145         if (dev->nShortOpCaches > 0) {
4146                 /* Invalidate it. */
4147                 for (i = 0; i < dev->nShortOpCaches; i++) {
4148                         if (dev->srCache[i].object == in) {
4149                                 dev->srCache[i].object = NULL;
4150                         }
4151                 }
4152         }
4153 }
4154
4155 /*--------------------- Checkpointing --------------------*/
4156
4157
4158 static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head)
4159 {
4160         yaffs_CheckpointValidity cp;
4161         
4162         memset(&cp,0,sizeof(cp));
4163         
4164         cp.structType = sizeof(cp);
4165         cp.magic = YAFFS_MAGIC;
4166         cp.version = YAFFS_CHECKPOINT_VERSION;
4167         cp.head = (head) ? 1 : 0;
4168         
4169         return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))?
4170                 1 : 0;
4171 }
4172
4173 static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
4174 {
4175         yaffs_CheckpointValidity cp;
4176         int ok;
4177         
4178         ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
4179         
4180         if(ok)
4181                 ok = (cp.structType == sizeof(cp)) &&
4182                      (cp.magic == YAFFS_MAGIC) &&
4183                      (cp.version == YAFFS_CHECKPOINT_VERSION) &&
4184                      (cp.head == ((head) ? 1 : 0));
4185         return ok ? 1 : 0;
4186 }
4187
4188 static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, 
4189                                            yaffs_Device *dev)
4190 {
4191         cp->nErasedBlocks = dev->nErasedBlocks;
4192         cp->allocationBlock = dev->allocationBlock;
4193         cp->allocationPage = dev->allocationPage;
4194         cp->nFreeChunks = dev->nFreeChunks;
4195         
4196         cp->nDeletedFiles = dev->nDeletedFiles;
4197         cp->nUnlinkedFiles = dev->nUnlinkedFiles;
4198         cp->nBackgroundDeletions = dev->nBackgroundDeletions;
4199         cp->sequenceNumber = dev->sequenceNumber;
4200         cp->oldestDirtySequence = dev->oldestDirtySequence;
4201         
4202 }
4203
4204 static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
4205                                            yaffs_CheckpointDevice *cp)
4206 {
4207         dev->nErasedBlocks = cp->nErasedBlocks;
4208         dev->allocationBlock = cp->allocationBlock;
4209         dev->allocationPage = cp->allocationPage;
4210         dev->nFreeChunks = cp->nFreeChunks;
4211         
4212         dev->nDeletedFiles = cp->nDeletedFiles;
4213         dev->nUnlinkedFiles = cp->nUnlinkedFiles;
4214         dev->nBackgroundDeletions = cp->nBackgroundDeletions;
4215         dev->sequenceNumber = cp->sequenceNumber;
4216         dev->oldestDirtySequence = cp->oldestDirtySequence;
4217 }
4218
4219
4220 static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
4221 {
4222         yaffs_CheckpointDevice cp;
4223         __u32 nBytes;
4224         __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
4225
4226         int ok;
4227                 
4228         /* Write device runtime values*/
4229         yaffs_DeviceToCheckpointDevice(&cp,dev);
4230         cp.structType = sizeof(cp);
4231         
4232         ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
4233         
4234         /* Write block info */
4235         if(ok) {
4236                 nBytes = nBlocks * sizeof(yaffs_BlockInfo);
4237                 ok = (yaffs_CheckpointWrite(dev,dev->blockInfo,nBytes) == nBytes);
4238         }
4239                 
4240         /* Write chunk bits */          
4241         if(ok) {
4242                 nBytes = nBlocks * dev->chunkBitmapStride;
4243                 ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes);
4244         }
4245         return   ok ? 1 : 0;
4246
4247 }
4248
4249 static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
4250 {
4251         yaffs_CheckpointDevice cp;
4252         __u32 nBytes;
4253         __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
4254
4255         int ok; 
4256         
4257         ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
4258         if(!ok)
4259                 return 0;
4260                 
4261         if(cp.structType != sizeof(cp))
4262                 return 0;
4263                 
4264         
4265         yaffs_CheckpointDeviceToDevice(dev,&cp);
4266         
4267         nBytes = nBlocks * sizeof(yaffs_BlockInfo);
4268         
4269         ok = (yaffs_CheckpointRead(dev,dev->blockInfo,nBytes) == nBytes);
4270         
4271         if(!ok)
4272                 return 0;
4273         nBytes = nBlocks * dev->chunkBitmapStride;
4274         
4275         ok = (yaffs_CheckpointRead(dev,dev->chunkBits,nBytes) == nBytes);
4276         
4277         return ok ? 1 : 0;
4278 }
4279
4280 static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
4281                                            yaffs_Object *obj)
4282 {
4283
4284         cp->objectId = obj->objectId;
4285         cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
4286         cp->hdrChunk = obj->hdrChunk;
4287         cp->variantType = obj->variantType;
4288         cp->deleted = obj->deleted;
4289         cp->softDeleted = obj->softDeleted;
4290         cp->unlinked = obj->unlinked;
4291         cp->fake = obj->fake;
4292         cp->renameAllowed = obj->renameAllowed;
4293         cp->unlinkAllowed = obj->unlinkAllowed;
4294         cp->serial = obj->serial;
4295         cp->nDataChunks = obj->nDataChunks;
4296         
4297         if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
4298                 cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
4299         else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
4300                 cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
4301 }
4302
4303 static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp)
4304 {
4305
4306         yaffs_Object *parent;
4307         
4308         obj->objectId = cp->objectId;
4309         
4310         if(cp->parentId)
4311                 parent = yaffs_FindOrCreateObjectByNumber(
4312                                         obj->myDev,
4313                                         cp->parentId,
4314                                         YAFFS_OBJECT_TYPE_DIRECTORY);
4315         else
4316                 parent = NULL;
4317                 
4318         if(parent)
4319                 yaffs_AddObjectToDirectory(parent, obj);
4320
4321         obj->hdrChunk = cp->hdrChunk;
4322         obj->variantType = cp->variantType;
4323         obj->deleted = cp->deleted;
4324         obj->softDeleted = cp->softDeleted;
4325         obj->unlinked = cp->unlinked;
4326         obj->fake = cp->fake;
4327         obj->renameAllowed = cp->renameAllowed;
4328         obj->unlinkAllowed = cp->unlinkAllowed;
4329         obj->serial = cp->serial;
4330         obj->nDataChunks = cp->nDataChunks;
4331         
4332         if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
4333                 obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
4334         else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
4335                 obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
4336
4337         if(obj->hdrChunk > 0)
4338                 obj->lazyLoaded = 1;
4339 }
4340
4341
4342
4343 static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn,
4344                                         __u32 level, int chunkOffset)
4345 {
4346         int i;
4347         yaffs_Device *dev = in->myDev;
4348         int ok = 1;
4349         int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
4350
4351         if(tnodeSize < sizeof(yaffs_Tnode))
4352                 tnodeSize = sizeof(yaffs_Tnode);
4353         
4354
4355         if (tn) {
4356                 if (level > 0) {
4357
4358                         for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){
4359                                 if (tn->internal[i]) {
4360                                         ok = yaffs_CheckpointTnodeWorker(in,
4361                                                         tn->internal[i],
4362                                                         level - 1,
4363                                                         (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
4364                                 }
4365                         }
4366                 } else if (level == 0) {
4367                         __u32 baseOffset = chunkOffset <<  YAFFS_TNODES_LEVEL0_BITS;
4368                         /* printf("write tnode at %d\n",baseOffset); */
4369                         ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset));
4370                         if(ok)
4371                                 ok = (yaffs_CheckpointWrite(dev,tn,tnodeSize) == tnodeSize);
4372                 }
4373         }
4374
4375         return ok;
4376
4377 }
4378
4379 static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
4380 {
4381         __u32 endMarker = ~0;
4382         int ok = 1;
4383         
4384         if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){
4385                 ok = yaffs_CheckpointTnodeWorker(obj,
4386                                             obj->variant.fileVariant.top,
4387                                             obj->variant.fileVariant.topLevel,
4388                                             0);
4389                 if(ok)
4390                         ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) == 
4391                                 sizeof(endMarker));
4392         }
4393         
4394         return ok ? 1 : 0;
4395 }
4396
4397 static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
4398 {
4399         __u32 baseChunk;
4400         int ok = 1;
4401         yaffs_Device *dev = obj->myDev;
4402         yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
4403         yaffs_Tnode *tn;
4404         int nread = 0;
4405         int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
4406
4407         if(tnodeSize < sizeof(yaffs_Tnode))
4408                 tnodeSize = sizeof(yaffs_Tnode);
4409
4410         ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk));
4411         
4412         while(ok && (~baseChunk)){
4413                 nread++;
4414                 /* Read level 0 tnode */
4415                 
4416                 
4417                 /* printf("read  tnode at %d\n",baseChunk); */
4418                 tn = yaffs_GetTnodeRaw(dev);
4419                 if(tn)
4420                         ok = (yaffs_CheckpointRead(dev,tn,tnodeSize) == tnodeSize);
4421                 else
4422                         ok = 0;
4423                         
4424                 if(tn && ok){
4425                         ok = yaffs_AddOrFindLevel0Tnode(dev,
4426                                                         fileStructPtr,
4427                                                         baseChunk,
4428                                                         tn) ? 1 : 0;
4429                                                         
4430                 }
4431                         
4432                 if(ok)
4433                         ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk));
4434                 
4435         }
4436
4437         T(YAFFS_TRACE_CHECKPOINT,(
4438                 TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
4439                 nread,baseChunk,ok));
4440
4441         return ok ? 1 : 0;      
4442 }
4443  
4444
4445 static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
4446 {
4447         yaffs_Object *obj;
4448         yaffs_CheckpointObject cp;
4449         int i;
4450         int ok = 1;
4451         struct ylist_head *lh;
4452
4453         
4454         /* Iterate through the objects in each hash entry,
4455          * dumping them to the checkpointing stream.
4456          */
4457          
4458          for(i = 0; ok &&  i <  YAFFS_NOBJECT_BUCKETS; i++){
4459                 ylist_for_each(lh, &dev->objectBucket[i].list) {
4460                         if (lh) {
4461                                 obj = ylist_entry(lh, yaffs_Object, hashLink);
4462                                 if (!obj->deferedFree) {
4463                                         yaffs_ObjectToCheckpointObject(&cp,obj);
4464                                         cp.structType = sizeof(cp);
4465
4466                                         T(YAFFS_TRACE_CHECKPOINT,(
4467                                                 TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
4468                                                 cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk,(unsigned) obj));
4469
4470                                         ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
4471                                         
4472                                         if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){
4473                                                 ok = yaffs_WriteCheckpointTnodes(obj);
4474                                         }
4475                                 }
4476                         }
4477                 }
4478          }
4479          
4480          /* Dump end of list */
4481         memset(&cp,0xFF,sizeof(yaffs_CheckpointObject));
4482         cp.structType = sizeof(cp);
4483         
4484         if(ok)
4485                 ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
4486                 
4487         return ok ? 1 : 0;
4488 }
4489
4490 static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
4491 {
4492         yaffs_Object *obj;
4493         yaffs_CheckpointObject cp;
4494         int ok = 1;
4495         int done = 0;
4496         yaffs_Object *hardList = NULL;
4497         
4498         while(ok && !done) {
4499                 ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
4500                 if(cp.structType != sizeof(cp)) {
4501                         T(YAFFS_TRACE_CHECKPOINT,(TSTR("struct size %d instead of %d ok %d"TENDSTR),
4502                                 cp.structType,sizeof(cp),ok));
4503                         ok = 0;
4504                 }
4505                         
4506                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
4507                         cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk));
4508
4509                 if(ok && cp.objectId == ~0)
4510                         done = 1;
4511                 else if(ok){
4512                         obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType);
4513                         if(obj) {
4514                                 yaffs_CheckpointObjectToObject(obj,&cp);
4515                                 if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
4516                                         ok = yaffs_ReadCheckpointTnodes(obj);
4517                                 } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
4518                                         obj->hardLinks.next =
4519                                                     (struct ylist_head *)
4520                                                     hardList;
4521                                         hardList = obj;
4522                                 }
4523                            
4524                         }
4525                 }
4526         }
4527         
4528         if(ok)
4529                 yaffs_HardlinkFixup(dev,hardList);
4530         
4531         return ok ? 1 : 0;
4532 }
4533
4534 static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
4535 {
4536         __u32 checkpointSum;
4537         int ok;
4538         
4539         yaffs_GetCheckpointSum(dev,&checkpointSum);
4540         
4541         ok = (yaffs_CheckpointWrite(dev,&checkpointSum,sizeof(checkpointSum)) == sizeof(checkpointSum));
4542         
4543         if(!ok)
4544                 return 0;
4545         
4546         return 1;
4547 }
4548
4549 static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
4550 {
4551         __u32 checkpointSum0;
4552         __u32 checkpointSum1;
4553         int ok;
4554         
4555         yaffs_GetCheckpointSum(dev,&checkpointSum0);
4556         
4557         ok = (yaffs_CheckpointRead(dev,&checkpointSum1,sizeof(checkpointSum1)) == sizeof(checkpointSum1));
4558         
4559         if(!ok)
4560                 return 0;
4561                 
4562         if(checkpointSum0 != checkpointSum1)
4563                 return 0;
4564         
4565         return 1;
4566 }
4567
4568
4569 static int yaffs_WriteCheckpointData(yaffs_Device *dev)
4570 {
4571
4572         int ok = 1;
4573         
4574         if(dev->skipCheckpointWrite || !dev->isYaffs2){
4575                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint write" TENDSTR)));
4576                 ok = 0;
4577         }
4578                 
4579         if(ok)
4580                 ok = yaffs_CheckpointOpen(dev,1);
4581         
4582         if(ok){
4583                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR)));
4584                 ok = yaffs_WriteCheckpointValidityMarker(dev,1);
4585         }
4586         if(ok){
4587                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint device" TENDSTR)));
4588                 ok = yaffs_WriteCheckpointDevice(dev);
4589         }
4590         if(ok){
4591                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR)));
4592                 ok = yaffs_WriteCheckpointObjects(dev);
4593         }
4594         if(ok){
4595                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR)));
4596                 ok = yaffs_WriteCheckpointValidityMarker(dev,0);
4597         }
4598         
4599         if(ok){
4600                 ok = yaffs_WriteCheckpointSum(dev);
4601         }
4602         
4603         
4604         if(!yaffs_CheckpointClose(dev))
4605                  ok = 0;
4606                  
4607         if(ok)
4608                 dev->isCheckpointed = 1;
4609          else 
4610                 dev->isCheckpointed = 0;
4611
4612         return dev->isCheckpointed;
4613 }
4614
4615 static int yaffs_ReadCheckpointData(yaffs_Device *dev)
4616 {
4617         int ok = 1;
4618         
4619         if(dev->skipCheckpointRead || !dev->isYaffs2){
4620                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint read" TENDSTR)));
4621                 ok = 0;
4622         }
4623         
4624         if(ok)
4625                 ok = yaffs_CheckpointOpen(dev,0); /* open for read */
4626         
4627         if(ok){
4628                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR)));   
4629                 ok = yaffs_ReadCheckpointValidityMarker(dev,1);
4630         }
4631         if(ok){
4632                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint device" TENDSTR)));
4633                 ok = yaffs_ReadCheckpointDevice(dev);
4634         }
4635         if(ok){
4636                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR)));    
4637                 ok = yaffs_ReadCheckpointObjects(dev);
4638         }
4639         if(ok){
4640                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR)));
4641                 ok = yaffs_ReadCheckpointValidityMarker(dev,0);
4642         }
4643         
4644         if(ok){
4645                 ok = yaffs_ReadCheckpointSum(dev);
4646                 T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint checksum %d" TENDSTR),ok));
4647         }
4648
4649         if(!yaffs_CheckpointClose(dev))
4650                 ok = 0;
4651
4652         if(ok)
4653                 dev->isCheckpointed = 1;
4654          else 
4655                 dev->isCheckpointed = 0;
4656
4657         return ok ? 1 : 0;
4658
4659 }
4660
4661 static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
4662 {
4663         if(dev->isCheckpointed || 
4664            dev->blocksInCheckpoint > 0){
4665                 dev->isCheckpointed = 0;
4666                 yaffs_CheckpointInvalidateStream(dev);
4667                 if(dev->superBlock && dev->markSuperBlockDirty)
4668                         dev->markSuperBlockDirty(dev->superBlock);
4669         }
4670 }
4671
4672
4673 int yaffs_CheckpointSave(yaffs_Device *dev)
4674 {
4675
4676         T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
4677
4678         yaffs_VerifyObjects(dev);
4679         yaffs_VerifyBlocks(dev);
4680         yaffs_VerifyFreeChunks(dev);
4681
4682         if(!dev->isCheckpointed) {
4683                 yaffs_InvalidateCheckpoint(dev);
4684                 yaffs_WriteCheckpointData(dev);
4685         }
4686         
4687         T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
4688
4689         return dev->isCheckpointed;
4690 }
4691
4692 int yaffs_CheckpointRestore(yaffs_Device *dev)
4693 {
4694         int retval;
4695         T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
4696                 
4697         retval = yaffs_ReadCheckpointData(dev);
4698
4699         if(dev->isCheckpointed){
4700                 yaffs_VerifyObjects(dev);
4701                 yaffs_VerifyBlocks(dev);
4702                 yaffs_VerifyFreeChunks(dev);
4703         }
4704
4705         T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
4706         
4707         return retval;
4708 }
4709
4710 /*--------------------- File read/write ------------------------
4711  * Read and write have very similar structures.
4712  * In general the read/write has three parts to it
4713  * An incomplete chunk to start with (if the read/write is not chunk-aligned)
4714  * Some complete chunks
4715  * An incomplete chunk to end off with
4716  *
4717  * Curve-balls: the first chunk might also be the last chunk.
4718  */
4719
4720 int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset,
4721                            int nBytes)
4722 {
4723
4724         int chunk;
4725         __u32 start;
4726         int nToCopy;
4727         int n = nBytes;
4728         int nDone = 0;
4729         yaffs_ChunkCache *cache;
4730
4731         yaffs_Device *dev;
4732
4733         dev = in->myDev;
4734
4735         while (n > 0) {
4736                 //chunk = offset / dev->nDataBytesPerChunk + 1;
4737                 //start = offset % dev->nDataBytesPerChunk;
4738                 yaffs_AddrToChunk(dev,offset,&chunk,&start);
4739                 chunk++;
4740
4741                 /* OK now check for the curveball where the start and end are in
4742                  * the same chunk.      
4743                  */
4744                 if ((start + n) < dev->nDataBytesPerChunk) {
4745                         nToCopy = n;
4746                 } else {
4747                         nToCopy = dev->nDataBytesPerChunk - start;
4748                 }
4749
4750                 cache = yaffs_FindChunkCache(in, chunk);
4751
4752                 /* If the chunk is already in the cache or it is less than a whole chunk
4753                  * or we're using inband tags then use the cache (if there is caching)
4754                  * else bypass the cache.
4755                  */
4756                 if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
4757                         if (dev->nShortOpCaches > 0) {
4758
4759                                 /* If we can't find the data in the cache, then load it up. */
4760
4761                                 if (!cache) {
4762                                         cache = yaffs_GrabChunkCache(in->myDev);
4763                                         cache->object = in;
4764                                         cache->chunkId = chunk;
4765                                         cache->dirty = 0;
4766                                         cache->locked = 0;
4767                                         yaffs_ReadChunkDataFromObject(in, chunk,
4768                                                                       cache->
4769                                                                       data);
4770                                         cache->nBytes = 0;
4771                                 }
4772
4773                                 yaffs_UseChunkCache(dev, cache, 0);
4774
4775                                 cache->locked = 1;
4776
4777 #ifdef CONFIG_YAFFS_WINCE
4778                                 yfsd_UnlockYAFFS(TRUE);
4779 #endif
4780                                 memcpy(buffer, &cache->data[start], nToCopy);
4781
4782 #ifdef CONFIG_YAFFS_WINCE
4783                                 yfsd_LockYAFFS(TRUE);
4784 #endif
4785                                 cache->locked = 0;
4786                         } else {
4787                                 /* Read into the local buffer then copy..*/
4788
4789                                 __u8 *localBuffer =
4790                                     yaffs_GetTempBuffer(dev, __LINE__);
4791                                 yaffs_ReadChunkDataFromObject(in, chunk,
4792                                                               localBuffer);
4793 #ifdef CONFIG_YAFFS_WINCE
4794                                 yfsd_UnlockYAFFS(TRUE);
4795 #endif
4796                                 memcpy(buffer, &localBuffer[start], nToCopy);
4797
4798 #ifdef CONFIG_YAFFS_WINCE
4799                                 yfsd_LockYAFFS(TRUE);
4800 #endif
4801                                 yaffs_ReleaseTempBuffer(dev, localBuffer,
4802                                                         __LINE__);
4803                         }
4804
4805                 } else {
4806 #ifdef CONFIG_YAFFS_WINCE
4807                         __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
4808
4809                         /* Under WinCE can't do direct transfer. Need to use a local buffer.
4810                          * This is because we otherwise screw up WinCE's memory mapper
4811                          */
4812                         yaffs_ReadChunkDataFromObject(in, chunk, localBuffer);
4813
4814 #ifdef CONFIG_YAFFS_WINCE
4815                         yfsd_UnlockYAFFS(TRUE);
4816 #endif
4817                         memcpy(buffer, localBuffer, dev->nDataBytesPerChunk);
4818
4819 #ifdef CONFIG_YAFFS_WINCE
4820                         yfsd_LockYAFFS(TRUE);
4821                         yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
4822 #endif
4823
4824 #else
4825                         /* A full chunk. Read directly into the supplied buffer. */
4826                         yaffs_ReadChunkDataFromObject(in, chunk, buffer);
4827 #endif
4828                 }
4829
4830                 n -= nToCopy;
4831                 offset += nToCopy;
4832                 buffer += nToCopy;
4833                 nDone += nToCopy;
4834
4835         }
4836
4837         return nDone;
4838 }
4839
4840 int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset,
4841                           int nBytes, int writeThrough)
4842 {
4843
4844         int chunk;
4845         __u32 start;
4846         int nToCopy;
4847         int n = nBytes;
4848         int nDone = 0;
4849         int nToWriteBack;
4850         int startOfWrite = offset;
4851         int chunkWritten = 0;
4852         int nBytesRead;
4853
4854         yaffs_Device *dev;
4855
4856         dev = in->myDev;
4857
4858         while (n > 0 && chunkWritten >= 0) {
4859                 //chunk = offset / dev->nDataBytesPerChunk + 1;
4860                 //start = offset % dev->nDataBytesPerChunk;
4861                 yaffs_AddrToChunk(dev,offset,&chunk,&start);
4862                 
4863                 if(chunk * dev->nDataBytesPerChunk + start != offset ||
4864                    start >= dev->nDataBytesPerChunk){
4865                    T(YAFFS_TRACE_ERROR,(TSTR("AddrToChunk of offset %d gives chunk %d start %d"TENDSTR),
4866                                         (int)offset, chunk,start));
4867                 }
4868                 chunk++;
4869
4870                 /* OK now check for the curveball where the start and end are in
4871                  * the same chunk.
4872                  */
4873
4874                 if ((start + n) < dev->nDataBytesPerChunk) {
4875                         nToCopy = n;
4876
4877                         /* Now folks, to calculate how many bytes to write back....
4878                          * If we're overwriting and not writing to then end of file then
4879                          * we need to write back as much as was there before.
4880                          */
4881
4882                         nBytesRead =
4883                             in->variant.fileVariant.fileSize -
4884                             ((chunk - 1) * dev->nDataBytesPerChunk);
4885
4886                         if (nBytesRead > dev->nDataBytesPerChunk) {
4887                                 nBytesRead = dev->nDataBytesPerChunk;
4888                         }
4889
4890                         nToWriteBack =
4891                             (nBytesRead >
4892                              ((int)start + n)) ? nBytesRead : (start + n);
4893
4894                 } else {
4895                         nToCopy = dev->nDataBytesPerChunk - start;
4896                         nToWriteBack = dev->nDataBytesPerChunk;
4897                 }
4898
4899                 if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
4900                         /* An incomplete start or end chunk (or maybe both start and end chunk), 
4901                          * or we're using inband tags, so we want to use the cache buffers.
4902                          */
4903                         if (dev->nShortOpCaches > 0) {
4904                                 yaffs_ChunkCache *cache;
4905                                 /* If we can't find the data in the cache, then load the cache */
4906                                 cache = yaffs_FindChunkCache(in, chunk);
4907                                 
4908                                 if (!cache
4909                                     && yaffs_CheckSpaceForAllocation(in->
4910                                                                      myDev)) {
4911                                         cache = yaffs_GrabChunkCache(in->myDev);
4912                                         cache->object = in;
4913                                         cache->chunkId = chunk;
4914                                         cache->dirty = 0;
4915                                         cache->locked = 0;
4916                                         yaffs_ReadChunkDataFromObject(in, chunk,
4917                                                                       cache->
4918                                                                       data);
4919                                 }
4920                                 else if(cache && 
4921                                         !cache->dirty &&
4922                                         !yaffs_CheckSpaceForAllocation(in->myDev)){
4923                                         /* Drop the cache if it was a read cache item and
4924                                          * no space check has been made for it.
4925                                          */ 
4926                                          cache = NULL;
4927                                 }
4928
4929                                 if (cache) {
4930                                         yaffs_UseChunkCache(dev, cache, 1);
4931                                         cache->locked = 1;
4932 #ifdef CONFIG_YAFFS_WINCE
4933                                         yfsd_UnlockYAFFS(TRUE);
4934 #endif
4935
4936                                         memcpy(&cache->data[start], buffer,
4937                                                nToCopy);
4938
4939 #ifdef CONFIG_YAFFS_WINCE
4940                                         yfsd_LockYAFFS(TRUE);
4941 #endif
4942                                         cache->locked = 0;
4943                                         cache->nBytes = nToWriteBack;
4944
4945                                         if (writeThrough) {
4946                                                 chunkWritten =
4947                                                     yaffs_WriteChunkDataToObject
4948                                                     (cache->object,
4949                                                      cache->chunkId,
4950                                                      cache->data, cache->nBytes,
4951                                                      1);
4952                                                 cache->dirty = 0;
4953                                         }
4954
4955                                 } else {
4956                                         chunkWritten = -1;      /* fail the write */
4957                                 }
4958                         } else {
4959                                 /* An incomplete start or end chunk (or maybe both start and end chunk)
4960                                  * Read into the local buffer then copy, then copy over and write back.
4961                                  */
4962
4963                                 __u8 *localBuffer =
4964                                     yaffs_GetTempBuffer(dev, __LINE__);
4965
4966                                 yaffs_ReadChunkDataFromObject(in, chunk,
4967                                                               localBuffer);
4968
4969 #ifdef CONFIG_YAFFS_WINCE
4970                                 yfsd_UnlockYAFFS(TRUE);
4971 #endif
4972
4973                                 memcpy(&localBuffer[start], buffer, nToCopy);
4974
4975 #ifdef CONFIG_YAFFS_WINCE
4976                                 yfsd_LockYAFFS(TRUE);
4977 #endif
4978                                 chunkWritten =
4979                                     yaffs_WriteChunkDataToObject(in, chunk,
4980                                                                  localBuffer,
4981                                                                  nToWriteBack,
4982                                                                  0);
4983
4984                                 yaffs_ReleaseTempBuffer(dev, localBuffer,
4985                                                         __LINE__);
4986
4987                         }
4988
4989                 } else {
4990                         /* A full chunk. Write directly from the supplied buffer. */
4991                         
4992 #ifdef CONFIG_YAFFS_WINCE
4993                         /* Under WinCE can't do direct transfer. Need to use a local buffer.
4994                          * This is because we otherwise screw up WinCE's memory mapper
4995                          */
4996                         __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
4997 #ifdef CONFIG_YAFFS_WINCE
4998                         yfsd_UnlockYAFFS(TRUE);
4999 #endif
5000                         memcpy(localBuffer, buffer, dev->nDataBytesPerChunk);
5001 #ifdef CONFIG_YAFFS_WINCE
5002                         yfsd_LockYAFFS(TRUE);
5003 #endif
5004                         chunkWritten =
5005                             yaffs_WriteChunkDataToObject(in, chunk, localBuffer,
5006                                                          dev->nDataBytesPerChunk,
5007                                                          0);
5008                         yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
5009 #else
5010
5011                         chunkWritten =
5012                             yaffs_WriteChunkDataToObject(in, chunk, buffer,
5013                                                          dev->nDataBytesPerChunk,
5014                                                          0);
5015 #endif
5016                         /* Since we've overwritten the cached data, we better invalidate it. */
5017                         yaffs_InvalidateChunkCache(in, chunk);
5018                 }
5019
5020                 if (chunkWritten >= 0) {
5021                         n -= nToCopy;
5022                         offset += nToCopy;
5023                         buffer += nToCopy;
5024                         nDone += nToCopy;
5025                 }
5026
5027         }
5028
5029         /* Update file object */
5030
5031         if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) {
5032                 in->variant.fileVariant.fileSize = (startOfWrite + nDone);
5033         }
5034
5035         in->dirty = 1;
5036
5037         return nDone;
5038 }
5039
5040
5041 /* ---------------------- File resizing stuff ------------------ */
5042
5043 static void yaffs_PruneResizedChunks(yaffs_Object * in, int newSize)
5044 {
5045
5046         yaffs_Device *dev = in->myDev;
5047         int oldFileSize = in->variant.fileVariant.fileSize;
5048
5049         int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
5050
5051         int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
5052             dev->nDataBytesPerChunk;
5053         int i;
5054         int chunkId;
5055
5056         /* Delete backwards so that we don't end up with holes if
5057          * power is lost part-way through the operation.
5058          */
5059         for (i = lastDel; i >= startDel; i--) {
5060                 /* NB this could be optimised somewhat,
5061                  * eg. could retrieve the tags and write them without
5062                  * using yaffs_DeleteChunk
5063                  */
5064
5065                 chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
5066                 if (chunkId > 0) {
5067                         if (chunkId <
5068                             (dev->internalStartBlock * dev->nChunksPerBlock)
5069                             || chunkId >=
5070                             ((dev->internalEndBlock +
5071                               1) * dev->nChunksPerBlock)) {
5072                                 T(YAFFS_TRACE_ALWAYS,
5073                                   (TSTR("Found daft chunkId %d for %d" TENDSTR),
5074                                    chunkId, i));
5075                         } else {
5076                                 in->nDataChunks--;
5077                                 yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
5078                         }
5079                 }
5080         }
5081
5082 }
5083
5084 int yaffs_ResizeFile(yaffs_Object * in, loff_t newSize)
5085 {
5086
5087         int oldFileSize = in->variant.fileVariant.fileSize;
5088         __u32 newSizeOfPartialChunk;
5089         int newFullChunks;
5090         
5091         yaffs_Device *dev = in->myDev;
5092
5093         yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
5094
5095         yaffs_FlushFilesChunkCache(in);
5096         yaffs_InvalidateWholeChunkCache(in);
5097
5098         yaffs_CheckGarbageCollection(dev);
5099
5100         if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
5101                 return YAFFS_FAIL;
5102         }
5103
5104         if (newSize == oldFileSize) {
5105                 return YAFFS_OK;
5106         }
5107
5108         if (newSize < oldFileSize) {
5109
5110                 yaffs_PruneResizedChunks(in, newSize);
5111
5112                 if (newSizeOfPartialChunk != 0) {
5113                         int lastChunk = 1 + newFullChunks;
5114                         
5115                         __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
5116
5117                         /* Got to read and rewrite the last chunk with its new size and zero pad */
5118                         yaffs_ReadChunkDataFromObject(in, lastChunk,
5119                                                       localBuffer);
5120
5121                         memset(localBuffer + newSizeOfPartialChunk, 0,
5122                                dev->nDataBytesPerChunk - newSizeOfPartialChunk);
5123
5124                         yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
5125                                                      newSizeOfPartialChunk, 1);
5126
5127                         yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
5128                 }
5129
5130                 in->variant.fileVariant.fileSize = newSize;
5131
5132                 yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
5133         } else {
5134                 /* newsSize > oldFileSize */
5135                 in->variant.fileVariant.fileSize = newSize;
5136         }
5137
5138                 
5139         
5140         /* Write a new object header.
5141          * show we've shrunk the file, if need be
5142          * Do this only if the file is not in the deleted directories.
5143          */
5144         if (in->parent &&
5145             in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
5146             in->parent->objectId != YAFFS_OBJECTID_DELETED) {
5147                 yaffs_UpdateObjectHeader(in, NULL, 0,
5148                                          (newSize < oldFileSize) ? 1 : 0, 0);
5149         }
5150
5151         return YAFFS_OK;
5152 }
5153
5154 loff_t yaffs_GetFileSize(yaffs_Object * obj)
5155 {
5156         obj = yaffs_GetEquivalentObject(obj);
5157
5158         switch (obj->variantType) {
5159         case YAFFS_OBJECT_TYPE_FILE:
5160                 return obj->variant.fileVariant.fileSize;
5161         case YAFFS_OBJECT_TYPE_SYMLINK:
5162                 return yaffs_strlen(obj->variant.symLinkVariant.alias);
5163         default:
5164                 return 0;
5165         }
5166 }
5167
5168
5169
5170 int yaffs_FlushFile(yaffs_Object * in, int updateTime)
5171 {
5172         int retVal;
5173         if (in->dirty) {
5174                 yaffs_FlushFilesChunkCache(in);
5175                 if (updateTime) {
5176 #ifdef CONFIG_YAFFS_WINCE
5177                         yfsd_WinFileTimeNow(in->win_mtime);
5178 #else
5179
5180                         in->yst_mtime = Y_CURRENT_TIME;
5181
5182 #endif
5183                 }
5184
5185                 retVal =
5186                     (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
5187                      0) ? YAFFS_OK : YAFFS_FAIL;
5188         } else {
5189                 retVal = YAFFS_OK;
5190         }
5191
5192         return retVal;
5193
5194 }
5195
5196 static int yaffs_DoGenericObjectDeletion(yaffs_Object * in)
5197 {
5198
5199         /* First off, invalidate the file's data in the cache, without flushing. */
5200         yaffs_InvalidateWholeChunkCache(in);
5201
5202         if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
5203                 /* Move to the unlinked directory so we have a record that it was deleted. */
5204                 yaffs_ChangeObjectName(in, in->myDev->deletedDir,_Y("deleted"), 0, 0);
5205
5206         }
5207
5208         yaffs_RemoveObjectFromDirectory(in);
5209         yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
5210         in->hdrChunk = 0;
5211
5212         yaffs_FreeObject(in);
5213         return YAFFS_OK;
5214
5215 }
5216
5217 /* yaffs_DeleteFile deletes the whole file data
5218  * and the inode associated with the file.
5219  * It does not delete the links associated with the file.
5220  */
5221  
5222 static int yaffs_UnlinkFile(yaffs_Object * in)
5223 {
5224
5225         int retVal;
5226         int immediateDeletion = 0;
5227
5228 #ifdef __KERNEL__
5229         if (!in->myInode) {
5230                 immediateDeletion = 1;
5231         }
5232 #else
5233         if (in->inUse <= 0) {
5234                 immediateDeletion = 1;
5235         }
5236 #endif
5237
5238         if (immediateDeletion) {
5239                 retVal =
5240                     yaffs_ChangeObjectName(in, in->myDev->deletedDir,
5241                                            _Y("deleted"), 0, 0);
5242                 T(YAFFS_TRACE_TRACING,
5243                   (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
5244                    in->objectId));
5245                 in->deleted = 1;
5246                 in->myDev->nDeletedFiles++;
5247                 if (1 || in->myDev->isYaffs2) {
5248                         yaffs_ResizeFile(in, 0);
5249                 }
5250                 yaffs_SoftDeleteFile(in);
5251         } else {
5252                 retVal =
5253                     yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
5254                                            _Y("unlinked"), 0, 0);
5255         }
5256
5257
5258         return retVal;
5259 }
5260
5261 int yaffs_DeleteFile(yaffs_Object * in)
5262 {
5263         int retVal = YAFFS_OK;
5264         int deleted = in->deleted;
5265         
5266         yaffs_ResizeFile(in,0);
5267
5268         if (in->nDataChunks > 0) {
5269                 /* Use soft deletion if there is data in the file.
5270                  * That won't be the case if it has been resized to zero.
5271                  */
5272                 if (!in->unlinked) {
5273                         retVal = yaffs_UnlinkFile(in);
5274                 }
5275                 if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
5276                         in->deleted = deleted = 1;
5277                         in->myDev->nDeletedFiles++;
5278                         yaffs_SoftDeleteFile(in);
5279                 }
5280                 return deleted ? YAFFS_OK : YAFFS_FAIL;
5281         } else {
5282                 /* The file has no data chunks so we toss it immediately */
5283                 yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
5284                 in->variant.fileVariant.top = NULL;
5285                 yaffs_DoGenericObjectDeletion(in);
5286
5287                 return YAFFS_OK;
5288         }
5289 }
5290
5291 static int yaffs_DeleteDirectory(yaffs_Object * in)
5292 {
5293         /* First check that the directory is empty. */
5294         if (ylist_empty(&in->variant.directoryVariant.children)) {
5295                 return yaffs_DoGenericObjectDeletion(in);
5296         }
5297
5298         return YAFFS_FAIL;
5299
5300 }
5301
5302 static int yaffs_DeleteSymLink(yaffs_Object * in)
5303 {
5304         YFREE(in->variant.symLinkVariant.alias);
5305
5306         return yaffs_DoGenericObjectDeletion(in);
5307 }
5308
5309 static int yaffs_DeleteHardLink(yaffs_Object * in)
5310 {
5311         /* remove this hardlink from the list assocaited with the equivalent
5312          * object
5313          */
5314         ylist_del_init(&in->hardLinks);
5315         return yaffs_DoGenericObjectDeletion(in);
5316 }
5317
5318 static void yaffs_DestroyObject(yaffs_Object * obj)
5319 {
5320         switch (obj->variantType) {
5321         case YAFFS_OBJECT_TYPE_FILE:
5322                 yaffs_DeleteFile(obj);
5323                 break;
5324         case YAFFS_OBJECT_TYPE_DIRECTORY:
5325                 yaffs_DeleteDirectory(obj);
5326                 break;
5327         case YAFFS_OBJECT_TYPE_SYMLINK:
5328                 yaffs_DeleteSymLink(obj);
5329                 break;
5330         case YAFFS_OBJECT_TYPE_HARDLINK:
5331                 yaffs_DeleteHardLink(obj);
5332                 break;
5333         case YAFFS_OBJECT_TYPE_SPECIAL:
5334                 yaffs_DoGenericObjectDeletion(obj);
5335                 break;
5336         case YAFFS_OBJECT_TYPE_UNKNOWN:
5337                 break;          /* should not happen. */
5338         }
5339 }
5340
5341 static int yaffs_UnlinkWorker(yaffs_Object * obj)
5342 {
5343
5344         if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
5345                 return yaffs_DeleteHardLink(obj);
5346         } else if (!ylist_empty(&obj->hardLinks)) {
5347                 /* Curve ball: We're unlinking an object that has a hardlink.
5348                  *
5349                  * This problem arises because we are not strictly following
5350                  * The Linux link/inode model.
5351                  *
5352                  * We can't really delete the object.
5353                  * Instead, we do the following:
5354                  * - Select a hardlink.
5355                  * - Unhook it from the hard links
5356                  * - Unhook it from its parent directory (so that the rename can work)
5357                  * - Rename the object to the hardlink's name.
5358                  * - Delete the hardlink
5359                  */
5360
5361                 yaffs_Object *hl;
5362                 int retVal;
5363                 YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
5364
5365                 hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
5366
5367                 ylist_del_init(&hl->hardLinks);
5368                 ylist_del_init(&hl->siblings);
5369
5370                 yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
5371
5372                 retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
5373
5374                 if (retVal == YAFFS_OK) {
5375                         retVal = yaffs_DoGenericObjectDeletion(hl);
5376                 }
5377                 return retVal;
5378
5379         } else {
5380                 switch (obj->variantType) {
5381                 case YAFFS_OBJECT_TYPE_FILE:
5382                         return yaffs_UnlinkFile(obj);
5383                         break;
5384                 case YAFFS_OBJECT_TYPE_DIRECTORY:
5385                         return yaffs_DeleteDirectory(obj);
5386                         break;
5387                 case YAFFS_OBJECT_TYPE_SYMLINK:
5388                         return yaffs_DeleteSymLink(obj);
5389                         break;
5390                 case YAFFS_OBJECT_TYPE_SPECIAL:
5391                         return yaffs_DoGenericObjectDeletion(obj);
5392                         break;
5393                 case YAFFS_OBJECT_TYPE_HARDLINK:
5394                 case YAFFS_OBJECT_TYPE_UNKNOWN:
5395                 default:
5396                         return YAFFS_FAIL;
5397                 }
5398         }
5399 }
5400
5401
5402 static int yaffs_UnlinkObject( yaffs_Object *obj)
5403 {
5404
5405         if (obj && obj->unlinkAllowed) {
5406                 return yaffs_UnlinkWorker(obj);
5407         }
5408
5409         return YAFFS_FAIL;
5410
5411 }
5412 int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name)
5413 {
5414         yaffs_Object *obj;
5415
5416         obj = yaffs_FindObjectByName(dir, name);
5417         return yaffs_UnlinkObject(obj);
5418 }
5419
5420 /*----------------------- Initialisation Scanning ---------------------- */
5421
5422 static void yaffs_HandleShadowedObject(yaffs_Device * dev, int objId,
5423                                        int backwardScanning)
5424 {
5425         yaffs_Object *obj;
5426
5427         if (!backwardScanning) {
5428                 /* Handle YAFFS1 forward scanning case
5429                  * For YAFFS1 we always do the deletion
5430                  */
5431
5432         } else {
5433                 /* Handle YAFFS2 case (backward scanning)
5434                  * If the shadowed object exists then ignore.
5435                  */
5436                 if (yaffs_FindObjectByNumber(dev, objId)) {
5437                         return;
5438                 }
5439         }
5440
5441         /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
5442          * We put it in unlinked dir to be cleaned up after the scanning
5443          */
5444         obj =
5445             yaffs_FindOrCreateObjectByNumber(dev, objId,
5446                                              YAFFS_OBJECT_TYPE_FILE);
5447         yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
5448         obj->variant.fileVariant.shrinkSize = 0;
5449         obj->valid = 1;         /* So that we don't read any other info for this file */
5450
5451 }
5452
5453 typedef struct {
5454         int seq;
5455         int block;
5456 } yaffs_BlockIndex;
5457
5458
5459 static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
5460 {
5461         yaffs_Object *hl;
5462         yaffs_Object *in;
5463         
5464         while (hardList) {
5465                 hl = hardList;
5466                 hardList = (yaffs_Object *) (hardList->hardLinks.next);
5467
5468                 in = yaffs_FindObjectByNumber(dev,
5469                                               hl->variant.hardLinkVariant.
5470                                               equivalentObjectId);
5471
5472                 if (in) {
5473                         /* Add the hardlink pointers */
5474                         hl->variant.hardLinkVariant.equivalentObject = in;
5475                         ylist_add(&hl->hardLinks, &in->hardLinks);
5476                 } else {
5477                         /* Todo Need to report/handle this better.
5478                          * Got a problem... hardlink to a non-existant object
5479                          */
5480                         hl->variant.hardLinkVariant.equivalentObject = NULL;
5481                         YINIT_LIST_HEAD(&hl->hardLinks);
5482
5483                 }
5484
5485         }
5486
5487 }
5488
5489
5490
5491
5492
5493 static int ybicmp(const void *a, const void *b){
5494     register int aseq = ((yaffs_BlockIndex *)a)->seq;
5495     register int bseq = ((yaffs_BlockIndex *)b)->seq;
5496     register int ablock = ((yaffs_BlockIndex *)a)->block;
5497     register int bblock = ((yaffs_BlockIndex *)b)->block;
5498     if( aseq == bseq )
5499         return ablock - bblock;
5500     else
5501         return aseq - bseq;
5502
5503 }
5504
5505
5506 struct yaffs_ShadowFixerStruct {
5507         int objectId;
5508         int shadowedId;
5509         struct yaffs_ShadowFixerStruct *next;
5510 };
5511
5512 static int yaffs_Scan(yaffs_Device * dev)
5513 {
5514         yaffs_ExtendedTags tags;
5515         int blk;
5516         int blockIterator;
5517         int startIterator;
5518         int endIterator;
5519         int result;
5520
5521         int chunk;
5522         int c;
5523         int deleted;
5524         yaffs_BlockState state;
5525         yaffs_Object *hardList = NULL;
5526         yaffs_BlockInfo *bi;
5527         __u32 sequenceNumber;
5528         yaffs_ObjectHeader *oh;
5529         yaffs_Object *in;
5530         yaffs_Object *parent;
5531         
5532         int alloc_failed = 0;
5533         
5534         struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
5535         
5536
5537         __u8 *chunkData;
5538
5539         
5540         
5541         T(YAFFS_TRACE_SCAN,
5542           (TSTR("yaffs_Scan starts  intstartblk %d intendblk %d..." TENDSTR),
5543            dev->internalStartBlock, dev->internalEndBlock));
5544
5545         chunkData = yaffs_GetTempBuffer(dev, __LINE__);
5546
5547         dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
5548
5549         /* Scan all the blocks to determine their state */
5550         for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
5551                 bi = yaffs_GetBlockInfo(dev, blk);
5552                 yaffs_ClearChunkBits(dev, blk);
5553                 bi->pagesInUse = 0;
5554                 bi->softDeletions = 0;
5555
5556                 yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
5557
5558                 bi->blockState = state;
5559                 bi->sequenceNumber = sequenceNumber;
5560
5561                 T(YAFFS_TRACE_SCAN_DEBUG,
5562                   (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
5563                    state, sequenceNumber));
5564
5565                 if (state == YAFFS_BLOCK_STATE_DEAD) {
5566                         T(YAFFS_TRACE_BAD_BLOCKS,
5567                           (TSTR("block %d is bad" TENDSTR), blk));
5568                 } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
5569                         T(YAFFS_TRACE_SCAN_DEBUG,
5570                           (TSTR("Block empty " TENDSTR)));
5571                         dev->nErasedBlocks++;
5572                         dev->nFreeChunks += dev->nChunksPerBlock;
5573                 } 
5574         }
5575
5576         startIterator = dev->internalStartBlock;
5577         endIterator = dev->internalEndBlock;
5578
5579         /* For each block.... */
5580         for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
5581              blockIterator++) {
5582                 
5583                 YYIELD();
5584
5585                 YYIELD();
5586                 
5587                 blk = blockIterator;
5588
5589                 bi = yaffs_GetBlockInfo(dev, blk);
5590                 state = bi->blockState;
5591
5592                 deleted = 0;
5593
5594                 /* For each chunk in each block that needs scanning....*/
5595                 for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
5596                      state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
5597                         /* Read the tags and decide what to do */
5598                         chunk = blk * dev->nChunksPerBlock + c;
5599
5600                         result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
5601                                                         &tags);
5602
5603                         /* Let's have a good look at this chunk... */
5604
5605                         if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
5606                                 /* YAFFS1 only...
5607                                  * A deleted chunk
5608                                  */
5609                                 deleted++;
5610                                 dev->nFreeChunks++;
5611                                 /*T((" %d %d deleted\n",blk,c)); */
5612                         } else if (!tags.chunkUsed) {
5613                                 /* An unassigned chunk in the block
5614                                  * This means that either the block is empty or 
5615                                  * this is the one being allocated from
5616                                  */
5617
5618                                 if (c == 0) {
5619                                         /* We're looking at the first chunk in the block so the block is unused */
5620                                         state = YAFFS_BLOCK_STATE_EMPTY;
5621                                         dev->nErasedBlocks++;
5622                                 } else {
5623                                         /* this is the block being allocated from */
5624                                         T(YAFFS_TRACE_SCAN,
5625                                           (TSTR
5626                                            (" Allocating from %d %d" TENDSTR),
5627                                            blk, c));
5628                                         state = YAFFS_BLOCK_STATE_ALLOCATING;
5629                                         dev->allocationBlock = blk;
5630                                         dev->allocationPage = c;
5631                                         dev->allocationBlockFinder = blk;       
5632                                         /* Set it to here to encourage the allocator to go forth from here. */
5633                                         
5634                                 }
5635
5636                                 dev->nFreeChunks += (dev->nChunksPerBlock - c);
5637                         } else if (tags.chunkId > 0) {
5638                                 /* chunkId > 0 so it is a data chunk... */
5639                                 unsigned int endpos;
5640
5641                                 yaffs_SetChunkBit(dev, blk, c);
5642                                 bi->pagesInUse++;
5643
5644                                 in = yaffs_FindOrCreateObjectByNumber(dev,
5645                                                                       tags.
5646                                                                       objectId,
5647                                                                       YAFFS_OBJECT_TYPE_FILE);
5648                                 /* PutChunkIntoFile checks for a clash (two data chunks with
5649                                  * the same chunkId).
5650                                  */
5651                                  
5652                                 if(!in)
5653                                         alloc_failed = 1;
5654
5655                                 if(in){
5656                                         if(!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,1))
5657                                                 alloc_failed = 1;
5658                                 }
5659                                 
5660                                 endpos =
5661                                     (tags.chunkId - 1) * dev->nDataBytesPerChunk +
5662                                     tags.byteCount;
5663                                 if (in && 
5664                                     in->variantType == YAFFS_OBJECT_TYPE_FILE
5665                                     && in->variant.fileVariant.scannedFileSize <
5666                                     endpos) {
5667                                         in->variant.fileVariant.
5668                                             scannedFileSize = endpos;
5669                                         if (!dev->useHeaderFileSize) {
5670                                                 in->variant.fileVariant.
5671                                                     fileSize =
5672                                                     in->variant.fileVariant.
5673                                                     scannedFileSize;
5674                                         }
5675
5676                                 }
5677                                 /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));   */
5678                         } else {
5679                                 /* chunkId == 0, so it is an ObjectHeader.
5680                                  * Thus, we read in the object header and make the object
5681                                  */
5682                                 yaffs_SetChunkBit(dev, blk, c);
5683                                 bi->pagesInUse++;
5684
5685                                 result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
5686                                                                 chunkData,
5687                                                                 NULL);
5688
5689                                 oh = (yaffs_ObjectHeader *) chunkData;
5690
5691                                 in = yaffs_FindObjectByNumber(dev,
5692                                                               tags.objectId);
5693                                 if (in && in->variantType != oh->type) {
5694                                         /* This should not happen, but somehow
5695                                          * Wev'e ended up with an objectId that has been reused but not yet 
5696                                          * deleted, and worse still it has changed type. Delete the old object.
5697                                          */
5698
5699                                         yaffs_DestroyObject(in);
5700
5701                                         in = 0;
5702                                 }
5703
5704                                 in = yaffs_FindOrCreateObjectByNumber(dev,
5705                                                                       tags.
5706                                                                       objectId,
5707                                                                       oh->type);
5708
5709                                 if(!in)
5710                                         alloc_failed = 1;
5711                                         
5712                                 if (in && oh->shadowsObject > 0) {
5713                                 
5714                                         struct yaffs_ShadowFixerStruct *fixer;
5715                                         fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
5716                                         if(fixer){
5717                                                 fixer-> next = shadowFixerList;
5718                                                 shadowFixerList = fixer;
5719                                                 fixer->objectId = tags.objectId;
5720                                                 fixer->shadowedId = oh->shadowsObject;
5721                                         }
5722                                         
5723                                 }
5724
5725                                 if (in && in->valid) {
5726                                         /* We have already filled this one. We have a duplicate and need to resolve it. */
5727
5728                                         unsigned existingSerial = in->serial;
5729                                         unsigned newSerial = tags.serialNumber;
5730
5731                                         if (((existingSerial + 1) & 3) == newSerial) {
5732                                                 /* Use new one - destroy the exisiting one */
5733                                                 yaffs_DeleteChunk(dev,
5734                                                                   in->hdrChunk,
5735                                                                   1, __LINE__);
5736                                                 in->valid = 0;
5737                                         } else {
5738                                                 /* Use existing - destroy this one. */
5739                                                 yaffs_DeleteChunk(dev, chunk, 1,
5740                                                                   __LINE__);
5741                                         }
5742                                 }
5743
5744                                 if (in && !in->valid &&
5745                                     (tags.objectId == YAFFS_OBJECTID_ROOT ||
5746                                      tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
5747                                         /* We only load some info, don't fiddle with directory structure */
5748                                         in->valid = 1;
5749                                         in->variantType = oh->type;
5750
5751                                         in->yst_mode = oh->yst_mode;
5752 #ifdef CONFIG_YAFFS_WINCE
5753                                         in->win_atime[0] = oh->win_atime[0];
5754                                         in->win_ctime[0] = oh->win_ctime[0];
5755                                         in->win_mtime[0] = oh->win_mtime[0];
5756                                         in->win_atime[1] = oh->win_atime[1];
5757                                         in->win_ctime[1] = oh->win_ctime[1];
5758                                         in->win_mtime[1] = oh->win_mtime[1];
5759 #else
5760                                         in->yst_uid = oh->yst_uid;
5761                                         in->yst_gid = oh->yst_gid;
5762                                         in->yst_atime = oh->yst_atime;
5763                                         in->yst_mtime = oh->yst_mtime;
5764                                         in->yst_ctime = oh->yst_ctime;
5765                                         in->yst_rdev = oh->yst_rdev;
5766 #endif
5767                                         in->hdrChunk = chunk;
5768                                         in->serial = tags.serialNumber;
5769
5770                                 } else if (in && !in->valid) {
5771                                         /* we need to load this info */
5772
5773                                         in->valid = 1;
5774                                         in->variantType = oh->type;
5775
5776                                         in->yst_mode = oh->yst_mode;
5777 #ifdef CONFIG_YAFFS_WINCE
5778                                         in->win_atime[0] = oh->win_atime[0];
5779                                         in->win_ctime[0] = oh->win_ctime[0];
5780                                         in->win_mtime[0] = oh->win_mtime[0];
5781                                         in->win_atime[1] = oh->win_atime[1];
5782                                         in->win_ctime[1] = oh->win_ctime[1];
5783                                         in->win_mtime[1] = oh->win_mtime[1];
5784 #else
5785                                         in->yst_uid = oh->yst_uid;
5786                                         in->yst_gid = oh->yst_gid;
5787                                         in->yst_atime = oh->yst_atime;
5788                                         in->yst_mtime = oh->yst_mtime;
5789                                         in->yst_ctime = oh->yst_ctime;
5790                                         in->yst_rdev = oh->yst_rdev;
5791 #endif
5792                                         in->hdrChunk = chunk;
5793                                         in->serial = tags.serialNumber;
5794
5795                                         yaffs_SetObjectName(in, oh->name);
5796                                         in->dirty = 0;
5797
5798                                         /* directory stuff...
5799                                          * hook up to parent
5800                                          */
5801
5802                                         parent =
5803                                             yaffs_FindOrCreateObjectByNumber
5804                                             (dev, oh->parentObjectId,
5805                                              YAFFS_OBJECT_TYPE_DIRECTORY);
5806                                         if (parent->variantType ==
5807                                             YAFFS_OBJECT_TYPE_UNKNOWN) {
5808                                                 /* Set up as a directory */
5809                                                 parent->variantType =
5810                                                     YAFFS_OBJECT_TYPE_DIRECTORY;
5811                                                 YINIT_LIST_HEAD(&parent->variant.
5812                                                                directoryVariant.
5813                                                                children);
5814                                         } else if (parent->variantType !=
5815                                                    YAFFS_OBJECT_TYPE_DIRECTORY)
5816                                         {
5817                                                 /* Hoosterman, another problem....
5818                                                  * We're trying to use a non-directory as a directory
5819                                                  */
5820
5821                                                 T(YAFFS_TRACE_ERROR,
5822                                                   (TSTR
5823                                                    ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
5824                                                     TENDSTR)));
5825                                                 parent = dev->lostNFoundDir;
5826                                         }
5827
5828                                         yaffs_AddObjectToDirectory(parent, in);
5829
5830                                         if (0 && (parent == dev->deletedDir ||
5831                                                   parent == dev->unlinkedDir)) {
5832                                                 in->deleted = 1;        /* If it is unlinked at start up then it wants deleting */
5833                                                 dev->nDeletedFiles++;
5834                                         }
5835                                         /* Note re hardlinks.
5836                                          * Since we might scan a hardlink before its equivalent object is scanned
5837                                          * we put them all in a list.
5838                                          * After scanning is complete, we should have all the objects, so we run through this
5839                                          * list and fix up all the chains.              
5840                                          */
5841
5842                                         switch (in->variantType) {
5843                                         case YAFFS_OBJECT_TYPE_UNKNOWN: 
5844                                                 /* Todo got a problem */
5845                                                 break;
5846                                         case YAFFS_OBJECT_TYPE_FILE:
5847                                                 if (dev->useHeaderFileSize)
5848
5849                                                         in->variant.fileVariant.
5850                                                             fileSize =
5851                                                             oh->fileSize;
5852
5853                                                 break;
5854                                         case YAFFS_OBJECT_TYPE_HARDLINK:
5855                                                 in->variant.hardLinkVariant.
5856                                                     equivalentObjectId =
5857                                                     oh->equivalentObjectId;
5858                                                 in->hardLinks.next =
5859                                                     (struct ylist_head *)
5860                                                     hardList;
5861                                                 hardList = in;
5862                                                 break;
5863                                         case YAFFS_OBJECT_TYPE_DIRECTORY:
5864                                                 /* Do nothing */
5865                                                 break;
5866                                         case YAFFS_OBJECT_TYPE_SPECIAL:
5867                                                 /* Do nothing */
5868                                                 break;
5869                                         case YAFFS_OBJECT_TYPE_SYMLINK: 
5870                                                 in->variant.symLinkVariant.alias =
5871                                                     yaffs_CloneString(oh->alias);
5872                                                 if(!in->variant.symLinkVariant.alias)
5873                                                         alloc_failed = 1;
5874                                                 break;
5875                                         }
5876
5877 /*
5878                                         if (parent == dev->deletedDir) {
5879                                                 yaffs_DestroyObject(in);
5880                                                 bi->hasShrinkHeader = 1;
5881                                         }
5882 */
5883                                 }
5884                         }
5885                 }
5886
5887                 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
5888                         /* If we got this far while scanning, then the block is fully allocated.*/
5889                         state = YAFFS_BLOCK_STATE_FULL;
5890                 }
5891
5892                 bi->blockState = state;
5893
5894                 /* Now let's see if it was dirty */
5895                 if (bi->pagesInUse == 0 &&
5896                     !bi->hasShrinkHeader &&
5897                     bi->blockState == YAFFS_BLOCK_STATE_FULL) {
5898                         yaffs_BlockBecameDirty(dev, blk);
5899                 }
5900
5901         }
5902
5903         
5904         /* Ok, we've done all the scanning.
5905          * Fix up the hard link chains.
5906          * We should now have scanned all the objects, now it's time to add these 
5907          * hardlinks.
5908          */
5909
5910         yaffs_HardlinkFixup(dev,hardList);
5911         
5912         /* Handle the unlinked files. Since they were left in an unlinked state we should
5913          * just delete them.
5914          */
5915         {
5916                 struct ylist_head *i;
5917                 struct ylist_head *n;
5918
5919                 yaffs_Object *l;
5920                 /* Soft delete all the unlinked files */
5921                 ylist_for_each_safe(i, n,
5922                                    &dev->unlinkedDir->variant.directoryVariant.
5923                                    children) {
5924                         if (i) {
5925                                 l = ylist_entry(i, yaffs_Object, siblings);
5926                                 yaffs_DestroyObject(l);
5927                         }
5928                 }
5929         }
5930
5931         /* Fix up any shadowed objects */
5932         {
5933                 struct yaffs_ShadowFixerStruct *fixer;
5934                 yaffs_Object *obj;
5935                 
5936                 while(shadowFixerList){
5937                         fixer = shadowFixerList;
5938                         shadowFixerList = fixer->next;
5939                         /* Complete the rename transaction by deleting the shadowed object
5940                          * then setting the object header to unshadowed.
5941                          */
5942                         obj = yaffs_FindObjectByNumber(dev,fixer->shadowedId);
5943                         if(obj)
5944                                 yaffs_DestroyObject(obj);
5945         
5946                         obj = yaffs_FindObjectByNumber(dev,fixer->objectId);
5947                         if(obj){
5948                                 yaffs_UpdateObjectHeader(obj,NULL,1,0,0);
5949                         }
5950                         
5951                         YFREE(fixer);
5952                 }
5953         }
5954
5955         yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
5956
5957         if(alloc_failed){
5958                 return YAFFS_FAIL;
5959         }
5960         
5961         T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
5962         
5963
5964         return YAFFS_OK;
5965 }
5966
5967 static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
5968 {
5969         __u8 *chunkData;
5970         yaffs_ObjectHeader *oh;
5971         yaffs_Device *dev;
5972         yaffs_ExtendedTags tags;
5973         int result;
5974         int alloc_failed = 0;
5975
5976         if(!in)
5977                 return;
5978                 
5979         dev = in->myDev;
5980                 
5981 #if 0
5982         T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR),
5983                 in->objectId,
5984                 in->lazyLoaded ? "not yet" : "already"));
5985 #endif
5986
5987         if(in->lazyLoaded && in->hdrChunk > 0){
5988                 in->lazyLoaded = 0;
5989                 chunkData = yaffs_GetTempBuffer(dev, __LINE__);
5990
5991                 result = yaffs_ReadChunkWithTagsFromNAND(dev,in->hdrChunk,chunkData,&tags);
5992                 oh = (yaffs_ObjectHeader *) chunkData;
5993
5994                 in->yst_mode = oh->yst_mode;
5995 #ifdef CONFIG_YAFFS_WINCE
5996                 in->win_atime[0] = oh->win_atime[0];
5997                 in->win_ctime[0] = oh->win_ctime[0];
5998                 in->win_mtime[0] = oh->win_mtime[0];
5999                 in->win_atime[1] = oh->win_atime[1];
6000                 in->win_ctime[1] = oh->win_ctime[1];
6001                 in->win_mtime[1] = oh->win_mtime[1];
6002 #else
6003                 in->yst_uid = oh->yst_uid;
6004                 in->yst_gid = oh->yst_gid;
6005                 in->yst_atime = oh->yst_atime;
6006                 in->yst_mtime = oh->yst_mtime;
6007                 in->yst_ctime = oh->yst_ctime;
6008                 in->yst_rdev = oh->yst_rdev;
6009                 
6010 #endif
6011                 yaffs_SetObjectName(in, oh->name);
6012                 
6013                 if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
6014                          in->variant.symLinkVariant.alias =
6015                                                     yaffs_CloneString(oh->alias);
6016                         if(!in->variant.symLinkVariant.alias)
6017                                 alloc_failed = 1; /* Not returned to caller */
6018                 }
6019                                                     
6020                 yaffs_ReleaseTempBuffer(dev,chunkData, __LINE__);
6021         }
6022 }
6023
6024 static int yaffs_ScanBackwards(yaffs_Device * dev)
6025 {
6026         yaffs_ExtendedTags tags;
6027         int blk;
6028         int blockIterator;
6029         int startIterator;
6030         int endIterator;
6031         int nBlocksToScan = 0;
6032
6033         int chunk;
6034         int result;
6035         int c;
6036         int deleted;
6037         yaffs_BlockState state;
6038         yaffs_Object *hardList = NULL;
6039         yaffs_BlockInfo *bi;
6040         __u32 sequenceNumber;
6041         yaffs_ObjectHeader *oh;
6042         yaffs_Object *in;
6043         yaffs_Object *parent;
6044         int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
6045         int itsUnlinked;
6046         __u8 *chunkData;
6047         
6048         int fileSize;
6049         int isShrink;
6050         int foundChunksInBlock;
6051         int equivalentObjectId;
6052         int alloc_failed = 0;
6053         
6054
6055         yaffs_BlockIndex *blockIndex = NULL;
6056         int altBlockIndex = 0;
6057
6058         if (!dev->isYaffs2) {
6059                 T(YAFFS_TRACE_SCAN,
6060                   (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
6061                 return YAFFS_FAIL;
6062         }
6063
6064         T(YAFFS_TRACE_SCAN,
6065           (TSTR
6066            ("yaffs_ScanBackwards starts  intstartblk %d intendblk %d..."
6067             TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
6068
6069
6070         dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
6071
6072         blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
6073         
6074         if(!blockIndex) {
6075                 blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
6076                 altBlockIndex = 1;
6077         }
6078         
6079         if(!blockIndex) {
6080                 T(YAFFS_TRACE_SCAN,
6081                   (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
6082                 return YAFFS_FAIL;
6083         }
6084         
6085         dev->blocksInCheckpoint = 0;
6086         
6087         chunkData = yaffs_GetTempBuffer(dev, __LINE__);
6088
6089         /* Scan all the blocks to determine their state */
6090         for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
6091                 bi = yaffs_GetBlockInfo(dev, blk);
6092                 yaffs_ClearChunkBits(dev, blk);
6093                 bi->pagesInUse = 0;
6094                 bi->softDeletions = 0;
6095
6096                 yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
6097
6098                 bi->blockState = state;
6099                 bi->sequenceNumber = sequenceNumber;
6100
6101                 if(bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
6102                         bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
6103                         
6104                 T(YAFFS_TRACE_SCAN_DEBUG,
6105                   (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
6106                    state, sequenceNumber));
6107
6108                 
6109                 if(state == YAFFS_BLOCK_STATE_CHECKPOINT){
6110                         dev->blocksInCheckpoint++;
6111                         
6112                 } else if (state == YAFFS_BLOCK_STATE_DEAD) {
6113                         T(YAFFS_TRACE_BAD_BLOCKS,
6114                           (TSTR("block %d is bad" TENDSTR), blk));
6115                 } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
6116                         T(YAFFS_TRACE_SCAN_DEBUG,
6117                           (TSTR("Block empty " TENDSTR)));
6118                         dev->nErasedBlocks++;
6119                         dev->nFreeChunks += dev->nChunksPerBlock;
6120                 } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
6121
6122                         /* Determine the highest sequence number */
6123                         if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
6124                             sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
6125
6126                                 blockIndex[nBlocksToScan].seq = sequenceNumber;
6127                                 blockIndex[nBlocksToScan].block = blk;
6128
6129                                 nBlocksToScan++;
6130
6131                                 if (sequenceNumber >= dev->sequenceNumber) {
6132                                         dev->sequenceNumber = sequenceNumber;
6133                                 }
6134                         } else {
6135                                 /* TODO: Nasty sequence number! */
6136                                 T(YAFFS_TRACE_SCAN,
6137                                   (TSTR
6138                                    ("Block scanning block %d has bad sequence number %d"
6139                                     TENDSTR), blk, sequenceNumber));
6140
6141                         }
6142                 }
6143         }
6144
6145         T(YAFFS_TRACE_SCAN,
6146         (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
6147
6148
6149
6150         YYIELD();
6151
6152         /* Sort the blocks */
6153 #ifndef CONFIG_YAFFS_USE_OWN_SORT
6154         {
6155                 /* Use qsort now. */
6156                 yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
6157         }
6158 #else
6159         {
6160                 /* Dungy old bubble sort... */
6161                 
6162                 yaffs_BlockIndex temp;
6163                 int i;
6164                 int j;
6165
6166                 for (i = 0; i < nBlocksToScan; i++)
6167                         for (j = i + 1; j < nBlocksToScan; j++)
6168                                 if (blockIndex[i].seq > blockIndex[j].seq) {
6169                                         temp = blockIndex[j];
6170                                         blockIndex[j] = blockIndex[i];
6171                                         blockIndex[i] = temp;
6172                                 }
6173         }
6174 #endif
6175
6176         YYIELD();
6177
6178         T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
6179
6180         /* Now scan the blocks looking at the data. */
6181         startIterator = 0;
6182         endIterator = nBlocksToScan - 1;
6183         T(YAFFS_TRACE_SCAN_DEBUG,
6184           (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
6185
6186         /* For each block.... backwards */
6187         for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
6188              blockIterator--) {
6189                 /* Cooperative multitasking! This loop can run for so
6190                    long that watchdog timers expire. */
6191                 YYIELD();
6192
6193                 /* get the block to scan in the correct order */
6194                 blk = blockIndex[blockIterator].block;
6195
6196                 bi = yaffs_GetBlockInfo(dev, blk);
6197                 
6198                 
6199                 state = bi->blockState;
6200
6201                 deleted = 0;
6202
6203                 /* For each chunk in each block that needs scanning.... */
6204                 foundChunksInBlock = 0;
6205                 for (c = dev->nChunksPerBlock - 1; 
6206                      !alloc_failed && c >= 0 &&
6207                      (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
6208                       state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
6209                         /* Scan backwards... 
6210                          * Read the tags and decide what to do
6211                          */
6212                         
6213                         chunk = blk * dev->nChunksPerBlock + c;
6214
6215                         result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
6216                                                         &tags);
6217
6218                         /* Let's have a good look at this chunk... */
6219
6220                         if (!tags.chunkUsed) {
6221                                 /* An unassigned chunk in the block.
6222                                  * If there are used chunks after this one, then
6223                                  * it is a chunk that was skipped due to failing the erased
6224                                  * check. Just skip it so that it can be deleted.
6225                                  * But, more typically, We get here when this is an unallocated
6226                                  * chunk and his means that either the block is empty or 
6227                                  * this is the one being allocated from
6228                                  */
6229
6230                                 if(foundChunksInBlock)
6231                                 {
6232                                         /* This is a chunk that was skipped due to failing the erased check */
6233                                         
6234                                 } else if (c == 0) {
6235                                         /* We're looking at the first chunk in the block so the block is unused */
6236                                         state = YAFFS_BLOCK_STATE_EMPTY;
6237                                         dev->nErasedBlocks++;
6238                                 } else {
6239                                         if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
6240                                             state == YAFFS_BLOCK_STATE_ALLOCATING) {
6241                                                 if(dev->sequenceNumber == bi->sequenceNumber) {
6242                                                         /* this is the block being allocated from */
6243                                                 
6244                                                         T(YAFFS_TRACE_SCAN,
6245                                                           (TSTR
6246                                                            (" Allocating from %d %d"
6247                                                             TENDSTR), blk, c));
6248
6249                                                         state = YAFFS_BLOCK_STATE_ALLOCATING;
6250                                                         dev->allocationBlock = blk;
6251                                                         dev->allocationPage = c;
6252                                                         dev->allocationBlockFinder = blk;       
6253                                                 }
6254                                                 else {
6255                                                         /* This is a partially written block that is not
6256                                                          * the current allocation block. This block must have
6257                                                          * had a write failure, so set up for retirement.
6258                                                          */
6259                                                   
6260                                                          /* bi->needsRetiring = 1; ??? TODO */
6261                                                          bi->gcPrioritise = 1;
6262                                                                                                          
6263                                                          T(YAFFS_TRACE_ALWAYS,
6264                                                          (TSTR("Partially written block %d detected" TENDSTR),
6265                                                          blk));
6266                                                 }
6267
6268                                         }
6269                                          
6270                                 }
6271
6272                                 dev->nFreeChunks++;
6273                                 
6274                         } else if (tags.chunkId > 0) {
6275                                 /* chunkId > 0 so it is a data chunk... */
6276                                 unsigned int endpos;
6277                                 __u32 chunkBase =
6278                                     (tags.chunkId - 1) * dev->nDataBytesPerChunk;
6279                                                                 
6280                                 foundChunksInBlock = 1;
6281
6282
6283                                 yaffs_SetChunkBit(dev, blk, c);
6284                                 bi->pagesInUse++;
6285
6286                                 in = yaffs_FindOrCreateObjectByNumber(dev,
6287                                                                       tags.
6288                                                                       objectId,
6289                                                                       YAFFS_OBJECT_TYPE_FILE);
6290                                 if(!in){
6291                                         /* Out of memory */
6292                                         alloc_failed = 1;
6293                                 }
6294                                 
6295                                 if (in &&
6296                                     in->variantType == YAFFS_OBJECT_TYPE_FILE
6297                                     && chunkBase <
6298                                     in->variant.fileVariant.shrinkSize) {
6299                                         /* This has not been invalidated by a resize */
6300                                         if(!yaffs_PutChunkIntoFile(in, tags.chunkId,
6301                                                                chunk, -1)){
6302                                                 alloc_failed = 1;
6303                                         }
6304
6305                                         /* File size is calculated by looking at the data chunks if we have not 
6306                                          * seen an object header yet. Stop this practice once we find an object header.
6307                                          */
6308                                         endpos =
6309                                             (tags.chunkId -
6310                                              1) * dev->nDataBytesPerChunk +
6311                                             tags.byteCount;
6312                                             
6313                                         if (!in->valid &&       /* have not got an object header yet */
6314                                             in->variant.fileVariant.
6315                                             scannedFileSize < endpos) {
6316                                                 in->variant.fileVariant.
6317                                                     scannedFileSize = endpos;
6318                                                 in->variant.fileVariant.
6319                                                     fileSize =
6320                                                     in->variant.fileVariant.
6321                                                     scannedFileSize;
6322                                         }
6323
6324                                 } else if(in) {
6325                                         /* This chunk has been invalidated by a resize, so delete */
6326                                         yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
6327
6328                                 }
6329                         } else {
6330                                 /* chunkId == 0, so it is an ObjectHeader.
6331                                  * Thus, we read in the object header and make the object
6332                                  */
6333                                 foundChunksInBlock = 1;
6334
6335                                 yaffs_SetChunkBit(dev, blk, c);
6336                                 bi->pagesInUse++;
6337
6338                                 oh = NULL;
6339                                 in = NULL;
6340
6341                                 if (tags.extraHeaderInfoAvailable) {
6342                                         in = yaffs_FindOrCreateObjectByNumber
6343                                             (dev, tags.objectId,
6344                                              tags.extraObjectType);
6345                                 }
6346
6347                                 if (!in ||
6348 #ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
6349                                     !in->valid ||
6350 #endif
6351                                     tags.extraShadows ||
6352                                     (!in->valid &&
6353                                     (tags.objectId == YAFFS_OBJECTID_ROOT ||
6354                                      tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
6355                                     ) {
6356
6357                                         /* If we don't have  valid info then we need to read the chunk
6358                                          * TODO In future we can probably defer reading the chunk and 
6359                                          * living with invalid data until needed.
6360                                          */
6361
6362                                         result = yaffs_ReadChunkWithTagsFromNAND(dev,
6363                                                                         chunk,
6364                                                                         chunkData,
6365                                                                         NULL);
6366
6367                                         oh = (yaffs_ObjectHeader *) chunkData;
6368                                         
6369                                         if(dev->inbandTags){
6370                                                 /* Fix up the header if they got corrupted by inband tags */
6371                                                 oh->shadowsObject = oh->inbandShadowsObject;
6372                                                 oh->isShrink = oh->inbandIsShrink;
6373                                         }
6374
6375                                         if (!in)
6376                                                 in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
6377
6378                                 }
6379
6380                                 if (!in) {
6381                                         /* TODO Hoosterman we have a problem! */
6382                                         T(YAFFS_TRACE_ERROR,
6383                                           (TSTR
6384                                            ("yaffs tragedy: Could not make object for object  %d at chunk %d during scan"
6385                                             TENDSTR), tags.objectId, chunk));
6386
6387                                 }
6388
6389                                 if (in->valid) {
6390                                         /* We have already filled this one.
6391                                          * We have a duplicate that will be discarded, but 
6392                                          * we first have to suck out resize info if it is a file.
6393                                          */
6394
6395                                         if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && 
6396                                              ((oh && 
6397                                                oh-> type == YAFFS_OBJECT_TYPE_FILE)||
6398                                               (tags.extraHeaderInfoAvailable  &&
6399                                                tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))
6400                                             ) {
6401                                                 __u32 thisSize =
6402                                                     (oh) ? oh->fileSize : tags.
6403                                                     extraFileLength;
6404                                                 __u32 parentObjectId =
6405                                                     (oh) ? oh->
6406                                                     parentObjectId : tags.
6407                                                     extraParentObjectId;
6408                                                 
6409                                                 
6410                                                 isShrink =
6411                                                     (oh) ? oh->isShrink : tags.
6412                                                     extraIsShrinkHeader;
6413
6414                                                 /* If it is deleted (unlinked at start also means deleted)
6415                                                  * we treat the file size as being zeroed at this point.
6416                                                  */
6417                                                 if (parentObjectId ==
6418                                                     YAFFS_OBJECTID_DELETED
6419                                                     || parentObjectId ==
6420                                                     YAFFS_OBJECTID_UNLINKED) {
6421                                                         thisSize = 0;
6422                                                         isShrink = 1;
6423                                                 }
6424
6425                                                 if (isShrink &&
6426                                                     in->variant.fileVariant.
6427                                                     shrinkSize > thisSize) {
6428                                                         in->variant.fileVariant.
6429                                                             shrinkSize =
6430                                                             thisSize;
6431                                                 }
6432
6433                                                 if (isShrink) {
6434                                                         bi->hasShrinkHeader = 1;
6435                                                 }
6436
6437                                         }
6438                                         /* Use existing - destroy this one. */
6439                                         yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
6440
6441                                 }
6442
6443                                 if (!in->valid &&
6444                                     (tags.objectId == YAFFS_OBJECTID_ROOT ||
6445                                      tags.objectId ==
6446                                      YAFFS_OBJECTID_LOSTNFOUND)) {
6447                                         /* We only load some info, don't fiddle with directory structure */
6448                                         in->valid = 1;
6449                                         
6450                                         if(oh) {
6451                                                 in->variantType = oh->type;
6452
6453                                                 in->yst_mode = oh->yst_mode;
6454 #ifdef CONFIG_YAFFS_WINCE
6455                                                 in->win_atime[0] = oh->win_atime[0];
6456                                                 in->win_ctime[0] = oh->win_ctime[0];
6457                                                 in->win_mtime[0] = oh->win_mtime[0];
6458                                                 in->win_atime[1] = oh->win_atime[1];
6459                                                 in->win_ctime[1] = oh->win_ctime[1];
6460                                                 in->win_mtime[1] = oh->win_mtime[1];
6461 #else
6462                                                 in->yst_uid = oh->yst_uid;
6463                                                 in->yst_gid = oh->yst_gid;
6464                                                 in->yst_atime = oh->yst_atime;
6465                                                 in->yst_mtime = oh->yst_mtime;
6466                                                 in->yst_ctime = oh->yst_ctime;
6467                                                 in->yst_rdev = oh->yst_rdev;
6468                 
6469 #endif
6470                                         } else {
6471                                                 in->variantType = tags.extraObjectType;
6472                                                 in->lazyLoaded = 1;
6473                                         }
6474
6475                                         in->hdrChunk = chunk;
6476
6477                                 } else if (!in->valid) {
6478                                         /* we need to load this info */
6479
6480                                         in->valid = 1;
6481                                         in->hdrChunk = chunk;
6482
6483                                         if(oh) {
6484                                                 in->variantType = oh->type;
6485
6486                                                 in->yst_mode = oh->yst_mode;
6487 #ifdef CONFIG_YAFFS_WINCE
6488                                                 in->win_atime[0] = oh->win_atime[0];
6489                                                 in->win_ctime[0] = oh->win_ctime[0];
6490                                                 in->win_mtime[0] = oh->win_mtime[0];
6491                                                 in->win_atime[1] = oh->win_atime[1];
6492                                                 in->win_ctime[1] = oh->win_ctime[1];
6493                                                 in->win_mtime[1] = oh->win_mtime[1];
6494 #else
6495                                                 in->yst_uid = oh->yst_uid;
6496                                                 in->yst_gid = oh->yst_gid;
6497                                                 in->yst_atime = oh->yst_atime;
6498                                                 in->yst_mtime = oh->yst_mtime;
6499                                                 in->yst_ctime = oh->yst_ctime;
6500                                                 in->yst_rdev = oh->yst_rdev;
6501 #endif
6502
6503                                                 if (oh->shadowsObject > 0) 
6504                                                         yaffs_HandleShadowedObject(dev,
6505                                                                            oh->
6506                                                                            shadowsObject,
6507                                                                            1);
6508                                         
6509
6510                                                 yaffs_SetObjectName(in, oh->name);
6511                                                 parent =
6512                                                     yaffs_FindOrCreateObjectByNumber
6513                                                         (dev, oh->parentObjectId,
6514                                                          YAFFS_OBJECT_TYPE_DIRECTORY);
6515
6516                                                  fileSize = oh->fileSize;
6517                                                  isShrink = oh->isShrink;
6518                                                  equivalentObjectId = oh->equivalentObjectId;
6519
6520                                         }
6521                                         else {
6522                                                 in->variantType = tags.extraObjectType;
6523                                                 parent =
6524                                                     yaffs_FindOrCreateObjectByNumber
6525                                                         (dev, tags.extraParentObjectId,
6526                                                          YAFFS_OBJECT_TYPE_DIRECTORY);
6527                                                  fileSize = tags.extraFileLength;
6528                                                  isShrink = tags.extraIsShrinkHeader;
6529                                                  equivalentObjectId = tags.extraEquivalentObjectId;
6530                                                 in->lazyLoaded = 1;
6531
6532                                         }
6533                                         in->dirty = 0;
6534
6535                                         /* directory stuff...
6536                                          * hook up to parent
6537                                          */
6538
6539                                         if (parent->variantType ==
6540                                             YAFFS_OBJECT_TYPE_UNKNOWN) {
6541                                                 /* Set up as a directory */
6542                                                 parent->variantType =
6543                                                     YAFFS_OBJECT_TYPE_DIRECTORY;
6544                                                 YINIT_LIST_HEAD(&parent->variant.
6545                                                                directoryVariant.
6546                                                                children);
6547                                         } else if (parent->variantType !=
6548                                                    YAFFS_OBJECT_TYPE_DIRECTORY)
6549                                         {
6550                                                 /* Hoosterman, another problem....
6551                                                  * We're trying to use a non-directory as a directory
6552                                                  */
6553
6554                                                 T(YAFFS_TRACE_ERROR,
6555                                                   (TSTR
6556                                                    ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
6557                                                     TENDSTR)));
6558                                                 parent = dev->lostNFoundDir;
6559                                         }
6560
6561                                         yaffs_AddObjectToDirectory(parent, in);
6562
6563                                         itsUnlinked = (parent == dev->deletedDir) ||
6564                                                       (parent == dev->unlinkedDir);
6565
6566                                         if (isShrink) {
6567                                                 /* Mark the block as having a shrinkHeader */
6568                                                 bi->hasShrinkHeader = 1;
6569                                         }
6570
6571                                         /* Note re hardlinks.
6572                                          * Since we might scan a hardlink before its equivalent object is scanned
6573                                          * we put them all in a list.
6574                                          * After scanning is complete, we should have all the objects, so we run
6575                                          * through this list and fix up all the chains.              
6576                                          */
6577
6578                                         switch (in->variantType) {
6579                                         case YAFFS_OBJECT_TYPE_UNKNOWN: 
6580                                                 /* Todo got a problem */
6581                                                 break;
6582                                         case YAFFS_OBJECT_TYPE_FILE:
6583
6584                                                 if (in->variant.fileVariant.
6585                                                     scannedFileSize < fileSize) {
6586                                                         /* This covers the case where the file size is greater
6587                                                          * than where the data is
6588                                                          * This will happen if the file is resized to be larger 
6589                                                          * than its current data extents.
6590                                                          */
6591                                                         in->variant.fileVariant.fileSize = fileSize;
6592                                                         in->variant.fileVariant.scannedFileSize =
6593                                                             in->variant.fileVariant.fileSize;
6594                                                 }
6595
6596                                                 if (isShrink &&
6597                                                     in->variant.fileVariant.shrinkSize > fileSize) {
6598                                                         in->variant.fileVariant.shrinkSize = fileSize;
6599                                                 }
6600
6601                                                 break;
6602                                         case YAFFS_OBJECT_TYPE_HARDLINK:
6603                                                 if(!itsUnlinked) {
6604                                                   in->variant.hardLinkVariant.equivalentObjectId =
6605                                                     equivalentObjectId;
6606                                                   in->hardLinks.next =
6607                                                     (struct ylist_head *) hardList;
6608                                                   hardList = in;
6609                                                 }
6610                                                 break;
6611                                         case YAFFS_OBJECT_TYPE_DIRECTORY:
6612                                                 /* Do nothing */
6613                                                 break;
6614                                         case YAFFS_OBJECT_TYPE_SPECIAL:
6615                                                 /* Do nothing */
6616                                                 break;
6617                                         case YAFFS_OBJECT_TYPE_SYMLINK:
6618                                                 if(oh){
6619                                                    in->variant.symLinkVariant.alias =
6620                                                     yaffs_CloneString(oh->
6621                                                                       alias);
6622                                                    if(!in->variant.symLinkVariant.alias)
6623                                                         alloc_failed = 1;
6624                                                 }
6625                                                 break;
6626                                         }
6627
6628                                 }
6629                                 
6630                         }
6631
6632                 } /* End of scanning for each chunk */
6633
6634                 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
6635                         /* If we got this far while scanning, then the block is fully allocated. */
6636                         state = YAFFS_BLOCK_STATE_FULL;
6637                 }
6638
6639                 bi->blockState = state;
6640
6641                 /* Now let's see if it was dirty */
6642                 if (bi->pagesInUse == 0 &&
6643                     !bi->hasShrinkHeader &&
6644                     bi->blockState == YAFFS_BLOCK_STATE_FULL) {
6645                         yaffs_BlockBecameDirty(dev, blk);
6646                 }
6647
6648         }
6649
6650         if (altBlockIndex) 
6651                 YFREE_ALT(blockIndex);
6652         else
6653                 YFREE(blockIndex);
6654         
6655         /* Ok, we've done all the scanning.
6656          * Fix up the hard link chains.
6657          * We should now have scanned all the objects, now it's time to add these 
6658          * hardlinks.
6659          */
6660         yaffs_HardlinkFixup(dev,hardList);
6661         
6662         
6663         /*
6664         *  Sort out state of unlinked and deleted objects.
6665         */
6666         {
6667                 struct ylist_head *i;
6668                 struct ylist_head *n;
6669
6670                 yaffs_Object *l;
6671
6672                 /* Soft delete all the unlinked files */
6673                 ylist_for_each_safe(i, n,
6674                                    &dev->unlinkedDir->variant.directoryVariant.
6675                                    children) {
6676                         if (i) {
6677                                 l = ylist_entry(i, yaffs_Object, siblings);
6678                                 yaffs_DestroyObject(l);
6679                         }
6680                 }
6681
6682                 /* Soft delete all the deletedDir files */
6683                 ylist_for_each_safe(i, n,
6684                                    &dev->deletedDir->variant.directoryVariant.
6685                                    children) {
6686                         if (i) {
6687                                 l = ylist_entry(i, yaffs_Object, siblings);
6688                                 yaffs_DestroyObject(l);
6689
6690                         }
6691                 }
6692         }
6693
6694         yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
6695         
6696         if(alloc_failed){
6697                 return YAFFS_FAIL;
6698         }
6699
6700         T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
6701
6702         return YAFFS_OK;
6703 }
6704
6705 /*------------------------------  Directory Functions ----------------------------- */
6706
6707 static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
6708 {
6709         struct ylist_head *lh;
6710         yaffs_Object *listObj;
6711         
6712         int count = 0;
6713
6714         if(!obj)
6715                 YBUG();
6716
6717         if(yaffs_SkipVerification(obj->myDev))
6718                 return;
6719
6720         if(!obj->parent)
6721                 YBUG();
6722                 
6723         if(obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6724                 YBUG();
6725         
6726         /* Iterate through the objects in each hash entry */
6727          
6728         ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
6729                 if (lh) {
6730                         listObj = ylist_entry(lh, yaffs_Object, siblings);
6731                         yaffs_VerifyObject(listObj);
6732                         if(obj == listObj)
6733                                 count ++;
6734                 }
6735          }
6736          
6737          if(count != 1)
6738                 YBUG();
6739          
6740
6741 }
6742
6743 static void yaffs_VerifyDirectory(yaffs_Object *directory)
6744 {
6745
6746         struct ylist_head *lh;
6747         yaffs_Object *listObj;
6748         
6749         if(!directory)
6750                 YBUG();
6751
6752         if(yaffs_SkipVerification(directory->myDev))
6753                 return;
6754
6755                 
6756         if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
6757                 YBUG();
6758         
6759         /* Iterate through the objects in each hash entry */
6760          
6761         ylist_for_each(lh, &directory->variant.directoryVariant.children) {
6762                 if (lh) {
6763                         listObj = ylist_entry(lh, yaffs_Object, siblings);
6764                         if(listObj->parent != directory)
6765                                 YBUG();
6766                         yaffs_VerifyObjectInDirectory(listObj);
6767                 }
6768          }
6769          
6770 }
6771
6772
6773 static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj)
6774 {
6775         yaffs_Device *dev = obj->myDev;
6776         yaffs_Object *parent;
6777         
6778         yaffs_VerifyObjectInDirectory(obj);
6779         parent = obj->parent;
6780         
6781         yaffs_VerifyDirectory(parent);
6782
6783         if(dev && dev->removeObjectCallback)
6784                 dev->removeObjectCallback(obj);
6785
6786            
6787         ylist_del_init(&obj->siblings);
6788         obj->parent = NULL;
6789
6790         yaffs_VerifyDirectory(parent);
6791
6792 }
6793
6794
6795 static void yaffs_AddObjectToDirectory(yaffs_Object * directory,
6796                                        yaffs_Object * obj)
6797 {
6798
6799         if (!directory) {
6800                 T(YAFFS_TRACE_ALWAYS,
6801                   (TSTR
6802                    ("tragedy: Trying to add an object to a null pointer directory"
6803                     TENDSTR)));
6804                 YBUG();
6805         }
6806         if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
6807                 T(YAFFS_TRACE_ALWAYS,
6808                   (TSTR
6809                    ("tragedy: Trying to add an object to a non-directory"
6810                     TENDSTR)));
6811                 YBUG();
6812         }
6813
6814         if (obj->siblings.prev == NULL) {
6815                 /* Not initialised */
6816                 YBUG();
6817
6818         } else if (ylist_empty(&obj->siblings)) {
6819                 YBUG();
6820         } 
6821
6822
6823         yaffs_VerifyDirectory(directory);
6824
6825         yaffs_RemoveObjectFromDirectory(obj);
6826         
6827         
6828         /* Now add it */
6829         ylist_add(&obj->siblings, &directory->variant.directoryVariant.children);
6830         obj->parent = directory;
6831
6832         if (directory == obj->myDev->unlinkedDir
6833             || directory == obj->myDev->deletedDir) {
6834                 obj->unlinked = 1;
6835                 obj->myDev->nUnlinkedFiles++;
6836                 obj->renameAllowed = 0;
6837         }
6838
6839         yaffs_VerifyDirectory(directory);
6840         yaffs_VerifyObjectInDirectory(obj);
6841
6842
6843 }
6844
6845 yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory,
6846                                      const YCHAR * name)
6847 {
6848         int sum;
6849
6850         struct ylist_head *i;
6851         YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
6852
6853         yaffs_Object *l;
6854
6855         if (!name) {
6856                 return NULL;
6857         }
6858
6859         if (!directory) {
6860                 T(YAFFS_TRACE_ALWAYS,
6861                   (TSTR
6862                    ("tragedy: yaffs_FindObjectByName: null pointer directory"
6863                     TENDSTR)));
6864                 YBUG();
6865         }
6866         if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
6867                 T(YAFFS_TRACE_ALWAYS,
6868                   (TSTR
6869                    ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
6870                 YBUG();
6871         }
6872
6873         sum = yaffs_CalcNameSum(name);
6874
6875         ylist_for_each(i, &directory->variant.directoryVariant.children) {
6876                 if (i) {
6877                         l = ylist_entry(i, yaffs_Object, siblings);
6878                         
6879                         if(l->parent != directory)
6880                                 YBUG();
6881                         
6882                         yaffs_CheckObjectDetailsLoaded(l);
6883
6884                         /* Special case for lost-n-found */
6885                         if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
6886                                 if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) {
6887                                         return l;
6888                                 }
6889                         } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0){
6890                                 /* LostnFound chunk called Objxxx
6891                                  * Do a real check
6892                                  */
6893                                 yaffs_GetObjectName(l, buffer,
6894                                                     YAFFS_MAX_NAME_LENGTH);
6895                                 if (yaffs_strncmp(name, buffer,YAFFS_MAX_NAME_LENGTH) == 0) {
6896                                         return l;
6897                                 }
6898
6899                         }
6900                 }
6901         }
6902
6903         return NULL;
6904 }
6905
6906
6907 #if 0
6908 int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
6909                                    int (*fn) (yaffs_Object *))
6910 {
6911         struct ylist_head *i;
6912         yaffs_Object *l;
6913
6914         if (!theDir) {
6915                 T(YAFFS_TRACE_ALWAYS,
6916                   (TSTR
6917                    ("tragedy: yaffs_FindObjectByName: null pointer directory"
6918                     TENDSTR)));
6919                 YBUG();
6920         }
6921         if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
6922                 T(YAFFS_TRACE_ALWAYS,
6923                   (TSTR
6924                    ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
6925                 YBUG();
6926         }
6927
6928         ylist_for_each(i, &theDir->variant.directoryVariant.children) {
6929                 if (i) {
6930                         l = ylist_entry(i, yaffs_Object, siblings);
6931                         if (l && !fn(l)) {
6932                                 return YAFFS_FAIL;
6933                         }
6934                 }
6935         }
6936
6937         return YAFFS_OK;
6938
6939 }
6940 #endif
6941
6942 /* GetEquivalentObject dereferences any hard links to get to the
6943  * actual object.
6944  */
6945
6946 yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj)
6947 {
6948         if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
6949                 /* We want the object id of the equivalent object, not this one */
6950                 obj = obj->variant.hardLinkVariant.equivalentObject;
6951                 yaffs_CheckObjectDetailsLoaded(obj);
6952         }
6953         return obj;
6954
6955 }
6956
6957 int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize)
6958 {
6959         memset(name, 0, buffSize * sizeof(YCHAR));
6960         
6961         yaffs_CheckObjectDetailsLoaded(obj);
6962
6963         if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
6964                 yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
6965         } else if (obj->hdrChunk <= 0) {
6966                 YCHAR locName[20];
6967                 YCHAR numString[20];
6968                 YCHAR *x = &numString[19];
6969                 unsigned v = obj->objectId;
6970                 numString[19] = 0;
6971                 while(v>0){
6972                         x--;
6973                         *x = '0' + (v % 10);
6974                         v /= 10;
6975                 }
6976                 /* make up a name */
6977                 yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
6978                 yaffs_strcat(locName,x);
6979                 yaffs_strncpy(name, locName, buffSize - 1);
6980
6981         }
6982 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
6983         else if (obj->shortName[0]) {
6984                 yaffs_strcpy(name, obj->shortName);
6985         }
6986 #endif
6987         else {
6988                 int result;
6989                 __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
6990
6991                 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer;
6992
6993                 memset(buffer, 0, obj->myDev->nDataBytesPerChunk);
6994
6995                 if (obj->hdrChunk > 0) {
6996                         result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,
6997                                                         obj->hdrChunk, buffer,
6998                                                         NULL);
6999                 }
7000                 yaffs_strncpy(name, oh->name, buffSize - 1);
7001
7002                 yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
7003         }
7004
7005         return yaffs_strlen(name);
7006 }
7007
7008 int yaffs_GetObjectFileLength(yaffs_Object * obj)
7009 {
7010
7011         /* Dereference any hard linking */
7012         obj = yaffs_GetEquivalentObject(obj);
7013
7014         if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
7015                 return obj->variant.fileVariant.fileSize;
7016         }
7017         if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
7018                 return yaffs_strlen(obj->variant.symLinkVariant.alias);
7019         } else {
7020                 /* Only a directory should drop through to here */
7021                 return obj->myDev->nDataBytesPerChunk;
7022         }
7023 }
7024
7025 int yaffs_GetObjectLinkCount(yaffs_Object * obj)
7026 {
7027         int count = 0;
7028         struct ylist_head *i;
7029
7030         if (!obj->unlinked) {
7031                 count++;        /* the object itself */
7032         }
7033         ylist_for_each(i, &obj->hardLinks) {
7034                 count++;        /* add the hard links; */
7035         }
7036         return count;
7037
7038 }
7039
7040 int yaffs_GetObjectInode(yaffs_Object * obj)
7041 {
7042         obj = yaffs_GetEquivalentObject(obj);
7043
7044         return obj->objectId;
7045 }
7046
7047 unsigned yaffs_GetObjectType(yaffs_Object * obj)
7048 {
7049         obj = yaffs_GetEquivalentObject(obj);
7050
7051         switch (obj->variantType) {
7052         case YAFFS_OBJECT_TYPE_FILE:
7053                 return DT_REG;
7054                 break;
7055         case YAFFS_OBJECT_TYPE_DIRECTORY:
7056                 return DT_DIR;
7057                 break;
7058         case YAFFS_OBJECT_TYPE_SYMLINK:
7059                 return DT_LNK;
7060                 break;
7061         case YAFFS_OBJECT_TYPE_HARDLINK:
7062                 return DT_REG;
7063                 break;
7064         case YAFFS_OBJECT_TYPE_SPECIAL:
7065                 if (S_ISFIFO(obj->yst_mode))
7066                         return DT_FIFO;
7067                 if (S_ISCHR(obj->yst_mode))
7068                         return DT_CHR;
7069                 if (S_ISBLK(obj->yst_mode))
7070                         return DT_BLK;
7071                 if (S_ISSOCK(obj->yst_mode))
7072                         return DT_SOCK;
7073         default:
7074                 return DT_REG;
7075                 break;
7076         }
7077 }
7078
7079 YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj)
7080 {
7081         obj = yaffs_GetEquivalentObject(obj);
7082         if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
7083                 return yaffs_CloneString(obj->variant.symLinkVariant.alias);
7084         } else {
7085                 return yaffs_CloneString(_Y(""));
7086         }
7087 }
7088
7089 #ifndef CONFIG_YAFFS_WINCE
7090
7091 int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr)
7092 {
7093         unsigned int valid = attr->ia_valid;
7094
7095         if (valid & ATTR_MODE)
7096                 obj->yst_mode = attr->ia_mode;
7097         if (valid & ATTR_UID)
7098                 obj->yst_uid = attr->ia_uid;
7099         if (valid & ATTR_GID)
7100                 obj->yst_gid = attr->ia_gid;
7101
7102         if (valid & ATTR_ATIME)
7103                 obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
7104         if (valid & ATTR_CTIME)
7105                 obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
7106         if (valid & ATTR_MTIME)
7107                 obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
7108
7109         if (valid & ATTR_SIZE)
7110                 yaffs_ResizeFile(obj, attr->ia_size);
7111
7112         yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
7113
7114         return YAFFS_OK;
7115
7116 }
7117 int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr)
7118 {
7119         unsigned int valid = 0;
7120
7121         attr->ia_mode = obj->yst_mode;
7122         valid |= ATTR_MODE;
7123         attr->ia_uid = obj->yst_uid;
7124         valid |= ATTR_UID;
7125         attr->ia_gid = obj->yst_gid;
7126         valid |= ATTR_GID;
7127
7128         Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
7129         valid |= ATTR_ATIME;
7130         Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
7131         valid |= ATTR_CTIME;
7132         Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
7133         valid |= ATTR_MTIME;
7134
7135         attr->ia_size = yaffs_GetFileSize(obj);
7136         valid |= ATTR_SIZE;
7137
7138         attr->ia_valid = valid;
7139
7140         return YAFFS_OK;
7141
7142 }
7143
7144 #endif
7145
7146 #if 0
7147 int yaffs_DumpObject(yaffs_Object * obj)
7148 {
7149         YCHAR name[257];
7150
7151         yaffs_GetObjectName(obj, name, 256);
7152
7153         T(YAFFS_TRACE_ALWAYS,
7154           (TSTR
7155            ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
7156             " chunk %d type %d size %d\n"
7157             TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,
7158            obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk,
7159            yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
7160
7161         return YAFFS_OK;
7162 }
7163 #endif
7164
7165 /*---------------------------- Initialisation code -------------------------------------- */
7166
7167 static int yaffs_CheckDevFunctions(const yaffs_Device * dev)
7168 {
7169
7170         /* Common functions, gotta have */
7171         if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
7172                 return 0;
7173
7174 #ifdef CONFIG_YAFFS_YAFFS2
7175
7176         /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
7177         if (dev->writeChunkWithTagsToNAND &&
7178             dev->readChunkWithTagsFromNAND &&
7179             !dev->writeChunkToNAND &&
7180             !dev->readChunkFromNAND &&
7181             dev->markNANDBlockBad && dev->queryNANDBlock)
7182                 return 1;
7183 #endif
7184
7185         /* Can use the "spare" style interface for yaffs1 */
7186         if (!dev->isYaffs2 &&
7187             !dev->writeChunkWithTagsToNAND &&
7188             !dev->readChunkWithTagsFromNAND &&
7189             dev->writeChunkToNAND &&
7190             dev->readChunkFromNAND &&
7191             !dev->markNANDBlockBad && !dev->queryNANDBlock)
7192                 return 1;
7193
7194         return 0;               /* bad */
7195 }
7196
7197
7198 static int yaffs_CreateInitialDirectories(yaffs_Device *dev)
7199 {
7200         /* Initialise the unlinked, deleted, root and lost and found directories */
7201         
7202         dev->lostNFoundDir = dev->rootDir =  NULL;
7203         dev->unlinkedDir = dev->deletedDir = NULL;
7204
7205         dev->unlinkedDir =
7206             yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
7207         
7208         dev->deletedDir =
7209             yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
7210
7211         dev->rootDir =
7212             yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,
7213                                       YAFFS_ROOT_MODE | S_IFDIR);
7214         dev->lostNFoundDir =
7215             yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,
7216                                       YAFFS_LOSTNFOUND_MODE | S_IFDIR);
7217         
7218         if(dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir){
7219                 yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);
7220                 return YAFFS_OK;
7221         }
7222         
7223         return YAFFS_FAIL;
7224 }
7225
7226 int yaffs_GutsInitialise(yaffs_Device * dev)
7227 {
7228         int init_failed = 0;
7229         unsigned x;
7230         int bits;
7231
7232         T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
7233
7234         /* Check stuff that must be set */
7235
7236         if (!dev) {
7237                 T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR)));
7238                 return YAFFS_FAIL;
7239         }
7240
7241         dev->internalStartBlock = dev->startBlock;
7242         dev->internalEndBlock = dev->endBlock;
7243         dev->blockOffset = 0;
7244         dev->chunkOffset = 0;
7245         dev->nFreeChunks = 0;
7246         
7247         dev->gcBlock = -1;
7248
7249         if (dev->startBlock == 0) {
7250                 dev->internalStartBlock = dev->startBlock + 1;
7251                 dev->internalEndBlock = dev->endBlock + 1;
7252                 dev->blockOffset = 1;
7253                 dev->chunkOffset = dev->nChunksPerBlock;
7254         }
7255
7256         /* Check geometry parameters. */
7257
7258         if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) || 
7259             (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) || 
7260             (dev->inbandTags && !dev->isYaffs2 ) ||
7261              dev->nChunksPerBlock < 2 || 
7262              dev->nReservedBlocks < 2 || 
7263              dev->internalStartBlock <= 0 || 
7264              dev->internalEndBlock <= 0 || 
7265              dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)      // otherwise it is too small
7266             ) {
7267                 T(YAFFS_TRACE_ALWAYS,
7268                   (TSTR
7269                    ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
7270                     TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
7271                 return YAFFS_FAIL;
7272         }
7273
7274         if (yaffs_InitialiseNAND(dev) != YAFFS_OK) {
7275                 T(YAFFS_TRACE_ALWAYS,
7276                   (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
7277                 return YAFFS_FAIL;
7278         }
7279         
7280         /* Sort out space for inband tags, if required */
7281         if(dev->inbandTags)
7282                 dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
7283         else 
7284                 dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
7285
7286         /* Got the right mix of functions? */
7287         if (!yaffs_CheckDevFunctions(dev)) {
7288                 /* Function missing */
7289                 T(YAFFS_TRACE_ALWAYS,
7290                   (TSTR
7291                    ("yaffs: device function(s) missing or wrong\n" TENDSTR)));
7292
7293                 return YAFFS_FAIL;
7294         }
7295
7296         /* This is really a compilation check. */
7297         if (!yaffs_CheckStructures()) {
7298                 T(YAFFS_TRACE_ALWAYS,
7299                   (TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
7300                 return YAFFS_FAIL;
7301         }
7302
7303         if (dev->isMounted) {
7304                 T(YAFFS_TRACE_ALWAYS,
7305                   (TSTR("yaffs: device already mounted\n" TENDSTR)));
7306                 return YAFFS_FAIL;
7307         }
7308
7309         /* Finished with most checks. One or two more checks happen later on too. */
7310
7311         dev->isMounted = 1;
7312
7313         /* OK now calculate a few things for the device */
7314         
7315         /*
7316          *  Calculate all the chunk size manipulation numbers:   
7317          */
7318         x = dev->nDataBytesPerChunk;
7319         /* We always use dev->chunkShift and dev->chunkDiv */
7320         dev->chunkShift = Shifts(x);
7321         x >>= dev->chunkShift;
7322         dev->chunkDiv = x;
7323         /* We only use chunk mask if chunkDiv is 1 */
7324         dev->chunkMask = (1<<dev->chunkShift) - 1;
7325                 
7326         /*
7327          * Calculate chunkGroupBits.
7328          * We need to find the next power of 2 > than internalEndBlock
7329          */
7330
7331         x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
7332         
7333         bits = ShiftsGE(x);
7334         
7335         /* Set up tnode width if wide tnodes are enabled. */
7336         if(!dev->wideTnodesDisabled){
7337                 /* bits must be even so that we end up with 32-bit words */
7338                 if(bits & 1)
7339                         bits++;
7340                 if(bits < 16)
7341                         dev->tnodeWidth = 16;
7342                 else
7343                         dev->tnodeWidth = bits;
7344         }
7345         else
7346                 dev->tnodeWidth = 16;
7347  
7348         dev->tnodeMask = (1<<dev->tnodeWidth)-1;
7349                 
7350         /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
7351          * so if the bitwidth of the
7352          * chunk range we're using is greater than 16 we need
7353          * to figure out chunk shift and chunkGroupSize
7354          */
7355                  
7356         if (bits <= dev->tnodeWidth)
7357                 dev->chunkGroupBits = 0;
7358         else
7359                 dev->chunkGroupBits = bits - dev->tnodeWidth;
7360                 
7361
7362         dev->chunkGroupSize = 1 << dev->chunkGroupBits;
7363
7364         if (dev->nChunksPerBlock < dev->chunkGroupSize) {
7365                 /* We have a problem because the soft delete won't work if
7366                  * the chunk group size > chunks per block.
7367                  * This can be remedied by using larger "virtual blocks".
7368                  */
7369                 T(YAFFS_TRACE_ALWAYS,
7370                   (TSTR("yaffs: chunk group too large\n" TENDSTR)));
7371
7372                 return YAFFS_FAIL;
7373         }
7374
7375         /* OK, we've finished verifying the device, lets continue with initialisation */
7376
7377         /* More device initialisation */
7378         dev->garbageCollections = 0;
7379         dev->passiveGarbageCollections = 0;
7380         dev->currentDirtyChecker = 0;
7381         dev->bufferedBlock = -1;
7382         dev->doingBufferedBlockRewrite = 0;
7383         dev->nDeletedFiles = 0;
7384         dev->nBackgroundDeletions = 0;
7385         dev->nUnlinkedFiles = 0;
7386         dev->eccFixed = 0;
7387         dev->eccUnfixed = 0;
7388         dev->tagsEccFixed = 0;
7389         dev->tagsEccUnfixed = 0;
7390         dev->nErasureFailures = 0;
7391         dev->nErasedBlocks = 0;
7392         dev->isDoingGC = 0;
7393         dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
7394
7395         /* Initialise temporary buffers and caches. */
7396         if(!yaffs_InitialiseTempBuffers(dev))
7397                 init_failed = 1;
7398         
7399         dev->srCache = NULL;
7400         dev->gcCleanupList = NULL;
7401         
7402         
7403         if (!init_failed &&
7404             dev->nShortOpCaches > 0) {
7405                 int i;
7406                 void *buf;
7407                 int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
7408
7409                 if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) {
7410                         dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
7411                 }
7412
7413                 dev->srCache =  YMALLOC(srCacheBytes);
7414                 
7415                 buf = (__u8 *) dev->srCache;
7416                     
7417                 if(dev->srCache)
7418                         memset(dev->srCache,0,srCacheBytes);
7419                    
7420                 for (i = 0; i < dev->nShortOpCaches && buf; i++) {
7421                         dev->srCache[i].object = NULL;
7422                         dev->srCache[i].lastUse = 0;
7423                         dev->srCache[i].dirty = 0;
7424                         dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
7425                 }
7426                 if(!buf)
7427                         init_failed = 1;
7428                         
7429                 dev->srLastUse = 0;
7430         }
7431
7432         dev->cacheHits = 0;
7433         
7434         if(!init_failed){
7435                 dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
7436                 if(!dev->gcCleanupList)
7437                         init_failed = 1;
7438         }
7439
7440         if (dev->isYaffs2) {
7441                 dev->useHeaderFileSize = 1;
7442         }
7443         if(!init_failed && !yaffs_InitialiseBlocks(dev))
7444                 init_failed = 1;
7445                 
7446         yaffs_InitialiseTnodes(dev);
7447         yaffs_InitialiseObjects(dev);
7448
7449         if(!init_failed && !yaffs_CreateInitialDirectories(dev))
7450                 init_failed = 1;
7451
7452
7453         if(!init_failed){
7454                 /* Now scan the flash. */
7455                 if (dev->isYaffs2) {
7456                         if(yaffs_CheckpointRestore(dev)) {
7457                                 yaffs_CheckObjectDetailsLoaded(dev->rootDir);
7458                                 T(YAFFS_TRACE_ALWAYS,
7459                                   (TSTR("yaffs: restored from checkpoint" TENDSTR)));
7460                         } else {
7461
7462                                 /* Clean up the mess caused by an aborted checkpoint load 
7463                                  * and scan backwards. 
7464                                  */
7465                                 yaffs_DeinitialiseBlocks(dev);
7466                                 yaffs_DeinitialiseTnodes(dev);
7467                                 yaffs_DeinitialiseObjects(dev);
7468                                 
7469                         
7470                                 dev->nErasedBlocks = 0;
7471                                 dev->nFreeChunks = 0;
7472                                 dev->allocationBlock = -1;
7473                                 dev->allocationPage = -1;
7474                                 dev->nDeletedFiles = 0;
7475                                 dev->nUnlinkedFiles = 0;
7476                                 dev->nBackgroundDeletions = 0;
7477                                 dev->oldestDirtySequence = 0;
7478
7479                                 if(!init_failed && !yaffs_InitialiseBlocks(dev))
7480                                         init_failed = 1;
7481                                         
7482                                 yaffs_InitialiseTnodes(dev);
7483                                 yaffs_InitialiseObjects(dev);
7484
7485                                 if(!init_failed && !yaffs_CreateInitialDirectories(dev))
7486                                         init_failed = 1;
7487
7488                                 if(!init_failed && !yaffs_ScanBackwards(dev))
7489                                         init_failed = 1;
7490                         }
7491                 }else
7492                         if(!yaffs_Scan(dev))
7493                                 init_failed = 1;
7494         }
7495                 
7496         if(init_failed){
7497                 /* Clean up the mess */
7498                 T(YAFFS_TRACE_TRACING,
7499                   (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR)));
7500
7501                 yaffs_Deinitialise(dev);
7502                 return YAFFS_FAIL;
7503         }
7504
7505         /* Zero out stats */
7506         dev->nPageReads = 0;
7507         dev->nPageWrites = 0;
7508         dev->nBlockErasures = 0;
7509         dev->nGCCopies = 0;
7510         dev->nRetriedWrites = 0;
7511
7512         dev->nRetiredBlocks = 0;
7513
7514         yaffs_VerifyFreeChunks(dev);
7515         yaffs_VerifyBlocks(dev);
7516         
7517
7518         T(YAFFS_TRACE_TRACING,
7519           (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
7520         return YAFFS_OK;
7521
7522 }
7523
7524 void yaffs_Deinitialise(yaffs_Device * dev)
7525 {
7526         if (dev->isMounted) {
7527                 int i;
7528
7529                 yaffs_DeinitialiseBlocks(dev);
7530                 yaffs_DeinitialiseTnodes(dev);
7531                 yaffs_DeinitialiseObjects(dev);
7532                 if (dev->nShortOpCaches > 0 &&
7533                     dev->srCache) {
7534
7535                         for (i = 0; i < dev->nShortOpCaches; i++) {
7536                                 if(dev->srCache[i].data)
7537                                         YFREE(dev->srCache[i].data);
7538                                 dev->srCache[i].data = NULL;
7539                         }
7540
7541                         YFREE(dev->srCache);
7542                         dev->srCache = NULL;
7543                 }
7544
7545                 YFREE(dev->gcCleanupList);
7546
7547                 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
7548                         YFREE(dev->tempBuffer[i].buffer);
7549                 }
7550
7551
7552                 dev->isMounted = 0;
7553                 
7554                 if(dev->deinitialiseNAND)
7555                         dev->deinitialiseNAND(dev);
7556         }
7557
7558 }
7559
7560 static int yaffs_CountFreeChunks(yaffs_Device * dev)
7561 {
7562         int nFree;
7563         int b;
7564
7565         yaffs_BlockInfo *blk;
7566
7567         for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
7568              b++) {
7569                 blk = yaffs_GetBlockInfo(dev, b);
7570
7571                 switch (blk->blockState) {
7572                 case YAFFS_BLOCK_STATE_EMPTY:
7573                 case YAFFS_BLOCK_STATE_ALLOCATING:
7574                 case YAFFS_BLOCK_STATE_COLLECTING:
7575                 case YAFFS_BLOCK_STATE_FULL:
7576                         nFree +=
7577                             (dev->nChunksPerBlock - blk->pagesInUse +
7578                              blk->softDeletions);
7579                         break;
7580                 default:
7581                         break;
7582                 }
7583
7584         }
7585
7586         return nFree;
7587 }
7588
7589 int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev)
7590 {
7591         /* This is what we report to the outside world */
7592
7593         int nFree;
7594         int nDirtyCacheChunks;
7595         int blocksForCheckpoint;
7596
7597 #if 1
7598         nFree = dev->nFreeChunks;
7599 #else
7600         nFree = yaffs_CountFreeChunks(dev);
7601 #endif
7602
7603         nFree += dev->nDeletedFiles;
7604         
7605         /* Now count the number of dirty chunks in the cache and subtract those */
7606
7607         {
7608                 int i;
7609                 for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
7610                         if (dev->srCache[i].dirty)
7611                                 nDirtyCacheChunks++;
7612                 }
7613         }
7614
7615         nFree -= nDirtyCacheChunks;
7616
7617         nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
7618         
7619         /* Now we figure out how much to reserve for the checkpoint and report that... */
7620         blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
7621         if(blocksForCheckpoint < 0)
7622                 blocksForCheckpoint = 0;
7623                 
7624         nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
7625
7626         if (nFree < 0)
7627                 nFree = 0;
7628
7629         return nFree;
7630
7631 }
7632
7633 static int yaffs_freeVerificationFailures;
7634
7635 static void yaffs_VerifyFreeChunks(yaffs_Device * dev)
7636 {
7637         int counted;
7638         int difference;
7639         
7640         if(yaffs_SkipVerification(dev))
7641                 return;
7642         
7643         counted = yaffs_CountFreeChunks(dev);
7644
7645         difference = dev->nFreeChunks - counted;
7646
7647         if (difference) {
7648                 T(YAFFS_TRACE_ALWAYS,
7649                   (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
7650                    dev->nFreeChunks, counted, difference));
7651                 yaffs_freeVerificationFailures++;
7652         }
7653 }
7654
7655 /*---------------------------------------- YAFFS test code ----------------------*/
7656
7657 #define yaffs_CheckStruct(structure,syze, name) \
7658         do { \
7659            if(sizeof(structure) != syze) \
7660                { \
7661                  T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),\
7662                  name,syze,sizeof(structure))); \
7663                  return YAFFS_FAIL; \
7664                 } \
7665         } while(0)
7666
7667 static int yaffs_CheckStructures(void)
7668 {
7669 /*      yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
7670 /*      yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
7671 /*      yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
7672 #ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
7673         yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
7674 #endif
7675 #ifndef CONFIG_YAFFS_WINCE
7676                 yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
7677 #endif
7678             return YAFFS_OK;
7679 }