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
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue