yaffs: Import yaffs from Wed Sep 9 03:03:01 2009 +0000
authorArve Hjønnevåg <arve@android.com>
Thu, 17 Sep 2009 01:30:41 +0000 (18:30 -0700)
committerArve Hjønnevåg <arve@android.com>
Mon, 8 Feb 2010 23:09:09 +0000 (15:09 -0800)
Author: charles <charles>
Date:   Wed Sep 9 03:03:01 2009 +0000

    Rationalise stats gathering for nand access. Does not instrument mounting.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
fs/yaffs2/yaffs_checkptrw.c
fs/yaffs2/yaffs_fs.c
fs/yaffs2/yaffs_guts.c
fs/yaffs2/yaffs_mtdif1.c
fs/yaffs2/yaffs_nand.c
fs/yaffs2/yaffs_tagscompat.c

index 288b550ae4dfac64de5312f42c700c9df117f68a..66a4e7d9f0f968fd50e506eece37c3e170f44242 100644 (file)
@@ -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); */
index 2288eeee2d77ba911eeb388da89e1f999a9d5637..47cae6f4f92cb7460889ce9ab8f0a205d9695c27 100644 (file)
@@ -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 && n) ? -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;
index 0de2ad329f92b72dc38793a8e39210e3ae278d2a..155b74643eb8044671704097444d109725f07ff5 100644 (file)
@@ -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
index 1d9311ae011e297012348505995b9cd22399dfca..bcac47025ece1362ad5ec0157ad9aaf0a10f49e9 100644 (file)
@@ -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;
index ec327610724987d0c5b83f147465ee11e84fe319..f6ba4c794ac437ad5ca9cc63b709ae614aa9b2cd 100644 (file)
@@ -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;
index 402537fb4ee1387132075c4247161bda4ab0d438..e3173cc2e23b1d237928a298ef221c7829535203 100644 (file)
@@ -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 */