summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorCharles Manning <cdhmanning@gmail.com>2009-12-08 12:40:28 +1300
committerArve Hjønnevåg <arve@android.com>2010-02-08 15:09:12 -0800
commit703932d07237252c0aca76ab693463664f0a71a3 (patch)
treebf2075d915b6c3c073142a79161e7dbc0552fe9f /fs
parentef330d560d9c3bb66ab1031af243b3171bba219f (diff)
yaffs: Better control over rename shadowing
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/yaffs2/yaffs_guts.c33
-rw-r--r--fs/yaffs2/yaffs_guts.h1
2 files changed, 28 insertions, 6 deletions
diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
index a565b08e6116..968223eb3e31 100644
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -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 */
diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
index c47a319445ce..1305909ecc03 100644
--- a/fs/yaffs2/yaffs_guts.h
+++ b/fs/yaffs2/yaffs_guts.h
@@ -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 */