2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
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.
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"
25 * Checkpoints are really no benefit on very small partitions.
27 * To save space on small partitions don't bother with checkpoints unless
28 * the partition is at least this big.
30 #define YAFFS_CHECKPOINT_MIN_BLOCKS 60
32 #define YAFFS_SMALL_HOLE_THRESHOLD 4
34 void yaffs2_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
36 if (!dev->param.isYaffs2)
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));
46 * Oldest Dirty Sequence Number handling.
49 /* yaffs2_CalcOldestDirtySequence()
50 * yaffs2_FindOldestDirtySequence()
51 * Calculate the oldest dirty sequence number if we don't know it.
53 void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev)
60 if(!dev->param.isYaffs2)
63 /* Find the oldest dirty sequence number. */
64 seq = dev->sequenceNumber + 1;
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;
77 dev->oldestDirtySequence = seq;
78 dev->oldestDirtyBlock = blockNo;
84 void yaffs2_FindOldestDirtySequence(yaffs_Device *dev)
86 if(!dev->param.isYaffs2)
89 if(!dev->oldestDirtySequence)
90 yaffs2_CalcOldestDirtySequence(dev);
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.
99 void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi)
102 if(!dev->param.isYaffs2)
105 if(!bi || bi->sequenceNumber == dev->oldestDirtySequence){
106 dev->oldestDirtySequence = 0;
107 dev->oldestDirtyBlock = 0;
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.
116 void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi)
118 if(!dev->param.isYaffs2)
121 if(dev->oldestDirtySequence){
122 if(dev->oldestDirtySequence > bi->sequenceNumber){
123 dev->oldestDirtySequence = bi->sequenceNumber;
124 dev->oldestDirtyBlock = blockNo;
129 int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
133 if (!dev->param.isYaffs2)
134 return 1; /* disqualification only applies to yaffs2. */
136 if (!bi->hasShrinkHeader)
137 return 1; /* can gc */
139 yaffs2_FindOldestDirtySequence(dev);
141 /* Can't do gc of this block if there are any blocks older than this one that have
144 return (bi->sequenceNumber <= dev->oldestDirtySequence);
148 * yaffs2_FindRefreshBlock()
149 * periodically finds the oldest full block by sequence number for refreshing.
152 __u32 yaffs2_FindRefreshBlock(yaffs_Device *dev)
157 __u32 oldestSequence = 0;
161 if(!dev->param.isYaffs2)
165 * If refresh period < 10 then refreshing is disabled.
167 if(dev->param.refreshPeriod < 10)
173 if(dev->refreshSkip > dev->param.refreshPeriod)
174 dev->refreshSkip = dev->param.refreshPeriod;
176 if(dev->refreshSkip > 0)
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.
184 dev->refreshSkip = dev->param.refreshPeriod;
187 for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){
189 if (bi->blockState == YAFFS_BLOCK_STATE_FULL){
192 bi->sequenceNumber < oldestSequence){
194 oldestSequence = bi->sequenceNumber;
202 (TSTR("GC refresh count %d selected block %d with sequenceNumber %d" TENDSTR),
203 dev->refreshCount, oldest, oldestSequence));
209 int yaffs2_CheckpointRequired(yaffs_Device *dev)
213 if(!dev->param.isYaffs2)
216 nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ;
218 return !dev->param.skipCheckpointWrite &&
219 (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
222 int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev)
226 if(!dev->param.isYaffs2)
229 if (!dev->nCheckpointBlocksRequired &&
230 yaffs2_CheckpointRequired(dev)){
231 /* Not a valid value so recalculate */
234 int devBlocks = (dev->param.endBlock - dev->param.startBlock + 1);
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*/
245 /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
247 nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->param.nChunksPerBlock)) + 3;
249 dev->nCheckpointBlocksRequired = nBlocks;
252 retval = dev->nCheckpointBlocksRequired - dev->blocksInCheckpoint;
258 /*--------------------- Checkpointing --------------------*/
261 static int yaffs2_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
263 yaffs_CheckpointValidity cp;
265 memset(&cp, 0, sizeof(cp));
267 cp.structType = sizeof(cp);
268 cp.magic = YAFFS_MAGIC;
269 cp.version = YAFFS_CHECKPOINT_VERSION;
270 cp.head = (head) ? 1 : 0;
272 return (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
276 static int yaffs2_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
278 yaffs_CheckpointValidity cp;
281 ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
284 ok = (cp.structType == sizeof(cp)) &&
285 (cp.magic == YAFFS_MAGIC) &&
286 (cp.version == YAFFS_CHECKPOINT_VERSION) &&
287 (cp.head == ((head) ? 1 : 0));
291 static void yaffs2_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
294 cp->nErasedBlocks = dev->nErasedBlocks;
295 cp->allocationBlock = dev->allocationBlock;
296 cp->allocationPage = dev->allocationPage;
297 cp->nFreeChunks = dev->nFreeChunks;
299 cp->nDeletedFiles = dev->nDeletedFiles;
300 cp->nUnlinkedFiles = dev->nUnlinkedFiles;
301 cp->nBackgroundDeletions = dev->nBackgroundDeletions;
302 cp->sequenceNumber = dev->sequenceNumber;
306 static void yaffs2_CheckpointDeviceToDevice(yaffs_Device *dev,
307 yaffs_CheckpointDevice *cp)
309 dev->nErasedBlocks = cp->nErasedBlocks;
310 dev->allocationBlock = cp->allocationBlock;
311 dev->allocationPage = cp->allocationPage;
312 dev->nFreeChunks = cp->nFreeChunks;
314 dev->nDeletedFiles = cp->nDeletedFiles;
315 dev->nUnlinkedFiles = cp->nUnlinkedFiles;
316 dev->nBackgroundDeletions = cp->nBackgroundDeletions;
317 dev->sequenceNumber = cp->sequenceNumber;
321 static int yaffs2_WriteCheckpointDevice(yaffs_Device *dev)
323 yaffs_CheckpointDevice cp;
325 __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
329 /* Write device runtime values*/
330 yaffs2_DeviceToCheckpointDevice(&cp, dev);
331 cp.structType = sizeof(cp);
333 ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
335 /* Write block info */
337 nBytes = nBlocks * sizeof(yaffs_BlockInfo);
338 ok = (yaffs2_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
341 /* Write chunk bits */
343 nBytes = nBlocks * dev->chunkBitmapStride;
344 ok = (yaffs2_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
350 static int yaffs2_ReadCheckpointDevice(yaffs_Device *dev)
352 yaffs_CheckpointDevice cp;
354 __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
358 ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
362 if (cp.structType != sizeof(cp))
366 yaffs2_CheckpointDeviceToDevice(dev, &cp);
368 nBytes = nBlocks * sizeof(yaffs_BlockInfo);
370 ok = (yaffs2_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
374 nBytes = nBlocks * dev->chunkBitmapStride;
376 ok = (yaffs2_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
381 static void yaffs2_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
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;
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;
404 static int yaffs2_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
407 yaffs_Object *parent;
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,
417 obj->objectId = cp->objectId;
420 parent = yaffs_FindOrCreateObjectByNumber(
423 YAFFS_OBJECT_TYPE_DIRECTORY);
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")
432 cp->objectId, cp->parentId, cp->variantType,
433 cp->hdrChunk, parent->variantType));
436 yaffs_AddObjectToDirectory(parent, obj);
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;
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;
455 if (obj->hdrChunk > 0)
462 static int yaffs2_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
463 __u32 level, int chunkOffset)
466 yaffs_Device *dev = in->myDev;
472 for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
473 if (tn->internal[i]) {
474 ok = yaffs2_CheckpointTnodeWorker(in,
477 (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
480 } else if (level == 0) {
481 __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
482 ok = (yaffs2_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
484 ok = (yaffs2_CheckpointWrite(dev, tn, dev->tnodeSize) == dev->tnodeSize);
492 static int yaffs2_WriteCheckpointTnodes(yaffs_Object *obj)
494 __u32 endMarker = ~0;
497 if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
498 ok = yaffs2_CheckpointTnodeWorker(obj,
499 obj->variant.fileVariant.top,
500 obj->variant.fileVariant.topLevel,
503 ok = (yaffs2_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
510 static int yaffs2_ReadCheckpointTnodes(yaffs_Object *obj)
514 yaffs_Device *dev = obj->myDev;
515 yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
519 ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
521 while (ok && (~baseChunk)) {
523 /* Read level 0 tnode */
526 tn = yaffs_GetTnode(dev);
528 ok = (yaffs2_CheckpointRead(dev, tn, dev->tnodeSize) == dev->tnodeSize);
533 ok = yaffs_AddOrFindLevel0Tnode(dev,
539 ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
543 T(YAFFS_TRACE_CHECKPOINT, (
544 TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
545 nread, baseChunk, ok));
551 static int yaffs2_WriteCheckpointObjects(yaffs_Device *dev)
554 yaffs_CheckpointObject cp;
557 struct ylist_head *lh;
560 /* Iterate through the objects in each hash entry,
561 * dumping them to the checkpointing stream.
564 for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
565 ylist_for_each(lh, &dev->objectBucket[i].list) {
567 obj = ylist_entry(lh, yaffs_Object, hashLink);
568 if (!obj->deferedFree) {
569 yaffs2_ObjectToCheckpointObject(&cp, obj);
570 cp.structType = sizeof(cp);
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));
576 ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
578 if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
579 ok = yaffs2_WriteCheckpointTnodes(obj);
585 /* Dump end of list */
586 memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
587 cp.structType = sizeof(cp);
590 ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
595 static int yaffs2_ReadCheckpointObjects(yaffs_Device *dev)
598 yaffs_CheckpointObject cp;
601 yaffs_Object *hardList = NULL;
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));
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));
614 if (ok && cp.objectId == ~0)
617 obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
619 ok = yaffs2_CheckpointObjectToObject(obj, &cp);
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;
635 yaffs_HardlinkFixup(dev, hardList);
640 static int yaffs2_WriteCheckpointSum(yaffs_Device *dev)
645 yaffs2_GetCheckpointSum(dev, &checkpointSum);
647 ok = (yaffs2_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
655 static int yaffs2_ReadCheckpointSum(yaffs_Device *dev)
657 __u32 checkpointSum0;
658 __u32 checkpointSum1;
661 yaffs2_GetCheckpointSum(dev, &checkpointSum0);
663 ok = (yaffs2_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
668 if (checkpointSum0 != checkpointSum1)
675 static int yaffs2_WriteCheckpointData(yaffs_Device *dev)
679 if (!yaffs2_CheckpointRequired(dev)) {
680 T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
685 ok = yaffs2_CheckpointOpen(dev, 1);
688 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
689 ok = yaffs2_WriteCheckpointValidityMarker(dev, 1);
692 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
693 ok = yaffs2_WriteCheckpointDevice(dev);
696 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
697 ok = yaffs2_WriteCheckpointObjects(dev);
700 T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
701 ok = yaffs2_WriteCheckpointValidityMarker(dev, 0);
705 ok = yaffs2_WriteCheckpointSum(dev);
707 if (!yaffs2_CheckpointClose(dev))
711 dev->isCheckpointed = 1;
713 dev->isCheckpointed = 0;
715 return dev->isCheckpointed;
718 static int yaffs2_ReadCheckpointData(yaffs_Device *dev)
722 if(!dev->param.isYaffs2)
725 if (ok && dev->param.skipCheckpointRead) {
726 T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
731 ok = yaffs2_CheckpointOpen(dev, 0); /* open for read */
734 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
735 ok = yaffs2_ReadCheckpointValidityMarker(dev, 1);
738 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
739 ok = yaffs2_ReadCheckpointDevice(dev);
742 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
743 ok = yaffs2_ReadCheckpointObjects(dev);
746 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
747 ok = yaffs2_ReadCheckpointValidityMarker(dev, 0);
751 ok = yaffs2_ReadCheckpointSum(dev);
752 T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
755 if (!yaffs2_CheckpointClose(dev))
759 dev->isCheckpointed = 1;
761 dev->isCheckpointed = 0;
767 void yaffs2_InvalidateCheckpoint(yaffs_Device *dev)
769 if (dev->isCheckpointed ||
770 dev->blocksInCheckpoint > 0) {
771 dev->isCheckpointed = 0;
772 yaffs2_CheckpointInvalidateStream(dev);
774 if (dev->param.markSuperBlockDirty)
775 dev->param.markSuperBlockDirty(dev);
779 int yaffs_CheckpointSave(yaffs_Device *dev)
782 T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
784 yaffs_VerifyObjects(dev);
785 yaffs_VerifyBlocks(dev);
786 yaffs_VerifyFreeChunks(dev);
788 if (!dev->isCheckpointed) {
789 yaffs2_InvalidateCheckpoint(dev);
790 yaffs2_WriteCheckpointData(dev);
793 T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
795 return dev->isCheckpointed;
798 int yaffs2_CheckpointRestore(yaffs_Device *dev)
801 T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
803 retval = yaffs2_ReadCheckpointData(dev);
805 if (dev->isCheckpointed) {
806 yaffs_VerifyObjects(dev);
807 yaffs_VerifyBlocks(dev);
808 yaffs_VerifyFreeChunks(dev);
811 T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
816 int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize)
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.
827 int result = YAFFS_OK;
828 yaffs_Device *dev = NULL;
830 __u8 *localBuffer = NULL;
832 int smallIncreaseOk = 0;
837 if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
842 /* Bail out if not yaffs2 mode */
843 if(!dev->param.isYaffs2)
846 oldFileSize = obj->variant.fileVariant.fileSize;
848 if (newSize <= oldFileSize)
851 increase = newSize - oldFileSize;
853 if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk &&
854 yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
860 localBuffer= yaffs_GetTempBuffer(dev, __LINE__);
863 /* fill hole with zero bytes */
864 int pos = oldFileSize;
867 memset(localBuffer,0,dev->nDataBytesPerChunk);
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){
877 increase -= thisWrite;
882 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
884 /* If we were out of space then reverse any chunks we've added */
886 yaffs_ResizeDown(obj, oldFileSize);
889 if (!smallIncreaseOk &&
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);
908 static int yaffs2_ybicmp(const void *a, const void *b)
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;
915 return ablock - bblock;
920 int yaffs2_ScanBackwards(yaffs_Device *dev)
922 yaffs_ExtendedTags tags;
927 int nBlocksToScan = 0;
933 yaffs_BlockState state;
934 yaffs_Object *hardList = NULL;
936 __u32 sequenceNumber;
937 yaffs_ObjectHeader *oh;
939 yaffs_Object *parent;
940 int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
946 int foundChunksInBlock;
947 int equivalentObjectId;
948 int alloc_failed = 0;
951 yaffs_BlockIndex *blockIndex = NULL;
952 int altBlockIndex = 0;
956 ("yaffs2_ScanBackwards starts intstartblk %d intendblk %d..."
957 TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
960 dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
962 blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
965 blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
971 (TSTR("yaffs2_ScanBackwards() could not allocate block index!" TENDSTR)));
975 dev->blocksInCheckpoint = 0;
977 chunkData = yaffs_GetTempBuffer(dev, __LINE__);
979 /* Scan all the blocks to determine their state */
981 for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
982 yaffs_ClearChunkBits(dev, blk);
984 bi->softDeletions = 0;
986 yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
988 bi->blockState = state;
989 bi->sequenceNumber = sequenceNumber;
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;
996 T(YAFFS_TRACE_SCAN_DEBUG,
997 (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
998 state, sequenceNumber));
1001 if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
1002 dev->blocksInCheckpoint++;
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) {
1014 /* Determine the highest sequence number */
1015 if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
1016 sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
1018 blockIndex[nBlocksToScan].seq = sequenceNumber;
1019 blockIndex[nBlocksToScan].block = blk;
1023 if (sequenceNumber >= dev->sequenceNumber)
1024 dev->sequenceNumber = sequenceNumber;
1026 /* TODO: Nasty sequence number! */
1029 ("Block scanning block %d has bad sequence number %d"
1030 TENDSTR), blk, sequenceNumber));
1038 (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
1044 /* Sort the blocks by sequence number*/
1045 yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
1049 T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
1051 /* Now scan the blocks looking at the data. */
1053 endIterator = nBlocksToScan - 1;
1054 T(YAFFS_TRACE_SCAN_DEBUG,
1055 (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
1057 /* For each block.... backwards */
1058 for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
1060 /* Cooperative multitasking! This loop can run for so
1061 long that watchdog timers expire. */
1064 /* get the block to scan in the correct order */
1065 blk = blockIndex[blockIterator].block;
1067 bi = yaffs_GetBlockInfo(dev, blk);
1070 state = bi->blockState;
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
1084 chunk = blk * dev->param.nChunksPerBlock + c;
1086 result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
1089 /* Let's have a good look at this chunk... */
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
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++;
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 */
1115 (" Allocating from %d %d"
1118 state = YAFFS_BLOCK_STATE_ALLOCATING;
1119 dev->allocationBlock = blk;
1120 dev->allocationPage = c;
1121 dev->allocationBlockFinder = blk;
1123 /* This is a partially written block that is not
1124 * the current allocation block.
1128 (TSTR("Partially written block %d detected" TENDSTR),
1136 } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
1138 (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
1143 } else if (tags.chunkId > 0) {
1144 /* chunkId > 0 so it is a data chunk... */
1145 unsigned int endpos;
1147 (tags.chunkId - 1) * dev->nDataBytesPerChunk;
1149 foundChunksInBlock = 1;
1152 yaffs_SetChunkBit(dev, blk, c);
1155 in = yaffs_FindOrCreateObjectByNumber(dev,
1158 YAFFS_OBJECT_TYPE_FILE);
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)) {
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.
1175 endpos = chunkBase + tags.byteCount;
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;
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__);
1190 /* chunkId == 0, so it is an ObjectHeader.
1191 * Thus, we read in the object header and make the object
1193 foundChunksInBlock = 1;
1195 yaffs_SetChunkBit(dev, blk, c);
1201 if (tags.extraHeaderInfoAvailable) {
1202 in = yaffs_FindOrCreateObjectByNumber(dev,
1204 tags.extraObjectType);
1210 (!in->valid && dev->param.disableLazyLoad) ||
1211 tags.extraShadows ||
1213 (tags.objectId == YAFFS_OBJECTID_ROOT ||
1214 tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
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.
1221 result = yaffs_ReadChunkWithTagsFromNAND(dev,
1226 oh = (yaffs_ObjectHeader *) chunkData;
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;
1235 in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
1243 /* TODO Hoosterman we have a problem! */
1244 T(YAFFS_TRACE_ERROR,
1246 ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
1247 TENDSTR), tags.objectId, chunk));
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.
1257 if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
1259 oh->type == YAFFS_OBJECT_TYPE_FILE) ||
1260 (tags.extraHeaderInfoAvailable &&
1261 tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
1263 (oh) ? oh->fileSize : tags.
1265 __u32 parentObjectId =
1267 parentObjectId : tags.
1268 extraParentObjectId;
1272 (oh) ? oh->isShrink : tags.
1273 extraIsShrinkHeader;
1275 /* If it is deleted (unlinked at start also means deleted)
1276 * we treat the file size as being zeroed at this point.
1278 if (parentObjectId ==
1279 YAFFS_OBJECTID_DELETED
1280 || parentObjectId ==
1281 YAFFS_OBJECTID_UNLINKED) {
1286 if (isShrink && in->variant.fileVariant.shrinkSize > thisSize)
1287 in->variant.fileVariant.shrinkSize = thisSize;
1290 bi->hasShrinkHeader = 1;
1293 /* Use existing - destroy this one. */
1294 yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
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")
1305 oh->type : tags.extraObjectType,
1306 in->variantType, tags.objectId,
1310 (tags.objectId == YAFFS_OBJECTID_ROOT ||
1312 YAFFS_OBJECTID_LOSTNFOUND)) {
1313 /* We only load some info, don't fiddle with directory structure */
1317 in->variantType = oh->type;
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];
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;
1337 in->variantType = tags.extraObjectType;
1341 in->hdrChunk = chunk;
1343 } else if (!in->valid) {
1344 /* we need to load this info */
1347 in->hdrChunk = chunk;
1350 in->variantType = oh->type;
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];
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;
1369 if (oh->shadowsObject > 0)
1370 yaffs_HandleShadowedObject(dev,
1377 yaffs_SetObjectName(in, oh->name);
1379 yaffs_FindOrCreateObjectByNumber
1380 (dev, oh->parentObjectId,
1381 YAFFS_OBJECT_TYPE_DIRECTORY);
1383 fileSize = oh->fileSize;
1384 isShrink = oh->isShrink;
1385 equivalentObjectId = oh->equivalentObjectId;
1388 in->variantType = tags.extraObjectType;
1390 yaffs_FindOrCreateObjectByNumber
1391 (dev, tags.extraParentObjectId,
1392 YAFFS_OBJECT_TYPE_DIRECTORY);
1393 fileSize = tags.extraFileLength;
1394 isShrink = tags.extraIsShrinkHeader;
1395 equivalentObjectId = tags.extraEquivalentObjectId;
1404 /* directory stuff...
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.
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
1422 T(YAFFS_TRACE_ERROR,
1424 ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
1426 parent = dev->lostNFoundDir;
1429 yaffs_AddObjectToDirectory(parent, in);
1431 itsUnlinked = (parent == dev->deletedDir) ||
1432 (parent == dev->unlinkedDir);
1435 /* Mark the block as having a shrinkHeader */
1436 bi->hasShrinkHeader = 1;
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.
1446 switch (in->variantType) {
1447 case YAFFS_OBJECT_TYPE_UNKNOWN:
1448 /* Todo got a problem */
1450 case YAFFS_OBJECT_TYPE_FILE:
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.
1459 in->variant.fileVariant.fileSize = fileSize;
1460 in->variant.fileVariant.scannedFileSize = fileSize;
1463 if (in->variant.fileVariant.shrinkSize > fileSize)
1464 in->variant.fileVariant.shrinkSize = fileSize;
1468 case YAFFS_OBJECT_TYPE_HARDLINK:
1470 in->variant.hardLinkVariant.equivalentObjectId =
1472 in->hardLinks.next =
1473 (struct ylist_head *) hardList;
1477 case YAFFS_OBJECT_TYPE_DIRECTORY:
1480 case YAFFS_OBJECT_TYPE_SPECIAL:
1483 case YAFFS_OBJECT_TYPE_SYMLINK:
1485 in->variant.symLinkVariant.alias =
1486 yaffs_CloneString(oh->alias);
1487 if (!in->variant.symLinkVariant.alias)
1497 } /* End of scanning for each chunk */
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;
1505 bi->blockState = state;
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);
1516 yaffs_SkipRestOfBlock(dev);
1519 YFREE_ALT(blockIndex);
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
1528 yaffs_HardlinkFixup(dev, hardList);
1531 yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
1536 T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_ScanBackwards ends" TENDSTR)));