X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=9509dd401a33e5e9eb0a6989f74f733b1cc33d61;hp=65e33a644b958c09b946f8a14c80d3bcbf933a05;hb=401f9eb48ce20b18902ad9a4a8039d43e363d2ec;hpb=c565b5da13774bc9d5f661d93a127ba86a8769e7 diff --git a/yaffs_guts.c b/yaffs_guts.c index 65e33a6..9509dd4 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -1,7 +1,7 @@ /* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002-2007 Aleph One Ltd. + * Copyright (C) 2002-2010 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning @@ -10,10 +10,6 @@ * 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.120 2010-03-15 23:10:34 charles Exp $"; - #include "yportenv.h" #include "yaffs_trace.h" @@ -37,8 +33,17 @@ const char *yaffs_guts_c_version = /* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ #define YAFFS_GC_GOOD_ENOUGH 2 #define YAFFS_GC_PASSIVE_THRESHOLD 4 + #define YAFFS_SMALL_HOLE_THRESHOLD 3 +/* + * Checkpoints are really no benefit on very small partitions. + * + * To save space on small partitions don't bother with checkpoints unless + * the partition is at least this big. + */ +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 + #include "yaffs_ecc.h" @@ -74,8 +79,6 @@ static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, int isShrink, int shadows); static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); static int yaffs_CheckStructures(void); -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, - int chunkOffset, int *limit); static int yaffs_DoGenericObjectDeletion(yaffs_Object *in); static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo); @@ -183,7 +186,7 @@ static __u32 ShiftsGE(__u32 x) static __u32 Shifts(__u32 x) { - int nShifts; + __u32 nShifts; nShifts = 0; @@ -610,7 +613,8 @@ static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, } - +#if 0 +/* Not being used, but don't want to throw away yet */ static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn, __u32 level, int chunkOffset) { @@ -656,6 +660,7 @@ static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn, } +#endif static void yaffs_VerifyFile(yaffs_Object *obj) { @@ -1708,9 +1713,10 @@ static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, return -1; } - +#if 0 +/* Experimental code not being used yet. Might speed up file deletion */ /* DeleteWorker scans backwards through the tnode tree and deletes all the - * chunks and tnodes in the file + * chunks and tnodes in the file. * Returns 1 if the tree was deleted. * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. */ @@ -1802,6 +1808,8 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, } +#endif + static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk) { yaffs_BlockInfo *theBlock; @@ -2956,10 +2964,17 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev) +static int yaffs_CheckpointRequired(yaffs_Device *dev) +{ + int nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ; + return dev->param.isYaffs2 && + !dev->param.skipCheckpointWrite && + (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); +} static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev) { if (!dev->nCheckpointBlocksRequired && - dev->param.isYaffs2) { + yaffs_CheckpointRequired(dev)){ /* Not a valid value so recalculate */ int nBytes = 0; int nBlocks; @@ -3428,8 +3443,10 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, int maxThreshold = dev->param.nChunksPerBlock/2; threshold = background ? (dev->gcNotDone + 2) * 2 : 0; - threshold = max(threshold, YAFFS_GC_PASSIVE_THRESHOLD); - threshold = min(threshold, maxThreshold); + if(threshold maxThreshold) + threshold = maxThreshold; iterations = nBlocks / 16 + 1; if (iterations > 100) @@ -3463,11 +3480,18 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, selected = dev->gcDirtiest; } - if(!selected && dev->param.isYaffs2 && dev->gcNotDone >= ( background ? 10 : 20)){ + /* + * If nothing has been selected for a while, try selecting the oldest dirty + * because that's gumming up the works. + */ + + if(!selected && dev->param.isYaffs2 && + dev->gcNotDone >= ( background ? 10 : 20)){ yaffs_FindOldestDirtySequence(dev); if(dev->oldestDirtyBlock > 0) { selected = dev->oldestDirtyBlock; dev->gcDirtiest = selected; + dev->oldestDirtyGCs++; bi = yaffs_GetBlockInfo(dev, selected); dev->gcPagesInUse = bi->pagesInUse - bi->softDeletions; } else @@ -3481,6 +3505,8 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, dev->param.nChunksPerBlock - dev->gcPagesInUse, prioritised)); + if(background) + dev->backgroundGCs++; dev->gcDirtiest = 0; dev->gcPagesInUse = 0; dev->gcNotDone = 0; @@ -3573,9 +3599,9 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background) } if (dev->gcBlock > 0) { - dev->garbageCollections++; + dev->allGCs++; if (!aggressive) - dev->passiveGarbageCollections++; + dev->passiveGCs++; T(YAFFS_TRACE_GC, (TSTR @@ -3603,11 +3629,11 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background) * Garbage collects. Intended to be called from a background thread. * Returns non-zero if at least half the free chunks are erased. */ -int yaffs_BackgroundGarbageCollect(yaffs_Device *dev) +int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency) { int erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; - T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc" TENDSTR))); + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency)); yaffs_CheckGarbageCollection(dev, 1); return erasedChunks > dev->nFreeChunks/2; @@ -4869,7 +4895,7 @@ static int yaffs_WriteCheckpointData(yaffs_Device *dev) { int ok = 1; - if (dev->param.skipCheckpointWrite || !dev->param.isYaffs2) { + if (!yaffs_CheckpointRequired(dev)) { T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR))); ok = 0; } @@ -5125,8 +5151,6 @@ int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, dev = in->myDev; while (n > 0 && chunkWritten >= 0) { - /* chunk = offset / dev->nDataBytesPerChunk + 1; */ - /* start = offset % dev->nDataBytesPerChunk; */ yaffs_AddrToChunk(dev, offset, &chunk, &start); if (chunk * dev->nDataBytesPerChunk + start != offset || @@ -5136,7 +5160,7 @@ int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, TENDSTR), (int)offset, chunk, start)); } - chunk++; + chunk++; /* File pos to chunk in file offset */ /* OK now check for the curveball where the start and end are in * the same chunk. @@ -5600,7 +5624,7 @@ static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in) int yaffs_DeleteFile(yaffs_Object *in) { int retVal = YAFFS_OK; - int deleted = in->deleted; + int deleted; /* Need to cache value on stack if in is freed */ yaffs_Device *dev = in->myDev; if (dev->param.disableSoftDelete || dev->param.isYaffs2) @@ -5613,6 +5637,8 @@ int yaffs_DeleteFile(yaffs_Object *in) if (!in->unlinked) retVal = yaffs_UnlinkFileIfNeeded(in); + deleted = in->deleted; + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { in->deleted = 1; deleted = 1; @@ -6760,7 +6786,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev) * the current allocation block. */ - T(YAFFS_TRACE_ALWAYS, + T(YAFFS_TRACE_SCAN, (TSTR("Partially written block %d detected" TENDSTR), blk)); } @@ -7905,8 +7931,10 @@ int yaffs_GutsInitialise(yaffs_Device *dev) /* OK, we've finished verifying the device, lets continue with initialisation */ /* More device initialisation */ - dev->garbageCollections = 0; - dev->passiveGarbageCollections = 0; + dev->allGCs = 0; + dev->passiveGCs = 0; + dev->oldestDirtyGCs = 0; + dev->backgroundGCs = 0; dev->gcBlockFinder = 0; dev->bufferedBlock = -1; dev->doingBufferedBlockRewrite = 0;