xref: /linux/fs/lockd/svcproc.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * linux/fs/lockd/svcproc.c
4  *
5  * Lockd server procedures. We don't implement the NLM_*_RES
6  * procedures because we don't use the async procedures.
7  *
8  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
9  */
10 
11 #include <linux/types.h>
12 #include <linux/time.h>
13 #include <linux/sunrpc/svc_xprt.h>
14 
15 #include "lockd.h"
16 #include "share.h"
17 
18 #define NLMDBG_FACILITY		NLMDBG_CLIENT
19 
20 #ifdef CONFIG_LOCKD_V4
21 static inline __be32 cast_status(__be32 status)
22 {
23 	switch (status) {
24 	case nlm_granted:
25 	case nlm_lck_denied:
26 	case nlm_lck_denied_nolocks:
27 	case nlm_lck_blocked:
28 	case nlm_lck_denied_grace_period:
29 	case nlm__int__drop_reply:
30 		break;
31 	case nlm__int__deadlock:
32 		status = nlm_lck_denied;
33 		break;
34 	default:
35 		status = nlm_lck_denied_nolocks;
36 	}
37 
38 	return status;
39 }
40 #else
41 static inline __be32 cast_status(__be32 status)
42 {
43 	switch (status) {
44 	case nlm__int__deadlock:
45 		status = nlm_lck_denied;
46 		break;
47 	case nlm__int__stale_fh:
48 	case nlm__int__failed:
49 		status = nlm_lck_denied_nolocks;
50 		break;
51 	default:
52 		if (be32_to_cpu(status) >= 30000)
53 			pr_warn_once("lockd: unhandled internal status %u\n",
54 				     be32_to_cpu(status));
55 		break;
56 	}
57 	return status;
58 }
59 #endif
60 
61 /*
62  * Obtain client and file from arguments
63  */
64 static __be32
65 nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
66 			struct nlm_host **hostp, struct nlm_file **filp)
67 {
68 	struct nlm_host		*host = NULL;
69 	struct nlm_file		*file = NULL;
70 	struct nlm_lock		*lock = &argp->lock;
71 	int			mode;
72 	__be32			error = 0;
73 
74 	/* nfsd callbacks must have been installed for this procedure */
75 	if (!nlmsvc_ops)
76 		return nlm_lck_denied_nolocks;
77 
78 	/* Obtain host handle */
79 	if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
80 	 || (argp->monitor && nsm_monitor(host) < 0))
81 		goto no_locks;
82 	*hostp = host;
83 
84 	/* Obtain file pointer. Not used by FREE_ALL call. */
85 	if (filp != NULL) {
86 		error = cast_status(nlm_lookup_file(rqstp, &file, lock));
87 		if (error != 0)
88 			goto no_locks;
89 		*filp = file;
90 
91 		/* Set up the missing parts of the file_lock structure */
92 		mode = lock_to_openmode(&lock->fl);
93 		lock->fl.c.flc_flags = FL_POSIX;
94 		lock->fl.c.flc_file  = file->f_file[mode];
95 		lock->fl.c.flc_pid = current->tgid;
96 		lock->fl.fl_lmops = &nlmsvc_lock_operations;
97 		nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
98 		if (!lock->fl.c.flc_owner) {
99 			/* lockowner allocation has failed */
100 			nlmsvc_release_host(host);
101 			return nlm_lck_denied_nolocks;
102 		}
103 	}
104 
105 	return 0;
106 
107 no_locks:
108 	nlmsvc_release_host(host);
109 	if (error)
110 		return error;
111 	return nlm_lck_denied_nolocks;
112 }
113 
114 /*
115  * NULL: Test for presence of service
116  */
117 static __be32
118 nlmsvc_proc_null(struct svc_rqst *rqstp)
119 {
120 	dprintk("lockd: NULL          called\n");
121 	return rpc_success;
122 }
123 
124 /*
125  * TEST: Check for conflicting lock
126  */
127 static __be32
128 __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
129 {
130 	struct nlm_args *argp = rqstp->rq_argp;
131 	struct nlm_host	*host;
132 	struct nlm_file	*file;
133 	__be32 rc = rpc_success;
134 
135 	dprintk("lockd: TEST          called\n");
136 	resp->cookie = argp->cookie;
137 
138 	/* Obtain client and file */
139 	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
140 		return resp->status == nlm__int__drop_reply ?
141 			rpc_drop_reply : rpc_success;
142 
143 	/* Now check for conflicting locks */
144 	resp->status = cast_status(nlmsvc_testlock(rqstp, file, host,
145 						   &argp->lock, &resp->lock));
146 	if (resp->status == nlm__int__drop_reply)
147 		rc = rpc_drop_reply;
148 	else
149 		dprintk("lockd: TEST          status %d vers %d\n",
150 			ntohl(resp->status), rqstp->rq_vers);
151 
152 	nlmsvc_release_lockowner(&argp->lock);
153 	nlmsvc_release_host(host);
154 	nlm_release_file(file);
155 	return rc;
156 }
157 
158 static __be32
159 nlmsvc_proc_test(struct svc_rqst *rqstp)
160 {
161 	return __nlmsvc_proc_test(rqstp, rqstp->rq_resp);
162 }
163 
164 static __be32
165 __nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_res *resp)
166 {
167 	struct nlm_args *argp = rqstp->rq_argp;
168 	struct nlm_host	*host;
169 	struct nlm_file	*file;
170 	__be32 rc = rpc_success;
171 
172 	dprintk("lockd: LOCK          called\n");
173 
174 	resp->cookie = argp->cookie;
175 
176 	/* Obtain client and file */
177 	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
178 		return resp->status == nlm__int__drop_reply ?
179 			rpc_drop_reply : rpc_success;
180 
181 	/* Now try to lock the file */
182 	resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock,
183 					       argp->block, &argp->cookie,
184 					       argp->reclaim));
185 	if (resp->status == nlm__int__drop_reply)
186 		rc = rpc_drop_reply;
187 	else
188 		dprintk("lockd: LOCK         status %d\n", ntohl(resp->status));
189 
190 	nlmsvc_release_lockowner(&argp->lock);
191 	nlmsvc_release_host(host);
192 	nlm_release_file(file);
193 	return rc;
194 }
195 
196 static __be32
197 nlmsvc_proc_lock(struct svc_rqst *rqstp)
198 {
199 	return __nlmsvc_proc_lock(rqstp, rqstp->rq_resp);
200 }
201 
202 static __be32
203 __nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_res *resp)
204 {
205 	struct nlm_args *argp = rqstp->rq_argp;
206 	struct nlm_host	*host;
207 	struct nlm_file	*file;
208 	struct net *net = SVC_NET(rqstp);
209 
210 	dprintk("lockd: CANCEL        called\n");
211 
212 	resp->cookie = argp->cookie;
213 
214 	/* Don't accept requests during grace period */
215 	if (locks_in_grace(net)) {
216 		resp->status = nlm_lck_denied_grace_period;
217 		return rpc_success;
218 	}
219 
220 	/* Obtain client and file */
221 	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
222 		return resp->status == nlm__int__drop_reply ?
223 			rpc_drop_reply : rpc_success;
224 
225 	/* Try to cancel request. */
226 	resp->status = cast_status(nlmsvc_cancel_blocked(net, file, &argp->lock));
227 
228 	dprintk("lockd: CANCEL        status %d\n", ntohl(resp->status));
229 	nlmsvc_release_lockowner(&argp->lock);
230 	nlmsvc_release_host(host);
231 	nlm_release_file(file);
232 	return rpc_success;
233 }
234 
235 static __be32
236 nlmsvc_proc_cancel(struct svc_rqst *rqstp)
237 {
238 	return __nlmsvc_proc_cancel(rqstp, rqstp->rq_resp);
239 }
240 
241 /*
242  * UNLOCK: release a lock
243  */
244 static __be32
245 __nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_res *resp)
246 {
247 	struct nlm_args *argp = rqstp->rq_argp;
248 	struct nlm_host	*host;
249 	struct nlm_file	*file;
250 	struct net *net = SVC_NET(rqstp);
251 
252 	dprintk("lockd: UNLOCK        called\n");
253 
254 	resp->cookie = argp->cookie;
255 
256 	/* Don't accept new lock requests during grace period */
257 	if (locks_in_grace(net)) {
258 		resp->status = nlm_lck_denied_grace_period;
259 		return rpc_success;
260 	}
261 
262 	/* Obtain client and file */
263 	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
264 		return resp->status == nlm__int__drop_reply ?
265 			rpc_drop_reply : rpc_success;
266 
267 	/* Now try to remove the lock */
268 	resp->status = cast_status(nlmsvc_unlock(net, file, &argp->lock));
269 
270 	dprintk("lockd: UNLOCK        status %d\n", ntohl(resp->status));
271 	nlmsvc_release_lockowner(&argp->lock);
272 	nlmsvc_release_host(host);
273 	nlm_release_file(file);
274 	return rpc_success;
275 }
276 
277 static __be32
278 nlmsvc_proc_unlock(struct svc_rqst *rqstp)
279 {
280 	return __nlmsvc_proc_unlock(rqstp, rqstp->rq_resp);
281 }
282 
283 /*
284  * GRANTED: A server calls us to tell that a process' lock request
285  * was granted
286  */
287 static __be32
288 __nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_res *resp)
289 {
290 	struct nlm_args *argp = rqstp->rq_argp;
291 
292 	resp->cookie = argp->cookie;
293 
294 	dprintk("lockd: GRANTED       called\n");
295 	resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
296 	dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
297 	return rpc_success;
298 }
299 
300 static __be32
301 nlmsvc_proc_granted(struct svc_rqst *rqstp)
302 {
303 	return __nlmsvc_proc_granted(rqstp, rqstp->rq_resp);
304 }
305 
306 /*
307  * This is the generic lockd callback for async RPC calls
308  */
309 static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
310 {
311 }
312 
313 void nlmsvc_release_call(struct nlm_rqst *call)
314 {
315 	if (!refcount_dec_and_test(&call->a_count))
316 		return;
317 	nlmsvc_release_host(call->a_host);
318 	kfree(call);
319 }
320 
321 static void nlmsvc_callback_release(void *data)
322 {
323 	nlmsvc_release_call(data);
324 }
325 
326 static const struct rpc_call_ops nlmsvc_callback_ops = {
327 	.rpc_call_done = nlmsvc_callback_exit,
328 	.rpc_release = nlmsvc_callback_release,
329 };
330 
331 /*
332  * `Async' versions of the above service routines. They aren't really,
333  * because we send the callback before the reply proper. I hope this
334  * doesn't break any clients.
335  */
336 static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc,
337 		__be32 (*func)(struct svc_rqst *, struct nlm_res *))
338 {
339 	struct nlm_args *argp = rqstp->rq_argp;
340 	struct nlm_host	*host;
341 	struct nlm_rqst	*call;
342 	__be32 stat;
343 
344 	host = nlmsvc_lookup_host(rqstp,
345 				  argp->lock.caller,
346 				  argp->lock.len);
347 	if (host == NULL)
348 		return rpc_system_err;
349 
350 	call = nlm_alloc_call(host);
351 	nlmsvc_release_host(host);
352 	if (call == NULL)
353 		return rpc_system_err;
354 
355 	stat = func(rqstp, &call->a_res);
356 	if (stat != 0) {
357 		nlmsvc_release_call(call);
358 		return stat;
359 	}
360 
361 	call->a_flags = RPC_TASK_ASYNC;
362 	if (nlm_async_reply(call, proc, &nlmsvc_callback_ops) < 0)
363 		return rpc_system_err;
364 	return rpc_success;
365 }
366 
367 static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp)
368 {
369 	dprintk("lockd: TEST_MSG      called\n");
370 	return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, __nlmsvc_proc_test);
371 }
372 
373 static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp)
374 {
375 	dprintk("lockd: LOCK_MSG      called\n");
376 	return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, __nlmsvc_proc_lock);
377 }
378 
379 static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp)
380 {
381 	dprintk("lockd: CANCEL_MSG    called\n");
382 	return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, __nlmsvc_proc_cancel);
383 }
384 
385 static __be32
386 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp)
387 {
388 	dprintk("lockd: UNLOCK_MSG    called\n");
389 	return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, __nlmsvc_proc_unlock);
390 }
391 
392 static __be32
393 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp)
394 {
395 	dprintk("lockd: GRANTED_MSG   called\n");
396 	return nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, __nlmsvc_proc_granted);
397 }
398 
399 /*
400  * SHARE: create a DOS share or alter existing share.
401  */
402 static __be32
403 nlmsvc_proc_share(struct svc_rqst *rqstp)
404 {
405 	struct nlm_args *argp = rqstp->rq_argp;
406 	struct nlm_res *resp = rqstp->rq_resp;
407 	struct nlm_host	*host;
408 	struct nlm_file	*file;
409 
410 	dprintk("lockd: SHARE         called\n");
411 
412 	resp->cookie = argp->cookie;
413 
414 	/* Don't accept new lock requests during grace period */
415 	if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) {
416 		resp->status = nlm_lck_denied_grace_period;
417 		return rpc_success;
418 	}
419 
420 	/* Obtain client and file */
421 	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
422 		return resp->status == nlm__int__drop_reply ?
423 			rpc_drop_reply : rpc_success;
424 
425 	/* Now try to create the share */
426 	resp->status = cast_status(nlmsvc_share_file(host, file, &argp->lock.oh,
427 						     argp->fsm_access,
428 						     argp->fsm_mode));
429 
430 	dprintk("lockd: SHARE         status %d\n", ntohl(resp->status));
431 	nlmsvc_release_lockowner(&argp->lock);
432 	nlmsvc_release_host(host);
433 	nlm_release_file(file);
434 	return rpc_success;
435 }
436 
437 /*
438  * UNSHARE: Release a DOS share.
439  */
440 static __be32
441 nlmsvc_proc_unshare(struct svc_rqst *rqstp)
442 {
443 	struct nlm_args *argp = rqstp->rq_argp;
444 	struct nlm_res *resp = rqstp->rq_resp;
445 	struct nlm_host	*host;
446 	struct nlm_file	*file;
447 
448 	dprintk("lockd: UNSHARE       called\n");
449 
450 	resp->cookie = argp->cookie;
451 
452 	/* Don't accept requests during grace period */
453 	if (locks_in_grace(SVC_NET(rqstp))) {
454 		resp->status = nlm_lck_denied_grace_period;
455 		return rpc_success;
456 	}
457 
458 	/* Obtain client and file */
459 	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
460 		return resp->status == nlm__int__drop_reply ?
461 			rpc_drop_reply : rpc_success;
462 
463 	/* Now try to unshare the file */
464 	resp->status = cast_status(nlmsvc_unshare_file(host, file,
465 						       &argp->lock.oh));
466 
467 	dprintk("lockd: UNSHARE       status %d\n", ntohl(resp->status));
468 	nlmsvc_release_lockowner(&argp->lock);
469 	nlmsvc_release_host(host);
470 	nlm_release_file(file);
471 	return rpc_success;
472 }
473 
474 /*
475  * NM_LOCK: Create an unmonitored lock
476  */
477 static __be32
478 nlmsvc_proc_nm_lock(struct svc_rqst *rqstp)
479 {
480 	struct nlm_args *argp = rqstp->rq_argp;
481 
482 	dprintk("lockd: NM_LOCK       called\n");
483 
484 	argp->monitor = 0;		/* just clean the monitor flag */
485 	return nlmsvc_proc_lock(rqstp);
486 }
487 
488 /*
489  * FREE_ALL: Release all locks and shares held by client
490  */
491 static __be32
492 nlmsvc_proc_free_all(struct svc_rqst *rqstp)
493 {
494 	struct nlm_args *argp = rqstp->rq_argp;
495 	struct nlm_host	*host;
496 
497 	/* Obtain client */
498 	if (nlmsvc_retrieve_args(rqstp, argp, &host, NULL))
499 		return rpc_success;
500 
501 	nlmsvc_free_host_resources(host);
502 	nlmsvc_release_host(host);
503 	return rpc_success;
504 }
505 
506 /*
507  * SM_NOTIFY: private callback from statd (not part of official NLM proto)
508  */
509 static __be32
510 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp)
511 {
512 	struct nlm_reboot *argp = rqstp->rq_argp;
513 
514 	dprintk("lockd: SM_NOTIFY     called\n");
515 
516 	if (!nlm_privileged_requester(rqstp)) {
517 		char buf[RPC_MAX_ADDRBUFLEN];
518 		printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
519 				svc_print_addr(rqstp, buf, sizeof(buf)));
520 		return rpc_system_err;
521 	}
522 
523 	nlm_host_rebooted(SVC_NET(rqstp), argp);
524 	return rpc_success;
525 }
526 
527 /*
528  * client sent a GRANTED_RES, let's remove the associated block
529  */
530 static __be32
531 nlmsvc_proc_granted_res(struct svc_rqst *rqstp)
532 {
533 	struct nlm_res *argp = rqstp->rq_argp;
534 
535 	if (!nlmsvc_ops)
536 		return rpc_success;
537 
538 	dprintk("lockd: GRANTED_RES   called\n");
539 
540 	nlmsvc_grant_reply(&argp->cookie, argp->status);
541 	return rpc_success;
542 }
543 
544 static __be32
545 nlmsvc_proc_unused(struct svc_rqst *rqstp)
546 {
547 	return rpc_proc_unavail;
548 }
549 
550 /*
551  * NLM Server procedures.
552  */
553 
554 struct nlm_void			{ int dummy; };
555 
556 #define	Ck	(1+XDR_QUADLEN(NLM_MAXCOOKIELEN))	/* cookie */
557 #define	St	1				/* status */
558 #define	No	(1+1024/4)			/* Net Obj */
559 #define	Rg	2				/* range - offset + size */
560 
561 static const struct svc_procedure nlmsvc_procedures[24] = {
562 	[NLMPROC_NULL] = {
563 		.pc_func = nlmsvc_proc_null,
564 		.pc_decode = nlmsvc_decode_void,
565 		.pc_encode = nlmsvc_encode_void,
566 		.pc_argsize = sizeof(struct nlm_void),
567 		.pc_argzero = sizeof(struct nlm_void),
568 		.pc_ressize = sizeof(struct nlm_void),
569 		.pc_xdrressize = St,
570 		.pc_name = "NULL",
571 	},
572 	[NLMPROC_TEST] = {
573 		.pc_func = nlmsvc_proc_test,
574 		.pc_decode = nlmsvc_decode_testargs,
575 		.pc_encode = nlmsvc_encode_testres,
576 		.pc_argsize = sizeof(struct nlm_args),
577 		.pc_argzero = sizeof(struct nlm_args),
578 		.pc_ressize = sizeof(struct nlm_res),
579 		.pc_xdrressize = Ck+St+2+No+Rg,
580 		.pc_name = "TEST",
581 	},
582 	[NLMPROC_LOCK] = {
583 		.pc_func = nlmsvc_proc_lock,
584 		.pc_decode = nlmsvc_decode_lockargs,
585 		.pc_encode = nlmsvc_encode_res,
586 		.pc_argsize = sizeof(struct nlm_args),
587 		.pc_argzero = sizeof(struct nlm_args),
588 		.pc_ressize = sizeof(struct nlm_res),
589 		.pc_xdrressize = Ck+St,
590 		.pc_name = "LOCK",
591 	},
592 	[NLMPROC_CANCEL] = {
593 		.pc_func = nlmsvc_proc_cancel,
594 		.pc_decode = nlmsvc_decode_cancargs,
595 		.pc_encode = nlmsvc_encode_res,
596 		.pc_argsize = sizeof(struct nlm_args),
597 		.pc_argzero = sizeof(struct nlm_args),
598 		.pc_ressize = sizeof(struct nlm_res),
599 		.pc_xdrressize = Ck+St,
600 		.pc_name = "CANCEL",
601 	},
602 	[NLMPROC_UNLOCK] = {
603 		.pc_func = nlmsvc_proc_unlock,
604 		.pc_decode = nlmsvc_decode_unlockargs,
605 		.pc_encode = nlmsvc_encode_res,
606 		.pc_argsize = sizeof(struct nlm_args),
607 		.pc_argzero = sizeof(struct nlm_args),
608 		.pc_ressize = sizeof(struct nlm_res),
609 		.pc_xdrressize = Ck+St,
610 		.pc_name = "UNLOCK",
611 	},
612 	[NLMPROC_GRANTED] = {
613 		.pc_func = nlmsvc_proc_granted,
614 		.pc_decode = nlmsvc_decode_testargs,
615 		.pc_encode = nlmsvc_encode_res,
616 		.pc_argsize = sizeof(struct nlm_args),
617 		.pc_argzero = sizeof(struct nlm_args),
618 		.pc_ressize = sizeof(struct nlm_res),
619 		.pc_xdrressize = Ck+St,
620 		.pc_name = "GRANTED",
621 	},
622 	[NLMPROC_TEST_MSG] = {
623 		.pc_func = nlmsvc_proc_test_msg,
624 		.pc_decode = nlmsvc_decode_testargs,
625 		.pc_encode = nlmsvc_encode_void,
626 		.pc_argsize = sizeof(struct nlm_args),
627 		.pc_argzero = sizeof(struct nlm_args),
628 		.pc_ressize = sizeof(struct nlm_void),
629 		.pc_xdrressize = St,
630 		.pc_name = "TEST_MSG",
631 	},
632 	[NLMPROC_LOCK_MSG] = {
633 		.pc_func = nlmsvc_proc_lock_msg,
634 		.pc_decode = nlmsvc_decode_lockargs,
635 		.pc_encode = nlmsvc_encode_void,
636 		.pc_argsize = sizeof(struct nlm_args),
637 		.pc_argzero = sizeof(struct nlm_args),
638 		.pc_ressize = sizeof(struct nlm_void),
639 		.pc_xdrressize = St,
640 		.pc_name = "LOCK_MSG",
641 	},
642 	[NLMPROC_CANCEL_MSG] = {
643 		.pc_func = nlmsvc_proc_cancel_msg,
644 		.pc_decode = nlmsvc_decode_cancargs,
645 		.pc_encode = nlmsvc_encode_void,
646 		.pc_argsize = sizeof(struct nlm_args),
647 		.pc_argzero = sizeof(struct nlm_args),
648 		.pc_ressize = sizeof(struct nlm_void),
649 		.pc_xdrressize = St,
650 		.pc_name = "CANCEL_MSG",
651 	},
652 	[NLMPROC_UNLOCK_MSG] = {
653 		.pc_func = nlmsvc_proc_unlock_msg,
654 		.pc_decode = nlmsvc_decode_unlockargs,
655 		.pc_encode = nlmsvc_encode_void,
656 		.pc_argsize = sizeof(struct nlm_args),
657 		.pc_argzero = sizeof(struct nlm_args),
658 		.pc_ressize = sizeof(struct nlm_void),
659 		.pc_xdrressize = St,
660 		.pc_name = "UNLOCK_MSG",
661 	},
662 	[NLMPROC_GRANTED_MSG] = {
663 		.pc_func = nlmsvc_proc_granted_msg,
664 		.pc_decode = nlmsvc_decode_testargs,
665 		.pc_encode = nlmsvc_encode_void,
666 		.pc_argsize = sizeof(struct nlm_args),
667 		.pc_argzero = sizeof(struct nlm_args),
668 		.pc_ressize = sizeof(struct nlm_void),
669 		.pc_xdrressize = St,
670 		.pc_name = "GRANTED_MSG",
671 	},
672 	[NLMPROC_TEST_RES] = {
673 		.pc_func = nlmsvc_proc_null,
674 		.pc_decode = nlmsvc_decode_void,
675 		.pc_encode = nlmsvc_encode_void,
676 		.pc_argsize = sizeof(struct nlm_res),
677 		.pc_argzero = sizeof(struct nlm_res),
678 		.pc_ressize = sizeof(struct nlm_void),
679 		.pc_xdrressize = St,
680 		.pc_name = "TEST_RES",
681 	},
682 	[NLMPROC_LOCK_RES] = {
683 		.pc_func = nlmsvc_proc_null,
684 		.pc_decode = nlmsvc_decode_void,
685 		.pc_encode = nlmsvc_encode_void,
686 		.pc_argsize = sizeof(struct nlm_res),
687 		.pc_argzero = sizeof(struct nlm_res),
688 		.pc_ressize = sizeof(struct nlm_void),
689 		.pc_xdrressize = St,
690 		.pc_name = "LOCK_RES",
691 	},
692 	[NLMPROC_CANCEL_RES] = {
693 		.pc_func = nlmsvc_proc_null,
694 		.pc_decode = nlmsvc_decode_void,
695 		.pc_encode = nlmsvc_encode_void,
696 		.pc_argsize = sizeof(struct nlm_res),
697 		.pc_argzero = sizeof(struct nlm_res),
698 		.pc_ressize = sizeof(struct nlm_void),
699 		.pc_xdrressize = St,
700 		.pc_name = "CANCEL_RES",
701 	},
702 	[NLMPROC_UNLOCK_RES] = {
703 		.pc_func = nlmsvc_proc_null,
704 		.pc_decode = nlmsvc_decode_void,
705 		.pc_encode = nlmsvc_encode_void,
706 		.pc_argsize = sizeof(struct nlm_res),
707 		.pc_argzero = sizeof(struct nlm_res),
708 		.pc_ressize = sizeof(struct nlm_void),
709 		.pc_xdrressize = St,
710 		.pc_name = "UNLOCK_RES",
711 	},
712 	[NLMPROC_GRANTED_RES] = {
713 		.pc_func = nlmsvc_proc_granted_res,
714 		.pc_decode = nlmsvc_decode_res,
715 		.pc_encode = nlmsvc_encode_void,
716 		.pc_argsize = sizeof(struct nlm_res),
717 		.pc_argzero = sizeof(struct nlm_res),
718 		.pc_ressize = sizeof(struct nlm_void),
719 		.pc_xdrressize = St,
720 		.pc_name = "GRANTED_RES",
721 	},
722 	[NLMPROC_NSM_NOTIFY] = {
723 		.pc_func = nlmsvc_proc_sm_notify,
724 		.pc_decode = nlmsvc_decode_reboot,
725 		.pc_encode = nlmsvc_encode_void,
726 		.pc_argsize = sizeof(struct nlm_reboot),
727 		.pc_argzero = sizeof(struct nlm_reboot),
728 		.pc_ressize = sizeof(struct nlm_void),
729 		.pc_xdrressize = St,
730 		.pc_name = "SM_NOTIFY",
731 	},
732 	[17] = {
733 		.pc_func = nlmsvc_proc_unused,
734 		.pc_decode = nlmsvc_decode_void,
735 		.pc_encode = nlmsvc_encode_void,
736 		.pc_argsize = sizeof(struct nlm_void),
737 		.pc_argzero = sizeof(struct nlm_void),
738 		.pc_ressize = sizeof(struct nlm_void),
739 		.pc_xdrressize = St,
740 		.pc_name = "UNUSED",
741 	},
742 	[18] = {
743 		.pc_func = nlmsvc_proc_unused,
744 		.pc_decode = nlmsvc_decode_void,
745 		.pc_encode = nlmsvc_encode_void,
746 		.pc_argsize = sizeof(struct nlm_void),
747 		.pc_argzero = sizeof(struct nlm_void),
748 		.pc_ressize = sizeof(struct nlm_void),
749 		.pc_xdrressize = St,
750 		.pc_name = "UNUSED",
751 	},
752 	[19] = {
753 		.pc_func = nlmsvc_proc_unused,
754 		.pc_decode = nlmsvc_decode_void,
755 		.pc_encode = nlmsvc_encode_void,
756 		.pc_argsize = sizeof(struct nlm_void),
757 		.pc_argzero = sizeof(struct nlm_void),
758 		.pc_ressize = sizeof(struct nlm_void),
759 		.pc_xdrressize = St,
760 		.pc_name = "UNUSED",
761 	},
762 	[NLMPROC_SHARE] = {
763 		.pc_func = nlmsvc_proc_share,
764 		.pc_decode = nlmsvc_decode_shareargs,
765 		.pc_encode = nlmsvc_encode_shareres,
766 		.pc_argsize = sizeof(struct nlm_args),
767 		.pc_argzero = sizeof(struct nlm_args),
768 		.pc_ressize = sizeof(struct nlm_res),
769 		.pc_xdrressize = Ck+St+1,
770 		.pc_name = "SHARE",
771 	},
772 	[NLMPROC_UNSHARE] = {
773 		.pc_func = nlmsvc_proc_unshare,
774 		.pc_decode = nlmsvc_decode_shareargs,
775 		.pc_encode = nlmsvc_encode_shareres,
776 		.pc_argsize = sizeof(struct nlm_args),
777 		.pc_argzero = sizeof(struct nlm_args),
778 		.pc_ressize = sizeof(struct nlm_res),
779 		.pc_xdrressize = Ck+St+1,
780 		.pc_name = "UNSHARE",
781 	},
782 	[NLMPROC_NM_LOCK] = {
783 		.pc_func = nlmsvc_proc_nm_lock,
784 		.pc_decode = nlmsvc_decode_lockargs,
785 		.pc_encode = nlmsvc_encode_res,
786 		.pc_argsize = sizeof(struct nlm_args),
787 		.pc_argzero = sizeof(struct nlm_args),
788 		.pc_ressize = sizeof(struct nlm_res),
789 		.pc_xdrressize = Ck+St,
790 		.pc_name = "NM_LOCK",
791 	},
792 	[NLMPROC_FREE_ALL] = {
793 		.pc_func = nlmsvc_proc_free_all,
794 		.pc_decode = nlmsvc_decode_notify,
795 		.pc_encode = nlmsvc_encode_void,
796 		.pc_argsize = sizeof(struct nlm_args),
797 		.pc_argzero = sizeof(struct nlm_args),
798 		.pc_ressize = sizeof(struct nlm_void),
799 		.pc_xdrressize = 0,
800 		.pc_name = "FREE_ALL",
801 	},
802 };
803 
804 /*
805  * Storage requirements for XDR arguments and results
806  */
807 union nlmsvc_xdrstore {
808 	struct nlm_args			args;
809 	struct nlm_res			res;
810 	struct nlm_reboot		reboot;
811 };
812 
813 /*
814  * NLMv1 defines only procedures 1 - 15. Linux lockd also implements
815  * procedures 0 (NULL) and 16 (SM_NOTIFY).
816  */
817 static DEFINE_PER_CPU_ALIGNED(unsigned long, nlm1svc_call_counters[17]);
818 
819 const struct svc_version nlmsvc_version1 = {
820 	.vs_vers	= 1,
821 	.vs_nproc	= 17,
822 	.vs_proc	= nlmsvc_procedures,
823 	.vs_count	= nlm1svc_call_counters,
824 	.vs_dispatch	= nlmsvc_dispatch,
825 	.vs_xdrsize	= sizeof(union nlmsvc_xdrstore),
826 };
827 
828 static DEFINE_PER_CPU_ALIGNED(unsigned long,
829 			      nlm3svc_call_counters[ARRAY_SIZE(nlmsvc_procedures)]);
830 
831 const struct svc_version nlmsvc_version3 = {
832 	.vs_vers	= 3,
833 	.vs_nproc	= ARRAY_SIZE(nlmsvc_procedures),
834 	.vs_proc	= nlmsvc_procedures,
835 	.vs_count	= nlm3svc_call_counters,
836 	.vs_dispatch	= nlmsvc_dispatch,
837 	.vs_xdrsize	= sizeof(union nlmsvc_xdrstore),
838 };
839