locking in fs/9p ->readdir()
... is really excessive. First of all, ->readdir() is serialized by file->f_path.dentry->d_inode->i_mutex; playing with file->f_path.dentry->d_lock is not buying you anything. Moreover, rdir->mutex is pointless for exactly the same reason - you'll never see contention on it. While we are at it, there's no point in having rdir->buf a pointer - you have it point just past the end of rdir, so it might as well be a flex array (and no, it's not a gccism). Absolutely untested patch follows: Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
This commit is contained in:
parent
836dc9e3fb
commit
7ffdea7ea3
1 changed files with 23 additions and 69 deletions
|
@ -52,10 +52,9 @@
|
|||
*/
|
||||
|
||||
struct p9_rdir {
|
||||
struct mutex mutex;
|
||||
int head;
|
||||
int tail;
|
||||
uint8_t *buf;
|
||||
uint8_t buf[];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -93,33 +92,12 @@ static void p9stat_init(struct p9_wstat *stbuf)
|
|||
*
|
||||
*/
|
||||
|
||||
static int v9fs_alloc_rdir_buf(struct file *filp, int buflen)
|
||||
static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
|
||||
{
|
||||
struct p9_rdir *rdir;
|
||||
struct p9_fid *fid;
|
||||
int err = 0;
|
||||
|
||||
fid = filp->private_data;
|
||||
if (!fid->rdir) {
|
||||
rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
|
||||
|
||||
if (rdir == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
spin_lock(&filp->f_dentry->d_lock);
|
||||
if (!fid->rdir) {
|
||||
rdir->buf = (uint8_t *)rdir + sizeof(struct p9_rdir);
|
||||
mutex_init(&rdir->mutex);
|
||||
rdir->head = rdir->tail = 0;
|
||||
fid->rdir = (void *) rdir;
|
||||
rdir = NULL;
|
||||
}
|
||||
spin_unlock(&filp->f_dentry->d_lock);
|
||||
kfree(rdir);
|
||||
}
|
||||
exit:
|
||||
return err;
|
||||
struct p9_fid *fid = filp->private_data;
|
||||
if (!fid->rdir)
|
||||
fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
|
||||
return fid->rdir;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,20 +123,16 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||
|
||||
buflen = fid->clnt->msize - P9_IOHDRSZ;
|
||||
|
||||
err = v9fs_alloc_rdir_buf(filp, buflen);
|
||||
if (err)
|
||||
goto exit;
|
||||
rdir = (struct p9_rdir *) fid->rdir;
|
||||
rdir = v9fs_alloc_rdir_buf(filp, buflen);
|
||||
if (!rdir)
|
||||
return -ENOMEM;
|
||||
|
||||
err = mutex_lock_interruptible(&rdir->mutex);
|
||||
if (err)
|
||||
return err;
|
||||
while (err == 0) {
|
||||
while (1) {
|
||||
if (rdir->tail == rdir->head) {
|
||||
err = v9fs_file_readn(filp, rdir->buf, NULL,
|
||||
buflen, filp->f_pos);
|
||||
if (err <= 0)
|
||||
goto unlock_and_exit;
|
||||
return err;
|
||||
|
||||
rdir->head = 0;
|
||||
rdir->tail = err;
|
||||
|
@ -169,9 +143,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||
rdir->tail - rdir->head, &st);
|
||||
if (err) {
|
||||
p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
|
||||
err = -EIO;
|
||||
p9stat_free(&st);
|
||||
goto unlock_and_exit;
|
||||
return -EIO;
|
||||
}
|
||||
reclen = st.size+2;
|
||||
|
||||
|
@ -180,19 +153,13 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||
|
||||
p9stat_free(&st);
|
||||
|
||||
if (over) {
|
||||
err = 0;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
if (over)
|
||||
return 0;
|
||||
|
||||
rdir->head += reclen;
|
||||
filp->f_pos += reclen;
|
||||
}
|
||||
}
|
||||
|
||||
unlock_and_exit:
|
||||
mutex_unlock(&rdir->mutex);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,21 +185,16 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
|
|||
|
||||
buflen = fid->clnt->msize - P9_READDIRHDRSZ;
|
||||
|
||||
err = v9fs_alloc_rdir_buf(filp, buflen);
|
||||
if (err)
|
||||
goto exit;
|
||||
rdir = (struct p9_rdir *) fid->rdir;
|
||||
rdir = v9fs_alloc_rdir_buf(filp, buflen);
|
||||
if (!rdir)
|
||||
return -ENOMEM;
|
||||
|
||||
err = mutex_lock_interruptible(&rdir->mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while (err == 0) {
|
||||
while (1) {
|
||||
if (rdir->tail == rdir->head) {
|
||||
err = p9_client_readdir(fid, rdir->buf, buflen,
|
||||
filp->f_pos);
|
||||
if (err <= 0)
|
||||
goto unlock_and_exit;
|
||||
return err;
|
||||
|
||||
rdir->head = 0;
|
||||
rdir->tail = err;
|
||||
|
@ -245,8 +207,7 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
|
|||
&curdirent);
|
||||
if (err < 0) {
|
||||
p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
|
||||
err = -EIO;
|
||||
goto unlock_and_exit;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* d_off in dirent structure tracks the offset into
|
||||
|
@ -261,20 +222,13 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
|
|||
curdirent.d_type);
|
||||
oldoffset = curdirent.d_off;
|
||||
|
||||
if (over) {
|
||||
err = 0;
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
if (over)
|
||||
return 0;
|
||||
|
||||
filp->f_pos = curdirent.d_off;
|
||||
rdir->head += err;
|
||||
}
|
||||
}
|
||||
|
||||
unlock_and_exit:
|
||||
mutex_unlock(&rdir->mutex);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue