yaffs Fix incorrect handling of deletion flag
[yaffs2.git] / yaffs_guts.c
index 42e234a73f56852b4d5760733c3f9ec59e3ae076..9509dd401a33e5e9eb0a6989f74f733b1cc33d61 100644 (file)
@@ -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 <charles@aleph1.co.uk>
  * 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;
@@ -3465,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
@@ -3483,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;
@@ -3575,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
@@ -3605,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;
@@ -4871,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;
        }
@@ -5127,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 ||
@@ -5138,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.
@@ -5602,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)
@@ -5615,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;
@@ -6762,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));
                                                }
@@ -7907,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;