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