+++ /dev/null
-From 03a9a42a1a7e5b3e7919ddfacc1d1cc81882a955 Mon Sep 17 00:00:00 2001
-From: Trond Myklebust <trond.myklebust@primarydata.com>
-Date: Fri, 30 Jan 2015 18:12:28 -0500
-Subject: SUNRPC: NULL utsname dereference on NFS umount during namespace cleanup
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-From: Trond Myklebust <trond.myklebust@primarydata.com>
-
-commit 03a9a42a1a7e5b3e7919ddfacc1d1cc81882a955 upstream.
-
-Fix an Oopsable condition when nsm_mon_unmon is called as part of the
-namespace cleanup, which now apparently happens after the utsname
-has been freed.
-
-Link: http://lkml.kernel.org/r/20150125220604.090121ae@neptune.home
-Reported-by: Bruno Prémont <bonbons@linux-vserver.org>
-Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- fs/lockd/mon.c | 13 +++++++++----
- include/linux/sunrpc/clnt.h | 3 ++-
- net/sunrpc/clnt.c | 12 +++++++-----
- net/sunrpc/rpcb_clnt.c | 8 ++++++--
- 4 files changed, 24 insertions(+), 12 deletions(-)
-
---- a/fs/lockd/mon.c
-+++ b/fs/lockd/mon.c
-@@ -65,7 +65,7 @@ static inline struct sockaddr *nsm_addr(
- return (struct sockaddr *)&nsm->sm_addr;
- }
-
--static struct rpc_clnt *nsm_create(struct net *net)
-+static struct rpc_clnt *nsm_create(struct net *net, const char *nodename)
- {
- struct sockaddr_in sin = {
- .sin_family = AF_INET,
-@@ -77,6 +77,7 @@ static struct rpc_clnt *nsm_create(struc
- .address = (struct sockaddr *)&sin,
- .addrsize = sizeof(sin),
- .servername = "rpc.statd",
-+ .nodename = nodename,
- .program = &nsm_program,
- .version = NSM_VERSION,
- .authflavor = RPC_AUTH_NULL,
-@@ -102,7 +103,7 @@ out:
- return clnt;
- }
-
--static struct rpc_clnt *nsm_client_get(struct net *net)
-+static struct rpc_clnt *nsm_client_get(struct net *net, const char *nodename)
- {
- struct rpc_clnt *clnt, *new;
- struct lockd_net *ln = net_generic(net, lockd_net_id);
-@@ -111,7 +112,7 @@ static struct rpc_clnt *nsm_client_get(s
- if (clnt != NULL)
- goto out;
-
-- clnt = new = nsm_create(net);
-+ clnt = new = nsm_create(net, nodename);
- if (IS_ERR(clnt))
- goto out;
-
-@@ -190,19 +191,23 @@ int nsm_monitor(const struct nlm_host *h
- struct nsm_res res;
- int status;
- struct rpc_clnt *clnt;
-+ const char *nodename = NULL;
-
- dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
-
- if (nsm->sm_monitored)
- return 0;
-
-+ if (host->h_rpcclnt)
-+ nodename = host->h_rpcclnt->cl_nodename;
-+
- /*
- * Choose whether to record the caller_name or IP address of
- * this peer in the local rpc.statd's database.
- */
- nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
-
-- clnt = nsm_client_get(host->net);
-+ clnt = nsm_client_get(host->net, nodename);
- if (IS_ERR(clnt)) {
- status = PTR_ERR(clnt);
- dprintk("lockd: failed to create NSM upcall transport, "
---- a/include/linux/sunrpc/clnt.h
-+++ b/include/linux/sunrpc/clnt.h
-@@ -57,7 +57,7 @@ struct rpc_clnt {
- const struct rpc_timeout *cl_timeout; /* Timeout strategy */
-
- int cl_nodelen; /* nodename length */
-- char cl_nodename[UNX_MAXNODENAME];
-+ char cl_nodename[UNX_MAXNODENAME+1];
- struct rpc_pipe_dir_head cl_pipedir_objects;
- struct rpc_clnt * cl_parent; /* Points to parent of clones */
- struct rpc_rtt cl_rtt_default;
-@@ -109,6 +109,7 @@ struct rpc_create_args {
- struct sockaddr *saddress;
- const struct rpc_timeout *timeout;
- const char *servername;
-+ const char *nodename;
- const struct rpc_program *program;
- u32 prognumber; /* overrides program->number */
- u32 version;
---- a/net/sunrpc/clnt.c
-+++ b/net/sunrpc/clnt.c
-@@ -286,10 +286,8 @@ static struct rpc_xprt *rpc_clnt_set_tra
-
- static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
- {
-- clnt->cl_nodelen = strlen(nodename);
-- if (clnt->cl_nodelen > UNX_MAXNODENAME)
-- clnt->cl_nodelen = UNX_MAXNODENAME;
-- memcpy(clnt->cl_nodename, nodename, clnt->cl_nodelen);
-+ clnt->cl_nodelen = strlcpy(clnt->cl_nodename,
-+ nodename, sizeof(clnt->cl_nodename));
- }
-
- static int rpc_client_register(struct rpc_clnt *clnt,
-@@ -360,6 +358,7 @@ static struct rpc_clnt * rpc_new_client(
- const struct rpc_version *version;
- struct rpc_clnt *clnt = NULL;
- const struct rpc_timeout *timeout;
-+ const char *nodename = args->nodename;
- int err;
-
- /* sanity check the name before trying to print it */
-@@ -415,8 +414,10 @@ static struct rpc_clnt * rpc_new_client(
-
- atomic_set(&clnt->cl_count, 1);
-
-+ if (nodename == NULL)
-+ nodename = utsname()->nodename;
- /* save the nodename */
-- rpc_clnt_set_nodename(clnt, utsname()->nodename);
-+ rpc_clnt_set_nodename(clnt, nodename);
-
- err = rpc_client_register(clnt, args->authflavor, args->client_name);
- if (err)
-@@ -563,6 +564,7 @@ static struct rpc_clnt *__rpc_clone_clie
- if (xprt == NULL)
- goto out_err;
- args->servername = xprt->servername;
-+ args->nodename = clnt->cl_nodename;
-
- new = rpc_new_client(args, xprt, clnt);
- if (IS_ERR(new)) {
---- a/net/sunrpc/rpcb_clnt.c
-+++ b/net/sunrpc/rpcb_clnt.c
-@@ -355,7 +355,8 @@ out:
- return result;
- }
-
--static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname,
-+static struct rpc_clnt *rpcb_create(struct net *net, const char *nodename,
-+ const char *hostname,
- struct sockaddr *srvaddr, size_t salen,
- int proto, u32 version)
- {
-@@ -365,6 +366,7 @@ static struct rpc_clnt *rpcb_create(stru
- .address = srvaddr,
- .addrsize = salen,
- .servername = hostname,
-+ .nodename = nodename,
- .program = &rpcb_program,
- .version = version,
- .authflavor = RPC_AUTH_UNIX,
-@@ -740,7 +742,9 @@ void rpcb_getport_async(struct rpc_task
- dprintk("RPC: %5u %s: trying rpcbind version %u\n",
- task->tk_pid, __func__, bind_version);
-
-- rpcb_clnt = rpcb_create(xprt->xprt_net, xprt->servername, sap, salen,
-+ rpcb_clnt = rpcb_create(xprt->xprt_net,
-+ clnt->cl_nodename,
-+ xprt->servername, sap, salen,
- xprt->prot, bind_version);
- if (IS_ERR(rpcb_clnt)) {
- status = PTR_ERR(rpcb_clnt);