Revert "yaffs: Fix readdir hang."
author黄涛 <huangtao@rock-chips.com>
Sat, 30 Jul 2011 14:45:05 +0000 (22:45 +0800)
committer黄涛 <huangtao@rock-chips.com>
Sat, 30 Jul 2011 14:45:05 +0000 (22:45 +0800)
This reverts commit ef330d560d9c3bb66ab1031af243b3171bba219f.

fs/yaffs2/yaffs_fs.c
fs/yaffs2/yaffs_guts.h

index 4c155aef0a35c929f550f1aaa86a82a988af04d6..45aa158b18d330196a7cf66cfd5119cd9926e9cf 100644 (file)
@@ -378,122 +378,6 @@ static void yaffs_GrossUnlock(yaffs_Device *dev)
        up(&dev->grossLock);
 }
 
-
-/*-----------------------------------------------------------------*/
-/* Directory search context allows us to unlock access to yaffs during
- * filldir without causing problems with the directory being modified.
- * This is similar to the tried and tested mechanism used in yaffs direct.
- *
- * A search context iterates along a doubly linked list of siblings in the
- * directory. If the iterating object is deleted then this would corrupt
- * the list iteration, likely causing a crash. The search context avoids
- * this by using the removeObjectCallback to move the search context to the
- * next object before the object is deleted.
- *
- * Many readdirs (and thus seach conexts) may be alive simulateously so
- * each yaffs_Device has a list of these.
- *
- * A seach context lives for the duration of a readdir.
- *
- * All these functions must be called while yaffs is locked.
- */
-
-struct yaffs_SearchContext {
-       yaffs_Device *dev;
-       yaffs_Object *dirObj;
-       yaffs_Object *nextReturn;
-       struct ylist_head others;
-};
-
-/*
- * yaffs_NewSearch() creates a new search context, initialises it and
- * adds it to the device's search context list.
- *
- * Called at start of readdir.
- */
-static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
-{
-       yaffs_Device *dev = dir->myDev;
-       struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
-       if(sc){
-               sc->dirObj = dir;
-               sc->dev = dev;
-               if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
-                       sc->nextReturn = NULL;
-               else
-                       sc->nextReturn = ylist_entry(
-                                dir->variant.directoryVariant.children.next,
-                               yaffs_Object,siblings);
-               YINIT_LIST_HEAD(&sc->others);
-               ylist_add(&sc->others,&dev->searchContexts);
-       }
-       return sc;
-}
-
-/*
- * yaffs_EndSearch() disposes of a search context and cleans up.
- */
-static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
-{
-       if(sc){
-               ylist_del(&sc->others);
-               YFREE(sc);
-       }
-}
-
-/*
- * yaffs_SearchAdvance() moves a search context to the next object.
- * Called when the search iterates or when an object removal causes
- * the search context to be moved to the next object.
- */
-static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
-{
-        if(!sc)
-                return;
-
-        if( sc->nextReturn == NULL ||
-                ylist_empty(&sc->dirObj->variant.directoryVariant.children))
-                sc->nextReturn = NULL;
-        else {
-                struct ylist_head *next = sc->nextReturn->siblings.next;
-
-                if( next == &sc->dirObj->variant.directoryVariant.children)
-                        sc->nextReturn = NULL; /* end of list */
-                else
-                        sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
-        }
-}
-
-/*
- * yaffs_RemoveObjectCallback() is called when an object is unlinked.
- * We check open search contexts and advance any which are currently
- * on the object being iterated.
- */
-static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
-{
-
-        struct ylist_head *i;
-        struct yaffs_SearchContext *sc;
-        struct ylist_head *search_contexts = &obj->myDev->searchContexts;
-
-
-        /* Iterate through the directory search contexts.
-         * If any are currently on the object being removed, then advance
-         * the search context to the next object to prevent a hanging pointer.
-         */
-         ylist_for_each(i, search_contexts) {
-                if (i) {
-                        sc = ylist_entry(i, struct yaffs_SearchContext,others);
-                        if(sc->nextReturn == obj)
-                                yaffs_SearchAdvance(sc);
-                }
-       }
-
-}
-
-
-/*-----------------------------------------------------------------*/
-
 static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
                        int buflen)
 {
@@ -1244,11 +1128,10 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
 {
        yaffs_Object *obj;
        yaffs_Device *dev;
-        struct yaffs_SearchContext *sc;
        struct inode *inode = f->f_dentry->d_inode;
        unsigned long offset, curoffs;
+       struct ylist_head *i;
        yaffs_Object *l;
-        int retVal = 0;
 
        char name[YAFFS_MAX_NAME_LENGTH + 1];
 
@@ -1259,22 +1142,14 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
 
        offset = f->f_pos;
 
-        sc = yaffs_NewSearch(obj);
-        if(!sc){
-                retVal = -ENOMEM;
-                goto unlock_out;
-        }
-
        T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
 
        if (offset == 0) {
                T(YAFFS_TRACE_OS,
                        ("yaffs_readdir: entry . ino %d \n",
                        (int)inode->i_ino));
-               yaffs_GrossUnlock(dev);
                if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
                        goto out;
-               yaffs_GrossLock(dev);
                offset++;
                f->f_pos++;
        }
@@ -1282,11 +1157,9 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                T(YAFFS_TRACE_OS,
                        ("yaffs_readdir: entry .. ino %d \n",
                        (int)f->f_dentry->d_parent->d_inode->i_ino));
-               yaffs_GrossUnlock(dev);
                if (filldir(dirent, "..", 2, offset,
                        f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
                        goto out;
-               yaffs_GrossLock(dev);
                offset++;
                f->f_pos++;
        }
@@ -1302,12 +1175,10 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                f->f_version = inode->i_version;
        }
 
-       while(sc->nextReturn){
+       ylist_for_each(i, &obj->variant.directoryVariant.children) {
                curoffs++;
-                l = sc->nextReturn;
                if (curoffs >= offset) {
-                        int this_inode = yaffs_GetObjectInode(l);
-                        int this_type = yaffs_GetObjectType(l);
+                       l = ylist_entry(i, yaffs_Object, siblings);
 
                        yaffs_GetObjectName(l, name,
                                            YAFFS_MAX_NAME_LENGTH + 1);
@@ -1315,30 +1186,24 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                          ("yaffs_readdir: %s inode %d\n", name,
                           yaffs_GetObjectInode(l)));
 
-                        yaffs_GrossUnlock(dev);
-
                        if (filldir(dirent,
                                        name,
                                        strlen(name),
                                        offset,
-                                       this_inode,
-                                       this_type) < 0)
-                               goto out;
-
-                        yaffs_GrossLock(dev);
+                                       yaffs_GetObjectInode(l),
+                                       yaffs_GetObjectType(l)) < 0)
+                               goto up_and_out;
 
                        offset++;
                        f->f_pos++;
                }
-                yaffs_SearchAdvance(sc);
        }
 
