xref: /openbmc/linux/fs/nfs/callback.c (revision f3a8b664)
1 /*
2  * linux/fs/nfs/callback.c
3  *
4  * Copyright (C) 2004 Trond Myklebust
5  *
6  * NFSv4 callback handling
7  */
8 
9 #include <linux/completion.h>
10 #include <linux/ip.h>
11 #include <linux/module.h>
12 #include <linux/sunrpc/svc.h>
13 #include <linux/sunrpc/svcsock.h>
14 #include <linux/nfs_fs.h>
15 #include <linux/errno.h>
16 #include <linux/mutex.h>
17 #include <linux/freezer.h>
18 #include <linux/kthread.h>
19 #include <linux/sunrpc/svcauth_gss.h>
20 #include <linux/sunrpc/bc_xprt.h>
21 
22 #include <net/inet_sock.h>
23 
24 #include "nfs4_fs.h"
25 #include "callback.h"
26 #include "internal.h"
27 #include "netns.h"
28 
29 #define NFSDBG_FACILITY NFSDBG_CALLBACK
30 
31 struct nfs_callback_data {
32 	unsigned int users;
33 	struct svc_serv *serv;
34 };
35 
36 static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1];
37 static DEFINE_MUTEX(nfs_callback_mutex);
38 static struct svc_program nfs4_callback_program;
39 
40 static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
41 {
42 	int ret;
43 	struct nfs_net *nn = net_generic(net, nfs_net_id);
44 
45 	ret = svc_create_xprt(serv, "tcp", net, PF_INET,
46 				nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
47 	if (ret <= 0)
48 		goto out_err;
49 	nn->nfs_callback_tcpport = ret;
50 	dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
51 			nn->nfs_callback_tcpport, PF_INET, net);
52 
53 	ret = svc_create_xprt(serv, "tcp", net, PF_INET6,
54 				nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
55 	if (ret > 0) {
56 		nn->nfs_callback_tcpport6 = ret;
57 		dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
58 				nn->nfs_callback_tcpport6, PF_INET6, net);
59 	} else if (ret != -EAFNOSUPPORT)
60 		goto out_err;
61 	return 0;
62 
63 out_err:
64 	return (ret) ? ret : -ENOMEM;
65 }
66 
67 /*
68  * This is the NFSv4 callback kernel thread.
69  */
70 static int
71 nfs4_callback_svc(void *vrqstp)
72 {
73 	int err;
74 	struct svc_rqst *rqstp = vrqstp;
75 
76 	set_freezable();
77 
78 	while (!kthread_should_stop()) {
79 		/*
80 		 * Listen for a request on the socket
81 		 */
82 		err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
83 		if (err == -EAGAIN || err == -EINTR)
84 			continue;
85 		svc_process(rqstp);
86 	}
87 	return 0;
88 }
89 
90 #if defined(CONFIG_NFS_V4_1)
91 /*
92  * The callback service for NFSv4.1 callbacks
93  */
94 static int
95 nfs41_callback_svc(void *vrqstp)
96 {
97 	struct svc_rqst *rqstp = vrqstp;
98 	struct svc_serv *serv = rqstp->rq_server;
99 	struct rpc_rqst *req;
100 	int error;
101 	DEFINE_WAIT(wq);
102 
103 	set_freezable();
104 
105 	while (!kthread_should_stop()) {
106 		if (try_to_freeze())
107 			continue;
108 
109 		prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
110 		spin_lock_bh(&serv->sv_cb_lock);
111 		if (!list_empty(&serv->sv_cb_list)) {
112 			req = list_first_entry(&serv->sv_cb_list,
113 					struct rpc_rqst, rq_bc_list);
114 			list_del(&req->rq_bc_list);
115 			spin_unlock_bh(&serv->sv_cb_lock);
116 			finish_wait(&serv->sv_cb_waitq, &wq);
117 			dprintk("Invoking bc_svc_process()\n");
118 			error = bc_svc_process(serv, req, rqstp);
119 			dprintk("bc_svc_process() returned w/ error code= %d\n",
120 				error);
121 		} else {
122 			spin_unlock_bh(&serv->sv_cb_lock);
123 			schedule();
124 			finish_wait(&serv->sv_cb_waitq, &wq);
125 		}
126 		flush_signals(current);
127 	}
128 	return 0;
129 }
130 
131 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
132 		struct svc_serv *serv)
133 {
134 	if (minorversion)
135 		/*
136 		 * Save the svc_serv in the transport so that it can
137 		 * be referenced when the session backchannel is initialized
138 		 */
139 		xprt->bc_serv = serv;
140 }
141 #else
142 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
143 		struct svc_serv *serv)
144 {
145 }
146 #endif /* CONFIG_NFS_V4_1 */
147 
148 static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
149 				  struct svc_serv *serv)
150 {
151 	int nrservs = nfs_callback_nr_threads;
152 	int ret;
153 
154 	nfs_callback_bc_serv(minorversion, xprt, serv);
155 
156 	if (nrservs < NFS4_MIN_NR_CALLBACK_THREADS)
157 		nrservs = NFS4_MIN_NR_CALLBACK_THREADS;
158 
159 	if (serv->sv_nrthreads-1 == nrservs)
160 		return 0;
161 
162 	ret = serv->sv_ops->svo_setup(serv, NULL, nrservs);
163 	if (ret) {
164 		serv->sv_ops->svo_setup(serv, NULL, 0);
165 		return ret;
166 	}
167 	dprintk("nfs_callback_up: service started\n");
168 	return 0;
169 }
170 
171 static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struct net *net)
172 {
173 	struct nfs_net *nn = net_generic(net, nfs_net_id);
174 
175 	if (--nn->cb_users[minorversion])
176 		return;
177 
178 	dprintk("NFS: destroy per-net callback data; net=%p\n", net);
179 	svc_shutdown_net(serv, net);
180 }
181 
182 static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
183 			       struct net *net, struct rpc_xprt *xprt)
184 {
185 	struct nfs_net *nn = net_generic(net, nfs_net_id);
186 	int ret;
187 
188 	if (nn->cb_users[minorversion]++)
189 		return 0;
190 
191 	dprintk("NFS: create per-net callback data; net=%p\n", net);
192 
193 	ret = svc_bind(serv, net);
194 	if (ret < 0) {
195 		printk(KERN_WARNING "NFS: bind callback service failed\n");
196 		goto err_bind;
197 	}
198 
199 	ret = -EPROTONOSUPPORT;
200 	if (minorversion == 0)
201 		ret = nfs4_callback_up_net(serv, net);
202 	else if (xprt->ops->bc_up)
203 		ret = xprt->ops->bc_up(serv, net);
204 
205 	if (ret < 0) {
206 		printk(KERN_ERR "NFS: callback service start failed\n");
207 		goto err_socks;
208 	}
209 	return 0;
210 
211 err_socks:
212 	svc_rpcb_cleanup(serv, net);
213 err_bind:
214 	nn->cb_users[minorversion]--;
215 	dprintk("NFS: Couldn't create callback socket: err = %d; "
216 			"net = %p\n", ret, net);
217 	return ret;
218 }
219 
220 static struct svc_serv_ops nfs40_cb_sv_ops = {
221 	.svo_function		= nfs4_callback_svc,
222 	.svo_enqueue_xprt	= svc_xprt_do_enqueue,
223 	.svo_setup		= svc_set_num_threads,
224 	.svo_module		= THIS_MODULE,
225 };
226 #if defined(CONFIG_NFS_V4_1)
227 static struct svc_serv_ops nfs41_cb_sv_ops = {
228 	.svo_function		= nfs41_callback_svc,
229 	.svo_enqueue_xprt	= svc_xprt_do_enqueue,
230 	.svo_setup		= svc_set_num_threads,
231 	.svo_module		= THIS_MODULE,
232 };
233 
234 struct svc_serv_ops *nfs4_cb_sv_ops[] = {
235 	[0] = &nfs40_cb_sv_ops,
236 	[1] = &nfs41_cb_sv_ops,
237 };
238 #else
239 struct svc_serv_ops *nfs4_cb_sv_ops[] = {
240 	[0] = &nfs40_cb_sv_ops,
241 	[1] = NULL,
242 };
243 #endif
244 
245 static struct svc_serv *nfs_callback_create_svc(int minorversion)
246 {
247 	struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
248 	struct svc_serv *serv;
249 	struct svc_serv_ops *sv_ops;
250 
251 	/*
252 	 * Check whether we're already up and running.
253 	 */
254 	if (cb_info->serv) {
255 		/*
256 		 * Note: increase service usage, because later in case of error
257 		 * svc_destroy() will be called.
258 		 */
259 		svc_get(cb_info->serv);
260 		return cb_info->serv;
261 	}
262 
263 	switch (minorversion) {
264 	case 0:
265 		sv_ops = nfs4_cb_sv_ops[0];
266 		break;
267 	default:
268 		sv_ops = nfs4_cb_sv_ops[1];
269 	}
270 
271 	if (sv_ops == NULL)
272 		return ERR_PTR(-ENOTSUPP);
273 
274 	/*
275 	 * Sanity check: if there's no task,
276 	 * we should be the first user ...
277 	 */
278 	if (cb_info->users)
279 		printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n",
280 			cb_info->users);
281 
282 	serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, sv_ops);
283 	if (!serv) {
284 		printk(KERN_ERR "nfs_callback_create_svc: create service failed\n");
285 		return ERR_PTR(-ENOMEM);
286 	}
287 	cb_info->serv = serv;
288 	/* As there is only one thread we need to over-ride the
289 	 * default maximum of 80 connections
290 	 */
291 	serv->sv_maxconn = 1024;
292 	dprintk("nfs_callback_create_svc: service created\n");
293 	return serv;
294 }
295 
296 /*
297  * Bring up the callback thread if it is not already up.
298  */
299 int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
300 {
301 	struct svc_serv *serv;
302 	struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
303 	int ret;
304 	struct net *net = xprt->xprt_net;
305 
306 	mutex_lock(&nfs_callback_mutex);
307 
308 	serv = nfs_callback_create_svc(minorversion);
309 	if (IS_ERR(serv)) {
310 		ret = PTR_ERR(serv);
311 		goto err_create;
312 	}
313 
314 	ret = nfs_callback_up_net(minorversion, serv, net, xprt);
315 	if (ret < 0)
316 		goto err_net;
317 
318 	ret = nfs_callback_start_svc(minorversion, xprt, serv);
319 	if (ret < 0)
320 		goto err_start;
321 
322 	cb_info->users++;
323 	/*
324 	 * svc_create creates the svc_serv with sv_nrthreads == 1, and then
325 	 * svc_prepare_thread increments that. So we need to call svc_destroy
326 	 * on both success and failure so that the refcount is 1 when the
327 	 * thread exits.
328 	 */
329 err_net:
330 	if (!cb_info->users)
331 		cb_info->serv = NULL;
332 	svc_destroy(serv);
333 err_create:
334 	mutex_unlock(&nfs_callback_mutex);
335 	return ret;
336 
337 err_start:
338 	nfs_callback_down_net(minorversion, serv, net);
339 	dprintk("NFS: Couldn't create server thread; err = %d\n", ret);
340 	goto err_net;
341 }
342 
343 /*
344  * Kill the callback thread if it's no longer being used.
345  */
346 void nfs_callback_down(int minorversion, struct net *net)
347 {
348 	struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
349 	struct svc_serv *serv;
350 
351 	mutex_lock(&nfs_callback_mutex);
352 	serv = cb_info->serv;
353 	nfs_callback_down_net(minorversion, serv, net);
354 	cb_info->users--;
355 	if (cb_info->users == 0) {
356 		svc_get(serv);
357 		serv->sv_ops->svo_setup(serv, NULL, 0);
358 		svc_destroy(serv);
359 		dprintk("nfs_callback_down: service destroyed\n");
360 		cb_info->serv = NULL;
361 	}
362 	mutex_unlock(&nfs_callback_mutex);
363 }
364 
365 /* Boolean check of RPC_AUTH_GSS principal */
366 int
367 check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
368 {
369 	char *p = rqstp->rq_cred.cr_principal;
370 
371 	if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
372 		return 1;
373 
374 	/* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
375 	if (clp->cl_minorversion != 0)
376 		return 0;
377 	/*
378 	 * It might just be a normal user principal, in which case
379 	 * userspace won't bother to tell us the name at all.
380 	 */
381 	if (p == NULL)
382 		return 0;
383 
384 	/*
385 	 * Did we get the acceptor from userland during the SETCLIENID
386 	 * negotiation?
387 	 */
388 	if (clp->cl_acceptor)
389 		return !strcmp(p, clp->cl_acceptor);
390 
391 	/*
392 	 * Otherwise try to verify it using the cl_hostname. Note that this
393 	 * doesn't work if a non-canonical hostname was used in the devname.
394 	 */
395 
396 	/* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
397 
398 	if (memcmp(p, "nfs@", 4) != 0)
399 		return 0;
400 	p += 4;
401 	if (strcmp(p, clp->cl_hostname) != 0)
402 		return 0;
403 	return 1;
404 }
405 
406 /*
407  * pg_authenticate method for nfsv4 callback threads.
408  *
409  * The authflavor has been negotiated, so an incorrect flavor is a server
410  * bug. Deny packets with incorrect authflavor.
411  *
412  * All other checking done after NFS decoding where the nfs_client can be
413  * found in nfs4_callback_compound
414  */
415 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
416 {
417 	switch (rqstp->rq_authop->flavour) {
418 	case RPC_AUTH_NULL:
419 		if (rqstp->rq_proc != CB_NULL)
420 			return SVC_DENIED;
421 		break;
422 	case RPC_AUTH_GSS:
423 		/* No RPC_AUTH_GSS support yet in NFSv4.1 */
424 		 if (svc_is_backchannel(rqstp))
425 			return SVC_DENIED;
426 	}
427 	return SVC_OK;
428 }
429 
430 /*
431  * Define NFS4 callback program
432  */
433 static struct svc_version *nfs4_callback_version[] = {
434 	[1] = &nfs4_callback_version1,
435 	[4] = &nfs4_callback_version4,
436 };
437 
438 static struct svc_stat nfs4_callback_stats;
439 
440 static struct svc_program nfs4_callback_program = {
441 	.pg_prog = NFS4_CALLBACK,			/* RPC service number */
442 	.pg_nvers = ARRAY_SIZE(nfs4_callback_version),	/* Number of entries */
443 	.pg_vers = nfs4_callback_version,		/* version table */
444 	.pg_name = "NFSv4 callback",			/* service name */
445 	.pg_class = "nfs",				/* authentication class */
446 	.pg_stats = &nfs4_callback_stats,
447 	.pg_authenticate = nfs_callback_authenticate,
448 };
449