--- /dev/null	Fri Aug 16 09:04:51 2013
+++ new/usr/src/uts/common/klm/nlm_dispatch.c	Fri Aug 16 09:04:51 2013
@@ -0,0 +1,755 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy is of the CDDL is also available via the Internet
+ * at http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+/*
+ * NFS Lock Manager, server-side dispatch tables and
+ * dispatch programs: nlm_prog_3, nlm_prog4
+ *
+ * These are called by RPC framework after the RPC service
+ * endpoints setup done in nlm_impl.c: nlm_svc_add_ep().
+ *
+ * Originally from rpcgen, then reduced.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sdt.h>
+#include <rpcsvc/nlm_prot.h>
+#include "nlm_impl.h"
+
+/*
+ * Dispatch entry function pointers.
+ */
+typedef bool_t (*nlm_svc_func_t)(void *, void *, struct svc_req *);
+typedef void (*nlm_freeres_func_t)(void *);
+
+/*
+ * Entries in the dispatch tables below.
+ */
+struct dispatch_entry {
+	nlm_svc_func_t		de_svc;		/* service routine function */
+	xdrproc_t		de_xargs;	/* XDR args decode function */
+	xdrproc_t		de_xres;	/* XDR res encode function */
+	nlm_freeres_func_t	de_resfree;	/* free res function */
+	int			de_ressz;	/* size of result */
+	uint_t			de_flags;	/* flags */
+};
+
+/* Flag bits in de_flags */
+#define	NLM_DISP_NOREMOTE	1	/* Local calls only */
+
+/*
+ * Cast macros for dispatch table function pointers.
+ */
+#define	NLM_SVC_FUNC(func)	(nlm_svc_func_t)func
+#define	NLM_FREERES_FUNC(func)	(nlm_freeres_func_t)func
+
+/* ARGSUSED */
+static bool_t
+nlm_null_svc(void *args, void *resp, struct svc_req *sr)
+{
+	return (TRUE);
+}
+
+/*
+ * The common NLM service dispatch function, used by
+ * both: nlm_prog_3, nlm_prog_4
+ */
+void
+nlm_dispatch(
+	struct svc_req *rqstp,
+	SVCXPRT *transp,
+	const struct dispatch_entry *de)
+{
+	union {
+		/* All the arg types */
+		nlm_cancargs	au_cancargs;
+		nlm_lockargs	au_lockargs;
+		nlm_notify	au_notify;
+		nlm_res		au_res;
+		nlm_shareargs	au_shareargs;
+		nlm_sm_status	au_sm_status;
+		nlm_testargs	au_testargs;
+		nlm_testres	au_testres;
+		nlm_unlockargs	au_unlockargs;
+		nlm4_cancargs	au_cancargs4;
+		nlm4_lockargs	au_lockargs4;
+		nlm4_notify	au_notify4;
+		nlm4_res	au_res4;
+		nlm4_shareargs	au_shareargs4;
+		nlm4_testargs	au_testargs4;
+		nlm4_testres	au_testres4;
+		nlm4_unlockargs	au_unlockargs4;
+	} argu;
+	void *args = &argu;
+	union {
+		/* All the ret types */
+		int		ru_int;
+		nlm_res		ru_res;
+		nlm_shareres	ru_shareres;
+		nlm_testres	ru_testres;
+		nlm4_res	ru_res4;
+		nlm4_shareres	ru_shareres4;
+		nlm4_testres	ru_testres4;
+
+	} resu;
+	void *res = &resu;
+	nlm_svc_func_t func;
+	bool_t do_reply = FALSE;
+	bool_t dupcached = FALSE;
+	struct dupreq *dr;
+	int dupstat;
+
+	if ((func = de->de_svc) == NULL) {
+		svcerr_noproc(transp);
+		return;
+	}
+
+	if ((de->de_flags & NLM_DISP_NOREMOTE) &&
+	    !nlm_caller_is_local(transp)) {
+		svcerr_noproc(transp);
+		return;
+	}
+
+	/*
+	 * This section from rpcgen, and then modified slightly.
+	 *
+	 * Dispatch entries that should _never_ send a response
+	 * (i.e. all the _MSG and _RES entries) put NULL in the
+	 * de_xres field to indicate that.  For such entries, we
+	 * will NOT call svc_sendreply nor xdr_free().  Normal
+	 * dispatch entries skip svc_sendreply if the dispatch
+	 * function returns zero, but always call xdr_free().
+	 *
+	 * There are more complex cases where some dispatch
+	 * functions need to send their own reply.  We chose
+	 * to indicate those by returning false from the
+	 * service routine.
+	 */
+	bzero(&argu, sizeof (argu));
+	if (!SVC_GETARGS(transp, de->de_xargs, args)) {
+		svcerr_decode(transp);
+		return;
+	}
+
+	/*
+	 * Duplicate request cache.
+	 *
+	 * Since none of the NLM replies are very large we have simplified the
+	 * DRC by not distinguishing between idempotent and non-idempotent
+	 * requests.
+	 */
+	dupstat = SVC_DUP_EXT(transp, rqstp, res, de->de_ressz, &dr,
+	    &dupcached);
+
+	switch (dupstat) {
+	case DUP_ERROR:
+		svcerr_systemerr(transp);
+		break;
+	case DUP_INPROGRESS:
+		break;
+	case DUP_NEW:
+	case DUP_DROP:
+		/*
+		 * When UFS is quiescing it uses lockfs to block vnode
+		 * operations until it has finished quiescing.  Set the
+		 * thread's T_DONTPEND flag to prevent the service routine
+		 * from blocking due to a lockfs lock. (See ufs_check_lockfs)
+		 */
+		curthread->t_flag |= T_DONTPEND;
+
+		bzero(&resu, sizeof (resu));
+		do_reply = (*func)(args, res, rqstp);
+
+		curthread->t_flag &= ~T_DONTPEND;
+		if (curthread->t_flag & T_WOULDBLOCK) {
+			curthread->t_flag &= ~T_WOULDBLOCK;
+			SVC_DUPDONE_EXT(transp, dr, res, NULL,
+			    de->de_ressz, DUP_DROP);
+			do_reply = FALSE;
+			break;
+		}
+		SVC_DUPDONE_EXT(transp, dr, res, de->de_resfree,
+		    de->de_ressz, DUP_DONE);
+		dupcached = TRUE;
+		break;
+	case DUP_DONE:
+		/*
+		 * The service routine may have been responsible for sending
+		 * the reply for the original request but for a re-xmitted
+		 * request we don't invoke the service routine so we must
+		 * re-xmit the reply from the dispatch function.
+		 *
+		 * If de_xres is NULL this is a one-way message so no reply is
+		 * needed.
+		 */
+		if (de->de_xres != NULL_xdrproc_t) {
+			do_reply = TRUE;
+		}
+		break;
+	}
+
+	if (do_reply) {
+		ASSERT(de->de_xres != NULL_xdrproc_t);
+		DTRACE_PROBE3(sendreply, struct svc_req *, rqstp,
+		    SVCXPRT *, transp, struct dispatch_entry *, de);
+
+		if (!svc_sendreply(transp, de->de_xres, res)) {
+			svcerr_systemerr(transp);
+			NLM_ERR("nlm_dispatch(): svc_sendreply() failed!\n");
+		}
+
+		if (!dupcached) {
+			xdr_free(de->de_xres, res);
+		}
+	}
+
+	if (!SVC_FREEARGS(transp, de->de_xargs, args))
+		NLM_WARN("nlm_dispatch(): unable to free arguments");
+}
+
+/*
+ * Result free functions.  The functions are called by the RPC duplicate
+ * request cache code when an entry is being evicted from the cache.
+ */
+static void
+nlm_res_free(nlm_res *resp)
+{
+	xdr_free(xdr_nlm_res, (char *)resp);
+}
+
+static void
+nlm_shareres_free(nlm_shareres *resp)
+{
+	xdr_free(xdr_nlm_shareres, (char *)resp);
+}
+
+static void
+nlm_testres_free(nlm_testres *resp)
+{
+	xdr_free(xdr_nlm_testres, (char *)resp);
+}
+
+static void
+nlm4_res_free(nlm4_res *resp)
+{
+	xdr_free(xdr_nlm4_res, (char *)resp);
+}
+
+static void
+nlm4_shareres_free(nlm4_shareres *resp)
+{
+	xdr_free(xdr_nlm4_shareres, (char *)resp);
+}
+
+static void
+nlm4_testres_free(nlm4_testres *resp)
+{
+	xdr_free(xdr_nlm4_testres, (char *)resp);
+}
+
+/*
+ * Dispatch tables for each program version.
+ *
+ * The tables here were all originally from rpcgen,
+ * but then arg/resp sizes removed, flags added.
+ */
+
+/*
+ * Dispatch table for versions 1, 2, 3
+ * (NLM_VERS, NLM_SM, NLM_VERSX)
+ */
+static const struct dispatch_entry
+nlm_prog_3_dtable[] = {
+
+	/*
+	 * Version 1 (NLM_VERS) entries.
+	 */
+
+	{ /* 0: NULLPROC */
+	NLM_SVC_FUNC(nlm_null_svc),
+	(xdrproc_t)xdr_void,
+	(xdrproc_t)xdr_void,
+	NULL,
+	0,
+	0 },
+
+	{ /* 1: NLM_TEST */
+	NLM_SVC_FUNC(nlm_test_1_svc),
+	(xdrproc_t)xdr_nlm_testargs,
+	(xdrproc_t)xdr_nlm_testres,
+	NLM_FREERES_FUNC(nlm_testres_free),
+	sizeof (nlm_testres),
+	0 },
+
+	{ /* 2: NLM_LOCK */
+	NLM_SVC_FUNC(nlm_lock_1_svc),
+	(xdrproc_t)xdr_nlm_lockargs,
+	(xdrproc_t)xdr_nlm_res,
+	NLM_FREERES_FUNC(nlm_res_free),
+	sizeof (nlm_res),
+	0 },
+
+	{ /* 3: NLM_CANCEL */
+	NLM_SVC_FUNC(nlm_cancel_1_svc),
+	(xdrproc_t)xdr_nlm_cancargs,
+	(xdrproc_t)xdr_nlm_res,
+	NLM_FREERES_FUNC(nlm_res_free),
+	sizeof (nlm_res),
+	0 },
+
+	{ /* 4: NLM_UNLOCK */
+	NLM_SVC_FUNC(nlm_unlock_1_svc),
+	(xdrproc_t)xdr_nlm_unlockargs,
+	(xdrproc_t)xdr_nlm_res,
+	NLM_FREERES_FUNC(nlm_res_free),
+	sizeof (nlm_res),
+	0 },
+
+	{ /* 5: NLM_GRANTED */
+	NLM_SVC_FUNC(nlm_granted_1_svc),
+	(xdrproc_t)xdr_nlm_testargs,
+	(xdrproc_t)xdr_nlm_res,
+	NLM_FREERES_FUNC(nlm_res_free),
+	sizeof (nlm_res),
+	0 },
+
+	/*
+	 * All the _MSG and _RES entries are "one way" calls that
+	 * skip the usual RPC reply.  We give them a null xdr_res
+	 * function so the dispatcher will not send a reply.
+	 */
+
+	{ /* 6: NLM_TEST_MSG */
+	NLM_SVC_FUNC(nlm_test_msg_1_svc),
+	(xdrproc_t)xdr_nlm_testargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 7: NLM_LOCK_MSG */
+	NLM_SVC_FUNC(nlm_lock_msg_1_svc),
+	(xdrproc_t)xdr_nlm_lockargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 8: NLM_CANCEL_MSG */
+	NLM_SVC_FUNC(nlm_cancel_msg_1_svc),
+	(xdrproc_t)xdr_nlm_cancargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 9: NLM_UNLOCK_MSG */
+	NLM_SVC_FUNC(nlm_unlock_msg_1_svc),
+	(xdrproc_t)xdr_nlm_unlockargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 10: NLM_GRANTED_MSG */
+	NLM_SVC_FUNC(nlm_granted_msg_1_svc),
+	(xdrproc_t)xdr_nlm_testargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 11: NLM_TEST_RES */
+	NLM_SVC_FUNC(nlm_test_res_1_svc),
+	(xdrproc_t)xdr_nlm_testres,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 12: NLM_LOCK_RES */
+	NLM_SVC_FUNC(nlm_lock_res_1_svc),
+	(xdrproc_t)xdr_nlm_res,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 13: NLM_CANCEL_RES */
+	NLM_SVC_FUNC(nlm_cancel_res_1_svc),
+	(xdrproc_t)xdr_nlm_res,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 14: NLM_UNLOCK_RES */
+	NLM_SVC_FUNC(nlm_unlock_res_1_svc),
+	(xdrproc_t)xdr_nlm_res,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 15: NLM_GRANTED_RES */
+	NLM_SVC_FUNC(nlm_granted_res_1_svc),
+	(xdrproc_t)xdr_nlm_res,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 16: not used */
+	NLM_SVC_FUNC(0),
+	(xdrproc_t)0,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 17: NLM_SM_NOTIFY1 */
+	NLM_SVC_FUNC(nlm_sm_notify1_2_svc),
+	(xdrproc_t)xdr_nlm_sm_status,
+	(xdrproc_t)xdr_void,
+	NULL,
+	0,
+	NLM_DISP_NOREMOTE },
+
+	{ /* 18: NLM_SM_NOTIFY2 */
+	NLM_SVC_FUNC(nlm_sm_notify2_2_svc),
+	(xdrproc_t)xdr_nlm_sm_status,
+	(xdrproc_t)xdr_void,
+	NULL,
+	0,
+	NLM_DISP_NOREMOTE },
+
+	/*
+	 * Version 3 (NLM_VERSX) entries.
+	 */
+
+	{ /* 19: not used */
+	NLM_SVC_FUNC(0),
+	(xdrproc_t)0,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 20: NLM_SHARE */
+	NLM_SVC_FUNC(nlm_share_3_svc),
+	(xdrproc_t)xdr_nlm_shareargs,
+	(xdrproc_t)xdr_nlm_shareres,
+	NLM_FREERES_FUNC(nlm_shareres_free),
+	sizeof (nlm_shareres),
+	0 },
+
+	{ /* 21: NLM_UNSHARE */
+	NLM_SVC_FUNC(nlm_unshare_3_svc),
+	(xdrproc_t)xdr_nlm_shareargs,
+	(xdrproc_t)xdr_nlm_shareres,
+	NLM_FREERES_FUNC(nlm_shareres_free),
+	sizeof (nlm_shareres),
+	0 },
+
+	{ /* 22: NLM_NM_LOCK */
+	NLM_SVC_FUNC(nlm_nm_lock_3_svc),
+	(xdrproc_t)xdr_nlm_lockargs,
+	(xdrproc_t)xdr_nlm_res,
+	NLM_FREERES_FUNC(nlm_res_free),
+	sizeof (nlm_res),
+	0 },
+
+	{ /* 23: NLM_FREE_ALL */
+	NLM_SVC_FUNC(nlm_free_all_3_svc),
+	(xdrproc_t)xdr_nlm_notify,
+	(xdrproc_t)xdr_void,
+	NULL,
+	0,
+	0 },
+};
+static int nlm_prog_3_dtsize =
+	sizeof (nlm_prog_3_dtable) /
+	sizeof (nlm_prog_3_dtable[0]);
+
+/*
+ * RPC dispatch function for nlm_prot versions: 1,2,3
+ */
+void
+nlm_prog_3(struct svc_req *rqstp, register SVCXPRT *transp)
+{
+	const struct dispatch_entry *de;
+	rpcproc_t max_proc;
+
+	switch (rqstp->rq_vers) {
+	case NLM_VERS:
+		max_proc = NLM_GRANTED_RES;
+		break;
+	case NLM_SM:
+		max_proc = NLM_SM_NOTIFY2;
+		break;
+	case NLM_VERSX:
+		max_proc = NLM_FREE_ALL;
+		break;
+	default:
+		/* Our svc registration should prevent this. */
+		ASSERT(0); /* paranoid */
+		svcerr_noprog(transp);
+		return;
+	}
+	ASSERT(max_proc < nlm_prog_3_dtsize);
+
+	if (rqstp->rq_proc > max_proc) {
+		svcerr_noproc(transp);
+		return;
+	}
+
+	de = &nlm_prog_3_dtable[rqstp->rq_proc];
+
+	nlm_dispatch(rqstp, transp, de);
+}
+
+/*
+ * Dispatch table for version 4 (NLM4_VERS)
+ */
+static const struct dispatch_entry
+nlm_prog_4_dtable[] = {
+
+	{ /* 0: NULLPROC */
+	NLM_SVC_FUNC(nlm_null_svc),
+	(xdrproc_t)xdr_void,
+	(xdrproc_t)xdr_void,
+	NULL,
+	0,
+	0 },
+
+	{ /* 1: NLM4_TEST */
+	NLM_SVC_FUNC(nlm4_test_4_svc),
+	(xdrproc_t)xdr_nlm4_testargs,
+	(xdrproc_t)xdr_nlm4_testres,
+	NLM_FREERES_FUNC(nlm4_testres_free),
+	sizeof (nlm4_testres),
+	0 },
+
+	{ /* 2: NLM4_LOCK */
+	NLM_SVC_FUNC(nlm4_lock_4_svc),
+	(xdrproc_t)xdr_nlm4_lockargs,
+	(xdrproc_t)xdr_nlm4_res,
+	NLM_FREERES_FUNC(nlm4_res_free),
+	sizeof (nlm4_res),
+	0 },
+
+	{ /* 3: NLM4_CANCEL */
+	NLM_SVC_FUNC(nlm4_cancel_4_svc),
+	(xdrproc_t)xdr_nlm4_cancargs,
+	(xdrproc_t)xdr_nlm4_res,
+	NLM_FREERES_FUNC(nlm4_res_free),
+	sizeof (nlm4_res),
+	0 },
+
+	{ /* 4: NLM4_UNLOCK */
+	NLM_SVC_FUNC(nlm4_unlock_4_svc),
+	(xdrproc_t)xdr_nlm4_unlockargs,
+	(xdrproc_t)xdr_nlm4_res,
+	NLM_FREERES_FUNC(nlm4_res_free),
+	sizeof (nlm4_res),
+	0 },
+
+	{ /* 5: NLM4_GRANTED */
+	NLM_SVC_FUNC(nlm4_granted_4_svc),
+	(xdrproc_t)xdr_nlm4_testargs,
+	(xdrproc_t)xdr_nlm4_res,
+	NLM_FREERES_FUNC(nlm4_res_free),
+	sizeof (nlm4_res),
+	0 },
+
+	/*
+	 * All the _MSG and _RES entries are "one way" calls that
+	 * skip the usual RPC reply.  We give them a null xdr_res
+	 * function so the dispatcher will not send a reply.
+	 */
+
+	{ /* 6: NLM4_TEST_MSG */
+	NLM_SVC_FUNC(nlm4_test_msg_4_svc),
+	(xdrproc_t)xdr_nlm4_testargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 7: NLM4_LOCK_MSG */
+	NLM_SVC_FUNC(nlm4_lock_msg_4_svc),
+	(xdrproc_t)xdr_nlm4_lockargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 8: NLM4_CANCEL_MSG */
+	NLM_SVC_FUNC(nlm4_cancel_msg_4_svc),
+	(xdrproc_t)xdr_nlm4_cancargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 9: NLM4_UNLOCK_MSG */
+	NLM_SVC_FUNC(nlm4_unlock_msg_4_svc),
+	(xdrproc_t)xdr_nlm4_unlockargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 10: NLM4_GRANTED_MSG */
+	NLM_SVC_FUNC(nlm4_granted_msg_4_svc),
+	(xdrproc_t)xdr_nlm4_testargs,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 11: NLM4_TEST_RES */
+	NLM_SVC_FUNC(nlm4_test_res_4_svc),
+	(xdrproc_t)xdr_nlm4_testres,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 12: NLM4_LOCK_RES */
+	NLM_SVC_FUNC(nlm4_lock_res_4_svc),
+	(xdrproc_t)xdr_nlm4_res,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 13: NLM4_CANCEL_RES */
+	NLM_SVC_FUNC(nlm4_cancel_res_4_svc),
+	(xdrproc_t)xdr_nlm4_res,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 14: NLM4_UNLOCK_RES */
+	NLM_SVC_FUNC(nlm4_unlock_res_4_svc),
+	(xdrproc_t)xdr_nlm4_res,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 15: NLM4_GRANTED_RES */
+	NLM_SVC_FUNC(nlm4_granted_res_4_svc),
+	(xdrproc_t)xdr_nlm4_res,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 16: not used */
+	NLM_SVC_FUNC(0),
+	(xdrproc_t)0,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 17: NLM_SM_NOTIFY1 (not in v4) */
+	NLM_SVC_FUNC(0),
+	(xdrproc_t)0,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 18: NLM_SM_NOTIFY2 (not in v4) */
+	NLM_SVC_FUNC(0),
+	(xdrproc_t)0,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 19: not used */
+	NLM_SVC_FUNC(0),
+	(xdrproc_t)0,
+	(xdrproc_t)0,
+	NULL,
+	0,
+	0 },
+
+	{ /* 20: NLM4_SHARE */
+	NLM_SVC_FUNC(nlm4_share_4_svc),
+	(xdrproc_t)xdr_nlm4_shareargs,
+	(xdrproc_t)xdr_nlm4_shareres,
+	NLM_FREERES_FUNC(nlm4_shareres_free),
+	sizeof (nlm4_shareres),
+	0 },
+
+	{ /* 21: NLM4_UNSHARE */
+	NLM_SVC_FUNC(nlm4_unshare_4_svc),
+	(xdrproc_t)xdr_nlm4_shareargs,
+	(xdrproc_t)xdr_nlm4_shareres,
+	NLM_FREERES_FUNC(nlm4_shareres_free),
+	sizeof (nlm4_shareres),
+	0 },
+
+	{ /* 22: NLM4_NM_LOCK */
+	NLM_SVC_FUNC(nlm4_nm_lock_4_svc),
+	(xdrproc_t)xdr_nlm4_lockargs,
+	(xdrproc_t)xdr_nlm4_res,
+	NLM_FREERES_FUNC(nlm4_res_free),
+	sizeof (nlm4_res),
+	0 },
+
+	{ /* 23: NLM4_FREE_ALL */
+	NLM_SVC_FUNC(nlm4_free_all_4_svc),
+	(xdrproc_t)xdr_nlm4_notify,
+	(xdrproc_t)xdr_void,
+	NULL,
+	0,
+	0 },
+};
+static int nlm_prog_4_dtsize =
+	sizeof (nlm_prog_4_dtable) /
+	sizeof (nlm_prog_4_dtable[0]);
+
+/*
+ * RPC dispatch function for nlm_prot version 4.
+ */
+void
+nlm_prog_4(struct svc_req *rqstp, register SVCXPRT *transp)
+{
+	const struct dispatch_entry *de;
+
+	if (rqstp->rq_vers != NLM4_VERS) {
+		/* Our svc registration should prevent this. */
+		ASSERT(0); /* paranoid */
+		svcerr_noprog(transp);
+		return;
+	}
+
+	if (rqstp->rq_proc >= nlm_prog_4_dtsize) {
+		svcerr_noproc(transp);
+		return;
+	}
+
+	de = &nlm_prog_4_dtable[rqstp->rq_proc];
+
+	nlm_dispatch(rqstp, transp, de);
+}
