X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=df368e3e746618b0c202e7cb11f87e1756c06010;hp=7b41a764941972cefd61949ccf499bb478b91d2a;hb=0258100e6185c153a09b5a0e34951605a48ae2a3;hpb=e434bac0480bf62ea4d66519ff40dad3d2e3e410 diff --git a/yaffs_guts.c b/yaffs_guts.c index 7b41a76..df368e3 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -1,7 +1,7 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -9,11 +9,10 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * */ const char *yaffs_guts_c_version = - "$Id: yaffs_guts.c,v 1.40 2006-10-13 08:52:49 charles Exp $"; + "$Id: yaffs_guts.c,v 1.48 2007-03-12 20:55:39 charles Exp $"; #include "yportenv.h" @@ -484,13 +483,15 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND) { + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); yaffs_InvalidateCheckpoint(dev); yaffs_MarkBlockBad(dev, blockInNAND); - yaffs_GetBlockInfo(dev, blockInNAND)->blockState = - YAFFS_BLOCK_STATE_DEAD; + bi->blockState = YAFFS_BLOCK_STATE_DEAD; + bi->gcPrioritise = 0; + bi->needsRetiring = 0; dev->nRetiredBlocks++; } @@ -527,6 +528,21 @@ void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) } } +static void yaffs_ReportOddballBlocks(yaffs_Device *dev) +{ + int i; + + for(i = dev->internalStartBlock; i <= dev->internalEndBlock && (yaffs_traceMask & YAFFS_TRACE_BAD_BLOCKS); i++){ + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); + if(bi->needsRetiring || bi->gcPrioritise) + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("yaffs block %d%s%s" TENDSTR), + i, + bi->needsRetiring ? " needs retiring" : "", + bi->gcPrioritise ? " gc prioritised" : "")); + + } +} + static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk) { @@ -539,6 +555,9 @@ static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int if(erasedOk ) { /* Was an actual write failure, so mark the block for retirement */ bi->needsRetiring = 1; + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND)); + } @@ -1937,7 +1956,7 @@ static int yaffs_InitialiseBlocks(yaffs_Device * dev) dev->blockInfoAlt = 0; /* Set up dynamic blockinfo stuff. */ - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; // round up bytes + dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); if(!dev->chunkBits){ dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); @@ -2010,8 +2029,6 @@ static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device * dev, */ return (bi->sequenceNumber <= dev->oldestDirtySequence); - return 1; - } /* FindDiretiestBlock is used to select the dirtiest block (or close enough) @@ -2038,15 +2055,15 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev, for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){ bi = yaffs_GetBlockInfo(dev, i); - if(bi->gcPrioritise) + if(bi->gcPrioritise) { pendingPrioritisedExist = 1; - if(bi->blockState == YAFFS_BLOCK_STATE_FULL && - bi->gcPrioritise && - yaffs_BlockNotDisqualifiedFromGC(dev, bi)){ - pagesInUse = (bi->pagesInUse - bi->softDeletions); - dirtiest = i; - prioritised = 1; - aggressive = 1; /* Fool the non-aggressive skip logiv below */ + if(bi->blockState == YAFFS_BLOCK_STATE_FULL && + yaffs_BlockNotDisqualifiedFromGC(dev, bi)){ + pagesInUse = (bi->pagesInUse - bi->softDeletions); + dirtiest = i; + prioritised = 1; + aggressive = 1; /* Fool the non-aggressive skip logiv below */ + } } } @@ -2138,6 +2155,11 @@ static void yaffs_BlockBecameDirty(yaffs_Device * dev, int blockNo) /* If the block is still healthy erase it and mark as clean. * If the block has had a data failure, then retire it. */ + + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, + (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), + blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); + bi->blockState = YAFFS_BLOCK_STATE_DIRTY; if (!bi->needsRetiring) { @@ -3712,7 +3734,11 @@ static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) if (!obj->deferedFree) { yaffs_ObjectToCheckpointObject(&cp,obj); cp.structType = sizeof(cp); - /* printf("Write out object %d type %d\n",obj->objectId,obj->variantType); */ + + T(YAFFS_TRACE_CHECKPOINT,( + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), + cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); + ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){ @@ -3751,9 +3777,9 @@ static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) if(ok && cp.objectId == ~0) done = 1; else if(ok){ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("Read object %d parent %d type %d" TENDSTR), - cp.objectId,cp.parentId,cp.variantType)); obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType); + T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d obj addr %x" TENDSTR), + cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); if(obj) { yaffs_CheckpointObjectToObject(obj,&cp); if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) { @@ -3845,6 +3871,7 @@ static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) int yaffs_CheckpointSave(yaffs_Device *dev) { + yaffs_ReportOddballBlocks(dev); T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); if(!dev->isCheckpointed) @@ -3864,6 +3891,8 @@ int yaffs_CheckpointRestore(yaffs_Device *dev) T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); + yaffs_ReportOddballBlocks(dev); + return retval; } @@ -4281,7 +4310,13 @@ int yaffs_ResizeFile(yaffs_Object * in, loff_t newSize) in->variant.fileVariant.fileSize = newSize; yaffs_PruneFileStructure(dev, &in->variant.fileVariant); + } else { + /* newsSize > oldFileSize */ + in->variant.fileVariant.fileSize = newSize; } + + + /* Write a new object header. * show we've shrunk the file, if need be * Do this only if the file is not in the deleted directories. @@ -5141,6 +5176,12 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) yaffs_ExtendedTags tags; int result; +#if 0 + T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR), + in->objectId, + in->lazyLoaded ? "not yet" : "already")); +#endif + if(in->lazyLoaded){ in->lazyLoaded = 0; chunkData = yaffs_GetTempBuffer(dev, __LINE__); @@ -5384,39 +5425,41 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) state = YAFFS_BLOCK_STATE_EMPTY; dev->nErasedBlocks++; } else { - /* this is the block being allocated from */ - if (state == - YAFFS_BLOCK_STATE_NEEDS_SCANNING) { - T(YAFFS_TRACE_SCAN, - (TSTR - (" Allocating from %d %d" - TENDSTR), blk, c)); + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || + state == YAFFS_BLOCK_STATE_ALLOCATING) { + if(dev->sequenceNumber == bi->sequenceNumber) { + /* this is the block being allocated from */ + + T(YAFFS_TRACE_SCAN, + (TSTR + (" Allocating from %d %d" + TENDSTR), blk, c)); + + state = YAFFS_BLOCK_STATE_ALLOCATING; + dev->allocationBlock = blk; + dev->allocationPage = c; + dev->allocationBlockFinder = blk; + } + else { + /* This is a partially written block that is not + * the current allocation block. This block must have + * had a write failure, so set up for retirement. + */ + + bi->needsRetiring = 1; + bi->gcPrioritise = 1; + + T(YAFFS_TRACE_ALWAYS, + (TSTR("Partially written block %d being set for retirement" TENDSTR), + blk)); + } + } - state = YAFFS_BLOCK_STATE_ALLOCATING; - dev->allocationBlock = blk; - dev->allocationPage = c; - dev->allocationBlockFinder = blk; - /* Set it to here to encourage the allocator to - * go forth from here. - */ - /* Yaffs2 sanity check: - * This should be the one with the highest sequence number - */ - if (dev->isYaffs2 - && (dev->sequenceNumber != - bi->sequenceNumber)) { - T(YAFFS_TRACE_ALWAYS, - (TSTR - ("yaffs: Allocation block %d was not highest sequence " - "id: block seq = %d, dev seq = %d" - TENDSTR), blk, - bi->sequenceNumber, - dev->sequenceNumber)); - } } dev->nFreeChunks++; + } else if (tags.chunkId > 0) { /* chunkId > 0 so it is a data chunk... */ unsigned int endpos;