Merge tag 'for-linus-merge-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Oct 2012 00:59:23 +0000 (09:59 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Oct 2012 00:59:23 +0000 (09:59 +0900)
Pull v9fs update from Eric Van Hensbergen.

* tag 'for-linus-merge-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs:
  9P: Fix race between p9_write_work() and p9_fd_request()
  9P: Fix race in p9_write_work()
  9P: fix test at the end of p9_write_work()
  9P: Fix race in p9_read_work()
  9p: don't use __getname/__putname for uname/aname
  net/9p: Check errno validity
  fs/9p: avoid debug OOPS when reading a long symlink

fs/9p/v9fs.c
fs/9p/vfs_inode.c
net/9p/client.c
net/9p/trans_fd.c

index 392c5da..d934f04 100644 (file)
@@ -184,10 +184,20 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                        v9ses->afid = option;
                        break;
                case Opt_uname:
-                       match_strlcpy(v9ses->uname, &args[0], PATH_MAX);
+                       kfree(v9ses->uname);
+                       v9ses->uname = match_strdup(&args[0]);
+                       if (!v9ses->uname) {
+                               ret = -ENOMEM;
+                               goto free_and_return;
+                       }
                        break;
                case Opt_remotename:
-                       match_strlcpy(v9ses->aname, &args[0], PATH_MAX);
+                       kfree(v9ses->aname);
+                       v9ses->aname = match_strdup(&args[0]);
+                       if (!v9ses->aname) {
+                               ret = -ENOMEM;
+                               goto free_and_return;
+                       }
                        break;
                case Opt_nodevmap:
                        v9ses->nodev = 1;
@@ -287,21 +297,21 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
        struct p9_fid *fid;
        int rc;
 
-       v9ses->uname = __getname();
+       v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);
        if (!v9ses->uname)
                return ERR_PTR(-ENOMEM);
 
-       v9ses->aname = __getname();
+       v9ses->aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);
        if (!v9ses->aname) {
-               __putname(v9ses->uname);
+               kfree(v9ses->uname);
                return ERR_PTR(-ENOMEM);
        }
        init_rwsem(&v9ses->rename_sem);
 
        rc = bdi_setup_and_register(&v9ses->bdi, "9p", BDI_CAP_MAP_COPY);
        if (rc) {
-               __putname(v9ses->aname);
-               __putname(v9ses->uname);
+               kfree(v9ses->aname);
+               kfree(v9ses->uname);
                return ERR_PTR(rc);
        }
 
@@ -309,8 +319,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
        list_add(&v9ses->slist, &v9fs_sessionlist);
        spin_unlock(&v9fs_sessionlist_lock);
 
-       strcpy(v9ses->uname, V9FS_DEFUSER);
-       strcpy(v9ses->aname, V9FS_DEFANAME);
        v9ses->uid = ~0;
        v9ses->dfltuid = V9FS_DEFUID;
        v9ses->dfltgid = V9FS_DEFGID;
@@ -412,8 +420,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
                kfree(v9ses->cachetag);
        }
 #endif
-       __putname(v9ses->uname);
-       __putname(v9ses->aname);
+       kfree(v9ses->uname);
+       kfree(v9ses->aname);
 
        bdi_destroy(&v9ses->bdi);
 
index cbf9dbb..890bed5 100644 (file)
@@ -1276,12 +1276,12 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
        }
 
        /* copy extension buffer into buffer */
-       strncpy(buffer, st->extension, buflen);
+       retval = min(strlen(st->extension)+1, (size_t)buflen);
+       memcpy(buffer, st->extension, retval);
 
-       p9_debug(P9_DEBUG_VFS, "%s -> %s (%s)\n",
-                dentry->d_name.name, st->extension, buffer);
+       p9_debug(P9_DEBUG_VFS, "%s -> %s (%.*s)\n",
+                dentry->d_name.name, st->extension, buflen, buffer);
 
-       retval = strnlen(buffer, buflen);
 done:
        p9stat_free(st);
        kfree(st);
