diff options
Diffstat (limited to 'fs/lockd/mon.c')
-rw-r--r-- | fs/lockd/mon.c | 86 |
1 files changed, 69 insertions, 17 deletions
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 7ef14b3c5bee..e4fb3ba5a58a 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -7,7 +7,6 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/utsname.h> | ||
11 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
12 | #include <linux/ktime.h> | 11 | #include <linux/ktime.h> |
13 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
@@ -19,6 +18,8 @@ | |||
19 | 18 | ||
20 | #include <asm/unaligned.h> | 19 | #include <asm/unaligned.h> |
21 | 20 | ||
21 | #include "netns.h" | ||
22 | |||
22 | #define NLMDBG_FACILITY NLMDBG_MONITOR | 23 | #define NLMDBG_FACILITY NLMDBG_MONITOR |
23 | #define NSM_PROGRAM 100024 | 24 | #define NSM_PROGRAM 100024 |
24 | #define NSM_VERSION 1 | 25 | #define NSM_VERSION 1 |
@@ -40,6 +41,7 @@ struct nsm_args { | |||
40 | u32 proc; | 41 | u32 proc; |
41 | 42 | ||
42 | char *mon_name; | 43 | char *mon_name; |
44 | char *nodename; | ||
43 | }; | 45 | }; |
44 | 46 | ||
45 | struct nsm_res { | 47 | struct nsm_res { |
@@ -70,7 +72,7 @@ static struct rpc_clnt *nsm_create(struct net *net) | |||
70 | }; | 72 | }; |
71 | struct rpc_create_args args = { | 73 | struct rpc_create_args args = { |
72 | .net = net, | 74 | .net = net, |
73 | .protocol = XPRT_TRANSPORT_UDP, | 75 | .protocol = XPRT_TRANSPORT_TCP, |
74 | .address = (struct sockaddr *)&sin, | 76 | .address = (struct sockaddr *)&sin, |
75 | .addrsize = sizeof(sin), | 77 | .addrsize = sizeof(sin), |
76 | .servername = "rpc.statd", | 78 | .servername = "rpc.statd", |
@@ -83,10 +85,54 @@ static struct rpc_clnt *nsm_create(struct net *net) | |||
83 | return rpc_create(&args); | 85 | return rpc_create(&args); |
84 | } | 86 | } |
85 | 87 | ||
86 | static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, | 88 | static struct rpc_clnt *nsm_client_get(struct net *net) |
87 | struct net *net) | ||
88 | { | 89 | { |
90 | static DEFINE_MUTEX(nsm_create_mutex); | ||
89 | struct rpc_clnt *clnt; | 91 | struct rpc_clnt *clnt; |
92 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
93 | |||
94 | spin_lock(&ln->nsm_clnt_lock); | ||
95 | if (ln->nsm_users) { | ||
96 | ln->nsm_users++; | ||
97 | clnt = ln->nsm_clnt; | ||
98 | spin_unlock(&ln->nsm_clnt_lock); | ||
99 | goto out; | ||
100 | } | ||
101 | spin_unlock(&ln->nsm_clnt_lock); | ||
102 | |||
103 | mutex_lock(&nsm_create_mutex); | ||
104 | clnt = nsm_create(net); | ||
105 | if (!IS_ERR(clnt)) { | ||
106 | ln->nsm_clnt = clnt; | ||
107 | smp_wmb(); | ||
108 | ln->nsm_users = 1; | ||
109 | } | ||
110 | mutex_unlock(&nsm_create_mutex); | ||
111 | out: | ||
112 | return clnt; | ||
113 | } | ||
114 | |||
115 | static void nsm_client_put(struct net *net) | ||
116 | { | ||
117 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
118 | struct rpc_clnt *clnt = ln->nsm_clnt; | ||
119 | int shutdown = 0; | ||
120 | |||
121 | spin_lock(&ln->nsm_clnt_lock); | ||
122 | if (ln->nsm_users) { | ||
123 | if (--ln->nsm_users) | ||
124 | ln->nsm_clnt = NULL; | ||
125 | shutdown = !ln->nsm_users; | ||
126 | } | ||
127 | spin_unlock(&ln->nsm_clnt_lock); | ||
128 | |||
129 | if (shutdown) | ||
130 | rpc_shutdown_client(clnt); | ||
131 | } | ||
132 | |||
133 | static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, | ||
134 | struct rpc_clnt *clnt) | ||
135 | { | ||
90 | int status; | 136 | int status; |
91 | struct nsm_args args = { | 137 | struct nsm_args args = { |
92 | .priv = &nsm->sm_priv, | 138 | .priv = &nsm->sm_priv, |
@@ -94,31 +140,24 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, | |||
94 | .vers = 3, | 140 | .vers = 3, |
95 | .proc = NLMPROC_NSM_NOTIFY, | 141 | .proc = NLMPROC_NSM_NOTIFY, |
96 | .mon_name = nsm->sm_mon_name, | 142 | .mon_name = nsm->sm_mon_name, |
143 | .nodename = clnt->cl_nodename, | ||
97 | }; | 144 | }; |
98 | struct rpc_message msg = { | 145 | struct rpc_message msg = { |
99 | .rpc_argp = &args, | 146 | .rpc_argp = &args, |
100 | .rpc_resp = res, | 147 | .rpc_resp = res, |
101 | }; | 148 | }; |
102 | 149 | ||
103 | clnt = nsm_create(net); | 150 | BUG_ON(clnt == NULL); |
104 | if (IS_ERR(clnt)) { | ||
105 | status = PTR_ERR(clnt); | ||
106 | dprintk("lockd: failed to create NSM upcall transport, " | ||
107 | "status=%d\n", status); | ||
108 | goto out; | ||
109 | } | ||
110 | 151 | ||
111 | memset(res, 0, sizeof(*res)); | 152 | memset(res, 0, sizeof(*res)); |
112 | 153 | ||
113 | msg.rpc_proc = &clnt->cl_procinfo[proc]; | 154 | msg.rpc_proc = &clnt->cl_procinfo[proc]; |
114 | status = rpc_call_sync(clnt, &msg, 0); | 155 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN); |
115 | if (status < 0) | 156 | if (status < 0) |
116 | dprintk("lockd: NSM upcall RPC failed, status=%d\n", | 157 | dprintk("lockd: NSM upcall RPC failed, status=%d\n", |
117 | status); | 158 | status); |
118 | else | 159 | else |
119 | status = 0; | 160 | status = 0; |
120 | rpc_shutdown_client(clnt); | ||
121 | out: | ||
122 | return status; | 161 | return status; |
123 | } | 162 | } |
124 | 163 | ||
@@ -138,6 +177,7 @@ int nsm_monitor(const struct nlm_host *host) | |||
138 | struct nsm_handle *nsm = host->h_nsmhandle; | 177 | struct nsm_handle *nsm = host->h_nsmhandle; |
139 | struct nsm_res res; | 178 | struct nsm_res res; |
140 | int status; | 179 | int status; |
180 | struct rpc_clnt *clnt; | ||
141 | 181 | ||
142 | dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); | 182 | dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); |
143 | 183 | ||
@@ -150,7 +190,15 @@ int nsm_monitor(const struct nlm_host *host) | |||
150 | */ | 190 | */ |
151 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; | 191 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; |
152 | 192 | ||
153 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host->net); | 193 | clnt = nsm_client_get(host->net); |
194 | if (IS_ERR(clnt)) { | ||
195 | status = PTR_ERR(clnt); | ||
196 | dprintk("lockd: failed to create NSM upcall transport, " | ||
197 | "status=%d, net=%p\n", status, host->net); | ||
198 | return status; | ||
199 | } | ||
200 | |||
201 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, clnt); | ||
154 | if (unlikely(res.status != 0)) | 202 | if (unlikely(res.status != 0)) |
155 | status = -EIO; | 203 | status = -EIO; |
156 | if (unlikely(status < 0)) { | 204 | if (unlikely(status < 0)) { |
@@ -182,9 +230,11 @@ void nsm_unmonitor(const struct nlm_host *host) | |||
182 | 230 | ||
183 | if (atomic_read(&nsm->sm_count) == 1 | 231 | if (atomic_read(&nsm->sm_count) == 1 |
184 | && nsm->sm_monitored && !nsm->sm_sticky) { | 232 | && nsm->sm_monitored && !nsm->sm_sticky) { |
233 | struct lockd_net *ln = net_generic(host->net, lockd_net_id); | ||
234 | |||
185 | dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); | 235 | dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); |
186 | 236 | ||
187 | status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host->net); | 237 | status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, ln->nsm_clnt); |
188 | if (res.status != 0) | 238 | if (res.status != 0) |
189 | status = -EIO; | 239 | status = -EIO; |
190 | if (status < 0) | 240 | if (status < 0) |
@@ -192,6 +242,8 @@ void nsm_unmonitor(const struct nlm_host *host) | |||
192 | nsm->sm_name); | 242 | nsm->sm_name); |
193 | else | 243 | else |
194 | nsm->sm_monitored = 0; | 244 | nsm->sm_monitored = 0; |
245 | |||
246 | nsm_client_put(host->net); | ||
195 | } | 247 | } |
196 | } | 248 | } |
197 | 249 | ||
@@ -430,7 +482,7 @@ static void encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp) | |||
430 | { | 482 | { |
431 | __be32 *p; | 483 | __be32 *p; |
432 | 484 | ||
433 | encode_nsm_string(xdr, utsname()->nodename); | 485 | encode_nsm_string(xdr, argp->nodename); |
434 | p = xdr_reserve_space(xdr, 4 + 4 + 4); | 486 | p = xdr_reserve_space(xdr, 4 + 4 + 4); |
435 | *p++ = cpu_to_be32(argp->prog); | 487 | *p++ = cpu_to_be32(argp->prog); |
436 | *p++ = cpu_to_be32(argp->vers); | 488 | *p++ = cpu_to_be32(argp->vers); |