Commit cb7323ff authored by Stanislav Kinsbursky's avatar Stanislav Kinsbursky Committed by Trond Myklebust

lockd: create and use per-net NSM RPC clients on MON/UNMON requests

NSM RPC client can be required on NFSv3 umount, when child reaper is dying
(and destroying it's mount namespace). It means, that current nsproxy is set
to NULL already, but creation of RPC client requires UTS namespace for gaining
hostname string.

This patch creates reference-counted per-net NSM client on first monitor
request and destroys it after last unmonitor request.
Signed-off-by: default avatarStanislav Kinsbursky <skinsbursky@parallels.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 303a7ce9
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/utsname.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -86,7 +85,7 @@ static struct rpc_clnt *nsm_create(struct net *net) ...@@ -86,7 +85,7 @@ static struct rpc_clnt *nsm_create(struct net *net)
return rpc_create(&args); return rpc_create(&args);
} }
__maybe_unused static struct rpc_clnt *nsm_client_get(struct net *net) static struct rpc_clnt *nsm_client_get(struct net *net)
{ {
static DEFINE_MUTEX(nsm_create_mutex); static DEFINE_MUTEX(nsm_create_mutex);
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
...@@ -113,7 +112,7 @@ __maybe_unused static struct rpc_clnt *nsm_client_get(struct net *net) ...@@ -113,7 +112,7 @@ __maybe_unused static struct rpc_clnt *nsm_client_get(struct net *net)
return clnt; return clnt;
} }
__maybe_unused static void nsm_client_put(struct net *net) static void nsm_client_put(struct net *net)
{ {
struct lockd_net *ln = net_generic(net, lockd_net_id); struct lockd_net *ln = net_generic(net, lockd_net_id);
struct rpc_clnt *clnt = ln->nsm_clnt; struct rpc_clnt *clnt = ln->nsm_clnt;
...@@ -132,9 +131,8 @@ __maybe_unused static void nsm_client_put(struct net *net) ...@@ -132,9 +131,8 @@ __maybe_unused static void nsm_client_put(struct net *net)
} }
static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
struct net *net) struct rpc_clnt *clnt)
{ {
struct rpc_clnt *clnt;
int status; int status;
struct nsm_args args = { struct nsm_args args = {
.priv = &nsm->sm_priv, .priv = &nsm->sm_priv,
...@@ -142,20 +140,14 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, ...@@ -142,20 +140,14 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
.vers = 3, .vers = 3,
.proc = NLMPROC_NSM_NOTIFY, .proc = NLMPROC_NSM_NOTIFY,
.mon_name = nsm->sm_mon_name, .mon_name = nsm->sm_mon_name,
.nodename = utsname()->nodename, .nodename = clnt->cl_nodename,
}; };
struct rpc_message msg = { struct rpc_message msg = {
.rpc_argp = &args, .rpc_argp = &args,
.rpc_resp = res, .rpc_resp = res,
}; };
clnt = nsm_create(net); BUG_ON(clnt == NULL);
if (IS_ERR(clnt)) {
status = PTR_ERR(clnt);
dprintk("lockd: failed to create NSM upcall transport, "
"status=%d\n", status);
goto out;
}
memset(res, 0, sizeof(*res)); memset(res, 0, sizeof(*res));
...@@ -166,8 +158,6 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, ...@@ -166,8 +158,6 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
status); status);
else else
status = 0; status = 0;
rpc_shutdown_client(clnt);
out:
return status; return status;
} }
...@@ -187,6 +177,7 @@ int nsm_monitor(const struct nlm_host *host) ...@@ -187,6 +177,7 @@ int nsm_monitor(const struct nlm_host *host)
struct nsm_handle *nsm = host->h_nsmhandle; struct nsm_handle *nsm = host->h_nsmhandle;
struct nsm_res res; struct nsm_res res;
int status; int status;
struct rpc_clnt *clnt;
dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
...@@ -199,7 +190,15 @@ int nsm_monitor(const struct nlm_host *host) ...@@ -199,7 +190,15 @@ int nsm_monitor(const struct nlm_host *host)
*/ */
nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host->net); clnt = nsm_client_get(host->net);
if (IS_ERR(clnt)) {
status = PTR_ERR(clnt);
dprintk("lockd: failed to create NSM upcall transport, "
"status=%d, net=%p\n", status, host->net);
return status;
}
status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, clnt);
if (unlikely(res.status != 0)) if (unlikely(res.status != 0))
status = -EIO; status = -EIO;
if (unlikely(status < 0)) { if (unlikely(status < 0)) {
...@@ -231,9 +230,11 @@ void nsm_unmonitor(const struct nlm_host *host) ...@@ -231,9 +230,11 @@ void nsm_unmonitor(const struct nlm_host *host)
if (atomic_read(&nsm->sm_count) == 1 if (atomic_read(&nsm->sm_count) == 1
&& nsm->sm_monitored && !nsm->sm_sticky) { && nsm->sm_monitored && !nsm->sm_sticky) {
struct lockd_net *ln = net_generic(host->net, lockd_net_id);
dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host->net); status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, ln->nsm_clnt);
if (res.status != 0) if (res.status != 0)
status = -EIO; status = -EIO;
if (status < 0) if (status < 0)
...@@ -241,6 +242,8 @@ void nsm_unmonitor(const struct nlm_host *host) ...@@ -241,6 +242,8 @@ void nsm_unmonitor(const struct nlm_host *host)
nsm->sm_name); nsm->sm_name);
else else
nsm->sm_monitored = 0; nsm->sm_monitored = 0;
nsm_client_put(host->net);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment