]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
locking in fs/9p ->readdir()
authorAl Viro <viro@ZenIV.linux.org.uk>
Sat, 26 Jan 2013 00:11:36 +0000 (00:11 +0000)
committerEric Van Hensbergen <ericvh@gmail.com>
Sun, 10 Feb 2013 22:29:33 +0000 (16:29 -0600)
... 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>
fs/9p/vfs_dir.c

index ff911e779651bcf5726c08ea412bceebd1f9b79b..be1e34adc3c602ca0e2eb49f3607c7076ddafb3c 100644 (file)
  */
 
 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;
 }