From 08fb5eb5c65f369560355db544eaa17c376096bc Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Sat, 30 Jul 2011 22:45:05 +0800 Subject: [PATCH] Revert "yaffs: Fix readdir hang." This reverts commit ef330d560d9c3bb66ab1031af243b3171bba219f. --- fs/yaffs2/yaffs_fs.c | 157 +++-------------------------------------- fs/yaffs2/yaffs_guts.h | 9 +-- 2 files changed, 11 insertions(+), 155 deletions(-) diff --git a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c index 4c155aef0a35..45aa158b18d3 100644 --- a/fs/yaffs2/yaffs_fs.c +++ b/fs/yaffs2/yaffs_fs.c @@ -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); diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h index c47a319445ce..acc2ae71c856 100644 --- a/fs/yaffs2/yaffs_guts.h +++ b/fs/yaffs2/yaffs_guts.h @@ -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; -- 2.34.1