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