]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.8-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 10 Apr 2013 16:50:13 +0000 (09:50 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 10 Apr 2013 16:50:13 +0000 (09:50 -0700)
added patches:
nfsv4-4.1-fix-bugs-in-nfs4_walk_client_list.patch
nfsv4-fix-a-memory-leak-in-nfs4_discover_server_trunking.patch
sunrpc-remove-extra-xprt_put.patch

queue-3.8/nfsv4-4.1-fix-bugs-in-nfs4_walk_client_list.patch [new file with mode: 0644]
queue-3.8/nfsv4-fix-a-memory-leak-in-nfs4_discover_server_trunking.patch [new file with mode: 0644]
queue-3.8/series
queue-3.8/sunrpc-remove-extra-xprt_put.patch [new file with mode: 0644]

diff --git a/queue-3.8/nfsv4-4.1-fix-bugs-in-nfs4_walk_client_list.patch b/queue-3.8/nfsv4-4.1-fix-bugs-in-nfs4_walk_client_list.patch
new file mode 100644 (file)
index 0000000..8dcdfa9
--- /dev/null
@@ -0,0 +1,132 @@
+From 7b1f1fd1842e6ede25183c267ae733a7f67f00bc Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+Date: Fri, 5 Apr 2013 16:11:11 -0400
+Subject: NFSv4/4.1: Fix bugs in nfs4[01]_walk_client_list
+
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+
+commit 7b1f1fd1842e6ede25183c267ae733a7f67f00bc upstream.
+
+It is unsafe to use list_for_each_entry_safe() here, because
+when we drop the nn->nfs_client_lock, we pin the _current_ list
+entry and ensure that it stays in the list, but we don't do the
+same for the _next_ list entry. Use of list_for_each_entry() is
+therefore the correct thing to do.
+
+Also fix the refcounting in nfs41_walk_client_list().
+
+Finally, ensure that the nfs_client has finished being initialised
+and, in the case of NFSv4.1, that the session is set up.
+
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Cc: Chuck Lever <chuck.lever@oracle.com>
+Cc: Bryan Schumaker <bjschuma@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/nfs4client.c |   44 ++++++++++++++++++++++++++++----------------
+ 1 file changed, 28 insertions(+), 16 deletions(-)
+
+--- a/fs/nfs/nfs4client.c
++++ b/fs/nfs/nfs4client.c
+@@ -300,7 +300,7 @@ int nfs40_walk_client_list(struct nfs_cl
+                          struct rpc_cred *cred)
+ {
+       struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
+-      struct nfs_client *pos, *n, *prev = NULL;
++      struct nfs_client *pos, *prev = NULL;
+       struct nfs4_setclientid_res clid = {
+               .clientid       = new->cl_clientid,
+               .confirm        = new->cl_confirm,
+@@ -308,10 +308,23 @@ int nfs40_walk_client_list(struct nfs_cl
+       int status = -NFS4ERR_STALE_CLIENTID;
+       spin_lock(&nn->nfs_client_lock);
+-      list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
++      list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
+               /* If "pos" isn't marked ready, we can't trust the
+                * remaining fields in "pos" */
+-              if (pos->cl_cons_state < NFS_CS_READY)
++              if (pos->cl_cons_state > NFS_CS_READY) {
++                      atomic_inc(&pos->cl_count);
++                      spin_unlock(&nn->nfs_client_lock);
++
++                      if (prev)
++                              nfs_put_client(prev);
++                      prev = pos;
++
++                      status = nfs_wait_client_init_complete(pos);
++                      spin_lock(&nn->nfs_client_lock);
++                      if (status < 0)
++                              continue;
++              }
++              if (pos->cl_cons_state != NFS_CS_READY)
+                       continue;
+               if (pos->rpc_ops != new->rpc_ops)
+@@ -423,16 +436,16 @@ int nfs41_walk_client_list(struct nfs_cl
+                          struct rpc_cred *cred)
+ {
+       struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
+-      struct nfs_client *pos, *n, *prev = NULL;
++      struct nfs_client *pos, *prev = NULL;
+       int status = -NFS4ERR_STALE_CLIENTID;
+       spin_lock(&nn->nfs_client_lock);
+-      list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
++      list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
+               /* If "pos" isn't marked ready, we can't trust the
+                * remaining fields in "pos", especially the client
+                * ID and serverowner fields.  Wait for CREATE_SESSION
+                * to finish. */
+-              if (pos->cl_cons_state < NFS_CS_READY) {
++              if (pos->cl_cons_state > NFS_CS_READY) {
+                       atomic_inc(&pos->cl_count);
+                       spin_unlock(&nn->nfs_client_lock);
+@@ -440,18 +453,17 @@ int nfs41_walk_client_list(struct nfs_cl
+                               nfs_put_client(prev);
+                       prev = pos;
+-                      nfs4_schedule_lease_recovery(pos);
+                       status = nfs_wait_client_init_complete(pos);
+-                      if (status < 0) {
+-                              nfs_put_client(pos);
+-                              spin_lock(&nn->nfs_client_lock);
+-                              continue;
++                      if (status == 0) {
++                              nfs4_schedule_lease_recovery(pos);
++                              status = nfs4_wait_clnt_recover(pos);
+                       }
+-                      status = pos->cl_cons_state;
+                       spin_lock(&nn->nfs_client_lock);
+                       if (status < 0)
+                               continue;
+               }
++              if (pos->cl_cons_state != NFS_CS_READY)
++                      continue;
+               if (pos->rpc_ops != new->rpc_ops)
+                       continue;
+@@ -469,17 +481,17 @@ int nfs41_walk_client_list(struct nfs_cl
+                       continue;
+               atomic_inc(&pos->cl_count);
+-              spin_unlock(&nn->nfs_client_lock);
++              *result = pos;
+               dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
+                       __func__, pos, atomic_read(&pos->cl_count));
+-
+-              *result = pos;
+-              return 0;
++              break;
+       }
+       /* No matching nfs_client found. */
+       spin_unlock(&nn->nfs_client_lock);
+       dprintk("NFS: <-- %s status = %d\n", __func__, status);
++      if (prev)
++              nfs_put_client(prev);
+       return status;
+ }
+ #endif        /* CONFIG_NFS_V4_1 */
diff --git a/queue-3.8/nfsv4-fix-a-memory-leak-in-nfs4_discover_server_trunking.patch b/queue-3.8/nfsv4-fix-a-memory-leak-in-nfs4_discover_server_trunking.patch
new file mode 100644 (file)
index 0000000..c362e9c
--- /dev/null
@@ -0,0 +1,37 @@
+From b193d59a4863ea670872d76dc99231ddeb598625 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+Date: Thu, 4 Apr 2013 15:55:00 -0400
+Subject: NFSv4: Fix a memory leak in nfs4_discover_server_trunking
+
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+
+commit b193d59a4863ea670872d76dc99231ddeb598625 upstream.
+
+When we assign a new rpc_client to clp->cl_rpcclient, we need to destroy
+the old one.
+
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Cc: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/nfs4state.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/fs/nfs/nfs4state.c
++++ b/fs/nfs/nfs4state.c
+@@ -1877,7 +1877,13 @@ again:
+                       status = PTR_ERR(clnt);
+                       break;
+               }
+-              clp->cl_rpcclient = clnt;
++              /* Note: this is safe because we haven't yet marked the
++               * client as ready, so we are the only user of
++               * clp->cl_rpcclient
++               */
++              clnt = xchg(&clp->cl_rpcclient, clnt);
++              rpc_shutdown_client(clnt);
++              clnt = clp->cl_rpcclient;
+               goto again;
+       case -NFS4ERR_MINOR_VERS_MISMATCH:
index fae6f23b7b10a82c3bb6de9b07f48aae991ed662..d26afae0f055b2ba782cc48ecd50f0a9a8ada030 100644 (file)
@@ -43,3 +43,6 @@ crypto-ux500-add-missing-comma.patch
 crypto-gcm-fix-assumption-that-assoc-has-one-segment.patch
 drm-mgag200-index-24-in-extended-crtc-registers-is-24-in-hex-not-decimal.patch
 block-avoid-using-uninitialized-value-in-from-queue_var_store.patch
+sunrpc-remove-extra-xprt_put.patch
+nfsv4-fix-a-memory-leak-in-nfs4_discover_server_trunking.patch
+nfsv4-4.1-fix-bugs-in-nfs4_walk_client_list.patch
diff --git a/queue-3.8/sunrpc-remove-extra-xprt_put.patch b/queue-3.8/sunrpc-remove-extra-xprt_put.patch
new file mode 100644 (file)
index 0000000..94bcad4
--- /dev/null
@@ -0,0 +1,46 @@
+From a58e0be6f6b3eb2079b0b8fedc9df6fa86869f1e Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 22 Mar 2013 12:52:59 -0400
+Subject: SUNRPC: Remove extra xprt_put()
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+commit a58e0be6f6b3eb2079b0b8fedc9df6fa86869f1e upstream.
+
+While testing error cases where rpc_new_client() fails, I saw
+some oopses.
+
+If rpc_new_client() fails, it already invokes xprt_put().  Thus
+__rpc_clone_client() does not need to invoke it again.
+
+Introduced by commit 1b63a751 "SUNRPC: Refactor rpc_clone_client()"
+Fri Sep 14, 2012.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/sunrpc/clnt.c |    4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/net/sunrpc/clnt.c
++++ b/net/sunrpc/clnt.c
+@@ -511,7 +511,7 @@ static struct rpc_clnt *__rpc_clone_clie
+       new = rpc_new_client(args, xprt);
+       if (IS_ERR(new)) {
+               err = PTR_ERR(new);
+-              goto out_put;
++              goto out_err;
+       }
+       atomic_inc(&clnt->cl_count);
+@@ -524,8 +524,6 @@ static struct rpc_clnt *__rpc_clone_clie
+       new->cl_chatty = clnt->cl_chatty;
+       return new;
+-out_put:
+-      xprt_put(xprt);
+ out_err:
+       dprintk("RPC:       %s: returned error %d\n", __func__, err);
+       return ERR_PTR(err);