From 811dd772435fa99871b738573bf83e4be8fe70a2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 10 Apr 2013 09:50:13 -0700 Subject: [PATCH] 3.8-stable patches 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 --- ....1-fix-bugs-in-nfs4_walk_client_list.patch | 132 ++++++++++++++++++ ...eak-in-nfs4_discover_server_trunking.patch | 37 +++++ queue-3.8/series | 3 + queue-3.8/sunrpc-remove-extra-xprt_put.patch | 46 ++++++ 4 files changed, 218 insertions(+) create mode 100644 queue-3.8/nfsv4-4.1-fix-bugs-in-nfs4_walk_client_list.patch create mode 100644 queue-3.8/nfsv4-fix-a-memory-leak-in-nfs4_discover_server_trunking.patch create mode 100644 queue-3.8/sunrpc-remove-extra-xprt_put.patch 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 index 00000000000..8dcdfa977c0 --- /dev/null +++ b/queue-3.8/nfsv4-4.1-fix-bugs-in-nfs4_walk_client_list.patch @@ -0,0 +1,132 @@ +From 7b1f1fd1842e6ede25183c267ae733a7f67f00bc Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Fri, 5 Apr 2013 16:11:11 -0400 +Subject: NFSv4/4.1: Fix bugs in nfs4[01]_walk_client_list + +From: Trond Myklebust + +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 +Cc: Chuck Lever +Cc: Bryan Schumaker +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..c362e9cfc27 --- /dev/null +++ b/queue-3.8/nfsv4-fix-a-memory-leak-in-nfs4_discover_server_trunking.patch @@ -0,0 +1,37 @@ +From b193d59a4863ea670872d76dc99231ddeb598625 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Thu, 4 Apr 2013 15:55:00 -0400 +Subject: NFSv4: Fix a memory leak in nfs4_discover_server_trunking + +From: Trond Myklebust + +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 +Cc: Chuck Lever +Signed-off-by: Greg Kroah-Hartman + +--- + 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: diff --git a/queue-3.8/series b/queue-3.8/series index fae6f23b7b1..d26afae0f05 100644 --- a/queue-3.8/series +++ b/queue-3.8/series @@ -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 index 00000000000..94bcad4a4e4 --- /dev/null +++ b/queue-3.8/sunrpc-remove-extra-xprt_put.patch @@ -0,0 +1,46 @@ +From a58e0be6f6b3eb2079b0b8fedc9df6fa86869f1e Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Fri, 22 Mar 2013 12:52:59 -0400 +Subject: SUNRPC: Remove extra xprt_put() + +From: Chuck Lever + +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 +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + 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); -- 2.47.3