xref: /titanic_50/usr/src/uts/common/klm/nlm_dispatch.c (revision e1d3217b9afde782c4d3e946fda0e6ef36a61306)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy is of the CDDL is also available via the Internet
9  * at http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 /*
17  * NFS Lock Manager, server-side dispatch tables and
18  * dispatch programs: nlm_prog_3, nlm_prog4
19  *
20  * These are called by RPC framework after the RPC service
21  * endpoints setup done in nlm_impl.c: nlm_svc_add_ep().
22  *
23  * Originally from rpcgen, then reduced.
24  */
25 
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/sdt.h>
29 #include <rpcsvc/nlm_prot.h>
30 #include "nlm_impl.h"
31 
32 /*
33  * Dispatch entry function pointers.
34  */
35 typedef bool_t (*nlm_svc_func_t)(void *, void *, struct svc_req *);
36 typedef void (*nlm_freeres_func_t)(void *);
37 
38 /*
39  * Entries in the dispatch tables below.
40  */
41 struct dispatch_entry {
42 	nlm_svc_func_t		de_svc;		/* service routine function */
43 	xdrproc_t		de_xargs;	/* XDR args decode function */
44 	xdrproc_t		de_xres;	/* XDR res encode function */
45 	nlm_freeres_func_t	de_resfree;	/* free res function */
46 	int			de_ressz;	/* size of result */
47 	uint_t			de_flags;	/* flags */
48 };
49 
50 /* Flag bits in de_flags */
51 #define	NLM_DISP_NOREMOTE	1	/* Local calls only */
52 
53 /*
54  * Cast macros for dispatch table function pointers.
55  */
56 #define	NLM_SVC_FUNC(func)	(nlm_svc_func_t)func
57 #define	NLM_FREERES_FUNC(func)	(nlm_freeres_func_t)func
58 
59 /* ARGSUSED */
60 static bool_t
61 nlm_null_svc(void *args, void *resp, struct svc_req *sr)
62 {
63 	return (TRUE);
64 }
65 
66 /*
67  * The common NLM service dispatch function, used by
68  * both: nlm_prog_3, nlm_prog_4
69  */
70 void
71 nlm_dispatch(
72 	struct svc_req *rqstp,
73 	SVCXPRT *transp,
74 	const struct dispatch_entry *de)
75 {
76 	union {
77 		/* All the arg types */
78 		nlm_cancargs	au_cancargs;
79 		nlm_lockargs	au_lockargs;
80 		nlm_notify	au_notify;
81 		nlm_res		au_res;
82 		nlm_shareargs	au_shareargs;
83 		nlm_sm_status	au_sm_status;
84 		nlm_testargs	au_testargs;
85 		nlm_testres	au_testres;
86 		nlm_unlockargs	au_unlockargs;
87 		nlm4_cancargs	au_cancargs4;
88 		nlm4_lockargs	au_lockargs4;
89 		nlm4_notify	au_notify4;
90 		nlm4_res	au_res4;
91 		nlm4_shareargs	au_shareargs4;
92 		nlm4_testargs	au_testargs4;
93 		nlm4_testres	au_testres4;
94 		nlm4_unlockargs	au_unlockargs4;
95 	} argu;
96 	void *args = &argu;
97 	union {
98 		/* All the ret types */
99 		int		ru_int;
100 		nlm_res		ru_res;
101 		nlm_shareres	ru_shareres;
102 		nlm_testres	ru_testres;
103 		nlm4_res	ru_res4;
104 		nlm4_shareres	ru_shareres4;
105 		nlm4_testres	ru_testres4;
106 
107 	} resu;
108 	void *res = &resu;
109 	nlm_svc_func_t func;
110 	bool_t do_reply = FALSE;
111 	bool_t dupcached = FALSE;
112 	struct dupreq *dr;
113 	int dupstat;
114 
115 	if ((func = de->de_svc) == NULL) {
116 		svcerr_noproc(transp);
117 		return;
118 	}
119 
120 	if ((de->de_flags & NLM_DISP_NOREMOTE) &&
121 	    !nlm_caller_is_local(transp)) {
122 		svcerr_noproc(transp);
123 		return;
124 	}
125 
126 	/*
127 	 * This section from rpcgen, and then modified slightly.
128 	 *
129 	 * Dispatch entries that should _never_ send a response
130 	 * (i.e. all the _MSG and _RES entries) put NULL in the
131 	 * de_xres field to indicate that.  For such entries, we
132 	 * will NOT call svc_sendreply nor xdr_free().  Normal
133 	 * dispatch entries skip svc_sendreply if the dispatch
134 	 * function returns zero, but always call xdr_free().
135 	 *
136 	 * There are more complex cases where some dispatch
137 	 * functions need to send their own reply.  We chose
138 	 * to indicate those by returning false from the
139 	 * service routine.
140 	 */
141 	bzero(&argu, sizeof (argu));
142 	if (!SVC_GETARGS(transp, de->de_xargs, args)) {
143 		svcerr_decode(transp);
144 		return;
145 	}
146 
147 	/*
148 	 * Duplicate request cache.
149 	 *
150 	 * Since none of the NLM replies are very large we have simplified the
151 	 * DRC by not distinguishing between idempotent and non-idempotent
152 	 * requests.
153 	 */
154 	dupstat = SVC_DUP_EXT(transp, rqstp, res, de->de_ressz, &dr,
155 	    &dupcached);
156 
157 	switch (dupstat) {
158 	case DUP_ERROR:
159 		svcerr_systemerr(transp);
160 		break;
161 	case DUP_INPROGRESS:
162 		break;
163 	case DUP_NEW:
164 	case DUP_DROP:
165 		/*
166 		 * When UFS is quiescing it uses lockfs to block vnode
167 		 * operations until it has finished quiescing.  Set the
168 		 * thread's T_DONTPEND flag to prevent the service routine
169 		 * from blocking due to a lockfs lock. (See ufs_check_lockfs)
170 		 */
171 		curthread->t_flag |= T_DONTPEND;
172 
173 		bzero(&resu, sizeof (resu));
174 		do_reply = (*func)(args, res, rqstp);
175 
176 		curthread->t_flag &= ~T_DONTPEND;
177 		if (curthread->t_flag & T_WOULDBLOCK) {
178 			curthread->t_flag &= ~T_WOULDBLOCK;
179 			SVC_DUPDONE_EXT(transp, dr, res, NULL,
180 			    de->de_ressz, DUP_DROP);
181 			do_reply = FALSE;
182 			break;
183 		}
184 		SVC_DUPDONE_EXT(transp, dr, res, de->de_resfree,
185 		    de->de_ressz, DUP_DONE);
186 		dupcached = TRUE;
187 		break;
188 	case DUP_DONE:
189 		/*
190 		 * The service routine may have been responsible for sending
191 		 * the reply for the original request but for a re-xmitted
192 		 * request we don't invoke the service routine so we must
193 		 * re-xmit the reply from the dispatch function.
194 		 *
195 		 * If de_xres is NULL this is a one-way message so no reply is
196 		 * needed.
197 		 */
198 		if (de->de_xres != NULL_xdrproc_t) {
199 			do_reply = TRUE;
200 		}
201 		break;
202 	}
203 
204 	if (do_reply) {
205 		ASSERT(de->de_xres != NULL_xdrproc_t);
206 		DTRACE_PROBE3(sendreply, struct svc_req *, rqstp,
207 		    SVCXPRT *, transp, struct dispatch_entry *, de);
208 
209 		if (!svc_sendreply(transp, de->de_xres, res)) {
210 			svcerr_systemerr(transp);
211 			NLM_ERR("nlm_dispatch(): svc_sendreply() failed!\n");
212 		}
213 
214 		if (!dupcached) {
215 			xdr_free(de->de_xres, res);
216 		}
217 	}
218 
219 	if (!SVC_FREEARGS(transp, de->de_xargs, args))
220 		NLM_WARN("nlm_dispatch(): unable to free arguments");
221 }
222 
223 /*
224  * Result free functions.  The functions are called by the RPC duplicate
225  * request cache code when an entry is being evicted from the cache.
226  */
227 static void
228 nlm_res_free(nlm_res *resp)
229 {
230 	xdr_free(xdr_nlm_res, (char *)resp);
231 }
232 
233 static void
234 nlm_shareres_free(nlm_shareres *resp)
235 {
236 	xdr_free(xdr_nlm_shareres, (char *)resp);
237 }
238 
239 static void
240 nlm_testres_free(nlm_testres *resp)
241 {
242 	xdr_free(xdr_nlm_testres, (char *)resp);
243 }
244 
245 static void
246 nlm4_res_free(nlm4_res *resp)
247 {
248 	xdr_free(xdr_nlm4_res, (char *)resp);
249 }
250 
251 static void
252 nlm4_shareres_free(nlm4_shareres *resp)
253 {
254 	xdr_free(xdr_nlm4_shareres, (char *)resp);
255 }
256 
257 static void
258 nlm4_testres_free(nlm4_testres *resp)
259 {
260 	xdr_free(xdr_nlm4_testres, (char *)resp);
261 }
262 
263 /*
264  * Dispatch tables for each program version.
265  *
266  * The tables here were all originally from rpcgen,
267  * but then arg/resp sizes removed, flags added.
268  */
269 
270 /*
271  * Dispatch table for versions 1, 2, 3
272  * (NLM_VERS, NLM_SM, NLM_VERSX)
273  */
274 static const struct dispatch_entry
275 nlm_prog_3_dtable[] = {
276 
277 	/*
278 	 * Version 1 (NLM_VERS) entries.
279 	 */
280 
281 	{ /* 0: NULLPROC */
282 	NLM_SVC_FUNC(nlm_null_svc),
283 	(xdrproc_t)xdr_void,
284 	(xdrproc_t)xdr_void,
285 	NULL,
286 	0,
287 	0 },
288 
289 	{ /* 1: NLM_TEST */
290 	NLM_SVC_FUNC(nlm_test_1_svc),
291 	(xdrproc_t)xdr_nlm_testargs,
292 	(xdrproc_t)xdr_nlm_testres,
293 	NLM_FREERES_FUNC(nlm_testres_free),
294 	sizeof (nlm_testres),
295 	0 },
296 
297 	{ /* 2: NLM_LOCK */
298 	NLM_SVC_FUNC(nlm_lock_1_svc),
299 	(xdrproc_t)xdr_nlm_lockargs,
300 	(xdrproc_t)xdr_nlm_res,
301 	NLM_FREERES_FUNC(nlm_res_free),
302 	sizeof (nlm_res),
303 	0 },
304 
305 	{ /* 3: NLM_CANCEL */
306 	NLM_SVC_FUNC(nlm_cancel_1_svc),
307 	(xdrproc_t)xdr_nlm_cancargs,
308 	(xdrproc_t)xdr_nlm_res,
309 	NLM_FREERES_FUNC(nlm_res_free),
310 	sizeof (nlm_res),
311 	0 },
312 
313 	{ /* 4: NLM_UNLOCK */
314 	NLM_SVC_FUNC(nlm_unlock_1_svc),
315 	(xdrproc_t)xdr_nlm_unlockargs,
316 	(xdrproc_t)xdr_nlm_res,
317 	NLM_FREERES_FUNC(nlm_res_free),
318 	sizeof (nlm_res),
319 	0 },
320 
321 	{ /* 5: NLM_GRANTED */
322 	NLM_SVC_FUNC(nlm_granted_1_svc),
323 	(xdrproc_t)xdr_nlm_testargs,
324 	(xdrproc_t)xdr_nlm_res,
325 	NLM_FREERES_FUNC(nlm_res_free),
326 	sizeof (nlm_res),
327 	0 },
328 
329 	/*
330 	 * All the _MSG and _RES entries are "one way" calls that
331 	 * skip the usual RPC reply.  We give them a null xdr_res
332 	 * function so the dispatcher will not send a reply.
333 	 */
334 
335 	{ /* 6: NLM_TEST_MSG */
336 	NLM_SVC_FUNC(nlm_test_msg_1_svc),
337 	(xdrproc_t)xdr_nlm_testargs,
338 	(xdrproc_t)0,
339 	NULL,
340 	0,
341 	0 },
342 
343 	{ /* 7: NLM_LOCK_MSG */
344 	NLM_SVC_FUNC(nlm_lock_msg_1_svc),
345 	(xdrproc_t)xdr_nlm_lockargs,
346 	(xdrproc_t)0,
347 	NULL,
348 	0,
349 	0 },
350 
351 	{ /* 8: NLM_CANCEL_MSG */
352 	NLM_SVC_FUNC(nlm_cancel_msg_1_svc),
353 	(xdrproc_t)xdr_nlm_cancargs,
354 	(xdrproc_t)0,
355 	NULL,
356 	0,
357 	0 },
358 
359 	{ /* 9: NLM_UNLOCK_MSG */
360 	NLM_SVC_FUNC(nlm_unlock_msg_1_svc),
361 	(xdrproc_t)xdr_nlm_unlockargs,
362 	(xdrproc_t)0,
363 	NULL,
364 	0,
365 	0 },
366 
367 	{ /* 10: NLM_GRANTED_MSG */
368 	NLM_SVC_FUNC(nlm_granted_msg_1_svc),
369 	(xdrproc_t)xdr_nlm_testargs,
370 	(xdrproc_t)0,
371 	NULL,
372 	0,
373 	0 },
374 
375 	{ /* 11: NLM_TEST_RES */
376 	NLM_SVC_FUNC(nlm_test_res_1_svc),
377 	(xdrproc_t)xdr_nlm_testres,
378 	(xdrproc_t)0,
379 	NULL,
380 	0,
381 	0 },
382 
383 	{ /* 12: NLM_LOCK_RES */
384 	NLM_SVC_FUNC(nlm_lock_res_1_svc),
385 	(xdrproc_t)xdr_nlm_res,
386 	(xdrproc_t)0,
387 	NULL,
388 	0,
389 	0 },
390 
391 	{ /* 13: NLM_CANCEL_RES */
392 	NLM_SVC_FUNC(nlm_cancel_res_1_svc),
393 	(xdrproc_t)xdr_nlm_res,
394 	(xdrproc_t)0,
395 	NULL,
396 	0,
397 	0 },
398 
399 	{ /* 14: NLM_UNLOCK_RES */
400 	NLM_SVC_FUNC(nlm_unlock_res_1_svc),
401 	(xdrproc_t)xdr_nlm_res,
402 	(xdrproc_t)0,
403 	NULL,
404 	0,
405 	0 },
406 
407 	{ /* 15: NLM_GRANTED_RES */
408 	NLM_SVC_FUNC(nlm_granted_res_1_svc),
409 	(xdrproc_t)xdr_nlm_res,
410 	(xdrproc_t)0,
411 	NULL,
412 	0,
413 	0 },
414 
415 	{ /* 16: not used */
416 	NLM_SVC_FUNC(0),
417 	(xdrproc_t)0,
418 	(xdrproc_t)0,
419 	NULL,
420 	0,
421 	0 },
422 
423 	{ /* 17: NLM_SM_NOTIFY1 */
424 	NLM_SVC_FUNC(nlm_sm_notify1_2_svc),
425 	(xdrproc_t)xdr_nlm_sm_status,
426 	(xdrproc_t)xdr_void,
427 	NULL,
428 	0,
429 	NLM_DISP_NOREMOTE },
430 
431 	{ /* 18: NLM_SM_NOTIFY2 */
432 	NLM_SVC_FUNC(nlm_sm_notify2_2_svc),
433 	(xdrproc_t)xdr_nlm_sm_status,
434 	(xdrproc_t)xdr_void,
435 	NULL,
436 	0,
437 	NLM_DISP_NOREMOTE },
438 
439 	/*
440 	 * Version 3 (NLM_VERSX) entries.
441 	 */
442 
443 	{ /* 19: not used */
444 	NLM_SVC_FUNC(0),
445 	(xdrproc_t)0,
446 	(xdrproc_t)0,
447 	NULL,
448 	0,
449 	0 },
450 
451 	{ /* 20: NLM_SHARE */
452 	NLM_SVC_FUNC(nlm_share_3_svc),
453 	(xdrproc_t)xdr_nlm_shareargs,
454 	(xdrproc_t)xdr_nlm_shareres,
455 	NLM_FREERES_FUNC(nlm_shareres_free),
456 	sizeof (nlm_shareres),
457 	0 },
458 
459 	{ /* 21: NLM_UNSHARE */
460 	NLM_SVC_FUNC(nlm_unshare_3_svc),
461 	(xdrproc_t)xdr_nlm_shareargs,
462 	(xdrproc_t)xdr_nlm_shareres,
463 	NLM_FREERES_FUNC(nlm_shareres_free),
464 	sizeof (nlm_shareres),
465 	0 },
466 
467 	{ /* 22: NLM_NM_LOCK */
468 	NLM_SVC_FUNC(nlm_nm_lock_3_svc),
469 	(xdrproc_t)xdr_nlm_lockargs,
470 	(xdrproc_t)xdr_nlm_res,
471 	NLM_FREERES_FUNC(nlm_res_free),
472 	sizeof (nlm_res),
473 	0 },
474 
475 	{ /* 23: NLM_FREE_ALL */
476 	NLM_SVC_FUNC(nlm_free_all_3_svc),
477 	(xdrproc_t)xdr_nlm_notify,
478 	(xdrproc_t)xdr_void,
479 	NULL,
480 	0,
481 	0 },
482 };
483 static int nlm_prog_3_dtsize =
484 	sizeof (nlm_prog_3_dtable) /
485 	sizeof (nlm_prog_3_dtable[0]);
486 
487 /*
488  * RPC dispatch function for nlm_prot versions: 1,2,3
489  */
490 void
491 nlm_prog_3(struct svc_req *rqstp, register SVCXPRT *transp)
492 {
493 	const struct dispatch_entry *de;
494 	rpcproc_t max_proc;
495 
496 	switch (rqstp->rq_vers) {
497 	case NLM_VERS:
498 		max_proc = NLM_GRANTED_RES;
499 		break;
500 	case NLM_SM:
501 		max_proc = NLM_SM_NOTIFY2;
502 		break;
503 	case NLM_VERSX:
504 		max_proc = NLM_FREE_ALL;
505 		break;
506 	default:
507 		/* Our svc registration should prevent this. */
508 		ASSERT(0); /* paranoid */
509 		svcerr_noprog(transp);
510 		return;
511 	}
512 	ASSERT(max_proc < nlm_prog_3_dtsize);
513 
514 	if (rqstp->rq_proc > max_proc) {
515 		svcerr_noproc(transp);
516 		return;
517 	}
518 
519 	de = &nlm_prog_3_dtable[rqstp->rq_proc];
520 
521 	nlm_dispatch(rqstp, transp, de);
522 }
523 
524 /*
525  * Dispatch table for version 4 (NLM4_VERS)
526  */
527 static const struct dispatch_entry
528 nlm_prog_4_dtable[] = {
529 
530 	{ /* 0: NULLPROC */
531 	NLM_SVC_FUNC(nlm_null_svc),
532 	(xdrproc_t)xdr_void,
533 	(xdrproc_t)xdr_void,
534 	NULL,
535 	0,
536 	0 },
537 
538 	{ /* 1: NLM4_TEST */
539 	NLM_SVC_FUNC(nlm4_test_4_svc),
540 	(xdrproc_t)xdr_nlm4_testargs,
541 	(xdrproc_t)xdr_nlm4_testres,
542 	NLM_FREERES_FUNC(nlm4_testres_free),
543 	sizeof (nlm4_testres),
544 	0 },
545 
546 	{ /* 2: NLM4_LOCK */
547 	NLM_SVC_FUNC(nlm4_lock_4_svc),
548 	(xdrproc_t)xdr_nlm4_lockargs,
549 	(xdrproc_t)xdr_nlm4_res,
550 	NLM_FREERES_FUNC(nlm4_res_free),
551 	sizeof (nlm4_res),
552 	0 },
553 
554 	{ /* 3: NLM4_CANCEL */
555 	NLM_SVC_FUNC(nlm4_cancel_4_svc),
556 	(xdrproc_t)xdr_nlm4_cancargs,
557 	(xdrproc_t)xdr_nlm4_res,
558 	NLM_FREERES_FUNC(nlm4_res_free),
559 	sizeof (nlm4_res),
560 	0 },
561 
562 	{ /* 4: NLM4_UNLOCK */
563 	NLM_SVC_FUNC(nlm4_unlock_4_svc),
564 	(xdrproc_t)xdr_nlm4_unlockargs,
565 	(xdrproc_t)xdr_nlm4_res,
566 	NLM_FREERES_FUNC(nlm4_res_free),
567 	sizeof (nlm4_res),
568 	0 },
569 
570 	{ /* 5: NLM4_GRANTED */
571 	NLM_SVC_FUNC(nlm4_granted_4_svc),
572 	(xdrproc_t)xdr_nlm4_testargs,
573 	(xdrproc_t)xdr_nlm4_res,
574 	NLM_FREERES_FUNC(nlm4_res_free),
575 	sizeof (nlm4_res),
576 	0 },
577 
578 	/*
579 	 * All the _MSG and _RES entries are "one way" calls that
580 	 * skip the usual RPC reply.  We give them a null xdr_res
581 	 * function so the dispatcher will not send a reply.
582 	 */
583 
584 	{ /* 6: NLM4_TEST_MSG */
585 	NLM_SVC_FUNC(nlm4_test_msg_4_svc),
586 	(xdrproc_t)xdr_nlm4_testargs,
587 	(xdrproc_t)0,
588 	NULL,
589 	0,
590 	0 },
591 
592 	{ /* 7: NLM4_LOCK_MSG */
593 	NLM_SVC_FUNC(nlm4_lock_msg_4_svc),
594 	(xdrproc_t)xdr_nlm4_lockargs,
595 	(xdrproc_t)0,
596 	NULL,
597 	0,
598 	0 },
599 
600 	{ /* 8: NLM4_CANCEL_MSG */
601 	NLM_SVC_FUNC(nlm4_cancel_msg_4_svc),
602 	(xdrproc_t)xdr_nlm4_cancargs,
603 	(xdrproc_t)0,
604 	NULL,
605 	0,
606 	0 },
607 
608 	{ /* 9: NLM4_UNLOCK_MSG */
609 	NLM_SVC_FUNC(nlm4_unlock_msg_4_svc),
610 	(xdrproc_t)xdr_nlm4_unlockargs,
611 	(xdrproc_t)0,
612 	NULL,
613 	0,
614 	0 },
615 
616 	{ /* 10: NLM4_GRANTED_MSG */
617 	NLM_SVC_FUNC(nlm4_granted_msg_4_svc),
618 	(xdrproc_t)xdr_nlm4_testargs,
619 	(xdrproc_t)0,
620 	NULL,
621 	0,
622 	0 },
623 
624 	{ /* 11: NLM4_TEST_RES */
625 	NLM_SVC_FUNC(nlm4_test_res_4_svc),
626 	(xdrproc_t)xdr_nlm4_testres,
627 	(xdrproc_t)0,
628 	NULL,
629 	0,
630 	0 },
631 
632 	{ /* 12: NLM4_LOCK_RES */
633 	NLM_SVC_FUNC(nlm4_lock_res_4_svc),
634 	(xdrproc_t)xdr_nlm4_res,
635 	(xdrproc_t)0,
636 	NULL,
637 	0,
638 	0 },
639 
640 	{ /* 13: NLM4_CANCEL_RES */
641 	NLM_SVC_FUNC(nlm4_cancel_res_4_svc),
642 	(xdrproc_t)xdr_nlm4_res,
643 	(xdrproc_t)0,
644 	NULL,
645 	0,
646 	0 },
647 
648 	{ /* 14: NLM4_UNLOCK_RES */
649 	NLM_SVC_FUNC(nlm4_unlock_res_4_svc),
650 	(xdrproc_t)xdr_nlm4_res,
651 	(xdrproc_t)0,
652 	NULL,
653 	0,
654 	0 },
655 
656 	{ /* 15: NLM4_GRANTED_RES */
657 	NLM_SVC_FUNC(nlm4_granted_res_4_svc),
658 	(xdrproc_t)xdr_nlm4_res,
659 	(xdrproc_t)0,
660 	NULL,
661 	0,
662 	0 },
663 
664 	{ /* 16: not used */
665 	NLM_SVC_FUNC(0),
666 	(xdrproc_t)0,
667 	(xdrproc_t)0,
668 	NULL,
669 	0,
670 	0 },
671 
672 	{ /* 17: NLM_SM_NOTIFY1 (not in v4) */
673 	NLM_SVC_FUNC(0),
674 	(xdrproc_t)0,
675 	(xdrproc_t)0,
676 	NULL,
677 	0,
678 	0 },
679 
680 	{ /* 18: NLM_SM_NOTIFY2 (not in v4) */
681 	NLM_SVC_FUNC(0),
682 	(xdrproc_t)0,
683 	(xdrproc_t)0,
684 	NULL,
685 	0,
686 	0 },
687 
688 	{ /* 19: not used */
689 	NLM_SVC_FUNC(0),
690 	(xdrproc_t)0,
691 	(xdrproc_t)0,
692 	NULL,
693 	0,
694 	0 },
695 
696 	{ /* 20: NLM4_SHARE */
697 	NLM_SVC_FUNC(nlm4_share_4_svc),
698 	(xdrproc_t)xdr_nlm4_shareargs,
699 	(xdrproc_t)xdr_nlm4_shareres,
700 	NLM_FREERES_FUNC(nlm4_shareres_free),
701 	sizeof (nlm4_shareres),
702 	0 },
703 
704 	{ /* 21: NLM4_UNSHARE */
705 	NLM_SVC_FUNC(nlm4_unshare_4_svc),
706 	(xdrproc_t)xdr_nlm4_shareargs,
707 	(xdrproc_t)xdr_nlm4_shareres,
708 	NLM_FREERES_FUNC(nlm4_shareres_free),
709 	sizeof (nlm4_shareres),
710 	0 },
711 
712 	{ /* 22: NLM4_NM_LOCK */
713 	NLM_SVC_FUNC(nlm4_nm_lock_4_svc),
714 	(xdrproc_t)xdr_nlm4_lockargs,
715 	(xdrproc_t)xdr_nlm4_res,
716 	NLM_FREERES_FUNC(nlm4_res_free),
717 	sizeof (nlm4_res),
718 	0 },
719 
720 	{ /* 23: NLM4_FREE_ALL */
721 	NLM_SVC_FUNC(nlm4_free_all_4_svc),
722 	(xdrproc_t)xdr_nlm4_notify,
723 	(xdrproc_t)xdr_void,
724 	NULL,
725 	0,
726 	0 },
727 };
728 static int nlm_prog_4_dtsize =
729 	sizeof (nlm_prog_4_dtable) /
730 	sizeof (nlm_prog_4_dtable[0]);
731 
732 /*
733  * RPC dispatch function for nlm_prot version 4.
734  */
735 void
736 nlm_prog_4(struct svc_req *rqstp, register SVCXPRT *transp)
737 {
738 	const struct dispatch_entry *de;
739 
740 	if (rqstp->rq_vers != NLM4_VERS) {
741 		/* Our svc registration should prevent this. */
742 		ASSERT(0); /* paranoid */
743 		svcerr_noprog(transp);
744 		return;
745 	}
746 
747 	if (rqstp->rq_proc >= nlm_prog_4_dtsize) {
748 		svcerr_noproc(transp);
749 		return;
750 	}
751 
752 	de = &nlm_prog_4_dtable[rqstp->rq_proc];
753 
754 	nlm_dispatch(rqstp, transp, de);
755 }
756