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 p9_rdir {
struct mutex mutex;
int head; int head;
int tail; 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 = filp->private_data;
struct p9_fid *fid; if (!fid->rdir)
int err = 0; fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
return fid->rdir;
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;
} }
/** /**
@ -145,20 +123,16 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
buflen = fid->clnt->msize - P9_IOHDRSZ; buflen = fid->clnt->msize - P9_IOHDRSZ;
err = v9fs_alloc_rdir_buf(filp, buflen); rdir = v9fs_alloc_rdir_buf(filp, buflen);
if (err) if (!rdir)
goto exit; return -ENOMEM;
rdir = (struct p9_rdir *) fid->rdir;
err = mutex_lock_interruptible(&rdir->mutex); while (1) {
if (err)
return err;
while (err == 0) {
if (rdir->tail == rdir->head) { if (rdir->tail == rdir->head) {
err = v9fs_file_readn(filp, rdir->buf, NULL, err = v9fs_file_readn(filp, rdir->buf, NULL,
buflen, filp->f_pos); buflen, filp->f_pos);
if (err <= 0) if (err <= 0)
goto unlock_and_exit; return err;
rdir->head = 0; rdir->head = 0;
rdir->tail = err; 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); rdir->tail - rdir->head, &st);
if (err) { if (err) {
p9_debug(P9_DEBUG_VFS, "returned %d\n", err); p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
err = -EIO;
p9stat_free(&st); p9stat_free(&st);
goto unlock_and_exit; return -EIO;
} }
reclen = st.size+2; reclen = st.size+2;
@ -180,19 +153,13 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
p9stat_free(&st); p9stat_free(&st);
if (over) { if (over)
err = 0; return 0;
goto unlock_and_exit;
}
rdir->head += reclen; rdir->head += reclen;
filp->f_pos += 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; buflen = fid->clnt->msize - P9_READDIRHDRSZ;
err = v9fs_alloc_rdir_buf(filp, buflen); rdir = v9fs_alloc_rdir_buf(filp, buflen);
if (err) if (!rdir)
goto exit; return -ENOMEM;
rdir = (struct p9_rdir *) fid->rdir;
err = mutex_lock_interruptible(&rdir->mutex); while (1) {
if (err)
return err;
while (err == 0) {
if (rdir->tail == rdir->head) { if (rdir->tail == rdir->head) {
err = p9_client_readdir(fid, rdir->buf, buflen, err = p9_client_readdir(fid, rdir->buf, buflen,
filp->f_pos); filp->f_pos);
if (err <= 0) if (err <= 0)
goto unlock_and_exit; return err;
rdir->head = 0; rdir->head = 0;
rdir->tail = err; rdir->tail = err;
@ -245,8 +207,7 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
&curdirent); &curdirent);
if (err < 0) { if (err < 0) {
p9_debug(P9_DEBUG_VFS, "returned %d\n", err); p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
err = -EIO; return -EIO;
goto unlock_and_exit;
} }
/* d_off in dirent structure tracks the offset into /* 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); curdirent.d_type);
oldoffset = curdirent.d_off; oldoffset = curdirent.d_off;
if (over) { if (over)
err = 0; return 0;
goto unlock_and_exit;
}
filp->f_pos = curdirent.d_off; filp->f_pos = curdirent.d_off;
rdir->head += err; rdir->head += err;
} }
} }
unlock_and_exit:
mutex_unlock(&rdir->mutex);
exit:
return err;
} }