index 8260f13..34d4176 100644 (file)
@@ -76,6 +76,20 @@ inline int p9_is_proto_dotu(struct p9_client *clnt)
 }
 EXPORT_SYMBOL(p9_is_proto_dotu);
 
+/*
+ * Some error codes are taken directly from the server replies,
+ * make sure they are valid.
+ */
+static int safe_errno(int err)
+{
+       if ((err > 0) || (err < -MAX_ERRNO)) {
+               p9_debug(P9_DEBUG_ERROR, "Invalid error code %d\n", err);
+               return -EPROTO;
+       }
+       return err;
+}
+
+
 /* Interpret mount option for protocol version */
 static int get_protocol_version(char *s)
 {
@@ -782,7 +796,7 @@ again:
                return req;
 reterr:
        p9_free_req(c, req);
-       return ERR_PTR(err);
+       return ERR_PTR(safe_errno(err));
 }
 
 /**
@@ -865,7 +879,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
                return req;
 reterr:
        p9_free_req(c, req);
-       return ERR_PTR(err);
+       return ERR_PTR(safe_errno(err));
 }
 
 static struct p9_fid *p9_fid_create(struct p9_client *clnt)
index 15656b8..02efb25 100644 (file)
@@ -316,8 +316,7 @@ static void p9_read_work(struct work_struct *work)
                                                m->rsize - m->rpos);
        p9_debug(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err);
        if (err == -EAGAIN) {
-               clear_bit(Rworksched, &m->wsched);
-               return;
+               goto end_clear;
        }
 
        if (err <= 0)
@@ -379,19 +378,20 @@ static void p9_read_work(struct work_struct *work)
                m->req = NULL;
        }
 
+end_clear:
+       clear_bit(Rworksched, &m->wsched);
+
        if (!list_empty(&m->req_list)) {
                if (test_and_clear_bit(Rpending, &m->wsched))
                        n = POLLIN;
                else
                        n = p9_fd_poll(m->client, NULL);
 
-               if (n & POLLIN) {
+               if ((n & POLLIN) && !test_and_set_bit(Rworksched, &m->wsched)) {
                        p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m);
                        schedule_work(&m->rq);
-               } else
-                       clear_bit(Rworksched, &m->wsched);
-       } else
-               clear_bit(Rworksched, &m->wsched);
+               }
+       }
 
        return;
 error:
@@ -453,12 +453,13 @@ static void p9_write_work(struct work_struct *work)
        }
 
        if (!m->wsize) {
+               spin_lock(&m->client->lock);
                if (list_empty(&m->unsent_req_list)) {
                        clear_bit(Wworksched, &m->wsched);
+                       spin_unlock(&m->client->lock);
                        return;
                }
 
-               spin_lock(&m->client->lock);
                req = list_entry(m->unsent_req_list.next, struct p9_req_t,
                               req_list);
                req->status = REQ_STATUS_SENT;
@@ -476,10 +477,9 @@ static void p9_write_work(struct work_struct *work)
        clear_bit(Wpending, &m->wsched);
        err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos);
        p9_debug(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err);
-       if (err == -EAGAIN) {
-               clear_bit(Wworksched, &m->wsched);
-               return;
-       }
+       if (err == -EAGAIN)
+               goto end_clear;
+
 
        if (err < 0)
                goto error;
@@ -492,19 +492,21 @@ static void p9_write_work(struct work_struct *work)
        if (m->wpos == m->wsize)
                m->wpos = m->wsize = 0;
 
-       if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
+end_clear:
+       clear_bit(Wworksched, &m->wsched);
+
+       if (m->wsize || !list_empty(&m->unsent_req_list)) {
                if (test_and_clear_bit(Wpending, &m->wsched))
                        n = POLLOUT;
                else
                        n = p9_fd_poll(m->client, NULL);
 
-               if (n & POLLOUT) {
+               if ((n & POLLOUT) &&
+                  !test_and_set_bit(Wworksched, &m->wsched)) {
                        p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m);
                        schedule_work(&m->wq);
-               } else
-                       clear_bit(Wworksched, &m->wsched);
-       } else
-               clear_bit(Wworksched, &m->wsched);
+               }
+       }
 
        return;