summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArve Hjønnevåg <arve@android.com>2009-09-18 12:47:26 -0700
committerArve Hjønnevåg <arve@android.com>2009-09-18 12:47:31 -0700
commit36455f811bc3d4c02accb79ad9efc45c91fac2b3 (patch)
treebbff10c707b9ffda64f3b03f924f3414986cc2fb
parent16259922b79cc7be7cec7f518f8729e0e66d9aa6 (diff)
parent633961f1220872291601732c6d70b5aa15d77f91 (diff)
Merge branch 'yaffs' into android-2.6.29
Signed-off-by: Arve Hjønnevåg <arve@android.com>
-rw-r--r--fs/yaffs2/yaffs_checkptrw.c10
-rw-r--r--fs/yaffs2/yaffs_fs.c19
-rw-r--r--fs/yaffs2/yaffs_guts.c86
-rw-r--r--fs/yaffs2/yaffs_mtdif1.c4
-rw-r--r--fs/yaffs2/yaffs_nand.c9
-rw-r--r--fs/yaffs2/yaffs_tagscompat.c3
6 files changed, 97 insertions, 34 deletions
diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c
index 288b550ae4df..66a4e7d9f0f9 100644
--- a/fs/yaffs2/yaffs_checkptrw.c
+++ b/fs/yaffs2/yaffs_checkptrw.c
@@ -43,6 +43,9 @@ static int yaffs_CheckpointErase(yaffs_Device *dev)
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
+
+ dev->nBlockErasures++;
+
if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
dev->nErasedBlocks++;
@@ -168,6 +171,9 @@ int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
dev->blocksInCheckpoint = 0;
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
+ if(!dev->checkpointBlockList)
+ return 0;
+
for (i = 0; i < dev->checkpointMaxBlocks; i++)
dev->checkpointBlockList[i] = -1;
}
@@ -219,6 +225,8 @@ static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
realignedChunk = chunk - dev->chunkOffset;
+ dev->nPageWrites++;
+
dev->writeChunkWithTagsToNAND(dev, realignedChunk,
dev->checkpointBuffer, &tags);
dev->checkpointByteOffset = 0;
@@ -306,6 +314,8 @@ int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
dev->checkpointCurrentChunk;
realignedChunk = chunk - dev->chunkOffset;
+
+ dev->nPageReads++;
/* read in the next chunk */
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
diff --git a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c
index 30ae7c7e259a..47cae6f4f92c 100644
--- a/fs/yaffs2/yaffs_fs.c
+++ b/fs/yaffs2/yaffs_fs.c
@@ -163,6 +163,11 @@ static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
#endif
+
+#define update_dir_time(dir) do {\
+ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+ } while(0)
+
static void yaffs_put_super(struct super_block *sb);
static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
@@ -1075,7 +1080,7 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
}
yaffs_GrossUnlock(dev);
- return nWritten == 0 ? -ENOSPC : nWritten;
+ return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
}
/* Space holding and freeing is done to ensure we have space available for write_begin/end */
@@ -1286,6 +1291,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
if (obj) {
inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
d_instantiate(dentry, inode);
+ update_dir_time(dir);
T(YAFFS_TRACE_OS,
("yaffs_mknod created object %d count = %d\n",
obj->objectId, atomic_read(&inode->i_count)));
@@ -1339,6 +1345,7 @@ static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
dir->i_version++;
yaffs_GrossUnlock(dev);
mark_inode_dirty(dentry->d_inode);
+ update_dir_time(dir);
return 0;
}
yaffs_GrossUnlock(dev);
@@ -1379,8 +1386,10 @@ static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
yaffs_GrossUnlock(dev);
- if (link)
+ if (link){
+ update_dir_time(dir);
return 0;
+ }
return -EPERM;
}
@@ -1406,6 +1415,7 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
d_instantiate(dentry, inode);
+ update_dir_time(dir);
T(YAFFS_TRACE_OS, ("symlink created OK\n"));
return 0;
} else {
@@ -1478,7 +1488,10 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
new_dentry->d_inode->i_nlink--;
mark_inode_dirty(new_dentry->d_inode);
}
-
+
+ update_dir_time(old_dir);
+ if(old_dir != new_dir)
+ update_dir_time(new_dir);
return 0;
} else {
return -ENOTEMPTY;
diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
index 0de2ad329f92..155b74643eb8 100644
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -49,6 +49,7 @@ static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
const yaffs_ExtendedTags *tags);
/* Other local prototypes */
+static void yaffs_UpdateParent(yaffs_Object *obj);
static int yaffs_UnlinkObject(yaffs_Object *obj);
static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
@@ -759,7 +760,7 @@ static void yaffs_VerifyObject(yaffs_Object *obj)
chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
- chunkIdOk = chunkInRange || obj->hdrChunk == 0;
+ chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
chunkValid = chunkInRange &&
yaffs_CheckChunkBit(dev,
obj->hdrChunk / dev->nChunksPerBlock,
@@ -1544,11 +1545,16 @@ static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
theChunk % dev->nChunksPerBlock)) {
- yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
- tags);
- if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
- /* found it; */
+
+ if(dev->chunkGroupSize == 1)
return theChunk;
+ else {
+ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
+ tags);
+ if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
+ /* found it; */
+ return theChunk;
+ }
}
}
theChunk++;
@@ -2345,6 +2351,7 @@ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
in = NULL;
}
+ yaffs_UpdateParent(parent);
}
return in;
@@ -2499,6 +2506,9 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
existingTarget->objectId);
yaffs_UnlinkObject(existingTarget);
}
+ yaffs_UpdateParent(oldDir);
+ if(newDir != oldDir)
+ yaffs_UpdateParent(newDir);
return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
}
@@ -2964,7 +2974,6 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
- bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
T(YAFFS_TRACE_TRACING,
(TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
@@ -2975,12 +2984,16 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
/*yaffs_VerifyFreeChunks(dev); */
+ if(bi->blockState == YAFFS_BLOCK_STATE_FULL)
+ bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
+
bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
/* Take off the number of soft deleted entries because
* they're going to get really deleted during GC.
*/
- dev->nFreeChunks -= bi->softDeletions;
+ if(dev->gcChunk == 0) /* first time through for this block */
+ dev->nFreeChunks -= bi->softDeletions;
dev->isDoingGC = 1;
@@ -3624,7 +3637,7 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
newTags.chunkId = chunkInInode;
newTags.objectId = in->objectId;
newTags.serialNumber =
- (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
+ (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1;
newTags.byteCount = nBytes;
if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
@@ -3640,7 +3653,7 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
if (newChunkId >= 0) {
yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
- if (prevChunkId >= 0)
+ if (prevChunkId > 0)
yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
yaffs_CheckFileSanity(in);
@@ -3726,7 +3739,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
if (name && *name) {
memset(oh->name, 0, sizeof(oh->name));
yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
- } else if (prevChunkId >= 0)
+ } else if (prevChunkId > 0)
memcpy(oh->name, oldName, sizeof(oh->name));
else
memset(oh->name, 0, sizeof(oh->name));
@@ -3784,13 +3797,13 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
/* Create new chunk in NAND */
newChunkId =
yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
- (prevChunkId >= 0) ? 1 : 0);
+ (prevChunkId > 0) ? 1 : 0);
if (newChunkId >= 0) {
in->hdrChunk = newChunkId;
- if (prevChunkId >= 0) {
+ if (prevChunkId > 0) {
yaffs_DeleteChunk(dev, prevChunkId, 1,
__LINE__);
}
@@ -5164,14 +5177,19 @@ int yaffs_DeleteFile(yaffs_Object *in)
}
}
-static int yaffs_DeleteDirectory(yaffs_Object *in)
+static int yaffs_IsNonEmptyDirectory(yaffs_Object *obj)
{
- /* First check that the directory is empty. */
- if (ylist_empty(&in->variant.directoryVariant.children))
- return yaffs_DoGenericObjectDeletion(in);
+ return (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) &&
+ !(ylist_empty(&obj->variant.directoryVariant.children));
+}
- return YAFFS_FAIL;
+static int yaffs_DeleteDirectory(yaffs_Object *obj)
+{
+ /* First check that the directory is empty. */
+ if (yaffs_IsNonEmptyDirectory(obj))
+ return YAFFS_FAIL;
+ return yaffs_DoGenericObjectDeletion(obj);
}
static int yaffs_DeleteSymLink(yaffs_Object *in)
@@ -5230,6 +5248,9 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
immediateDeletion = 1;
#endif
+ if(obj)
+ yaffs_UpdateParent(obj->parent);
+
if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
return yaffs_DeleteHardLink(obj);
} else if (!ylist_empty(&obj->hardLinks)) {
@@ -5284,7 +5305,9 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
default:
return YAFFS_FAIL;
}
- } else
+ } else if(yaffs_IsNonEmptyDirectory(obj))
+ return YAFFS_FAIL;
+ else
return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
_Y("unlinked"), 0, 0);
}
@@ -6666,6 +6689,26 @@ static void yaffs_VerifyDirectory(yaffs_Object *directory)
}
}
+/*
+ *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
+ * link (ie. name) is created or deleted in the directory.
+ *
+ * ie.
+ * create dir/a : update dir's mtime/ctime
+ * rm dir/a: update dir's mtime/ctime
+ * modify dir/a: don't update dir's mtimme/ctime
+ */
+
+static void yaffs_UpdateParent(yaffs_Object *obj)
+{
+ if(!obj)
+ return;
+
+ obj->dirty = 1;
+ obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
+
+ yaffs_UpdateObjectHeader(obj,NULL,0,0,0);
+}
static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
{
@@ -6683,11 +6726,10 @@ static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
ylist_del_init(&obj->siblings);
obj->parent = NULL;
-
+
yaffs_VerifyDirectory(parent);
}
-
static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
yaffs_Object *obj)
{
@@ -6781,7 +6823,7 @@ yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,
* Do a real check
*/
yaffs_GetObjectName(l, buffer,
- YAFFS_MAX_NAME_LENGTH);
+ YAFFS_MAX_NAME_LENGTH + 1);
if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
return l;
}
@@ -7030,7 +7072,7 @@ int yaffs_DumpObject(yaffs_Object *obj)
{
YCHAR name[257];
- yaffs_GetObjectName(obj, name, 256);
+ yaffs_GetObjectName(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
T(YAFFS_TRACE_ALWAYS,
(TSTR
diff --git a/fs/yaffs2/yaffs_mtdif1.c b/fs/yaffs2/yaffs_mtdif1.c
index 1d9311ae011e..bcac47025ece 100644
--- a/fs/yaffs2/yaffs_mtdif1.c
+++ b/fs/yaffs2/yaffs_mtdif1.c
@@ -102,8 +102,6 @@ int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
compile_time_assertion(sizeof(yaffs_Tags) == 8);
- dev->nPageWrites++;
-
yaffs_PackTags1(&pt1, etags);
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
@@ -180,8 +178,6 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
int retval;
int deleted;
- dev->nPageReads++;
-
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
index ec3276107249..f6ba4c794ac4 100644
--- a/fs/yaffs2/yaffs_nand.c
+++ b/fs/yaffs2/yaffs_nand.c
@@ -29,6 +29,8 @@ int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
+ dev->nPageReads++;
+
/* If there are no tags provided, use local tags to get prioritised gc working */
if (!tags)
tags = &localTags;
@@ -56,6 +58,9 @@ int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
const __u8 *buffer,
yaffs_ExtendedTags *tags)
{
+
+ dev->nPageWrites++;
+
chunkInNAND -= dev->chunkOffset;
@@ -89,7 +94,7 @@ int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
{
blockNo -= dev->blockOffset;
-;
+
if (dev->markNANDBlockBad)
return dev->markNANDBlockBad(dev, blockNo);
else
@@ -119,8 +124,8 @@ int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
blockInNAND -= dev->blockOffset;
-
dev->nBlockErasures++;
+
result = dev->eraseBlockInNAND(dev, blockInNAND);
return result;
diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c
index 402537fb4ee1..e3173cc2e23b 100644
--- a/fs/yaffs2/yaffs_tagscompat.c
+++ b/fs/yaffs2/yaffs_tagscompat.c
@@ -170,7 +170,6 @@ static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
return YAFFS_FAIL;
}
- dev->nPageWrites++;
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
}
@@ -184,8 +183,6 @@ static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
int retVal;
yaffs_Spare localSpare;
- dev->nPageReads++;
-
if (!spare && data) {
/* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */