3.5.7.27 -stable review patch. If anyone has any objections, please let me know. ------------------ From: Trond Myklebust <Trond.Myklebust@xxxxxxxxxx> commit d07ba8422f1e58be94cc98a1f475946dc1b89f1b upstream. In cases where an rpc client has a parent hierarchy, then rpc_free_client may end up calling rpc_release_client() on the parent, thus recursing back into rpc_free_client. If the hierarchy is deep enough, then we can get into situations where the stack simply overflows. The fix is to have rpc_release_client() loop so that it can take care of the parent rpc client hierarchy without needing to recurse. Reported-by: Jeff Layton <jlayton@xxxxxxxxxx> Reported-by: Weston Andros Adamson <dros@xxxxxxxxxx> Reported-by: Bruce Fields <bfields@xxxxxxxxxxxx> Link: http://lkml.kernel.org/r/2C73011F-0939-434C-9E4D-13A1EB1403D7@xxxxxxxxxx Signed-off-by: Trond Myklebust <Trond.Myklebust@xxxxxxxxxx> [ luis: backported to 3.5: adjusted context ] Signed-off-by: Luis Henriques <luis.henriques@xxxxxxxxxxxxx> --- net/sunrpc/clnt.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 6b0dd20..3321e09 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -599,14 +599,16 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client); /* * Free an RPC client */ -static void +static struct rpc_clnt * rpc_free_client(struct rpc_clnt *clnt) { + struct rpc_clnt *parent = NULL; + dprintk_rcu("RPC: destroying %s client for %s\n", clnt->cl_protname, rcu_dereference(clnt->cl_xprt)->servername); if (clnt->cl_parent != clnt) - rpc_release_client(clnt->cl_parent); + parent = clnt->cl_parent; rpc_unregister_client(clnt); rpc_clnt_remove_pipedir(clnt); rpc_free_iostats(clnt->cl_metrics); @@ -615,18 +617,17 @@ rpc_free_client(struct rpc_clnt *clnt) xprt_put(rcu_dereference_raw(clnt->cl_xprt)); rpciod_down(); kfree(clnt); + return parent; } /* * Free an RPC client */ -static void +static struct rpc_clnt * rpc_free_auth(struct rpc_clnt *clnt) { - if (clnt->cl_auth == NULL) { - rpc_free_client(clnt); - return; - } + if (clnt->cl_auth == NULL) + return rpc_free_client(clnt); /* * Note: RPCSEC_GSS may need to send NULL RPC calls in order to @@ -637,7 +638,8 @@ rpc_free_auth(struct rpc_clnt *clnt) rpcauth_release(clnt->cl_auth); clnt->cl_auth = NULL; if (atomic_dec_and_test(&clnt->cl_count)) - rpc_free_client(clnt); + return rpc_free_client(clnt); + return NULL; } /* @@ -648,10 +650,13 @@ rpc_release_client(struct rpc_clnt *clnt) { dprintk("RPC: rpc_release_client(%p)\n", clnt); - if (list_empty(&clnt->cl_tasks)) - wake_up(&destroy_wait); - if (atomic_dec_and_test(&clnt->cl_count)) - rpc_free_auth(clnt); + do { + if (list_empty(&clnt->cl_tasks)) + wake_up(&destroy_wait); + if (!atomic_dec_and_test(&clnt->cl_count)) + break; + clnt = rpc_free_auth(clnt); + } while (clnt != NULL); } /** -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html