mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user