The commit is pushed to "branch-rh7-3.10.0-229.7.2.vz7.8.x-ovz" and will appear 
at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-229.7.2.vz7.8.5
------>
commit a7e1413049ff1d97e0e726fb1e58fb631e0dbcd6
Author: Trond Myklebust <trond.mykleb...@primarydata.com>
Date:   Fri Oct 9 15:13:58 2015 +0400

    ms/SUNRPC: NULL utsname dereference on NFS umount during namespace cleanup
    
    ms commit: 03a9a42a1a7e5b3e7919ddfacc1d1cc81882a955
    
    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.09012...@neptune.home
    Reported-by: Bruno Prémont <bonb...@linux-vserver.org>
    Signed-off-by: Trond Myklebust <trond.mykleb...@primarydata.com>
    
    [aryabinin: I've hit this while invetigating
     https://jira.sw.ru/browse/PSBM-39721, although this is
     an another issue]
    
    Signed-off-by: Andrey Ryabinin <aryabi...@virtuozzo.com>
---
 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(-)

diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 6ae664b..22626c1 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -65,7 +65,7 @@ static inline struct sockaddr *nsm_addr(const struct 
nsm_handle *nsm)
        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(struct net *net)
                .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(struct net *net)
        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 *host)
        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, "
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 70736b9..b363a0f 100644
--- 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;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 488ddee..4186422 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -286,10 +286,8 @@ static struct rpc_xprt *rpc_clnt_set_transport(struct 
rpc_clnt *clnt,
 
 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_create_args *args,
        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(const struct 
rpc_create_args *args,
 
        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)
@@ -569,6 +570,7 @@ static struct rpc_clnt *__rpc_clone_client(struct 
rpc_create_args *args,
        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)) {
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 1891a10..74b75c3 100644
--- 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(struct net *net, const 
char *hostname,
                .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 *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);
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to