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
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.
13 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
17 * NFS Lock Manager, server-side dispatch tables and
18 * dispatch programs: nlm_prog_3, nlm_prog4
20 * These are called by RPC framework after the RPC service
21 * endpoints setup done in nlm_impl.c: nlm_svc_add_ep().
23 * Originally from rpcgen, then reduced.
26 #include <sys/param.h>
27 #include <sys/systm.h>
29 #include <rpcsvc/nlm_prot.h>
33 * Dispatch entry function pointers.
35 typedef bool_t (*nlm_svc_func_t
)(void *, void *, struct svc_req
*);
36 typedef void (*nlm_freeres_func_t
)(void *);
39 * Entries in the dispatch tables below.
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 */
50 /* Flag bits in de_flags */
51 #define NLM_DISP_NOREMOTE 1 /* Local calls only */
54 * Cast macros for dispatch table function pointers.
56 #define NLM_SVC_FUNC(func) (nlm_svc_func_t)func
57 #define NLM_FREERES_FUNC(func) (nlm_freeres_func_t)func
61 nlm_null_svc(void *args
, void *resp
, struct svc_req
*sr
)
67 * The common NLM service dispatch function, used by
68 * both: nlm_prog_3, nlm_prog_4
72 struct svc_req
*rqstp
,
74 const struct dispatch_entry
*de
)
77 /* All the arg types */
78 nlm_cancargs au_cancargs
;
79 nlm_lockargs au_lockargs
;
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
;
91 nlm4_shareargs au_shareargs4
;
92 nlm4_testargs au_testargs4
;
93 nlm4_testres au_testres4
;
94 nlm4_unlockargs au_unlockargs4
;
98 /* All the ret types */
101 nlm_shareres ru_shareres
;
102 nlm_testres ru_testres
;
104 nlm4_shareres ru_shareres4
;
105 nlm4_testres ru_testres4
;
110 bool_t do_reply
= FALSE
;
111 bool_t dupcached
= FALSE
;
115 if ((func
= de
->de_svc
) == NULL
) {
116 svcerr_noproc(transp
);
120 if ((de
->de_flags
& NLM_DISP_NOREMOTE
) &&
121 !nlm_caller_is_local(transp
)) {
122 svcerr_noproc(transp
);
127 * This section from rpcgen, and then modified slightly.
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().
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
141 bzero(&argu
, sizeof (argu
));
142 if (!SVC_GETARGS(transp
, de
->de_xargs
, args
)) {
143 svcerr_decode(transp
);
148 * Duplicate request cache.
150 * Since none of the NLM replies are very large we have simplified the
151 * DRC by not distinguishing between idempotent and non-idempotent
154 dupstat
= SVC_DUP_EXT(transp
, rqstp
, res
, de
->de_ressz
, &dr
,
159 svcerr_systemerr(transp
);
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)
171 curthread
->t_flag
|= T_DONTPEND
;
173 bzero(&resu
, sizeof (resu
));
174 do_reply
= (*func
)(args
, res
, rqstp
);
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
);
184 SVC_DUPDONE_EXT(transp
, dr
, res
, de
->de_resfree
,
185 de
->de_ressz
, DUP_DONE
);
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.
195 * If de_xres is NULL this is a one-way message so no reply is
198 if (de
->de_xres
!= NULL_xdrproc_t
) {
205 ASSERT(de
->de_xres
!= NULL_xdrproc_t
);
206 DTRACE_PROBE3(sendreply
, struct svc_req
*, rqstp
,
207 SVCXPRT
*, transp
, struct dispatch_entry
*, de
);
209 if (!svc_sendreply(transp
, de
->de_xres
, res
)) {
210 svcerr_systemerr(transp
);
211 NLM_ERR("nlm_dispatch(): svc_sendreply() failed!\n");
215 xdr_free(de
->de_xres
, res
);
219 if (!SVC_FREEARGS(transp
, de
->de_xargs
, args
))
220 NLM_WARN("nlm_dispatch(): unable to free arguments");
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.
228 nlm_res_free(nlm_res
*resp
)
230 xdr_free(xdr_nlm_res
, (char *)resp
);
234 nlm_shareres_free(nlm_shareres
*resp
)
236 xdr_free(xdr_nlm_shareres
, (char *)resp
);
240 nlm_testres_free(nlm_testres
*resp
)
242 xdr_free(xdr_nlm_testres
, (char *)resp
);
246 nlm4_res_free(nlm4_res
*resp
)
248 xdr_free(xdr_nlm4_res
, (char *)resp
);
252 nlm4_shareres_free(nlm4_shareres
*resp
)
254 xdr_free(xdr_nlm4_shareres
, (char *)resp
);
258 nlm4_testres_free(nlm4_testres
*resp
)
260 xdr_free(xdr_nlm4_testres
, (char *)resp
);
264 * Dispatch tables for each program version.
266 * The tables here were all originally from rpcgen,
267 * but then arg/resp sizes removed, flags added.
271 * Dispatch table for versions 1, 2, 3
272 * (NLM_VERS, NLM_SM, NLM_VERSX)
274 static const struct dispatch_entry
275 nlm_prog_3_dtable
[] = {
278 * Version 1 (NLM_VERS) entries.
282 NLM_SVC_FUNC(nlm_null_svc
),
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
),
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
),
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
),
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
),
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
),
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.
335 { /* 6: NLM_TEST_MSG */
336 NLM_SVC_FUNC(nlm_test_msg_1_svc
),
337 (xdrproc_t
)xdr_nlm_testargs
,
343 { /* 7: NLM_LOCK_MSG */
344 NLM_SVC_FUNC(nlm_lock_msg_1_svc
),
345 (xdrproc_t
)xdr_nlm_lockargs
,
351 { /* 8: NLM_CANCEL_MSG */
352 NLM_SVC_FUNC(nlm_cancel_msg_1_svc
),
353 (xdrproc_t
)xdr_nlm_cancargs
,
359 { /* 9: NLM_UNLOCK_MSG */
360 NLM_SVC_FUNC(nlm_unlock_msg_1_svc
),
361 (xdrproc_t
)xdr_nlm_unlockargs
,
367 { /* 10: NLM_GRANTED_MSG */
368 NLM_SVC_FUNC(nlm_granted_msg_1_svc
),
369 (xdrproc_t
)xdr_nlm_testargs
,
375 { /* 11: NLM_TEST_RES */
376 NLM_SVC_FUNC(nlm_test_res_1_svc
),
377 (xdrproc_t
)xdr_nlm_testres
,
383 { /* 12: NLM_LOCK_RES */
384 NLM_SVC_FUNC(nlm_lock_res_1_svc
),
385 (xdrproc_t
)xdr_nlm_res
,
391 { /* 13: NLM_CANCEL_RES */
392 NLM_SVC_FUNC(nlm_cancel_res_1_svc
),
393 (xdrproc_t
)xdr_nlm_res
,
399 { /* 14: NLM_UNLOCK_RES */
400 NLM_SVC_FUNC(nlm_unlock_res_1_svc
),
401 (xdrproc_t
)xdr_nlm_res
,
407 { /* 15: NLM_GRANTED_RES */
408 NLM_SVC_FUNC(nlm_granted_res_1_svc
),
409 (xdrproc_t
)xdr_nlm_res
,
423 { /* 17: NLM_SM_NOTIFY1 */
424 NLM_SVC_FUNC(nlm_sm_notify1_2_svc
),
425 (xdrproc_t
)xdr_nlm_sm_status
,
431 { /* 18: NLM_SM_NOTIFY2 */
432 NLM_SVC_FUNC(nlm_sm_notify2_2_svc
),
433 (xdrproc_t
)xdr_nlm_sm_status
,
440 * Version 3 (NLM_VERSX) entries.
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
),
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
),
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
),
475 { /* 23: NLM_FREE_ALL */
476 NLM_SVC_FUNC(nlm_free_all_3_svc
),
477 (xdrproc_t
)xdr_nlm_notify
,
483 static int nlm_prog_3_dtsize
=
484 sizeof (nlm_prog_3_dtable
) /
485 sizeof (nlm_prog_3_dtable
[0]);
488 * RPC dispatch function for nlm_prot versions: 1,2,3
491 nlm_prog_3(struct svc_req
*rqstp
, register SVCXPRT
*transp
)
493 const struct dispatch_entry
*de
;
496 switch (rqstp
->rq_vers
) {
498 max_proc
= NLM_GRANTED_RES
;
501 max_proc
= NLM_SM_NOTIFY2
;
504 max_proc
= NLM_FREE_ALL
;
507 /* Our svc registration should prevent this. */
508 ASSERT(0); /* paranoid */
509 svcerr_noprog(transp
);
512 ASSERT(max_proc
< nlm_prog_3_dtsize
);
514 if (rqstp
->rq_proc
> max_proc
) {
515 svcerr_noproc(transp
);
519 de
= &nlm_prog_3_dtable
[rqstp
->rq_proc
];
521 nlm_dispatch(rqstp
, transp
, de
);
525 * Dispatch table for version 4 (NLM4_VERS)
527 static const struct dispatch_entry
528 nlm_prog_4_dtable
[] = {
531 NLM_SVC_FUNC(nlm_null_svc
),
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
),
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
),
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
),
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
),
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
),
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.
584 { /* 6: NLM4_TEST_MSG */
585 NLM_SVC_FUNC(nlm4_test_msg_4_svc
),
586 (xdrproc_t
)xdr_nlm4_testargs
,
592 { /* 7: NLM4_LOCK_MSG */
593 NLM_SVC_FUNC(nlm4_lock_msg_4_svc
),
594 (xdrproc_t
)xdr_nlm4_lockargs
,
600 { /* 8: NLM4_CANCEL_MSG */
601 NLM_SVC_FUNC(nlm4_cancel_msg_4_svc
),
602 (xdrproc_t
)xdr_nlm4_cancargs
,
608 { /* 9: NLM4_UNLOCK_MSG */
609 NLM_SVC_FUNC(nlm4_unlock_msg_4_svc
),
610 (xdrproc_t
)xdr_nlm4_unlockargs
,
616 { /* 10: NLM4_GRANTED_MSG */
617 NLM_SVC_FUNC(nlm4_granted_msg_4_svc
),
618 (xdrproc_t
)xdr_nlm4_testargs
,
624 { /* 11: NLM4_TEST_RES */
625 NLM_SVC_FUNC(nlm4_test_res_4_svc
),
626 (xdrproc_t
)xdr_nlm4_testres
,
632 { /* 12: NLM4_LOCK_RES */
633 NLM_SVC_FUNC(nlm4_lock_res_4_svc
),
634 (xdrproc_t
)xdr_nlm4_res
,
640 { /* 13: NLM4_CANCEL_RES */
641 NLM_SVC_FUNC(nlm4_cancel_res_4_svc
),
642 (xdrproc_t
)xdr_nlm4_res
,
648 { /* 14: NLM4_UNLOCK_RES */
649 NLM_SVC_FUNC(nlm4_unlock_res_4_svc
),
650 (xdrproc_t
)xdr_nlm4_res
,
656 { /* 15: NLM4_GRANTED_RES */
657 NLM_SVC_FUNC(nlm4_granted_res_4_svc
),
658 (xdrproc_t
)xdr_nlm4_res
,
672 { /* 17: NLM_SM_NOTIFY1 (not in v4) */
680 { /* 18: NLM_SM_NOTIFY2 (not in v4) */
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
),
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
),
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
),
720 { /* 23: NLM4_FREE_ALL */
721 NLM_SVC_FUNC(nlm4_free_all_4_svc
),
722 (xdrproc_t
)xdr_nlm4_notify
,
728 static int nlm_prog_4_dtsize
=
729 sizeof (nlm_prog_4_dtable
) /
730 sizeof (nlm_prog_4_dtable
[0]);
733 * RPC dispatch function for nlm_prot version 4.
736 nlm_prog_4(struct svc_req
*rqstp
, register SVCXPRT
*transp
)
738 const struct dispatch_entry
*de
;
740 if (rqstp
->rq_vers
!= NLM4_VERS
) {
741 /* Our svc registration should prevent this. */
742 ASSERT(0); /* paranoid */
743 svcerr_noprog(transp
);
747 if (rqstp
->rq_proc
>= nlm_prog_4_dtsize
) {
748 svcerr_noproc(transp
);
752 de
= &nlm_prog_4_dtable
[rqstp
->rq_proc
];
754 nlm_dispatch(rqstp
, transp
, de
);