yaffs Reactoring WIP
[yaffs2.git] / yaffs_yaffs2.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
14
15 #include "yaffs_guts.h"
16 #include "yaffs_trace.h"
17 #include "yaffs_yaffs2.h"
18 #include "yaffs_checkptrw.h"
19 #include "yaffs_bitmap.h"
20 #include "yaffs_qsort.h"
21 #include "yaffs_nand.h"
22 #include "yaffs_getblockinfo.h"
23
24 /*
25  * Checkpoints are really no benefit on very small partitions.
26  *
27  * To save space on small partitions don't bother with checkpoints unless
28  * the partition is at least this big.
29  */
30 #define YAFFS_CHECKPOINT_MIN_BLOCKS 60
31
32 #define YAFFS_SMALL_HOLE_THRESHOLD 4
33
34 void yaffs2_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
35 {
36         if (!dev->param.isYaffs2)
37                 return;
38
39         if((bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
40            (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
41                 T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
42                 n, bi->sequenceNumber));
43 }
44
45 /*
46  * Oldest Dirty Sequence Number handling.
47  */
48  
49 /* yaffs2_CalcOldestDirtySequence()
50  * yaffs2_FindOldestDirtySequence()
51  * Calculate the oldest dirty sequence number if we don't know it.
52  */
53 void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev)
54 {
55         int i;
56         unsigned seq;
57         unsigned blockNo = 0;
58         yaffs_BlockInfo *b;
59
60         if(!dev->param.isYaffs2)
61                 return;
62
63         /* Find the oldest dirty sequence number. */
64         seq = dev->sequenceNumber + 1;
65         b = dev->blockInfo;
66         for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
67                 if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
68                         (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock &&
69                         b->sequenceNumber < seq) {
70                         seq = b->sequenceNumber;
71                         blockNo = i;
72                 }
73                 b++;
74         }
75
76         if(blockNo){
77                 dev->oldestDirtySequence = seq;
78                 dev->oldestDirtyBlock = blockNo;
79         }
80
81 }
82
83
84 void yaffs2_FindOldestDirtySequence(yaffs_Device *dev)
85 {
86         if(!dev->param.isYaffs2)
87                 return;
88
89         if(!dev->oldestDirtySequence)
90                 yaffs2_CalcOldestDirtySequence(dev);
91 }
92
93 /*
94  * yaffs_ClearOldestDirtySequence()
95  * Called when a block is erased or marked bad. (ie. when its sequenceNumber
96  * becomes invalid). If the value matches the oldest then we clear 
97  * dev->oldestDirtySequence to force its recomputation.
98  */
99 void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi)
100 {
101
102         if(!dev->param.isYaffs2)
103                 return;
104
105         if(!bi || bi->sequenceNumber == dev->oldestDirtySequence){
106                 dev->oldestDirtySequence = 0;
107                 dev->oldestDirtyBlock = 0;
108         }
109 }
110
111 /*
112  * yaffs2_UpdateOldestDirtySequence()
113  * Update the oldest dirty sequence number whenever we dirty a block.
114  * Only do this if the oldestDirtySequence is actually being tracked.
115  */
116 void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi)
117 {
118         if(!dev->param.isYaffs2)
119                 return;
120
121         if(dev->oldestDirtySequence){
122                 if(dev->oldestDirtySequence > bi->sequenceNumber){
123                         dev->oldestDirtySequence = bi->sequenceNumber;
124                         dev->oldestDirtyBlock = blockNo;
125                 }
126         }
127 }
128
129 int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
130                                         yaffs_BlockInfo *bi)
131 {
132
133         if (!dev->param.isYaffs2)
134                 return 1;       /* disqualification only applies to yaffs2. */
135
136         if (!bi->hasShrinkHeader)
137                 return 1;       /* can gc */
138
139         yaffs2_FindOldestDirtySequence(dev);
140
141         /* Can't do gc of this block if there are any blocks older than this one that have
142          * discarded pages.
143          */
144         return (bi->sequenceNumber <= dev->oldestDirtySequence);
145 }
146
147 /*
148  * yaffs2_FindRefreshBlock()
149  * periodically finds the oldest full block by sequence number for refreshing.
150  * Only for yaffs2.
151  */
152 __u32 yaffs2_FindRefreshBlock(yaffs_Device *dev)
153 {
154         __u32 b ;
155
156         __u32 oldest = 0;
157         __u32 oldestSequence = 0;
158
159         yaffs_BlockInfo *bi;
160
161         if(!dev->param.isYaffs2)
162                 return oldest;
163
164         /*
165          * If refresh period < 10 then refreshing is disabled.
166          */
167         if(dev->param.refreshPeriod < 10)
168                 return oldest;
169
170         /*
171          * Fix broken values.
172          */
173         if(dev->refreshSkip > dev->param.refreshPeriod)
174                 dev->refreshSkip = dev->param.refreshPeriod;
175
176         if(dev->refreshSkip > 0)
177                 return oldest;
178
179         /*
180          * Refresh skip is now zero.
181          * We'll do a refresh this time around....
182          * Update the refresh skip and find the oldest block.
183          */
184         dev->refreshSkip = dev->param.refreshPeriod;
185         dev->refreshCount++;
186         bi = dev->blockInfo;
187         for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){
188
189                 if (bi->blockState == YAFFS_BLOCK_STATE_FULL){
190
191                         if(oldest < 1 ||
192                                 bi->sequenceNumber < oldestSequence){
193                                 oldest = b;
194                                 oldestSequence = bi->sequenceNumber;
195                         }
196                 }
197                 bi++;
198         }
199
200         if (oldest > 0) {
201                 T(YAFFS_TRACE_GC,
202                   (TSTR("GC refresh count %d selected block %d with sequenceNumber %d" TENDSTR),
203                    dev->refreshCount, oldest, oldestSequence));
204         }
205
206         return oldest;
207 }
208
209 int yaffs2_CheckpointRequired(yaffs_Device *dev)
210 {
211         int nblocks;
212         
213         if(!dev->param.isYaffs2)
214                 return 0;
215         
216         nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ;
217
218         return  !dev->param.skipCheckpointWrite &&
219                 (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
220 }
221
222 int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev)
223 {
224         int retval;
225
226         if(!dev->param.isYaffs2)
227                 return 0;
228
229         if (!dev->nCheckpointBlocksRequired &&
230                 yaffs2_CheckpointRequired(dev)){
231                 /* Not a valid value so recalculate */
232                 int nBytes = 0;
233                 int nBlocks;
234                 int devBlocks = (dev->param.endBlock - dev->param.startBlock + 1);
235
236                 nBytes += sizeof(yaffs_CheckpointValidity);
237                 nBytes += sizeof(yaffs_CheckpointDevice);
238                 nBytes += devBlocks * sizeof(yaffs_BlockInfo);
239                 nBytes += devBlocks * dev->chunkBitmapStride;
240                 nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjects);
241                 nBytes += (dev->tnodeSize + sizeof(__u32)) * (dev->nTnodes);
242                 nBytes += sizeof(yaffs_CheckpointValidity);
243                 nBytes += sizeof(__u32); /* checksum*/
244
245                 /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
246
247                 nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->param.nChunksPerBlock)) + 3;
248
249                 dev->nCheckpointBlocksRequired = nBlocks;
250         }
251
252         retval = dev->nCheckpointBlocksRequired - dev->blocksInCheckpoint;
253         if(retval < 0)
254                 retval = 0;
255         return retval;
256 }
257
258 /*--------------------- Checkpointing --------------------*/
259
260
261 static int yaffs2_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
262 {
263         yaffs_CheckpointValidity cp;
264
265         memset(&cp, 0, sizeof(cp));
266
267         cp.structType = sizeof(cp);
268         cp.magic = YAFFS_MAGIC;
269         cp.version = YAFFS_CHECKPOINT_VERSION;
270         cp.head = (head) ? 1 : 0;
271
272         return (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
273                 1 : 0;
274 }
275
276 static int yaffs2_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
277 {
278         yaffs_CheckpointValidity cp;
279         int ok;
280
281         ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
282
283         if (ok)
284                 ok = (cp.structType == sizeof(cp)) &&
285                      (cp.magic == YAFFS_MAGIC) &&
286                      (cp.version == YAFFS_CHECKPOINT_VERSION) &&
287                      (cp.head == ((head) ? 1 : 0));
288         return ok ? 1 : 0;
289 }
290
291 static void yaffs2_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
292                                            yaffs_Device *dev)
293 {
294         cp->nErasedBlocks = dev->nErasedBlocks;
295         cp->allocationBlock = dev->allocationBlock;
296         cp->allocationPage = dev->allocationPage;
297         cp->nFreeChunks = dev->nFreeChunks;
298
299         cp->nDeletedFiles = dev->nDeletedFiles;
300         cp->nUnlinkedFiles = dev->nUnlinkedFiles;
301         cp->nBackgroundDeletions = dev->nBackgroundDeletions;
302         cp->sequenceNumber = dev->sequenceNumber;
303
304 }
305
306 static void yaffs2_CheckpointDeviceToDevice(yaffs_Device *dev,
307                                            yaffs_CheckpointDevice *cp)
308 {
309         dev->nErasedBlocks = cp->nErasedBlocks;
310         dev->allocationBlock = cp->allocationBlock;
311         dev->allocationPage = cp->allocationPage;
312         dev->nFreeChunks = cp->nFreeChunks;
313
314         dev->nDeletedFiles = cp->nDeletedFiles;
315         dev->nUnlinkedFiles = cp->nUnlinkedFiles;
316         dev->nBackgroundDeletions = cp->nBackgroundDeletions;
317         dev->sequenceNumber = cp->sequenceNumber;
318 }
319
320
321 static int yaffs2_WriteCheckpointDevice(yaffs_Device *dev)
322 {
323         yaffs_CheckpointDevice cp;
324         __u32 nBytes;
325         __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
326
327         int ok;
328
329         /* Write device runtime values*/
330         yaffs2_DeviceToCheckpointDevice(&cp, dev);
331         cp.structType = sizeof(cp);
332
333         ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
334
335         /* Write block info */
336         if (ok) {
337                 nBytes = nBlocks * sizeof(yaffs_BlockInfo);
338                 ok = (yaffs2_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
339         }
340
341         /* Write chunk bits */
342         if (ok) {
343                 nBytes = nBlocks * dev->chunkBitmapStride;
344                 ok = (yaffs2_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
345         }
346         return   ok ? 1 : 0;
347
348 }
349
350 static int yaffs2_ReadCheckpointDevice(yaffs_Device *dev)
351 {
352         yaffs_CheckpointDevice cp;
353         __u32 nBytes;
354         __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
355
356         int ok;
357
358         ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
359         if (!ok)
360                 return 0;
361
362         if (cp.structType != sizeof(cp))
363                 return 0;
364
365
366         yaffs2_CheckpointDeviceToDevice(dev, &cp);
367
368         nBytes = nBlocks * sizeof(yaffs_BlockInfo);
369
370         ok = (yaffs2_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
371
372         if (!ok)
373                 return 0;
374         nBytes = nBlocks * dev->chunkBitmapStride;
375
376         ok = (yaffs2_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
377
378         return ok ? 1 : 0;
379 }
380
381 static void yaffs2_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
382                                            yaffs_Object *obj)
383 {
384
385         cp->objectId = obj->objectId;
386         cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
387         cp->hdrChunk = obj->hdrChunk;
388         cp->variantType = obj->variantType;
389         cp->deleted = obj->deleted;
390         cp->softDeleted = obj->softDeleted;
391         cp->unlinked = obj->unlinked;
392         cp->fake = obj->fake;
393         cp->renameAllowed = obj->renameAllowed;
394         cp->unlinkAllowed = obj->unlinkAllowed;
395         cp->serial = obj->serial;
396         cp->nDataChunks = obj->nDataChunks;
397
398         if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
399                 cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
400         else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
401                 cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
402 }
403
404 static int yaffs2_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
405 {
406
407         yaffs_Object *parent;
408
409         if (obj->variantType != cp->variantType) {
410                 T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
411                         TCONT("chunk %d does not match existing object type %d")
412                         TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
413                         obj->variantType));
414                 return 0;
415         }
416
417         obj->objectId = cp->objectId;
418
419         if (cp->parentId)
420                 parent = yaffs_FindOrCreateObjectByNumber(
421                                         obj->myDev,
422                                         cp->parentId,
423                                         YAFFS_OBJECT_TYPE_DIRECTORY);
424         else
425                 parent = NULL;
426
427         if (parent) {
428                 if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
429                         T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
430                                 TCONT(" chunk %d Parent type, %d, not directory")
431                                 TENDSTR),
432                                 cp->objectId, cp->parentId, cp->variantType,
433                                 cp->hdrChunk, parent->variantType));
434                         return 0;
435                 }
436                 yaffs_AddObjectToDirectory(parent, obj);
437         }
438
439         obj->hdrChunk = cp->hdrChunk;
440         obj->variantType = cp->variantType;
441         obj->deleted = cp->deleted;
442         obj->softDeleted = cp->softDeleted;
443         obj->unlinked = cp->unlinked;
444         obj->fake = cp->fake;
445         obj->renameAllowed = cp->renameAllowed;
446         obj->unlinkAllowed = cp->unlinkAllowed;
447         obj->serial = cp->serial;
448         obj->nDataChunks = cp->nDataChunks;
449
450         if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
451                 obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
452         else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
453                 obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
454
455         if (obj->hdrChunk > 0)
456                 obj->lazyLoaded = 1;
457         return 1;
458 }
459
460
461
462 static int yaffs2_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
463                                         __u32 level, int chunkOffset)
464 {
465         int i;
466         yaffs_Device *dev = in->myDev;
467         int ok = 1;
468
469         if (tn) {
470                 if (level > 0) {
471
472                         for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
473                                 if (tn->internal[i]) {
474                                         ok = yaffs2_CheckpointTnodeWorker(in,
475                                                         tn->internal[i],
476                                                         level - 1,
477                                                         (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
478                                 }
479                         }
480                 } else if (level == 0) {
481                         __u32 baseOffset = chunkOffset <<  YAFFS_TNODES_LEVEL0_BITS;
482                         ok = (yaffs2_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
483                         if (ok)
484                                 ok = (yaffs2_CheckpointWrite(dev, tn, dev->tnodeSize) == dev->tnodeSize);
485                 }
486         }
487
488         return ok;
489
490 }
491
492 static int yaffs2_WriteCheckpointTnodes(yaffs_Object *obj)
493 {
494         __u32 endMarker = ~0;
495         int ok = 1;
496
497         if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
498                 ok = yaffs2_CheckpointTnodeWorker(obj,
499                                             obj->variant.fileVariant.top,
500                                             obj->variant.fileVariant.topLevel,
501                                             0);
502                 if (ok)
503                         ok = (yaffs2_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
504                                 sizeof(endMarker));
505         }
506
507         return ok ? 1 : 0;
508 }
509
510 static int yaffs2_ReadCheckpointTnodes(yaffs_Object *obj)
511 {
512         __u32 baseChunk;
513         int ok = 1;
514         yaffs_Device *dev = obj->myDev;
515         yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
516         yaffs_Tnode *tn;
517         int nread = 0;
518
519         ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
520
521         while (ok && (~baseChunk)) {
522                 nread++;
523                 /* Read level 0 tnode */
524
525
526                 tn = yaffs_GetTnode(dev);
527                 if (tn){
528                         ok = (yaffs2_CheckpointRead(dev, tn, dev->tnodeSize) == dev->tnodeSize);
529                 } else
530                         ok = 0;
531
532                 if (tn && ok)
533                         ok = yaffs_AddOrFindLevel0Tnode(dev,
534                                                         fileStructPtr,
535                                                         baseChunk,
536                                                         tn) ? 1 : 0;
537
538                 if (ok)
539                         ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
540
541         }
542
543         T(YAFFS_TRACE_CHECKPOINT, (
544                 TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
545                 nread, baseChunk, ok));
546
547         return ok ? 1 : 0;
548 }
549
550
551 static int yaffs2_WriteCheckpointObjects(yaffs_Device *dev)
552 {
553         yaffs_Object *obj;
554         yaffs_CheckpointObject cp;
555         int i;
556         int ok = 1;
557         struct ylist_head *lh;
558
559
560         /* Iterate through the objects in each hash entry,
561          * dumping them to the checkpointing stream.
562          */
563
564         for (i = 0; ok &&  i <  YAFFS_NOBJECT_BUCKETS; i++) {
565                 ylist_for_each(lh, &dev->objectBucket[i].list) {
566                         if (lh) {
567                                 obj = ylist_entry(lh, yaffs_Object, hashLink);
568                                 if (!obj->deferedFree) {
569                                         yaffs2_ObjectToCheckpointObject(&cp, obj);
570                                         cp.structType = sizeof(cp);
571
572                                         T(YAFFS_TRACE_CHECKPOINT, (
573                                                 TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
574                                                 cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj));
575
576                                         ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
577
578                                         if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
579                                                 ok = yaffs2_WriteCheckpointTnodes(obj);
580                                 }
581                         }
582                 }
583         }
584
585         /* Dump end of list */
586         memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
587         cp.structType = sizeof(cp);
588
589         if (ok)
590                 ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
591
592         return ok ? 1 : 0;
593 }
594
595 static int yaffs2_ReadCheckpointObjects(yaffs_Device *dev)
596 {
597         yaffs_Object *obj;
598         yaffs_CheckpointObject cp;
599         int ok = 1;
600         int done = 0;
601         yaffs_Object *hardList = NULL;
602
603         while (ok && !done) {
604                 ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
605                 if (cp.structType != sizeof(cp)) {
606                         T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
607                                 cp.structType, (int)sizeof(cp), ok));
608                         ok = 0;
609                 }
610
611                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
612                         cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
613
614                 if (ok && cp.objectId == ~0)
615                         done = 1;
616                 else if (ok) {
617                         obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
618                         if (obj) {
619                                 ok = yaffs2_CheckpointObjectToObject(obj, &cp);
620                                 if (!ok)
621                                         break;
622                                 if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
623                                         ok = yaffs2_ReadCheckpointTnodes(obj);
624                                 } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
625                                         obj->hardLinks.next =
626                                                 (struct ylist_head *) hardList;
627                                         hardList = obj;
628                                 }
629                         } else
630                                 ok = 0;
631                 }
632         }
633
634         if (ok)
635                 yaffs_HardlinkFixup(dev, hardList);
636
637         return ok ? 1 : 0;
638 }
639
640 static int yaffs2_WriteCheckpointSum(yaffs_Device *dev)
641 {
642         __u32 checkpointSum;
643         int ok;
644
645         yaffs2_GetCheckpointSum(dev, &checkpointSum);
646
647         ok = (yaffs2_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
648
649         if (!ok)
650                 return 0;
651
652         return 1;
653 }
654
655 static int yaffs2_ReadCheckpointSum(yaffs_Device *dev)
656 {
657         __u32 checkpointSum0;
658         __u32 checkpointSum1;
659         int ok;
660
661         yaffs2_GetCheckpointSum(dev, &checkpointSum0);
662
663         ok = (yaffs2_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
664
665         if (!ok)
666                 return 0;
667
668         if (checkpointSum0 != checkpointSum1)
669                 return 0;
670
671         return 1;
672 }
673
674
675 static int yaffs2_WriteCheckpointData(yaffs_Device *dev)
676 {
677         int ok = 1;
678
679         if (!yaffs2_CheckpointRequired(dev)) {
680                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
681                 ok = 0;
682         }
683
684         if (ok)
685                 ok = yaffs2_CheckpointOpen(dev, 1);
686
687         if (ok) {
688                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
689                 ok = yaffs2_WriteCheckpointValidityMarker(dev, 1);
690         }
691         if (ok) {
692                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
693                 ok = yaffs2_WriteCheckpointDevice(dev);
694         }
695         if (ok) {
696                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
697                 ok = yaffs2_WriteCheckpointObjects(dev);
698         }
699         if (ok) {
700                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
701                 ok = yaffs2_WriteCheckpointValidityMarker(dev, 0);
702         }
703
704         if (ok)
705                 ok = yaffs2_WriteCheckpointSum(dev);
706
707         if (!yaffs2_CheckpointClose(dev))
708                 ok = 0;
709
710         if (ok)
711                 dev->isCheckpointed = 1;
712         else
713                 dev->isCheckpointed = 0;
714
715         return dev->isCheckpointed;
716 }
717
718 static int yaffs2_ReadCheckpointData(yaffs_Device *dev)
719 {
720         int ok = 1;
721         
722         if(!dev->param.isYaffs2)
723                 ok = 0;
724
725         if (ok && dev->param.skipCheckpointRead) {
726                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
727                 ok = 0;
728         }
729
730         if (ok)
731                 ok = yaffs2_CheckpointOpen(dev, 0); /* open for read */
732
733         if (ok) {
734                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
735                 ok = yaffs2_ReadCheckpointValidityMarker(dev, 1);
736         }
737         if (ok) {
738                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
739                 ok = yaffs2_ReadCheckpointDevice(dev);
740         }
741         if (ok) {
742                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
743                 ok = yaffs2_ReadCheckpointObjects(dev);
744         }
745         if (ok) {
746                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
747                 ok = yaffs2_ReadCheckpointValidityMarker(dev, 0);
748         }
749
750         if (ok) {
751                 ok = yaffs2_ReadCheckpointSum(dev);
752                 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
753         }
754
755         if (!yaffs2_CheckpointClose(dev))
756                 ok = 0;
757
758         if (ok)
759                 dev->isCheckpointed = 1;
760         else
761                 dev->isCheckpointed = 0;
762
763         return ok ? 1 : 0;
764
765 }
766
767 void yaffs2_InvalidateCheckpoint(yaffs_Device *dev)
768 {
769         if (dev->isCheckpointed ||
770                         dev->blocksInCheckpoint > 0) {
771                 dev->isCheckpointed = 0;
772                 yaffs2_CheckpointInvalidateStream(dev);
773         }
774         if (dev->param.markSuperBlockDirty)
775                 dev->param.markSuperBlockDirty(dev);
776 }
777
778
779 int yaffs_CheckpointSave(yaffs_Device *dev)
780 {
781
782         T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
783
784         yaffs_VerifyObjects(dev);
785         yaffs_VerifyBlocks(dev);
786         yaffs_VerifyFreeChunks(dev);
787
788         if (!dev->isCheckpointed) {
789                 yaffs2_InvalidateCheckpoint(dev);
790                 yaffs2_WriteCheckpointData(dev);
791         }
792
793         T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
794
795         return dev->isCheckpointed;
796 }
797
798 int yaffs2_CheckpointRestore(yaffs_Device *dev)
799 {
800         int retval;
801         T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
802
803         retval = yaffs2_ReadCheckpointData(dev);
804
805         if (dev->isCheckpointed) {
806                 yaffs_VerifyObjects(dev);
807                 yaffs_VerifyBlocks(dev);
808                 yaffs_VerifyFreeChunks(dev);
809         }
810
811         T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
812
813         return retval;
814 }
815
816 int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize)
817 {
818         /* if newsSize > oldFileSize.
819          * We're going to be writing a hole.
820          * If the hole is small then write zeros otherwise write a start of hole marker.
821          */
822                 
823
824         loff_t oldFileSize;
825         int increase;
826         int smallHole   ;
827         int result = YAFFS_OK;
828         yaffs_Device *dev = NULL;
829
830         __u8 *localBuffer = NULL;
831         
832         int smallIncreaseOk = 0;
833         
834         if(!obj)
835                 return YAFFS_FAIL;
836
837         if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
838                 return YAFFS_FAIL;
839         
840         dev = obj->myDev;
841         
842         /* Bail out if not yaffs2 mode */
843         if(!dev->param.isYaffs2)
844                 return YAFFS_OK;
845
846         oldFileSize = obj->variant.fileVariant.fileSize;
847
848         if (newSize <= oldFileSize)
849                 return YAFFS_OK;
850
851         increase = newSize - oldFileSize;
852
853         if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk &&
854                 yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
855                 smallHole = 1;
856         else
857                 smallHole = 0;
858
859         if(smallHole)
860                 localBuffer= yaffs_GetTempBuffer(dev, __LINE__);
861         
862         if(localBuffer){
863                 /* fill hole with zero bytes */
864                 int pos = oldFileSize;
865                 int thisWrite;
866                 int written;
867                 memset(localBuffer,0,dev->nDataBytesPerChunk);
868                 smallIncreaseOk = 1;
869
870                 while(increase > 0 && smallIncreaseOk){
871                         thisWrite = increase;
872                         if(thisWrite > dev->nDataBytesPerChunk)
873                                 thisWrite = dev->nDataBytesPerChunk;
874                         written = yaffs_DoWriteDataToFile(obj,localBuffer,pos,thisWrite,0);
875                         if(written == thisWrite){
876                                 pos += thisWrite;
877                                 increase -= thisWrite;
878                         } else
879                                 smallIncreaseOk = 0;
880                 }
881
882                 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
883
884                 /* If we were out of space then reverse any chunks we've added */               
885                 if(!smallIncreaseOk)
886                         yaffs_ResizeDown(obj, oldFileSize);
887         }
888         
889         if (!smallIncreaseOk &&
890                 obj->parent &&
891                 obj->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
892                 obj->parent->objectId != YAFFS_OBJECTID_DELETED){
893                 /* Write a hole start header with the old file size */
894                 yaffs_UpdateObjectHeader(obj, NULL, 0, 1, 0, NULL);
895         }
896
897         return result;
898
899 }
900
901
902 typedef struct {
903         int seq;
904         int block;
905 } yaffs_BlockIndex;
906
907
908 static int yaffs2_ybicmp(const void *a, const void *b)
909 {
910         register int aseq = ((yaffs_BlockIndex *)a)->seq;
911         register int bseq = ((yaffs_BlockIndex *)b)->seq;
912         register int ablock = ((yaffs_BlockIndex *)a)->block;
913         register int bblock = ((yaffs_BlockIndex *)b)->block;
914         if (aseq == bseq)
915                 return ablock - bblock;
916         else
917                 return aseq - bseq;
918 }
919
920 int yaffs2_ScanBackwards(yaffs_Device *dev)
921 {
922         yaffs_ExtendedTags tags;
923         int blk;
924         int blockIterator;
925         int startIterator;
926         int endIterator;
927         int nBlocksToScan = 0;
928
929         int chunk;
930         int result;
931         int c;
932         int deleted;
933         yaffs_BlockState state;
934         yaffs_Object *hardList = NULL;
935         yaffs_BlockInfo *bi;
936         __u32 sequenceNumber;
937         yaffs_ObjectHeader *oh;
938         yaffs_Object *in;
939         yaffs_Object *parent;
940         int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
941         int itsUnlinked;
942         __u8 *chunkData;
943
944         int fileSize;
945         int isShrink;
946         int foundChunksInBlock;
947         int equivalentObjectId;
948         int alloc_failed = 0;
949
950
951         yaffs_BlockIndex *blockIndex = NULL;
952         int altBlockIndex = 0;
953
954         T(YAFFS_TRACE_SCAN,
955           (TSTR
956            ("yaffs2_ScanBackwards starts  intstartblk %d intendblk %d..."
957             TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
958
959
960         dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
961
962         blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
963
964         if (!blockIndex) {
965                 blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
966                 altBlockIndex = 1;
967         }
968
969         if (!blockIndex) {
970                 T(YAFFS_TRACE_SCAN,
971                   (TSTR("yaffs2_ScanBackwards() could not allocate block index!" TENDSTR)));
972                 return YAFFS_FAIL;
973         }
974
975         dev->blocksInCheckpoint = 0;
976
977         chunkData = yaffs_GetTempBuffer(dev, __LINE__);
978
979         /* Scan all the blocks to determine their state */
980         bi = dev->blockInfo;
981         for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
982                 yaffs_ClearChunkBits(dev, blk);
983                 bi->pagesInUse = 0;
984                 bi->softDeletions = 0;
985
986                 yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
987
988                 bi->blockState = state;
989                 bi->sequenceNumber = sequenceNumber;
990
991                 if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
992                         bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
993                 if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
994                         bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
995
996                 T(YAFFS_TRACE_SCAN_DEBUG,
997                   (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
998                    state, sequenceNumber));
999
1000
1001                 if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
1002                         dev->blocksInCheckpoint++;
1003
1004                 } else if (state == YAFFS_BLOCK_STATE_DEAD) {
1005                         T(YAFFS_TRACE_BAD_BLOCKS,
1006                           (TSTR("block %d is bad" TENDSTR), blk));
1007                 } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
1008                         T(YAFFS_TRACE_SCAN_DEBUG,
1009                           (TSTR("Block empty " TENDSTR)));
1010                         dev->nErasedBlocks++;
1011                         dev->nFreeChunks += dev->param.nChunksPerBlock;
1012                 } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
1013
1014                         /* Determine the highest sequence number */
1015                         if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
1016                             sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
1017
1018                                 blockIndex[nBlocksToScan].seq = sequenceNumber;
1019                                 blockIndex[nBlocksToScan].block = blk;
1020
1021                                 nBlocksToScan++;
1022
1023                                 if (sequenceNumber >= dev->sequenceNumber)
1024                                         dev->sequenceNumber = sequenceNumber;
1025                         } else {
1026                                 /* TODO: Nasty sequence number! */
1027                                 T(YAFFS_TRACE_SCAN,
1028                                   (TSTR
1029                                    ("Block scanning block %d has bad sequence number %d"
1030                                     TENDSTR), blk, sequenceNumber));
1031
1032                         }
1033                 }
1034                 bi++;
1035         }
1036
1037         T(YAFFS_TRACE_SCAN,
1038         (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
1039
1040
1041
1042         YYIELD();
1043
1044         /* Sort the blocks by sequence number*/
1045         yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
1046
1047         YYIELD();
1048
1049         T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
1050
1051         /* Now scan the blocks looking at the data. */
1052         startIterator = 0;
1053         endIterator = nBlocksToScan - 1;
1054         T(YAFFS_TRACE_SCAN_DEBUG,
1055           (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
1056
1057         /* For each block.... backwards */
1058         for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
1059                         blockIterator--) {
1060                 /* Cooperative multitasking! This loop can run for so
1061                    long that watchdog timers expire. */
1062                 YYIELD();
1063
1064                 /* get the block to scan in the correct order */
1065                 blk = blockIndex[blockIterator].block;
1066
1067                 bi = yaffs_GetBlockInfo(dev, blk);
1068
1069
1070                 state = bi->blockState;
1071
1072                 deleted = 0;
1073
1074                 /* For each chunk in each block that needs scanning.... */
1075                 foundChunksInBlock = 0;
1076                 for (c = dev->param.nChunksPerBlock - 1;
1077                      !alloc_failed && c >= 0 &&
1078                      (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
1079                       state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
1080                         /* Scan backwards...
1081                          * Read the tags and decide what to do
1082                          */
1083
1084                         chunk = blk * dev->param.nChunksPerBlock + c;
1085
1086                         result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
1087                                                         &tags);
1088
1089                         /* Let's have a good look at this chunk... */
1090
1091                         if (!tags.chunkUsed) {
1092                                 /* An unassigned chunk in the block.
1093                                  * If there are used chunks after this one, then
1094                                  * it is a chunk that was skipped due to failing the erased
1095                                  * check. Just skip it so that it can be deleted.
1096                                  * But, more typically, We get here when this is an unallocated
1097                                  * chunk and his means that either the block is empty or
1098                                  * this is the one being allocated from
1099                                  */
1100
1101                                 if (foundChunksInBlock) {
1102                                         /* This is a chunk that was skipped due to failing the erased check */
1103                                 } else if (c == 0) {
1104                                         /* We're looking at the first chunk in the block so the block is unused */
1105                                         state = YAFFS_BLOCK_STATE_EMPTY;
1106                                         dev->nErasedBlocks++;
1107                                 } else {
1108                                         if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
1109                                             state == YAFFS_BLOCK_STATE_ALLOCATING) {
1110                                                 if (dev->sequenceNumber == bi->sequenceNumber) {
1111                                                         /* this is the block being allocated from */
1112
1113                                                         T(YAFFS_TRACE_SCAN,
1114                                                           (TSTR
1115                                                            (" Allocating from %d %d"
1116                                                             TENDSTR), blk, c));
1117
1118                                                         state = YAFFS_BLOCK_STATE_ALLOCATING;
1119                                                         dev->allocationBlock = blk;
1120                                                         dev->allocationPage = c;
1121                                                         dev->allocationBlockFinder = blk;
1122                                                 } else {
1123                                                         /* This is a partially written block that is not
1124                                                          * the current allocation block.
1125                                                          */
1126
1127                                                          T(YAFFS_TRACE_SCAN,
1128                                                          (TSTR("Partially written block %d detected" TENDSTR),
1129                                                          blk));
1130                                                 }
1131                                         }
1132                                 }
1133
1134                                 dev->nFreeChunks++;
1135
1136                         } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
1137                                 T(YAFFS_TRACE_SCAN,
1138                                   (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
1139                                   blk, c));
1140
1141                                   dev->nFreeChunks++;
1142
1143                         } else if (tags.chunkId > 0) {
1144                                 /* chunkId > 0 so it is a data chunk... */
1145                                 unsigned int endpos;
1146                                 __u32 chunkBase =
1147                                     (tags.chunkId - 1) * dev->nDataBytesPerChunk;
1148
1149                                 foundChunksInBlock = 1;
1150
1151
1152                                 yaffs_SetChunkBit(dev, blk, c);
1153                                 bi->pagesInUse++;
1154
1155                                 in = yaffs_FindOrCreateObjectByNumber(dev,
1156                                                                       tags.
1157                                                                       objectId,
1158                                                                       YAFFS_OBJECT_TYPE_FILE);
1159                                 if (!in) {
1160                                         /* Out of memory */
1161                                         alloc_failed = 1;
1162                                 }
1163
1164                                 if (in &&
1165                                     in->variantType == YAFFS_OBJECT_TYPE_FILE
1166                                     && chunkBase < in->variant.fileVariant.shrinkSize) {
1167                                         /* This has not been invalidated by a resize */
1168                                         if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, -1)) {
1169                                                 alloc_failed = 1;
1170                                         }
1171
1172                                         /* File size is calculated by looking at the data chunks if we have not
1173                                          * seen an object header yet. Stop this practice once we find an object header.
1174                                          */
1175                                         endpos = chunkBase + tags.byteCount;
1176
1177                                         if (!in->valid &&       /* have not got an object header yet */
1178                                             in->variant.fileVariant.scannedFileSize < endpos) {
1179                                                 in->variant.fileVariant.scannedFileSize = endpos;
1180                                                 in->variant.fileVariant.fileSize = endpos;
1181                                         }
1182
1183                                 } else if (in) {
1184                                         /* This chunk has been invalidated by a resize, or a past file deletion
1185                                          * so delete the chunk*/
1186                                         yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
1187
1188                                 }
1189                         } else {
1190                                 /* chunkId == 0, so it is an ObjectHeader.
1191                                  * Thus, we read in the object header and make the object
1192                                  */
1193                                 foundChunksInBlock = 1;
1194
1195                                 yaffs_SetChunkBit(dev, blk, c);
1196                                 bi->pagesInUse++;
1197
1198                                 oh = NULL;
1199                                 in = NULL;
1200
1201                                 if (tags.extraHeaderInfoAvailable) {
1202                                         in = yaffs_FindOrCreateObjectByNumber(dev,
1203                                                 tags.objectId,
1204                                                 tags.extraObjectType);
1205                                         if (!in)
1206                                                 alloc_failed = 1;
1207                                 }
1208
1209                                 if (!in ||
1210                                     (!in->valid && dev->param.disableLazyLoad) ||
1211                                     tags.extraShadows ||
1212                                     (!in->valid &&
1213                                     (tags.objectId == YAFFS_OBJECTID_ROOT ||
1214                                      tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
1215
1216                                         /* If we don't have  valid info then we need to read the chunk
1217                                          * TODO In future we can probably defer reading the chunk and
1218                                          * living with invalid data until needed.
1219                                          */
1220
1221                                         result = yaffs_ReadChunkWithTagsFromNAND(dev,
1222                                                                         chunk,
1223                                                                         chunkData,
1224                                                                         NULL);
1225
1226                                         oh = (yaffs_ObjectHeader *) chunkData;
1227
1228                                         if (dev->param.inbandTags) {
1229                                                 /* Fix up the header if they got corrupted by inband tags */
1230                                                 oh->shadowsObject = oh->inbandShadowsObject;
1231                                                 oh->isShrink = oh->inbandIsShrink;
1232                                         }
1233
1234                                         if (!in) {
1235                                                 in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
1236                                                 if (!in)
1237                                                         alloc_failed = 1;
1238                                         }
1239
1240                                 }
1241
1242                                 if (!in) {
1243                                         /* TODO Hoosterman we have a problem! */
1244                                         T(YAFFS_TRACE_ERROR,
1245                                           (TSTR
1246                                            ("yaffs tragedy: Could not make object for object  %d at chunk %d during scan"
1247                                             TENDSTR), tags.objectId, chunk));
1248                                         continue;
1249                                 }
1250
1251                                 if (in->valid) {
1252                                         /* We have already filled this one.
1253                                          * We have a duplicate that will be discarded, but
1254                                          * we first have to suck out resize info if it is a file.
1255                                          */
1256
1257                                         if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
1258                                              ((oh &&
1259                                                oh->type == YAFFS_OBJECT_TYPE_FILE) ||
1260                                               (tags.extraHeaderInfoAvailable  &&
1261                                                tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
1262                                                 __u32 thisSize =
1263                                                     (oh) ? oh->fileSize : tags.
1264                                                     extraFileLength;
1265                                                 __u32 parentObjectId =
1266                                                     (oh) ? oh->
1267                                                     parentObjectId : tags.
1268                                                     extraParentObjectId;
1269
1270
1271                                                 isShrink =
1272                                                     (oh) ? oh->isShrink : tags.
1273                                                     extraIsShrinkHeader;
1274
1275                                                 /* If it is deleted (unlinked at start also means deleted)
1276                                                  * we treat the file size as being zeroed at this point.
1277                                                  */
1278                                                 if (parentObjectId ==
1279                                                     YAFFS_OBJECTID_DELETED
1280                                                     || parentObjectId ==
1281                                                     YAFFS_OBJECTID_UNLINKED) {
1282                                                         thisSize = 0;
1283                                                         isShrink = 1;
1284                                                 }
1285
1286                                                 if (isShrink && in->variant.fileVariant.shrinkSize > thisSize)
1287                                                         in->variant.fileVariant.shrinkSize = thisSize;
1288
1289                                                 if (isShrink)
1290                                                         bi->hasShrinkHeader = 1;
1291
1292                                         }
1293                                         /* Use existing - destroy this one. */
1294                                         yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
1295
1296                                 }
1297
1298                                 if (!in->valid && in->variantType !=
1299                                     (oh ? oh->type : tags.extraObjectType))
1300                                         T(YAFFS_TRACE_ERROR, (
1301                                                 TSTR("yaffs tragedy: Bad object type, "
1302                                             TCONT("%d != %d, for object %d at chunk ")
1303                                             TCONT("%d during scan")
1304                                                 TENDSTR), oh ?
1305                                             oh->type : tags.extraObjectType,
1306                                             in->variantType, tags.objectId,
1307                                             chunk));
1308
1309                                 if (!in->valid &&
1310                                     (tags.objectId == YAFFS_OBJECTID_ROOT ||
1311                                      tags.objectId ==
1312                                      YAFFS_OBJECTID_LOSTNFOUND)) {
1313                                         /* We only load some info, don't fiddle with directory structure */
1314                                         in->valid = 1;
1315
1316                                         if (oh) {
1317                                                 in->variantType = oh->type;
1318
1319                                                 in->yst_mode = oh->yst_mode;
1320 #ifdef CONFIG_YAFFS_WINCE
1321                                                 in->win_atime[0] = oh->win_atime[0];
1322                                                 in->win_ctime[0] = oh->win_ctime[0];
1323                                                 in->win_mtime[0] = oh->win_mtime[0];
1324                                                 in->win_atime[1] = oh->win_atime[1];
1325                                                 in->win_ctime[1] = oh->win_ctime[1];
1326                                                 in->win_mtime[1] = oh->win_mtime[1];
1327 #else
1328                                                 in->yst_uid = oh->yst_uid;
1329                                                 in->yst_gid = oh->yst_gid;
1330                                                 in->yst_atime = oh->yst_atime;
1331                                                 in->yst_mtime = oh->yst_mtime;
1332                                                 in->yst_ctime = oh->yst_ctime;
1333                                                 in->yst_rdev = oh->yst_rdev;
1334
1335 #endif
1336                                         } else {
1337                                                 in->variantType = tags.extraObjectType;
1338                                                 in->lazyLoaded = 1;
1339                                         }
1340
1341                                         in->hdrChunk = chunk;
1342
1343                                 } else if (!in->valid) {
1344                                         /* we need to load this info */
1345
1346                                         in->valid = 1;
1347                                         in->hdrChunk = chunk;
1348
1349                                         if (oh) {
1350                                                 in->variantType = oh->type;
1351
1352                                                 in->yst_mode = oh->yst_mode;
1353 #ifdef CONFIG_YAFFS_WINCE
1354                                                 in->win_atime[0] = oh->win_atime[0];
1355                                                 in->win_ctime[0] = oh->win_ctime[0];
1356                                                 in->win_mtime[0] = oh->win_mtime[0];
1357                                                 in->win_atime[1] = oh->win_atime[1];
1358                                                 in->win_ctime[1] = oh->win_ctime[1];
1359                                                 in->win_mtime[1] = oh->win_mtime[1];
1360 #else
1361                                                 in->yst_uid = oh->yst_uid;
1362                                                 in->yst_gid = oh->yst_gid;
1363                                                 in->yst_atime = oh->yst_atime;
1364                                                 in->yst_mtime = oh->yst_mtime;
1365                                                 in->yst_ctime = oh->yst_ctime;
1366                                                 in->yst_rdev = oh->yst_rdev;
1367 #endif
1368
1369                                                 if (oh->shadowsObject > 0)
1370                                                         yaffs_HandleShadowedObject(dev,
1371                                                                            oh->
1372                                                                            shadowsObject,
1373                                                                            1);
1374                                                         
1375
1376
1377                                                 yaffs_SetObjectName(in, oh->name);
1378                                                 parent =
1379                                                     yaffs_FindOrCreateObjectByNumber
1380                                                         (dev, oh->parentObjectId,
1381                                                          YAFFS_OBJECT_TYPE_DIRECTORY);
1382
1383                                                  fileSize = oh->fileSize;
1384                                                  isShrink = oh->isShrink;
1385                                                  equivalentObjectId = oh->equivalentObjectId;
1386
1387                                         } else {
1388                                                 in->variantType = tags.extraObjectType;
1389                                                 parent =
1390                                                     yaffs_FindOrCreateObjectByNumber
1391                                                         (dev, tags.extraParentObjectId,
1392                                                          YAFFS_OBJECT_TYPE_DIRECTORY);
1393                                                  fileSize = tags.extraFileLength;
1394                                                  isShrink = tags.extraIsShrinkHeader;
1395                                                  equivalentObjectId = tags.extraEquivalentObjectId;
1396                                                 in->lazyLoaded = 1;
1397
1398                                         }
1399                                         in->dirty = 0;
1400
1401                                         if (!parent)
1402                                                 alloc_failed = 1;
1403
1404                                         /* directory stuff...
1405                                          * hook up to parent
1406                                          */
1407
1408                                         if (parent && parent->variantType ==
1409                                             YAFFS_OBJECT_TYPE_UNKNOWN) {
1410                                                 /* Set up as a directory */
1411                                                 parent->variantType =
1412                                                         YAFFS_OBJECT_TYPE_DIRECTORY;
1413                                                 YINIT_LIST_HEAD(&parent->variant.
1414                                                         directoryVariant.
1415                                                         children);
1416                                         } else if (!parent || parent->variantType !=
1417                                                    YAFFS_OBJECT_TYPE_DIRECTORY) {
1418                                                 /* Hoosterman, another problem....
1419                                                  * We're trying to use a non-directory as a directory
1420                                                  */
1421
1422                                                 T(YAFFS_TRACE_ERROR,
1423                                                   (TSTR
1424                                                    ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
1425                                                     TENDSTR)));
1426                                                 parent = dev->lostNFoundDir;
1427                                         }
1428
1429                                         yaffs_AddObjectToDirectory(parent, in);
1430
1431                                         itsUnlinked = (parent == dev->deletedDir) ||
1432                                                       (parent == dev->unlinkedDir);
1433
1434                                         if (isShrink) {
1435                                                 /* Mark the block as having a shrinkHeader */
1436                                                 bi->hasShrinkHeader = 1;
1437                                         }
1438
1439                                         /* Note re hardlinks.
1440                                          * Since we might scan a hardlink before its equivalent object is scanned
1441                                          * we put them all in a list.
1442                                          * After scanning is complete, we should have all the objects, so we run
1443                                          * through this list and fix up all the chains.
1444                                          */
1445
1446                                         switch (in->variantType) {
1447                                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1448                                                 /* Todo got a problem */
1449                                                 break;
1450                                         case YAFFS_OBJECT_TYPE_FILE:
1451
1452                                                 if (in->variant.fileVariant.
1453                                                     scannedFileSize < fileSize) {
1454                                                         /* This covers the case where the file size is greater
1455                                                          * than where the data is
1456                                                          * This will happen if the file is resized to be larger
1457                                                          * than its current data extents.
1458                                                          */
1459                                                         in->variant.fileVariant.fileSize = fileSize;
1460                                                         in->variant.fileVariant.scannedFileSize = fileSize;
1461                                                 }
1462
1463                                                 if (in->variant.fileVariant.shrinkSize > fileSize)
1464                                                         in->variant.fileVariant.shrinkSize = fileSize;
1465                                 
1466
1467                                                 break;
1468                                         case YAFFS_OBJECT_TYPE_HARDLINK:
1469                                                 if (!itsUnlinked) {
1470                                                         in->variant.hardLinkVariant.equivalentObjectId =
1471                                                                 equivalentObjectId;
1472                                                         in->hardLinks.next =
1473                                                                 (struct ylist_head *) hardList;
1474                                                         hardList = in;
1475                                                 }
1476                                                 break;
1477                                         case YAFFS_OBJECT_TYPE_DIRECTORY:
1478                                                 /* Do nothing */
1479                                                 break;
1480                                         case YAFFS_OBJECT_TYPE_SPECIAL:
1481                                                 /* Do nothing */
1482                                                 break;
1483                                         case YAFFS_OBJECT_TYPE_SYMLINK:
1484                                                 if (oh) {
1485                                                         in->variant.symLinkVariant.alias =
1486                                                                 yaffs_CloneString(oh->alias);
1487                                                         if (!in->variant.symLinkVariant.alias)
1488                                                                 alloc_failed = 1;
1489                                                 }
1490                                                 break;
1491                                         }
1492
1493                                 }
1494
1495                         }
1496
1497                 } /* End of scanning for each chunk */
1498
1499                 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
1500                         /* If we got this far while scanning, then the block is fully allocated. */
1501                         state = YAFFS_BLOCK_STATE_FULL;
1502                 }
1503
1504
1505                 bi->blockState = state;
1506
1507                 /* Now let's see if it was dirty */
1508                 if (bi->pagesInUse == 0 &&
1509                     !bi->hasShrinkHeader &&
1510                     bi->blockState == YAFFS_BLOCK_STATE_FULL) {
1511                         yaffs_BlockBecameDirty(dev, blk);
1512                 }
1513
1514         }
1515         
1516         yaffs_SkipRestOfBlock(dev);
1517
1518         if (altBlockIndex)
1519                 YFREE_ALT(blockIndex);
1520         else
1521                 YFREE(blockIndex);
1522
1523         /* Ok, we've done all the scanning.
1524          * Fix up the hard link chains.
1525          * We should now have scanned all the objects, now it's time to add these
1526          * hardlinks.
1527          */
1528         yaffs_HardlinkFixup(dev, hardList);
1529
1530
1531         yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
1532
1533         if (alloc_failed)
1534                 return YAFFS_FAIL;
1535
1536         T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_ScanBackwards ends" TENDSTR)));
1537
1538         return YAFFS_OK;
1539 }