-unlock_out:
-       yaffs_GrossUnlock(dev);
+up_and_out:
 out:
-        yaffs_EndSearch(sc);
+       yaffs_GrossUnlock(dev);
 
-       return retVal;
+       return 0;
 }
 
 /*
@@ -2250,10 +2115,6 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        /* we assume this is protected by lock_kernel() in mount/umount */
        ylist_add_tail(&dev->devList, &yaffs_dev_list);
 
-        /* Directory search handling...*/
-        YINIT_LIST_HEAD(&dev->searchContexts);
-        dev->removeObjectCallback = yaffs_RemoveObjectCallback;
-
        init_MUTEX(&dev->grossLock);
 
        yaffs_GrossLock(dev);
index c47a319445ceb8ef49b2efd5dbbce81ba8696066..acc2ae71c8566a362c05f5a6e300c0ba40a19d6a 100644 (file)
@@ -594,9 +594,8 @@ struct yaffs_DeviceStruct {
        int isYaffs2;
 
        /* The removeObjectCallback function must be supplied by OS flavours that
-        * need it.
-         * yaffs direct uses it to implement the faster readdir.
-         * Linux uses it to protect the directory during unlocking.
+        * need it. The Linux kernel does not use this, but yaffs direct does use
+        * it to implement the faster readdir
         */
        void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
 
@@ -636,14 +635,10 @@ struct yaffs_DeviceStruct {
 
        struct semaphore sem;   /* Semaphore for waiting on erasure.*/
        struct semaphore grossLock;     /* Gross locking semaphore */
-       struct rw_semaphore dirLock; /* Lock the directory structure */
        __u8 *spareBuffer;      /* For mtdif2 use. Don't know the size of the buffer
                                 * at compile time so we have to allocate it.
-
                                 */
        void (*putSuperFunc) (struct super_block *sb);
-        struct ylist_head searchContexts;
-
 #endif
 
        int isMounted;