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:
Al Viro 2013-01-26 00:11:36 +00:00 committed by Eric Van Hensbergen
parent 836dc9e3fb
commit 7ffdea7ea3
1 changed files with 23 additions and 69 deletions

View File

@ -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;
}