yaffs: Better control over rename shadowing
authorCharles Manning <cdhmanning@gmail.com>
Mon, 7 Dec 2009 23:40:28 +0000 (12:40 +1300)
committerArve Hjønnevåg <arve@android.com>
Mon, 8 Feb 2010 23:09:12 +0000 (15:09 -0800)
The shadowing mechanism is used to ensure that the right
interlocking happens when an object is renamed over an existing object.

Extreme power fail stress testing revealed that garbage collection could
disrupt the shadowing process causing object loss.

This fixes the problem and has survived millions of simulated power failures.

Change-Id: I1c9c4365632c0f8be4ed6a4b41534a732ea81507
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
fs/yaffs2/yaffs_guts.c
fs/yaffs2/yaffs_guts.h

index a565b08e6116108d401263d6ec5421d70c85ab48..968223eb3e31c6aa4f0851bd0d8b3db3010e6359 100644 (file)
@@ -2465,6 +2465,8 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
        yaffs_Object *obj = NULL;
        yaffs_Object *existingTarget = NULL;
        int force = 0;
+       int result;
+       yaffs_Device *dev;
 
 
        if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
@@ -2472,6 +2474,8 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
        if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
                YBUG();
 
+       dev = oldDir->myDev;
+
 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
        /* Special case for case insemsitive systems (eg. WinCE).
         * While look-up is case insensitive, the name isn't.
@@ -2481,7 +2485,7 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
                force = 1;
 #endif
 
-       else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+       if(yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
                /* ENAMETOOLONG */
                return YAFFS_FAIL;
 
@@ -2499,17 +2503,26 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
                        return YAFFS_FAIL;      /* EEXIST or ENOTEMPTY */
                } else if (existingTarget && existingTarget != obj) {
                        /* Nuke the target first, using shadowing,
-                        * but only if it isn't the same object
+                        * but only if it isn't the same object.
+                        *
+                        * Note we must disable gc otherwise it can mess up the shadowing.
+                        *
                         */
+                       dev->isDoingGC=1;
                        yaffs_ChangeObjectName(obj, newDir, newName, force,
                                                existingTarget->objectId);
+                       existingTarget->isShadowed = 1;
                        yaffs_UnlinkObject(existingTarget);
+                       dev->isDoingGC=0;
                }
+
+               result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+
                yaffs_UpdateParent(oldDir);
                if(newDir != oldDir)
                        yaffs_UpdateParent(newDir);
 
-               return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+               return result;
        }
        return YAFFS_FAIL;
 }
@@ -3108,6 +3121,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
                                        if (tags.chunkId == 0) {
                                                /* It is an object Id,
                                                 * We need to nuke the shrinkheader flags first
+                                                * Also need to clean up shadowing.
                                                 * We no longer want the shrinkHeader flag since its work is done
                                                 * and if it is left in place it will mess up scanning.
                                                 */
@@ -3116,6 +3130,9 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
                                                oh = (yaffs_ObjectHeader *)buffer;
                                                oh->isShrink = 0;
                                                tags.extraIsShrinkHeader = 0;
+                                               oh->shadowsObject = 0;
+                                               oh->inbandShadowsObject = 0;
+                                               tags.extraShadows = 0;
 
                                                yaffs_VerifyObjectHeader(object, oh, &tags, 1);
                                        }
@@ -5030,11 +5047,13 @@ int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
        }
 
 
-       /* Write a new object header.
+       /* Write a new object header to reflect the resize.
         * show we've shrunk the file, if need be
-        * Do this only if the file is not in the deleted directories.
+        * Do this only if the file is not in the deleted directories
+        * and is not shadowed.
         */
        if (in->parent &&
+           !in->isShadowed &&
            in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
            in->parent->objectId != YAFFS_OBJECTID_DELETED)
                yaffs_UpdateObjectHeader(in, NULL, 0,
@@ -5345,7 +5364,8 @@ static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
                /* Handle YAFFS2 case (backward scanning)
                 * If the shadowed object exists then ignore.
                 */
-               if (yaffs_FindObjectByNumber(dev, objId))
+               obj = yaffs_FindObjectByNumber(dev, objId);
+               if(obj)
                        return;
        }
 
@@ -5357,6 +5377,7 @@ static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
                                             YAFFS_OBJECT_TYPE_FILE);
        if (!obj)
                return;
+       obj->isShadowed = 1;
        yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
        obj->variant.fileVariant.shrinkSize = 0;
        obj->valid = 1;         /* So that we don't read any other info for this file */
index c47a319445ceb8ef49b2efd5dbbce81ba8696066..1305909ecc03a38b1689da60ea840345873dbd17 100644 (file)
@@ -424,6 +424,7 @@ struct yaffs_ObjectStruct {
                                 * until the inode is released.
                                 */
        __u8 beingCreated:1;    /* This object is still being created so skip some checks. */
+       __u8 isShadowed:1;      /* This object is shadowed on the way to being renamed. */
 
        __u8 serial;            /* serial number of chunk in NAND. Cached here */
        __u16 sum;              /* sum of the name to speed searching */