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