Revert "yaffs: Fix readdir hang."

This reverts commit ef330d560d.
This commit is contained in:
黄涛
2011-07-30 22:45:05 +08:00
parent 60efa09fa2
commit 08fb5eb5c6
2 changed files with 11 additions and 155 deletions

View 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);

View 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;