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