xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs_server.c (revision f44e1126)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
527242a7cSthurlow  * Common Development and Distribution License (the "License").
627242a7cSthurlow  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
220a4b0810SKaren Rochford  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
2389b43686SBayard Bell  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
24e36d7b11SSebastien Roy  * Copyright (c) 2013 by Delphix. All rights reserved.
25b1cdc720SAlex Wilson  * Copyright (c) 2017 Joyent Inc
260dfe541eSEvan Layton  * Copyright 2019 Nexenta by DDN, Inc.
27214d537cSVitaliy Gusev  * Copyright 2021 Racktop Systems, Inc.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
327c478bd9Sstevel@tonic-gate  *	All rights reserved.
337c478bd9Sstevel@tonic-gate  *	Use is subject to license terms.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <sys/param.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/systm.h>
397c478bd9Sstevel@tonic-gate #include <sys/cred.h>
407c478bd9Sstevel@tonic-gate #include <sys/proc.h>
417c478bd9Sstevel@tonic-gate #include <sys/user.h>
427c478bd9Sstevel@tonic-gate #include <sys/buf.h>
437c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
447c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
457c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
467c478bd9Sstevel@tonic-gate #include <sys/uio.h>
477c478bd9Sstevel@tonic-gate #include <sys/file.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <sys/errno.h>
507c478bd9Sstevel@tonic-gate #include <sys/socket.h>
517c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
527c478bd9Sstevel@tonic-gate #include <sys/siginfo.h>
537c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
547c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
557c478bd9Sstevel@tonic-gate #include <sys/stream.h>
56e36d7b11SSebastien Roy #include <sys/strsun.h>
577c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
587c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
597c478bd9Sstevel@tonic-gate #include <sys/timod.h>
607c478bd9Sstevel@tonic-gate #include <sys/t_kuser.h>
617c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
627c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
637c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
647c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
657c478bd9Sstevel@tonic-gate #include <sys/debug.h>
667c478bd9Sstevel@tonic-gate #include <sys/unistd.h>
677c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
687c478bd9Sstevel@tonic-gate #include <sys/mode.h>
697c478bd9Sstevel@tonic-gate #include <sys/acl.h>
707c478bd9Sstevel@tonic-gate #include <sys/sdt.h>
71b1cdc720SAlex Wilson #include <sys/debug.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #include <rpc/types.h>
747c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
757c478bd9Sstevel@tonic-gate #include <rpc/auth_unix.h>
767c478bd9Sstevel@tonic-gate #include <rpc/auth_des.h>
777c478bd9Sstevel@tonic-gate #include <rpc/svc.h>
787c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
7951f34d4bSRajkumar Sivaprakasam #include <rpc/rpc_rdma.h>
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
827c478bd9Sstevel@tonic-gate #include <nfs/export.h>
837c478bd9Sstevel@tonic-gate #include <nfs/nfssys.h>
847c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
857c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h>
867c478bd9Sstevel@tonic-gate #include <nfs/nfs_log.h>
877c478bd9Sstevel@tonic-gate #include <nfs/lm.h>
88d9ad96c1Srg #include <nfs/nfs_dispatch.h>
89d9ad96c1Srg #include <nfs/nfs4_drc.h>
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
927c478bd9Sstevel@tonic-gate #include <sys/cladm.h>
937c478bd9Sstevel@tonic-gate #include <sys/clconf.h>
947c478bd9Sstevel@tonic-gate 
95bd6f1640SJarrett Lu #include <sys/tsol/label.h>
96bd6f1640SJarrett Lu 
977c478bd9Sstevel@tonic-gate #define	MAXHOST 32
987c478bd9Sstevel@tonic-gate const char *kinet_ntop6(uchar_t *, char *, size_t);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate  * Module linkage information.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
1057c478bd9Sstevel@tonic-gate 	&mod_miscops, "NFS server module"
1067c478bd9Sstevel@tonic-gate };
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1097c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
1107c478bd9Sstevel@tonic-gate };
1117c478bd9Sstevel@tonic-gate 
1120dfe541eSEvan Layton zone_key_t	nfssrv_zone_key;
1130dfe541eSEvan Layton list_t		nfssrv_globals_list;
1140dfe541eSEvan Layton krwlock_t	nfssrv_globals_rwl;
1150dfe541eSEvan Layton 
116c242f9a0Schunli zhang - Sun Microsystems - Irvine United States kmem_cache_t *nfs_xuio_cache;
117c242f9a0Schunli zhang - Sun Microsystems - Irvine United States int nfs_loaned_buffers = 0;
118c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
119aab20b47SToomas Soome /* array of paths passed-in from nfsd command-line; stored in nvlist */
120aab20b47SToomas Soome char		**rfs4_dss_newpaths;
121aab20b47SToomas Soome uint_t		rfs4_dss_numnewpaths;
122aab20b47SToomas Soome 
123aab20b47SToomas Soome /* nvlists of all DSS paths: current, and before last warmstart */
124aab20b47SToomas Soome nvlist_t *rfs4_dss_paths, *rfs4_dss_oldpaths;
125aab20b47SToomas Soome 
1267c478bd9Sstevel@tonic-gate int
_init(void)1277c478bd9Sstevel@tonic-gate _init(void)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	int status;
1307c478bd9Sstevel@tonic-gate 
1310dfe541eSEvan Layton 	nfs_srvinit();
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	status = mod_install((struct modlinkage *)&modlinkage);
1347c478bd9Sstevel@tonic-gate 	if (status != 0) {
1357c478bd9Sstevel@tonic-gate 		/*
1367c478bd9Sstevel@tonic-gate 		 * Could not load module, cleanup previous
1377c478bd9Sstevel@tonic-gate 		 * initialization work.
1387c478bd9Sstevel@tonic-gate 		 */
1397c478bd9Sstevel@tonic-gate 		nfs_srvfini();
14041bec5e3SMarcel Telka 
14141bec5e3SMarcel Telka 		return (status);
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
144cee86682Scalum 	/*
145cee86682Scalum 	 * Initialise some placeholders for nfssys() calls. These have
146cee86682Scalum 	 * to be declared by the nfs module, since that handles nfssys()
147cee86682Scalum 	 * calls - also used by NFS clients - but are provided by this
148cee86682Scalum 	 * nfssrv module. These also then serve as confirmation to the
149cee86682Scalum 	 * relevant code in nfs that nfssrv has been loaded, as they're
150cee86682Scalum 	 * initially NULL.
151cee86682Scalum 	 */
1527c478bd9Sstevel@tonic-gate 	nfs_srv_quiesce_func = nfs_srv_quiesce_all;
153cee86682Scalum 	nfs_srv_dss_func = rfs4_dss_setpaths;
154cee86682Scalum 
155cee86682Scalum 	/* setup DSS paths here; must be done before initial server startup */
156cee86682Scalum 	rfs4_dss_paths = rfs4_dss_oldpaths = NULL;
1577c478bd9Sstevel@tonic-gate 
158c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	/* initialize the copy reduction caches */
159c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
160c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfs_xuio_cache = kmem_cache_create("nfs_xuio_cache",
161c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	    sizeof (nfs_xuio_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
162c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
1637c478bd9Sstevel@tonic-gate 	return (status);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate int
_fini()1677c478bd9Sstevel@tonic-gate _fini()
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate 	return (EBUSY);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1737c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate /*
1797c478bd9Sstevel@tonic-gate  * PUBLICFH_CHECK() checks if the dispatch routine supports
1807c478bd9Sstevel@tonic-gate  * RPC_PUBLICFH_OK, if the filesystem is exported public, and if the
1817c478bd9Sstevel@tonic-gate  * incoming request is using the public filehandle. The check duplicates
1827c478bd9Sstevel@tonic-gate  * the exportmatch() call done in checkexport(), and we should consider
1837c478bd9Sstevel@tonic-gate  * modifying those routines to avoid the duplication. For now, we optimize
1847c478bd9Sstevel@tonic-gate  * by calling exportmatch() only after checking that the dispatch routine
1857c478bd9Sstevel@tonic-gate  * supports RPC_PUBLICFH_OK, and if the filesystem is explicitly exported
1867c478bd9Sstevel@tonic-gate  * public (i.e., not the placeholder).
1877c478bd9Sstevel@tonic-gate  */
1880dfe541eSEvan Layton #define	PUBLICFH_CHECK(ne, disp, exi, fsid, xfid) \
1897c478bd9Sstevel@tonic-gate 		((disp->dis_flags & RPC_PUBLICFH_OK) && \
1907c478bd9Sstevel@tonic-gate 		((exi->exi_export.ex_flags & EX_PUBLIC) || \
1910dfe541eSEvan Layton 		(exi == ne->exi_public && exportmatch(ne->exi_root, \
19227242a7cSthurlow 		fsid, xfid))))
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate static void	nfs_srv_shutdown_all(int);
1950dfe541eSEvan Layton static void	rfs4_server_start(nfs_globals_t *, int);
1967c478bd9Sstevel@tonic-gate static void	nullfree(void);
1977c478bd9Sstevel@tonic-gate static void	rfs_dispatch(struct svc_req *, SVCXPRT *);
1987c478bd9Sstevel@tonic-gate static void	acl_dispatch(struct svc_req *, SVCXPRT *);
1997c478bd9Sstevel@tonic-gate static	int	checkauth(struct exportinfo *, struct svc_req *, cred_t *, int,
2005cb0d679SMarcel Telka 		bool_t, bool_t *);
2017c478bd9Sstevel@tonic-gate static char	*client_name(struct svc_req *req);
2027c478bd9Sstevel@tonic-gate static char	*client_addr(struct svc_req *req, char *buf);
2037c478bd9Sstevel@tonic-gate extern	bool_t	sec_svc_inrootlist(int, caddr_t, int, caddr_t *);
2040dfe541eSEvan Layton static void	*nfs_server_zone_init(zoneid_t);
2050dfe541eSEvan Layton static void	nfs_server_zone_fini(zoneid_t, void *);
2060dfe541eSEvan Layton static void	nfs_server_zone_shutdown(zoneid_t, void *);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate #define	NFSLOG_COPY_NETBUF(exi, xprt, nb)	{		\
2097c478bd9Sstevel@tonic-gate 	(nb)->maxlen = (xprt)->xp_rtaddr.maxlen;		\
2107c478bd9Sstevel@tonic-gate 	(nb)->len = (xprt)->xp_rtaddr.len;			\
2117c478bd9Sstevel@tonic-gate 	(nb)->buf = kmem_alloc((nb)->len, KM_SLEEP);		\
2127c478bd9Sstevel@tonic-gate 	bcopy((xprt)->xp_rtaddr.buf, (nb)->buf, (nb)->len);	\
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate  * Public Filehandle common nfs routines
2177c478bd9Sstevel@tonic-gate  */
2187c478bd9Sstevel@tonic-gate static int	MCLpath(char **);
2197c478bd9Sstevel@tonic-gate static void	URLparse(char *);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate /*
2227c478bd9Sstevel@tonic-gate  * NFS callout table.
2237c478bd9Sstevel@tonic-gate  * This table is used by svc_getreq() to dispatch a request with
2247c478bd9Sstevel@tonic-gate  * a given prog/vers pair to an appropriate service provider
2257c478bd9Sstevel@tonic-gate  * dispatch routine.
2267c478bd9Sstevel@tonic-gate  *
2277c478bd9Sstevel@tonic-gate  * NOTE: ordering is relied upon below when resetting the version min/max
2287c478bd9Sstevel@tonic-gate  * for NFS_PROGRAM.  Careful, if this is ever changed.
2297c478bd9Sstevel@tonic-gate  */
2307c478bd9Sstevel@tonic-gate static SVC_CALLOUT __nfs_sc_clts[] = {
2317c478bd9Sstevel@tonic-gate 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
2327c478bd9Sstevel@tonic-gate 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
2337c478bd9Sstevel@tonic-gate };
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate static SVC_CALLOUT_TABLE nfs_sct_clts = {
2367c478bd9Sstevel@tonic-gate 	sizeof (__nfs_sc_clts) / sizeof (__nfs_sc_clts[0]), FALSE,
2377c478bd9Sstevel@tonic-gate 	__nfs_sc_clts
2387c478bd9Sstevel@tonic-gate };
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate static SVC_CALLOUT __nfs_sc_cots[] = {
2417c478bd9Sstevel@tonic-gate 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
2427c478bd9Sstevel@tonic-gate 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
2437c478bd9Sstevel@tonic-gate };
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate static SVC_CALLOUT_TABLE nfs_sct_cots = {
2467c478bd9Sstevel@tonic-gate 	sizeof (__nfs_sc_cots) / sizeof (__nfs_sc_cots[0]), FALSE, __nfs_sc_cots
2477c478bd9Sstevel@tonic-gate };
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate static SVC_CALLOUT __nfs_sc_rdma[] = {
2507c478bd9Sstevel@tonic-gate 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
2517c478bd9Sstevel@tonic-gate 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
2527c478bd9Sstevel@tonic-gate };
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate static SVC_CALLOUT_TABLE nfs_sct_rdma = {
2557c478bd9Sstevel@tonic-gate 	sizeof (__nfs_sc_rdma) / sizeof (__nfs_sc_rdma[0]), FALSE, __nfs_sc_rdma
2567c478bd9Sstevel@tonic-gate };
2577c478bd9Sstevel@tonic-gate 
258cee86682Scalum /*
259cee86682Scalum  * DSS: distributed stable storage
260cee86682Scalum  * lists of all DSS paths: current, and before last warmstart
261cee86682Scalum  */
262cee86682Scalum nvlist_t *rfs4_dss_paths, *rfs4_dss_oldpaths;
263cee86682Scalum 
2647d12f3bcSmaheshvs bool_t rfs4_minorvers_mismatch(struct svc_req *, SVCXPRT *, void *);
265d9ad96c1Srg 
2667c478bd9Sstevel@tonic-gate /*
2670dfe541eSEvan Layton  * Stash NFS zone globals in TSD to avoid some lock contention
2680dfe541eSEvan Layton  * from frequent zone_getspecific calls.
2697c478bd9Sstevel@tonic-gate  */
2700dfe541eSEvan Layton static uint_t nfs_server_tsd_key;
2710dfe541eSEvan Layton 
2720dfe541eSEvan Layton nfs_globals_t *
nfs_srv_getzg(void)2730dfe541eSEvan Layton nfs_srv_getzg(void)
2740dfe541eSEvan Layton {
2750dfe541eSEvan Layton 	nfs_globals_t *ng;
2760dfe541eSEvan Layton 
2770dfe541eSEvan Layton 	ng = tsd_get(nfs_server_tsd_key);
2780dfe541eSEvan Layton 	if (ng == NULL) {
2790dfe541eSEvan Layton 		ng = zone_getspecific(nfssrv_zone_key, curzone);
2800dfe541eSEvan Layton 		(void) tsd_set(nfs_server_tsd_key, ng);
2810dfe541eSEvan Layton 	}
2820dfe541eSEvan Layton 
2830dfe541eSEvan Layton 	return (ng);
2840dfe541eSEvan Layton }
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate  * Will be called at the point the server pool is being unregistered
2887c478bd9Sstevel@tonic-gate  * from the pool list. From that point onwards, the pool is waiting
2897c478bd9Sstevel@tonic-gate  * to be drained and as such the server state is stale and pertains
2907c478bd9Sstevel@tonic-gate  * to the old instantiation of the NFS server pool.
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate void
nfs_srv_offline(void)2937c478bd9Sstevel@tonic-gate nfs_srv_offline(void)
2947c478bd9Sstevel@tonic-gate {
2950dfe541eSEvan Layton 	nfs_globals_t *ng;
2960dfe541eSEvan Layton 
2970dfe541eSEvan Layton 	ng = nfs_srv_getzg();
2980dfe541eSEvan Layton 
2990dfe541eSEvan Layton 	mutex_enter(&ng->nfs_server_upordown_lock);
3000dfe541eSEvan Layton 	if (ng->nfs_server_upordown == NFS_SERVER_RUNNING) {
3010dfe541eSEvan Layton 		ng->nfs_server_upordown = NFS_SERVER_OFFLINE;
3027c478bd9Sstevel@tonic-gate 	}
3030dfe541eSEvan Layton 	mutex_exit(&ng->nfs_server_upordown_lock);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate  * Will be called at the point the server pool is being destroyed so
3087c478bd9Sstevel@tonic-gate  * all transports have been closed and no service threads are in
3097c478bd9Sstevel@tonic-gate  * existence.
3107c478bd9Sstevel@tonic-gate  *
3117c478bd9Sstevel@tonic-gate  * If we quiesce the server, we're shutting it down without destroying the
3127c478bd9Sstevel@tonic-gate  * server state. This allows it to warm start subsequently.
3137c478bd9Sstevel@tonic-gate  */
3147c478bd9Sstevel@tonic-gate void
nfs_srv_stop_all(void)3157c478bd9Sstevel@tonic-gate nfs_srv_stop_all(void)
3167c478bd9Sstevel@tonic-gate {
3177c478bd9Sstevel@tonic-gate 	int quiesce = 0;
3187c478bd9Sstevel@tonic-gate 	nfs_srv_shutdown_all(quiesce);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  * This alternative shutdown routine can be requested via nfssys()
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate void
nfs_srv_quiesce_all(void)3257c478bd9Sstevel@tonic-gate nfs_srv_quiesce_all(void)
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate 	int quiesce = 1;
3287c478bd9Sstevel@tonic-gate 	nfs_srv_shutdown_all(quiesce);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate static void
nfs_srv_shutdown_all(int quiesce)3320dfe541eSEvan Layton nfs_srv_shutdown_all(int quiesce)
3330dfe541eSEvan Layton {
3340dfe541eSEvan Layton 	nfs_globals_t *ng = nfs_srv_getzg();
3350dfe541eSEvan Layton 
3360dfe541eSEvan Layton 	mutex_enter(&ng->nfs_server_upordown_lock);
3377c478bd9Sstevel@tonic-gate 	if (quiesce) {
3380dfe541eSEvan Layton 		if (ng->nfs_server_upordown == NFS_SERVER_RUNNING ||
3390dfe541eSEvan Layton 		    ng->nfs_server_upordown == NFS_SERVER_OFFLINE) {
3400dfe541eSEvan Layton 			ng->nfs_server_upordown = NFS_SERVER_QUIESCED;
3410dfe541eSEvan Layton 			cv_signal(&ng->nfs_server_upordown_cv);
342cee86682Scalum 
3430dfe541eSEvan Layton 			/* reset DSS state */
344cee86682Scalum 			rfs4_dss_numnewpaths = 0;
345cee86682Scalum 			rfs4_dss_newpaths = NULL;
346cee86682Scalum 
3477c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "nfs_server: server is now quiesced; "
3487c478bd9Sstevel@tonic-gate 			    "NFSv4 state has been preserved");
3497c478bd9Sstevel@tonic-gate 		}
3507c478bd9Sstevel@tonic-gate 	} else {
3510dfe541eSEvan Layton 		if (ng->nfs_server_upordown == NFS_SERVER_OFFLINE) {
3520dfe541eSEvan Layton 			ng->nfs_server_upordown = NFS_SERVER_STOPPING;
3530dfe541eSEvan Layton 			mutex_exit(&ng->nfs_server_upordown_lock);
3540dfe541eSEvan Layton 			rfs4_state_zone_fini();
3550dfe541eSEvan Layton 			rfs4_fini_drc();
3560dfe541eSEvan Layton 			mutex_enter(&ng->nfs_server_upordown_lock);
3570dfe541eSEvan Layton 			ng->nfs_server_upordown = NFS_SERVER_STOPPED;
3580dfe541eSEvan Layton 
3590dfe541eSEvan Layton 			/* reset DSS state */
3600dfe541eSEvan Layton 			rfs4_dss_numnewpaths = 0;
3610dfe541eSEvan Layton 			rfs4_dss_newpaths = NULL;
3620dfe541eSEvan Layton 
3630dfe541eSEvan Layton 			cv_signal(&ng->nfs_server_upordown_cv);
3647c478bd9Sstevel@tonic-gate 		}
3657c478bd9Sstevel@tonic-gate 	}
3660dfe541eSEvan Layton 	mutex_exit(&ng->nfs_server_upordown_lock);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate static int
nfs_srv_set_sc_versions(struct file * fp,SVC_CALLOUT_TABLE ** sctpp,rpcvers_t versmin,rpcvers_t versmax)3707c478bd9Sstevel@tonic-gate nfs_srv_set_sc_versions(struct file *fp, SVC_CALLOUT_TABLE **sctpp,
3710dfe541eSEvan Layton     rpcvers_t versmin, rpcvers_t versmax)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	struct strioctl strioc;
3747c478bd9Sstevel@tonic-gate 	struct T_info_ack tinfo;
3757c478bd9Sstevel@tonic-gate 	int		error, retval;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	/*
3787c478bd9Sstevel@tonic-gate 	 * Find out what type of transport this is.
3797c478bd9Sstevel@tonic-gate 	 */
3807c478bd9Sstevel@tonic-gate 	strioc.ic_cmd = TI_GETINFO;
3817c478bd9Sstevel@tonic-gate 	strioc.ic_timout = -1;
3827c478bd9Sstevel@tonic-gate 	strioc.ic_len = sizeof (tinfo);
3837c478bd9Sstevel@tonic-gate 	strioc.ic_dp = (char *)&tinfo;
3847c478bd9Sstevel@tonic-gate 	tinfo.PRIM_type = T_INFO_REQ;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	error = strioctl(fp->f_vnode, I_STR, (intptr_t)&strioc, 0, K_TO_K,
3877c478bd9Sstevel@tonic-gate 	    CRED(), &retval);
3887c478bd9Sstevel@tonic-gate 	if (error || retval)
3897c478bd9Sstevel@tonic-gate 		return (error);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/*
3927c478bd9Sstevel@tonic-gate 	 * Based on our query of the transport type...
3937c478bd9Sstevel@tonic-gate 	 *
3947c478bd9Sstevel@tonic-gate 	 * Reset the min/max versions based on the caller's request
3957c478bd9Sstevel@tonic-gate 	 * NOTE: This assumes that NFS_PROGRAM is first in the array!!
3967c478bd9Sstevel@tonic-gate 	 * And the second entry is the NFS_ACL_PROGRAM.
3977c478bd9Sstevel@tonic-gate 	 */
3987c478bd9Sstevel@tonic-gate 	switch (tinfo.SERV_type) {
3997c478bd9Sstevel@tonic-gate 	case T_CLTS:
4007c478bd9Sstevel@tonic-gate 		if (versmax == NFS_V4)
4017c478bd9Sstevel@tonic-gate 			return (EINVAL);
4027c478bd9Sstevel@tonic-gate 		__nfs_sc_clts[0].sc_versmin = versmin;
4037c478bd9Sstevel@tonic-gate 		__nfs_sc_clts[0].sc_versmax = versmax;
4047c478bd9Sstevel@tonic-gate 		__nfs_sc_clts[1].sc_versmin = versmin;
4057c478bd9Sstevel@tonic-gate 		__nfs_sc_clts[1].sc_versmax = versmax;
4067c478bd9Sstevel@tonic-gate 		*sctpp = &nfs_sct_clts;
4077c478bd9Sstevel@tonic-gate 		break;
4087c478bd9Sstevel@tonic-gate 	case T_COTS:
4097c478bd9Sstevel@tonic-gate 	case T_COTS_ORD:
4107c478bd9Sstevel@tonic-gate 		__nfs_sc_cots[0].sc_versmin = versmin;
4117c478bd9Sstevel@tonic-gate 		__nfs_sc_cots[0].sc_versmax = versmax;
4127c478bd9Sstevel@tonic-gate 		/* For the NFS_ACL program, check the max version */
4137c478bd9Sstevel@tonic-gate 		if (versmax > NFS_ACL_VERSMAX)
4147c478bd9Sstevel@tonic-gate 			versmax = NFS_ACL_VERSMAX;
4157c478bd9Sstevel@tonic-gate 		__nfs_sc_cots[1].sc_versmin = versmin;
4167c478bd9Sstevel@tonic-gate 		__nfs_sc_cots[1].sc_versmax = versmax;
4177c478bd9Sstevel@tonic-gate 		*sctpp = &nfs_sct_cots;
4187c478bd9Sstevel@tonic-gate 		break;
4197c478bd9Sstevel@tonic-gate 	default:
4207c478bd9Sstevel@tonic-gate 		error = EINVAL;
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	return (error);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate  * NFS Server system call.
4287c478bd9Sstevel@tonic-gate  * Does all of the work of running a NFS server.
4297c478bd9Sstevel@tonic-gate  * uap->fd is the fd of an open transport provider
4307c478bd9Sstevel@tonic-gate  */
4317c478bd9Sstevel@tonic-gate int
nfs_svc(struct nfs_svc_args * arg,model_t model)4327c478bd9Sstevel@tonic-gate nfs_svc(struct nfs_svc_args *arg, model_t model)
4337c478bd9Sstevel@tonic-gate {
4340dfe541eSEvan Layton 	nfs_globals_t *ng;
4357c478bd9Sstevel@tonic-gate 	file_t *fp;
4367c478bd9Sstevel@tonic-gate 	SVCMASTERXPRT *xprt;
4377c478bd9Sstevel@tonic-gate 	int error;
4387c478bd9Sstevel@tonic-gate 	int readsize;
4397c478bd9Sstevel@tonic-gate 	char buf[KNC_STRSIZE];
4407c478bd9Sstevel@tonic-gate 	size_t len;
4417c478bd9Sstevel@tonic-gate 	STRUCT_HANDLE(nfs_svc_args, uap);
4427c478bd9Sstevel@tonic-gate 	struct netbuf addrmask;
4437c478bd9Sstevel@tonic-gate 	SVC_CALLOUT_TABLE *sctp = NULL;
4447c478bd9Sstevel@tonic-gate 
4450dfe541eSEvan Layton 	ng = nfs_srv_getzg();
4467c478bd9Sstevel@tonic-gate 	STRUCT_SET_HANDLE(uap, model, arg);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	/* Check privileges in nfssys() */
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	if ((fp = getf(STRUCT_FGET(uap, fd))) == NULL)
4517c478bd9Sstevel@tonic-gate 		return (EBADF);
4527c478bd9Sstevel@tonic-gate 
4530dfe541eSEvan Layton 	/* Setup global file handle in nfs_export */
4540dfe541eSEvan Layton 	if ((error = nfs_export_get_rootfh(ng)) != 0)
4550dfe541eSEvan Layton 		return (error);
4560dfe541eSEvan Layton 
4577c478bd9Sstevel@tonic-gate 	/*
4587c478bd9Sstevel@tonic-gate 	 * Set read buffer size to rsize
4597c478bd9Sstevel@tonic-gate 	 * and add room for RPC headers.
4607c478bd9Sstevel@tonic-gate 	 */
4617c478bd9Sstevel@tonic-gate 	readsize = nfs3tsize() + (RPC_MAXDATASIZE - NFS_MAXDATA);
4627c478bd9Sstevel@tonic-gate 	if (readsize < RPC_MAXDATASIZE)
4637c478bd9Sstevel@tonic-gate 		readsize = RPC_MAXDATASIZE;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	error = copyinstr((const char *)STRUCT_FGETP(uap, netid), buf,
4667c478bd9Sstevel@tonic-gate 	    KNC_STRSIZE, &len);
4677c478bd9Sstevel@tonic-gate 	if (error) {
4687c478bd9Sstevel@tonic-gate 		releasef(STRUCT_FGET(uap, fd));
4697c478bd9Sstevel@tonic-gate 		return (error);
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	addrmask.len = STRUCT_FGET(uap, addrmask.len);
4737c478bd9Sstevel@tonic-gate 	addrmask.maxlen = STRUCT_FGET(uap, addrmask.maxlen);
4747c478bd9Sstevel@tonic-gate 	addrmask.buf = kmem_alloc(addrmask.maxlen, KM_SLEEP);
4757c478bd9Sstevel@tonic-gate 	error = copyin(STRUCT_FGETP(uap, addrmask.buf), addrmask.buf,
4767c478bd9Sstevel@tonic-gate 	    addrmask.len);
4777c478bd9Sstevel@tonic-gate 	if (error) {
4787c478bd9Sstevel@tonic-gate 		releasef(STRUCT_FGET(uap, fd));
4797c478bd9Sstevel@tonic-gate 		kmem_free(addrmask.buf, addrmask.maxlen);
4807c478bd9Sstevel@tonic-gate 		return (error);
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 
483*f44e1126SVitaliy Gusev 	ng->nfs_versmin = STRUCT_FGET(uap, nfs_versmin);
484*f44e1126SVitaliy Gusev 	ng->nfs_versmax = STRUCT_FGET(uap, nfs_versmax);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	/* Double check the vers min/max ranges */
4870dfe541eSEvan Layton 	if ((ng->nfs_versmin > ng->nfs_versmax) ||
488*f44e1126SVitaliy Gusev 	    (ng->nfs_versmin < NFS_SRV_VERS_MIN) ||
489*f44e1126SVitaliy Gusev 	    (ng->nfs_versmax > NFS_SRV_VERS_MAX)) {
490*f44e1126SVitaliy Gusev 		cmn_err(CE_NOTE, "%s: bad min (%u) or max (%u) version number",
491*f44e1126SVitaliy Gusev 		    "NFS", ng->nfs_versmin, ng->nfs_versmax);
492*f44e1126SVitaliy Gusev 		ng->nfs_versmin = NFS_SRV_VERSMIN_DEFAULT;
493*f44e1126SVitaliy Gusev 		ng->nfs_versmax = NFS_SRV_VERSMAX_DEFAULT;
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 
496*f44e1126SVitaliy Gusev 	error = nfs_srv_set_sc_versions(fp, &sctp,
497*f44e1126SVitaliy Gusev 	    NFS_PROT_VERSION(ng->nfs_versmin),
498*f44e1126SVitaliy Gusev 	    NFS_PROT_VERSION(ng->nfs_versmax));
499bd3561fbSToomas Soome 	if (error != 0) {
5007c478bd9Sstevel@tonic-gate 		releasef(STRUCT_FGET(uap, fd));
5017c478bd9Sstevel@tonic-gate 		kmem_free(addrmask.buf, addrmask.maxlen);
5027c478bd9Sstevel@tonic-gate 		return (error);
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	/* Initialize nfsv4 server */
506*f44e1126SVitaliy Gusev 	if (NFS_PROT_VERSION(ng->nfs_versmax) == NFS_V4)
5070dfe541eSEvan Layton 		rfs4_server_start(ng, STRUCT_FGET(uap, delegation));
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/* Create a transport handle. */
5107c478bd9Sstevel@tonic-gate 	error = svc_tli_kcreate(fp, readsize, buf, &addrmask, &xprt,
511b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    sctp, NULL, NFS_SVCPOOL_ID, TRUE);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (error)
5147c478bd9Sstevel@tonic-gate 		kmem_free(addrmask.buf, addrmask.maxlen);
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	releasef(STRUCT_FGET(uap, fd));
5177c478bd9Sstevel@tonic-gate 
518cee86682Scalum 	/* HA-NFSv4: save the cluster nodeid */
5197c478bd9Sstevel@tonic-gate 	if (cluster_bootflags & CLUSTER_BOOTED)
5207c478bd9Sstevel@tonic-gate 		lm_global_nlmid = clconf_get_nodeid();
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	return (error);
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate static void
rfs4_server_start(nfs_globals_t * ng,int nfs4_srv_delegation)5260dfe541eSEvan Layton rfs4_server_start(nfs_globals_t *ng, int nfs4_srv_delegation)
5277c478bd9Sstevel@tonic-gate {
528*f44e1126SVitaliy Gusev 	nfs4_minor_t nfs4_minor_max;
529*f44e1126SVitaliy Gusev 
530*f44e1126SVitaliy Gusev 	nfs4_minor_max = NFS_PROT_V4_MINORVERSION(ng->nfs_versmax);
531*f44e1126SVitaliy Gusev 
5327c478bd9Sstevel@tonic-gate 	/*
5337c478bd9Sstevel@tonic-gate 	 * Determine if the server has previously been "started" and
5347c478bd9Sstevel@tonic-gate 	 * if not, do the per instance initialization
5357c478bd9Sstevel@tonic-gate 	 */
5360dfe541eSEvan Layton 	mutex_enter(&ng->nfs_server_upordown_lock);
5377c478bd9Sstevel@tonic-gate 
5380dfe541eSEvan Layton 	if (ng->nfs_server_upordown != NFS_SERVER_RUNNING) {
5397c478bd9Sstevel@tonic-gate 		/* Do we need to stop and wait on the previous server? */
5400dfe541eSEvan Layton 		while (ng->nfs_server_upordown == NFS_SERVER_STOPPING ||
5410dfe541eSEvan Layton 		    ng->nfs_server_upordown == NFS_SERVER_OFFLINE)
5420dfe541eSEvan Layton 			cv_wait(&ng->nfs_server_upordown_cv,
5430dfe541eSEvan Layton 			    &ng->nfs_server_upordown_lock);
5447c478bd9Sstevel@tonic-gate 
5450dfe541eSEvan Layton 		if (ng->nfs_server_upordown != NFS_SERVER_RUNNING) {
5467c478bd9Sstevel@tonic-gate 			(void) svc_pool_control(NFS_SVCPOOL_ID,
5477c478bd9Sstevel@tonic-gate 			    SVCPSET_UNREGISTER_PROC, (void *)&nfs_srv_offline);
5487c478bd9Sstevel@tonic-gate 			(void) svc_pool_control(NFS_SVCPOOL_ID,
5497c478bd9Sstevel@tonic-gate 			    SVCPSET_SHUTDOWN_PROC, (void *)&nfs_srv_stop_all);
5507c478bd9Sstevel@tonic-gate 
5510dfe541eSEvan Layton 			rfs4_do_server_start(ng->nfs_server_upordown,
552*f44e1126SVitaliy Gusev 			    nfs4_srv_delegation, nfs4_minor_max,
5530dfe541eSEvan Layton 			    cluster_bootflags & CLUSTER_BOOTED);
5547c478bd9Sstevel@tonic-gate 
5550dfe541eSEvan Layton 			ng->nfs_server_upordown = NFS_SERVER_RUNNING;
5567c478bd9Sstevel@tonic-gate 		}
5570dfe541eSEvan Layton 		cv_signal(&ng->nfs_server_upordown_cv);
5587c478bd9Sstevel@tonic-gate 	}
5590dfe541eSEvan Layton 	mutex_exit(&ng->nfs_server_upordown_lock);
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate  * If RDMA device available,
5647c478bd9Sstevel@tonic-gate  * start RDMA listener.
5657c478bd9Sstevel@tonic-gate  */
5667c478bd9Sstevel@tonic-gate int
rdma_start(struct rdma_svc_args * rsa)5677c478bd9Sstevel@tonic-gate rdma_start(struct rdma_svc_args *rsa)
5687c478bd9Sstevel@tonic-gate {
5690dfe541eSEvan Layton 	nfs_globals_t *ng;
5707c478bd9Sstevel@tonic-gate 	int error;
5717c478bd9Sstevel@tonic-gate 	rdma_xprt_group_t started_rdma_xprts;
57251f34d4bSRajkumar Sivaprakasam 	rdma_stat stat;
57351f34d4bSRajkumar Sivaprakasam 	int svc_state = 0;
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	/* Double check the vers min/max ranges */
5767c478bd9Sstevel@tonic-gate 	if ((rsa->nfs_versmin > rsa->nfs_versmax) ||
577*f44e1126SVitaliy Gusev 	    (rsa->nfs_versmin < NFS_SRV_VERS_MIN) ||
578*f44e1126SVitaliy Gusev 	    (rsa->nfs_versmax > NFS_SRV_VERS_MAX)) {
579*f44e1126SVitaliy Gusev 		rsa->nfs_versmin = NFS_SRV_VERSMIN_DEFAULT;
580*f44e1126SVitaliy Gusev 		rsa->nfs_versmax = NFS_SRV_VERSMAX_DEFAULT;
5817c478bd9Sstevel@tonic-gate 	}
5820dfe541eSEvan Layton 
5830dfe541eSEvan Layton 	ng = nfs_srv_getzg();
5840dfe541eSEvan Layton 	ng->nfs_versmin = rsa->nfs_versmin;
5850dfe541eSEvan Layton 	ng->nfs_versmax = rsa->nfs_versmax;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	/* Set the versions in the callout table */
588*f44e1126SVitaliy Gusev 	__nfs_sc_rdma[0].sc_versmin = NFS_PROT_VERSION(rsa->nfs_versmin);
589*f44e1126SVitaliy Gusev 	__nfs_sc_rdma[0].sc_versmax = NFS_PROT_VERSION(rsa->nfs_versmax);
5907c478bd9Sstevel@tonic-gate 	/* For the NFS_ACL program, check the max version */
591*f44e1126SVitaliy Gusev 	__nfs_sc_rdma[1].sc_versmin = NFS_PROT_VERSION(rsa->nfs_versmin);
592*f44e1126SVitaliy Gusev 	__nfs_sc_rdma[1].sc_versmax =
593*f44e1126SVitaliy Gusev 	    MIN(NFS_PROT_VERSION(rsa->nfs_versmax), NFS_ACL_VERSMAX);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	/* Initialize nfsv4 server */
596*f44e1126SVitaliy Gusev 	if (NFS_PROT_VERSION(rsa->nfs_versmax) == NFS_V4)
5970dfe541eSEvan Layton 		rfs4_server_start(ng, rsa->delegation);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	started_rdma_xprts.rtg_count = 0;
6007c478bd9Sstevel@tonic-gate 	started_rdma_xprts.rtg_listhead = NULL;
6017c478bd9Sstevel@tonic-gate 	started_rdma_xprts.rtg_poolid = rsa->poolid;
60251f34d4bSRajkumar Sivaprakasam 
60351f34d4bSRajkumar Sivaprakasam restart:
6047c478bd9Sstevel@tonic-gate 	error = svc_rdma_kcreate(rsa->netid, &nfs_sct_rdma, rsa->poolid,
6057c478bd9Sstevel@tonic-gate 	    &started_rdma_xprts);
6067c478bd9Sstevel@tonic-gate 
60751f34d4bSRajkumar Sivaprakasam 	svc_state = !error;
60851f34d4bSRajkumar Sivaprakasam 
60951f34d4bSRajkumar Sivaprakasam 	while (!error) {
61051f34d4bSRajkumar Sivaprakasam 
61151f34d4bSRajkumar Sivaprakasam 		/*
61251f34d4bSRajkumar Sivaprakasam 		 * wait till either interrupted by a signal on
61351f34d4bSRajkumar Sivaprakasam 		 * nfs service stop/restart or signalled by a
6140dfe541eSEvan Layton 		 * rdma attach/detatch.
61551f34d4bSRajkumar Sivaprakasam 		 */
61651f34d4bSRajkumar Sivaprakasam 
61751f34d4bSRajkumar Sivaprakasam 		stat = rdma_kwait();
61851f34d4bSRajkumar Sivaprakasam 
61951f34d4bSRajkumar Sivaprakasam 		/*
62051f34d4bSRajkumar Sivaprakasam 		 * stop services if running -- either on a HCA detach event
62151f34d4bSRajkumar Sivaprakasam 		 * or if the nfs service is stopped/restarted.
62251f34d4bSRajkumar Sivaprakasam 		 */
62351f34d4bSRajkumar Sivaprakasam 
62451f34d4bSRajkumar Sivaprakasam 		if ((stat == RDMA_HCA_DETACH || stat == RDMA_INTR) &&
62551f34d4bSRajkumar Sivaprakasam 		    svc_state) {
62651f34d4bSRajkumar Sivaprakasam 			rdma_stop(&started_rdma_xprts);
62751f34d4bSRajkumar Sivaprakasam 			svc_state = 0;
6287c478bd9Sstevel@tonic-gate 		}
62951f34d4bSRajkumar Sivaprakasam 
63051f34d4bSRajkumar Sivaprakasam 		/*
63151f34d4bSRajkumar Sivaprakasam 		 * nfs service stop/restart, break out of the
63251f34d4bSRajkumar Sivaprakasam 		 * wait loop and return;
63351f34d4bSRajkumar Sivaprakasam 		 */
63451f34d4bSRajkumar Sivaprakasam 		if (stat == RDMA_INTR)
63551f34d4bSRajkumar Sivaprakasam 			return (0);
63651f34d4bSRajkumar Sivaprakasam 
63751f34d4bSRajkumar Sivaprakasam 		/*
63851f34d4bSRajkumar Sivaprakasam 		 * restart stopped services on a HCA attach event
63951f34d4bSRajkumar Sivaprakasam 		 * (if not already running)
64051f34d4bSRajkumar Sivaprakasam 		 */
64151f34d4bSRajkumar Sivaprakasam 
64251f34d4bSRajkumar Sivaprakasam 		if ((stat == RDMA_HCA_ATTACH) && (svc_state == 0))
64351f34d4bSRajkumar Sivaprakasam 			goto restart;
64451f34d4bSRajkumar Sivaprakasam 
64551f34d4bSRajkumar Sivaprakasam 		/*
64651f34d4bSRajkumar Sivaprakasam 		 * loop until a nfs service stop/restart
64751f34d4bSRajkumar Sivaprakasam 		 */
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	return (error);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate /* ARGSUSED */
654d9ad96c1Srg void
rpc_null(caddr_t * argp,caddr_t * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)6555cb0d679SMarcel Telka rpc_null(caddr_t *argp, caddr_t *resp, struct exportinfo *exi,
6565cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
6577c478bd9Sstevel@tonic-gate {
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate 
660e1adf50cSahl /* ARGSUSED */
661e1adf50cSahl void
rpc_null_v3(caddr_t * argp,caddr_t * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)662e1adf50cSahl rpc_null_v3(caddr_t *argp, caddr_t *resp, struct exportinfo *exi,
6635cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
664e1adf50cSahl {
6650dfe541eSEvan Layton 	DTRACE_NFSV3_4(op__null__start, struct svc_req *, req,
6660dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi);
6670dfe541eSEvan Layton 	DTRACE_NFSV3_4(op__null__done, struct svc_req *, req,
6680dfe541eSEvan Layton 	    cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi);
669e1adf50cSahl }
670e1adf50cSahl 
6717c478bd9Sstevel@tonic-gate /* ARGSUSED */
6727c478bd9Sstevel@tonic-gate static void
rfs_error(caddr_t * argp,caddr_t * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr,bool_t ro)6735cb0d679SMarcel Telka rfs_error(caddr_t *argp, caddr_t *resp, struct exportinfo *exi,
6745cb0d679SMarcel Telka     struct svc_req *req, cred_t *cr, bool_t ro)
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 	/* return (EOPNOTSUPP); */
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate static void
nullfree(void)6807c478bd9Sstevel@tonic-gate nullfree(void)
6817c478bd9Sstevel@tonic-gate {
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate static char *rfscallnames_v2[] = {
6857c478bd9Sstevel@tonic-gate 	"RFS2_NULL",
6867c478bd9Sstevel@tonic-gate 	"RFS2_GETATTR",
6877c478bd9Sstevel@tonic-gate 	"RFS2_SETATTR",
6887c478bd9Sstevel@tonic-gate 	"RFS2_ROOT",
6897c478bd9Sstevel@tonic-gate 	"RFS2_LOOKUP",
6907c478bd9Sstevel@tonic-gate 	"RFS2_READLINK",
6917c478bd9Sstevel@tonic-gate 	"RFS2_READ",
6927c478bd9Sstevel@tonic-gate 	"RFS2_WRITECACHE",
6937c478bd9Sstevel@tonic-gate 	"RFS2_WRITE",
6947c478bd9Sstevel@tonic-gate 	"RFS2_CREATE",
6957c478bd9Sstevel@tonic-gate 	"RFS2_REMOVE",
6967c478bd9Sstevel@tonic-gate 	"RFS2_RENAME",
6977c478bd9Sstevel@tonic-gate 	"RFS2_LINK",
6987c478bd9Sstevel@tonic-gate 	"RFS2_SYMLINK",
6997c478bd9Sstevel@tonic-gate 	"RFS2_MKDIR",
7007c478bd9Sstevel@tonic-gate 	"RFS2_RMDIR",
7017c478bd9Sstevel@tonic-gate 	"RFS2_READDIR",
7027c478bd9Sstevel@tonic-gate 	"RFS2_STATFS"
7037c478bd9Sstevel@tonic-gate };
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate static struct rpcdisp rfsdisptab_v2[] = {
7067c478bd9Sstevel@tonic-gate 	/*
7077c478bd9Sstevel@tonic-gate 	 * NFS VERSION 2
7087c478bd9Sstevel@tonic-gate 	 */
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
7117c478bd9Sstevel@tonic-gate 	{rpc_null,
7127c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7137c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7147c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
715d9ad96c1Srg 	    0},
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	/* RFS_GETATTR = 1 */
7187c478bd9Sstevel@tonic-gate 	{rfs_getattr,
7197c478bd9Sstevel@tonic-gate 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
7207c478bd9Sstevel@tonic-gate 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
7217c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
722d9ad96c1Srg 	    rfs_getattr_getfh},
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	/* RFS_SETATTR = 2 */
7257c478bd9Sstevel@tonic-gate 	{rfs_setattr,
7267c478bd9Sstevel@tonic-gate 	    xdr_saargs, NULL_xdrproc_t, sizeof (struct nfssaargs),
7277c478bd9Sstevel@tonic-gate 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
7287c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
729d9ad96c1Srg 	    rfs_setattr_getfh},
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
7327c478bd9Sstevel@tonic-gate 	{rfs_error,
7337c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7347c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7357c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
736d9ad96c1Srg 	    0},
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	/* RFS_LOOKUP = 4 */
7397c478bd9Sstevel@tonic-gate 	{rfs_lookup,
7407c478bd9Sstevel@tonic-gate 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
7417c478bd9Sstevel@tonic-gate 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
7427c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_MAPRESP|RPC_PUBLICFH_OK,
743d9ad96c1Srg 	    rfs_lookup_getfh},
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	/* RFS_READLINK = 5 */
7467c478bd9Sstevel@tonic-gate 	{rfs_readlink,
7477c478bd9Sstevel@tonic-gate 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
7487c478bd9Sstevel@tonic-gate 	    xdr_rdlnres, NULL_xdrproc_t, sizeof (struct nfsrdlnres),
7497c478bd9Sstevel@tonic-gate 	    rfs_rlfree, RPC_IDEMPOTENT,
750d9ad96c1Srg 	    rfs_readlink_getfh},
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	/* RFS_READ = 6 */
7537c478bd9Sstevel@tonic-gate 	{rfs_read,
7547c478bd9Sstevel@tonic-gate 	    xdr_readargs, NULL_xdrproc_t, sizeof (struct nfsreadargs),
7557c478bd9Sstevel@tonic-gate 	    xdr_rdresult, NULL_xdrproc_t, sizeof (struct nfsrdresult),
7567c478bd9Sstevel@tonic-gate 	    rfs_rdfree, RPC_IDEMPOTENT,
757d9ad96c1Srg 	    rfs_read_getfh},
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
7607c478bd9Sstevel@tonic-gate 	{rfs_error,
7617c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7627c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
7637c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
764d9ad96c1Srg 	    0},
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	/* RFS_WRITE = 8 */
7677c478bd9Sstevel@tonic-gate 	{rfs_write,
7687c478bd9Sstevel@tonic-gate 	    xdr_writeargs, NULL_xdrproc_t, sizeof (struct nfswriteargs),
7697c478bd9Sstevel@tonic-gate 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
7707c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
771d9ad96c1Srg 	    rfs_write_getfh},
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	/* RFS_CREATE = 9 */
7747c478bd9Sstevel@tonic-gate 	{rfs_create,
7757c478bd9Sstevel@tonic-gate 	    xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
7767c478bd9Sstevel@tonic-gate 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
7777c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
778d9ad96c1Srg 	    rfs_create_getfh},
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	/* RFS_REMOVE = 10 */
7817c478bd9Sstevel@tonic-gate 	{rfs_remove,
7827c478bd9Sstevel@tonic-gate 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
7837c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
7847c478bd9Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
7857c478bd9Sstevel@tonic-gate #else
7867c478bd9Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
7877c478bd9Sstevel@tonic-gate #endif
7887c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
789d9ad96c1Srg 	    rfs_remove_getfh},
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	/* RFS_RENAME = 11 */
7927c478bd9Sstevel@tonic-gate 	{rfs_rename,
7937c478bd9Sstevel@tonic-gate 	    xdr_rnmargs, NULL_xdrproc_t, sizeof (struct nfsrnmargs),
7947c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
7957c478bd9Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
7967c478bd9Sstevel@tonic-gate #else
7977c478bd9Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
7987c478bd9Sstevel@tonic-gate #endif
7997c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
800d9ad96c1Srg 	    rfs_rename_getfh},
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	/* RFS_LINK = 12 */
8037c478bd9Sstevel@tonic-gate 	{rfs_link,
8047c478bd9Sstevel@tonic-gate 	    xdr_linkargs, NULL_xdrproc_t, sizeof (struct nfslinkargs),
8057c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
8067c478bd9Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
8077c478bd9Sstevel@tonic-gate #else
8087c478bd9Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
8097c478bd9Sstevel@tonic-gate #endif
8107c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
811d9ad96c1Srg 	    rfs_link_getfh},
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	/* RFS_SYMLINK = 13 */
8147c478bd9Sstevel@tonic-gate 	{rfs_symlink,
8157c478bd9Sstevel@tonic-gate 	    xdr_slargs, NULL_xdrproc_t, sizeof (struct nfsslargs),
8167c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
8177c478bd9Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
8187c478bd9Sstevel@tonic-gate #else
8197c478bd9Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
8207c478bd9Sstevel@tonic-gate #endif
8217c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
822d9ad96c1Srg 	    rfs_symlink_getfh},
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	/* RFS_MKDIR = 14 */
8257c478bd9Sstevel@tonic-gate 	{rfs_mkdir,
8267c478bd9Sstevel@tonic-gate 	    xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
8277c478bd9Sstevel@tonic-gate 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
8287c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
829d9ad96c1Srg 	    rfs_mkdir_getfh},
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	/* RFS_RMDIR = 15 */
8327c478bd9Sstevel@tonic-gate 	{rfs_rmdir,
8337c478bd9Sstevel@tonic-gate 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
8347c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
8357c478bd9Sstevel@tonic-gate 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
8367c478bd9Sstevel@tonic-gate #else
8377c478bd9Sstevel@tonic-gate 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
8387c478bd9Sstevel@tonic-gate #endif
8397c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
840d9ad96c1Srg 	    rfs_rmdir_getfh},
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	/* RFS_READDIR = 16 */
8437c478bd9Sstevel@tonic-gate 	{rfs_readdir,
8447c478bd9Sstevel@tonic-gate 	    xdr_rddirargs, NULL_xdrproc_t, sizeof (struct nfsrddirargs),
8457c478bd9Sstevel@tonic-gate 	    xdr_putrddirres, NULL_xdrproc_t, sizeof (struct nfsrddirres),
8467c478bd9Sstevel@tonic-gate 	    rfs_rddirfree, RPC_IDEMPOTENT,
847d9ad96c1Srg 	    rfs_readdir_getfh},
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	/* RFS_STATFS = 17 */
8507c478bd9Sstevel@tonic-gate 	{rfs_statfs,
8517c478bd9Sstevel@tonic-gate 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
8527c478bd9Sstevel@tonic-gate 	    xdr_statfs, xdr_faststatfs, sizeof (struct nfsstatfs),
8537c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
854d9ad96c1Srg 	    rfs_statfs_getfh},
8557c478bd9Sstevel@tonic-gate };
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate static char *rfscallnames_v3[] = {
8587c478bd9Sstevel@tonic-gate 	"RFS3_NULL",
8597c478bd9Sstevel@tonic-gate 	"RFS3_GETATTR",
8607c478bd9Sstevel@tonic-gate 	"RFS3_SETATTR",
8617c478bd9Sstevel@tonic-gate 	"RFS3_LOOKUP",
8627c478bd9Sstevel@tonic-gate 	"RFS3_ACCESS",
8637c478bd9Sstevel@tonic-gate 	"RFS3_READLINK",
8647c478bd9Sstevel@tonic-gate 	"RFS3_READ",
8657c478bd9Sstevel@tonic-gate 	"RFS3_WRITE",
8667c478bd9Sstevel@tonic-gate 	"RFS3_CREATE",
8677c478bd9Sstevel@tonic-gate 	"RFS3_MKDIR",
8687c478bd9Sstevel@tonic-gate 	"RFS3_SYMLINK",
8697c478bd9Sstevel@tonic-gate 	"RFS3_MKNOD",
8707c478bd9Sstevel@tonic-gate 	"RFS3_REMOVE",
8717c478bd9Sstevel@tonic-gate 	"RFS3_RMDIR",
8727c478bd9Sstevel@tonic-gate 	"RFS3_RENAME",
8737c478bd9Sstevel@tonic-gate 	"RFS3_LINK",
8747c478bd9Sstevel@tonic-gate 	"RFS3_READDIR",
8757c478bd9Sstevel@tonic-gate 	"RFS3_READDIRPLUS",
8767c478bd9Sstevel@tonic-gate 	"RFS3_FSSTAT",
8777c478bd9Sstevel@tonic-gate 	"RFS3_FSINFO",
8787c478bd9Sstevel@tonic-gate 	"RFS3_PATHCONF",
8797c478bd9Sstevel@tonic-gate 	"RFS3_COMMIT"
8807c478bd9Sstevel@tonic-gate };
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate static struct rpcdisp rfsdisptab_v3[] = {
8837c478bd9Sstevel@tonic-gate 	/*
8847c478bd9Sstevel@tonic-gate 	 * NFS VERSION 3
8857c478bd9Sstevel@tonic-gate 	 */
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
888e1adf50cSahl 	{rpc_null_v3,
8897c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
8907c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
8917c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
892d9ad96c1Srg 	    0},
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	/* RFS3_GETATTR = 1 */
8957c478bd9Sstevel@tonic-gate 	{rfs3_getattr,
89627242a7cSthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (GETATTR3args),
8977c478bd9Sstevel@tonic-gate 	    xdr_GETATTR3res, NULL_xdrproc_t, sizeof (GETATTR3res),
8987c478bd9Sstevel@tonic-gate 	    nullfree, (RPC_IDEMPOTENT | RPC_ALLOWANON),
899d9ad96c1Srg 	    rfs3_getattr_getfh},
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	/* RFS3_SETATTR = 2 */
9027c478bd9Sstevel@tonic-gate 	{rfs3_setattr,
9037c478bd9Sstevel@tonic-gate 	    xdr_SETATTR3args, NULL_xdrproc_t, sizeof (SETATTR3args),
9047c478bd9Sstevel@tonic-gate 	    xdr_SETATTR3res, NULL_xdrproc_t, sizeof (SETATTR3res),
9057c478bd9Sstevel@tonic-gate 	    nullfree, 0,
906d9ad96c1Srg 	    rfs3_setattr_getfh},
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	/* RFS3_LOOKUP = 3 */
9097c478bd9Sstevel@tonic-gate 	{rfs3_lookup,
9107c478bd9Sstevel@tonic-gate 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (LOOKUP3args),
9117c478bd9Sstevel@tonic-gate 	    xdr_LOOKUP3res, NULL_xdrproc_t, sizeof (LOOKUP3res),
9127c478bd9Sstevel@tonic-gate 	    nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK),
913d9ad96c1Srg 	    rfs3_lookup_getfh},
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	/* RFS3_ACCESS = 4 */
9167c478bd9Sstevel@tonic-gate 	{rfs3_access,
9177c478bd9Sstevel@tonic-gate 	    xdr_ACCESS3args, NULL_xdrproc_t, sizeof (ACCESS3args),
9187c478bd9Sstevel@tonic-gate 	    xdr_ACCESS3res, NULL_xdrproc_t, sizeof (ACCESS3res),
9197c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
920d9ad96c1Srg 	    rfs3_access_getfh},
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	/* RFS3_READLINK = 5 */
9237c478bd9Sstevel@tonic-gate 	{rfs3_readlink,
92427242a7cSthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (READLINK3args),
9257c478bd9Sstevel@tonic-gate 	    xdr_READLINK3res, NULL_xdrproc_t, sizeof (READLINK3res),
9267c478bd9Sstevel@tonic-gate 	    rfs3_readlink_free, RPC_IDEMPOTENT,
927d9ad96c1Srg 	    rfs3_readlink_getfh},
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	/* RFS3_READ = 6 */
9307c478bd9Sstevel@tonic-gate 	{rfs3_read,
9317c478bd9Sstevel@tonic-gate 	    xdr_READ3args, NULL_xdrproc_t, sizeof (READ3args),
9327c478bd9Sstevel@tonic-gate 	    xdr_READ3res, NULL_xdrproc_t, sizeof (READ3res),
9337c478bd9Sstevel@tonic-gate 	    rfs3_read_free, RPC_IDEMPOTENT,
934d9ad96c1Srg 	    rfs3_read_getfh},
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	/* RFS3_WRITE = 7 */
9377c478bd9Sstevel@tonic-gate 	{rfs3_write,
9387c478bd9Sstevel@tonic-gate 	    xdr_WRITE3args, NULL_xdrproc_t, sizeof (WRITE3args),
9397c478bd9Sstevel@tonic-gate 	    xdr_WRITE3res, NULL_xdrproc_t, sizeof (WRITE3res),
9407c478bd9Sstevel@tonic-gate 	    nullfree, 0,
941d9ad96c1Srg 	    rfs3_write_getfh},
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	/* RFS3_CREATE = 8 */
9447c478bd9Sstevel@tonic-gate 	{rfs3_create,
9457c478bd9Sstevel@tonic-gate 	    xdr_CREATE3args, NULL_xdrproc_t, sizeof (CREATE3args),
9467c478bd9Sstevel@tonic-gate 	    xdr_CREATE3res, NULL_xdrproc_t, sizeof (CREATE3res),
9477c478bd9Sstevel@tonic-gate 	    nullfree, 0,
948d9ad96c1Srg 	    rfs3_create_getfh},
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	/* RFS3_MKDIR = 9 */
9517c478bd9Sstevel@tonic-gate 	{rfs3_mkdir,
9527c478bd9Sstevel@tonic-gate 	    xdr_MKDIR3args, NULL_xdrproc_t, sizeof (MKDIR3args),
9537c478bd9Sstevel@tonic-gate 	    xdr_MKDIR3res, NULL_xdrproc_t, sizeof (MKDIR3res),
9547c478bd9Sstevel@tonic-gate 	    nullfree, 0,
955d9ad96c1Srg 	    rfs3_mkdir_getfh},
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	/* RFS3_SYMLINK = 10 */
9587c478bd9Sstevel@tonic-gate 	{rfs3_symlink,
9597c478bd9Sstevel@tonic-gate 	    xdr_SYMLINK3args, NULL_xdrproc_t, sizeof (SYMLINK3args),
9607c478bd9Sstevel@tonic-gate 	    xdr_SYMLINK3res, NULL_xdrproc_t, sizeof (SYMLINK3res),
9617c478bd9Sstevel@tonic-gate 	    nullfree, 0,
962d9ad96c1Srg 	    rfs3_symlink_getfh},
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	/* RFS3_MKNOD = 11 */
9657c478bd9Sstevel@tonic-gate 	{rfs3_mknod,
9667c478bd9Sstevel@tonic-gate 	    xdr_MKNOD3args, NULL_xdrproc_t, sizeof (MKNOD3args),
9677c478bd9Sstevel@tonic-gate 	    xdr_MKNOD3res, NULL_xdrproc_t, sizeof (MKNOD3res),
9687c478bd9Sstevel@tonic-gate 	    nullfree, 0,
969d9ad96c1Srg 	    rfs3_mknod_getfh},
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	/* RFS3_REMOVE = 12 */
9727c478bd9Sstevel@tonic-gate 	{rfs3_remove,
9737c478bd9Sstevel@tonic-gate 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (REMOVE3args),
9747c478bd9Sstevel@tonic-gate 	    xdr_REMOVE3res, NULL_xdrproc_t, sizeof (REMOVE3res),
9757c478bd9Sstevel@tonic-gate 	    nullfree, 0,
976d9ad96c1Srg 	    rfs3_remove_getfh},
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	/* RFS3_RMDIR = 13 */
9797c478bd9Sstevel@tonic-gate 	{rfs3_rmdir,
9807c478bd9Sstevel@tonic-gate 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (RMDIR3args),
9817c478bd9Sstevel@tonic-gate 	    xdr_RMDIR3res, NULL_xdrproc_t, sizeof (RMDIR3res),
9827c478bd9Sstevel@tonic-gate 	    nullfree, 0,
983d9ad96c1Srg 	    rfs3_rmdir_getfh},
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	/* RFS3_RENAME = 14 */
9867c478bd9Sstevel@tonic-gate 	{rfs3_rename,
9877c478bd9Sstevel@tonic-gate 	    xdr_RENAME3args, NULL_xdrproc_t, sizeof (RENAME3args),
9887c478bd9Sstevel@tonic-gate 	    xdr_RENAME3res, NULL_xdrproc_t, sizeof (RENAME3res),
9897c478bd9Sstevel@tonic-gate 	    nullfree, 0,
990d9ad96c1Srg 	    rfs3_rename_getfh},
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	/* RFS3_LINK = 15 */
9937c478bd9Sstevel@tonic-gate 	{rfs3_link,
9947c478bd9Sstevel@tonic-gate 	    xdr_LINK3args, NULL_xdrproc_t, sizeof (LINK3args),
9957c478bd9Sstevel@tonic-gate 	    xdr_LINK3res, NULL_xdrproc_t, sizeof (LINK3res),
9967c478bd9Sstevel@tonic-gate 	    nullfree, 0,
997d9ad96c1Srg 	    rfs3_link_getfh},
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	/* RFS3_READDIR = 16 */
10007c478bd9Sstevel@tonic-gate 	{rfs3_readdir,
10017c478bd9Sstevel@tonic-gate 	    xdr_READDIR3args, NULL_xdrproc_t, sizeof (READDIR3args),
10027c478bd9Sstevel@tonic-gate 	    xdr_READDIR3res, NULL_xdrproc_t, sizeof (READDIR3res),
10037c478bd9Sstevel@tonic-gate 	    rfs3_readdir_free, RPC_IDEMPOTENT,
1004d9ad96c1Srg 	    rfs3_readdir_getfh},
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	/* RFS3_READDIRPLUS = 17 */
10077c478bd9Sstevel@tonic-gate 	{rfs3_readdirplus,
10087c478bd9Sstevel@tonic-gate 	    xdr_READDIRPLUS3args, NULL_xdrproc_t, sizeof (READDIRPLUS3args),
10097c478bd9Sstevel@tonic-gate 	    xdr_READDIRPLUS3res, NULL_xdrproc_t, sizeof (READDIRPLUS3res),
10107c478bd9Sstevel@tonic-gate 	    rfs3_readdirplus_free, RPC_AVOIDWORK,
1011d9ad96c1Srg 	    rfs3_readdirplus_getfh},
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	/* RFS3_FSSTAT = 18 */
10147c478bd9Sstevel@tonic-gate 	{rfs3_fsstat,
101527242a7cSthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSSTAT3args),
10167c478bd9Sstevel@tonic-gate 	    xdr_FSSTAT3res, NULL_xdrproc_t, sizeof (FSSTAT3res),
10177c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
1018d9ad96c1Srg 	    rfs3_fsstat_getfh},
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	/* RFS3_FSINFO = 19 */
10217c478bd9Sstevel@tonic-gate 	{rfs3_fsinfo,
102227242a7cSthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSINFO3args),
10237c478bd9Sstevel@tonic-gate 	    xdr_FSINFO3res, NULL_xdrproc_t, sizeof (FSINFO3res),
10247c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON,
1025d9ad96c1Srg 	    rfs3_fsinfo_getfh},
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	/* RFS3_PATHCONF = 20 */
10287c478bd9Sstevel@tonic-gate 	{rfs3_pathconf,
102927242a7cSthurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (PATHCONF3args),
10307c478bd9Sstevel@tonic-gate 	    xdr_PATHCONF3res, NULL_xdrproc_t, sizeof (PATHCONF3res),
10317c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
1032d9ad96c1Srg 	    rfs3_pathconf_getfh},
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	/* RFS3_COMMIT = 21 */
10357c478bd9Sstevel@tonic-gate 	{rfs3_commit,
10367c478bd9Sstevel@tonic-gate 	    xdr_COMMIT3args, NULL_xdrproc_t, sizeof (COMMIT3args),
10377c478bd9Sstevel@tonic-gate 	    xdr_COMMIT3res, NULL_xdrproc_t, sizeof (COMMIT3res),
10387c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
1039d9ad96c1Srg 	    rfs3_commit_getfh},
10407c478bd9Sstevel@tonic-gate };
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate static char *rfscallnames_v4[] = {
10437c478bd9Sstevel@tonic-gate 	"RFS4_NULL",
10447c478bd9Sstevel@tonic-gate 	"RFS4_COMPOUND",
10457c478bd9Sstevel@tonic-gate 	"RFS4_NULL",
10467c478bd9Sstevel@tonic-gate 	"RFS4_NULL",
10477c478bd9Sstevel@tonic-gate 	"RFS4_NULL",
10487c478bd9Sstevel@tonic-gate 	"RFS4_NULL",
10497c478bd9Sstevel@tonic-gate 	"RFS4_NULL",
10507c478bd9Sstevel@tonic-gate 	"RFS4_NULL",
10517c478bd9Sstevel@tonic-gate 	"RFS4_CREATE"
10527c478bd9Sstevel@tonic-gate };
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate static struct rpcdisp rfsdisptab_v4[] = {
10557c478bd9Sstevel@tonic-gate 	/*
10567c478bd9Sstevel@tonic-gate 	 * NFS VERSION 4
10577c478bd9Sstevel@tonic-gate 	 */
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
1060*f44e1126SVitaliy Gusev 	[NFSPROC4_NULL] = {
1061*f44e1126SVitaliy Gusev 	    .dis_proc = NULL,
1062*f44e1126SVitaliy Gusev 	    .dis_xdrargs = xdr_void,
1063*f44e1126SVitaliy Gusev 	    .dis_fastxdrargs = NULL_xdrproc_t,
1064*f44e1126SVitaliy Gusev 	    .dis_argsz = 0,
1065*f44e1126SVitaliy Gusev 	    .dis_xdrres = xdr_void,
1066*f44e1126SVitaliy Gusev 	    .dis_fastxdrres = NULL_xdrproc_t,
1067*f44e1126SVitaliy Gusev 	    .dis_ressz = 0,
1068*f44e1126SVitaliy Gusev 	    .dis_resfree = nullfree,
1069*f44e1126SVitaliy Gusev 	    .dis_flags = RPC_IDEMPOTENT,
1070*f44e1126SVitaliy Gusev 	    .dis_getfh = NULL
1071*f44e1126SVitaliy Gusev 	},
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	/* RFS4_compound = 1 */
1074*f44e1126SVitaliy Gusev 	[NFSPROC4_COMPOUND] = {
1075*f44e1126SVitaliy Gusev 	    .dis_proc = NULL,
1076*f44e1126SVitaliy Gusev 	    .dis_xdrargs = xdr_COMPOUND4args_srv,
1077*f44e1126SVitaliy Gusev 	    .dis_fastxdrargs = NULL_xdrproc_t,
1078*f44e1126SVitaliy Gusev 	    .dis_argsz = sizeof (COMPOUND4args),
1079*f44e1126SVitaliy Gusev 	    .dis_xdrres = xdr_COMPOUND4res_srv,
1080*f44e1126SVitaliy Gusev 	    .dis_fastxdrres = NULL_xdrproc_t,
1081*f44e1126SVitaliy Gusev 	    .dis_ressz = sizeof (COMPOUND4res),
1082*f44e1126SVitaliy Gusev 	    .dis_resfree = rfs4_compound_free,
1083*f44e1126SVitaliy Gusev 	    .dis_flags = 0,
1084*f44e1126SVitaliy Gusev 	    .dis_getfh = NULL
1085*f44e1126SVitaliy Gusev 	},
10867c478bd9Sstevel@tonic-gate };
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate union rfs_args {
10897c478bd9Sstevel@tonic-gate 	/*
10907c478bd9Sstevel@tonic-gate 	 * NFS VERSION 2
10917c478bd9Sstevel@tonic-gate 	 */
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	/* RFS_GETATTR = 1 */
10967c478bd9Sstevel@tonic-gate 	fhandle_t nfs2_getattr_args;
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	/* RFS_SETATTR = 2 */
10997c478bd9Sstevel@tonic-gate 	struct nfssaargs nfs2_setattr_args;
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	/* RFS_LOOKUP = 4 */
11047c478bd9Sstevel@tonic-gate 	struct nfsdiropargs nfs2_lookup_args;
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	/* RFS_READLINK = 5 */
11077c478bd9Sstevel@tonic-gate 	fhandle_t nfs2_readlink_args;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	/* RFS_READ = 6 */
11107c478bd9Sstevel@tonic-gate 	struct nfsreadargs nfs2_read_args;
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	/* RFS_WRITE = 8 */
11157c478bd9Sstevel@tonic-gate 	struct nfswriteargs nfs2_write_args;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	/* RFS_CREATE = 9 */
11187c478bd9Sstevel@tonic-gate 	struct nfscreatargs nfs2_create_args;
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 	/* RFS_REMOVE = 10 */
11217c478bd9Sstevel@tonic-gate 	struct nfsdiropargs nfs2_remove_args;
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	/* RFS_RENAME = 11 */
11247c478bd9Sstevel@tonic-gate 	struct nfsrnmargs nfs2_rename_args;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	/* RFS_LINK = 12 */
11277c478bd9Sstevel@tonic-gate 	struct nfslinkargs nfs2_link_args;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	/* RFS_SYMLINK = 13 */
11307c478bd9Sstevel@tonic-gate 	struct nfsslargs nfs2_symlink_args;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	/* RFS_MKDIR = 14 */
11337c478bd9Sstevel@tonic-gate 	struct nfscreatargs nfs2_mkdir_args;
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	/* RFS_RMDIR = 15 */
11367c478bd9Sstevel@tonic-gate 	struct nfsdiropargs nfs2_rmdir_args;
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	/* RFS_READDIR = 16 */
11397c478bd9Sstevel@tonic-gate 	struct nfsrddirargs nfs2_readdir_args;
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 	/* RFS_STATFS = 17 */
11427c478bd9Sstevel@tonic-gate 	fhandle_t nfs2_statfs_args;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	/*
11457c478bd9Sstevel@tonic-gate 	 * NFS VERSION 3
11467c478bd9Sstevel@tonic-gate 	 */
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	/* RFS3_GETATTR = 1 */
11517c478bd9Sstevel@tonic-gate 	GETATTR3args nfs3_getattr_args;
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	/* RFS3_SETATTR = 2 */
11547c478bd9Sstevel@tonic-gate 	SETATTR3args nfs3_setattr_args;
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	/* RFS3_LOOKUP = 3 */
11577c478bd9Sstevel@tonic-gate 	LOOKUP3args nfs3_lookup_args;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	/* RFS3_ACCESS = 4 */
11607c478bd9Sstevel@tonic-gate 	ACCESS3args nfs3_access_args;
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	/* RFS3_READLINK = 5 */
11637c478bd9Sstevel@tonic-gate 	READLINK3args nfs3_readlink_args;
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	/* RFS3_READ = 6 */
11667c478bd9Sstevel@tonic-gate 	READ3args nfs3_read_args;
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	/* RFS3_WRITE = 7 */
11697c478bd9Sstevel@tonic-gate 	WRITE3args nfs3_write_args;
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	/* RFS3_CREATE = 8 */
11727c478bd9Sstevel@tonic-gate 	CREATE3args nfs3_create_args;
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	/* RFS3_MKDIR = 9 */
11757c478bd9Sstevel@tonic-gate 	MKDIR3args nfs3_mkdir_args;
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	/* RFS3_SYMLINK = 10 */
11787c478bd9Sstevel@tonic-gate 	SYMLINK3args nfs3_symlink_args;
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	/* RFS3_MKNOD = 11 */
11817c478bd9Sstevel@tonic-gate 	MKNOD3args nfs3_mknod_args;
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	/* RFS3_REMOVE = 12 */
11847c478bd9Sstevel@tonic-gate 	REMOVE3args nfs3_remove_args;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	/* RFS3_RMDIR = 13 */
11877c478bd9Sstevel@tonic-gate 	RMDIR3args nfs3_rmdir_args;
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	/* RFS3_RENAME = 14 */
11907c478bd9Sstevel@tonic-gate 	RENAME3args nfs3_rename_args;
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	/* RFS3_LINK = 15 */
11937c478bd9Sstevel@tonic-gate 	LINK3args nfs3_link_args;
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	/* RFS3_READDIR = 16 */
11967c478bd9Sstevel@tonic-gate 	READDIR3args nfs3_readdir_args;
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	/* RFS3_READDIRPLUS = 17 */
11997c478bd9Sstevel@tonic-gate 	READDIRPLUS3args nfs3_readdirplus_args;
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	/* RFS3_FSSTAT = 18 */
12027c478bd9Sstevel@tonic-gate 	FSSTAT3args nfs3_fsstat_args;
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	/* RFS3_FSINFO = 19 */
12057c478bd9Sstevel@tonic-gate 	FSINFO3args nfs3_fsinfo_args;
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	/* RFS3_PATHCONF = 20 */
12087c478bd9Sstevel@tonic-gate 	PATHCONF3args nfs3_pathconf_args;
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 	/* RFS3_COMMIT = 21 */
12117c478bd9Sstevel@tonic-gate 	COMMIT3args nfs3_commit_args;
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	/*
12147c478bd9Sstevel@tonic-gate 	 * NFS VERSION 4
12157c478bd9Sstevel@tonic-gate 	 */
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	/* COMPUND = 1 */
12207c478bd9Sstevel@tonic-gate 	COMPOUND4args nfs4_compound_args;
12217c478bd9Sstevel@tonic-gate };
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate union rfs_res {
12247c478bd9Sstevel@tonic-gate 	/*
12257c478bd9Sstevel@tonic-gate 	 * NFS VERSION 2
12267c478bd9Sstevel@tonic-gate 	 */
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	/* RFS_GETATTR = 1 */
12317c478bd9Sstevel@tonic-gate 	struct nfsattrstat nfs2_getattr_res;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	/* RFS_SETATTR = 2 */
12347c478bd9Sstevel@tonic-gate 	struct nfsattrstat nfs2_setattr_res;
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	/* RFS_LOOKUP = 4 */
12397c478bd9Sstevel@tonic-gate 	struct nfsdiropres nfs2_lookup_res;
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	/* RFS_READLINK = 5 */
12427c478bd9Sstevel@tonic-gate 	struct nfsrdlnres nfs2_readlink_res;
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	/* RFS_READ = 6 */
12457c478bd9Sstevel@tonic-gate 	struct nfsrdresult nfs2_read_res;
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	/* RFS_WRITE = 8 */
12507c478bd9Sstevel@tonic-gate 	struct nfsattrstat nfs2_write_res;
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	/* RFS_CREATE = 9 */
12537c478bd9Sstevel@tonic-gate 	struct nfsdiropres nfs2_create_res;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	/* RFS_REMOVE = 10 */
12567c478bd9Sstevel@tonic-gate 	enum nfsstat nfs2_remove_res;
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	/* RFS_RENAME = 11 */
12597c478bd9Sstevel@tonic-gate 	enum nfsstat nfs2_rename_res;
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	/* RFS_LINK = 12 */
12627c478bd9Sstevel@tonic-gate 	enum nfsstat nfs2_link_res;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	/* RFS_SYMLINK = 13 */
12657c478bd9Sstevel@tonic-gate 	enum nfsstat nfs2_symlink_res;
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	/* RFS_MKDIR = 14 */
12687c478bd9Sstevel@tonic-gate 	struct nfsdiropres nfs2_mkdir_res;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	/* RFS_RMDIR = 15 */
12717c478bd9Sstevel@tonic-gate 	enum nfsstat nfs2_rmdir_res;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	/* RFS_READDIR = 16 */
12747c478bd9Sstevel@tonic-gate 	struct nfsrddirres nfs2_readdir_res;
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	/* RFS_STATFS = 17 */
12777c478bd9Sstevel@tonic-gate 	struct nfsstatfs nfs2_statfs_res;
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 	/*
12807c478bd9Sstevel@tonic-gate 	 * NFS VERSION 3
12817c478bd9Sstevel@tonic-gate 	 */
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	/* RFS3_GETATTR = 1 */
12867c478bd9Sstevel@tonic-gate 	GETATTR3res nfs3_getattr_res;
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	/* RFS3_SETATTR = 2 */
12897c478bd9Sstevel@tonic-gate 	SETATTR3res nfs3_setattr_res;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	/* RFS3_LOOKUP = 3 */
12927c478bd9Sstevel@tonic-gate 	LOOKUP3res nfs3_lookup_res;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	/* RFS3_ACCESS = 4 */
12957c478bd9Sstevel@tonic-gate 	ACCESS3res nfs3_access_res;
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 	/* RFS3_READLINK = 5 */
12987c478bd9Sstevel@tonic-gate 	READLINK3res nfs3_readlink_res;
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	/* RFS3_READ = 6 */
13017c478bd9Sstevel@tonic-gate 	READ3res nfs3_read_res;
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	/* RFS3_WRITE = 7 */
13047c478bd9Sstevel@tonic-gate 	WRITE3res nfs3_write_res;
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	/* RFS3_CREATE = 8 */
13077c478bd9Sstevel@tonic-gate 	CREATE3res nfs3_create_res;
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 	/* RFS3_MKDIR = 9 */
13107c478bd9Sstevel@tonic-gate 	MKDIR3res nfs3_mkdir_res;
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	/* RFS3_SYMLINK = 10 */
13137c478bd9Sstevel@tonic-gate 	SYMLINK3res nfs3_symlink_res;
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	/* RFS3_MKNOD = 11 */
13167c478bd9Sstevel@tonic-gate 	MKNOD3res nfs3_mknod_res;
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	/* RFS3_REMOVE = 12 */
13197c478bd9Sstevel@tonic-gate 	REMOVE3res nfs3_remove_res;
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	/* RFS3_RMDIR = 13 */
13227c478bd9Sstevel@tonic-gate 	RMDIR3res nfs3_rmdir_res;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	/* RFS3_RENAME = 14 */
13257c478bd9Sstevel@tonic-gate 	RENAME3res nfs3_rename_res;
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	/* RFS3_LINK = 15 */
13287c478bd9Sstevel@tonic-gate 	LINK3res nfs3_link_res;
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	/* RFS3_READDIR = 16 */
13317c478bd9Sstevel@tonic-gate 	READDIR3res nfs3_readdir_res;
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	/* RFS3_READDIRPLUS = 17 */
13347c478bd9Sstevel@tonic-gate 	READDIRPLUS3res nfs3_readdirplus_res;
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	/* RFS3_FSSTAT = 18 */
13377c478bd9Sstevel@tonic-gate 	FSSTAT3res nfs3_fsstat_res;
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	/* RFS3_FSINFO = 19 */
13407c478bd9Sstevel@tonic-gate 	FSINFO3res nfs3_fsinfo_res;
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	/* RFS3_PATHCONF = 20 */
13437c478bd9Sstevel@tonic-gate 	PATHCONF3res nfs3_pathconf_res;
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 	/* RFS3_COMMIT = 21 */
13467c478bd9Sstevel@tonic-gate 	COMMIT3res nfs3_commit_res;
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	/*
13497c478bd9Sstevel@tonic-gate 	 * NFS VERSION 4
13507c478bd9Sstevel@tonic-gate 	 */
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	/* RFS_NULL = 0 */
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	/* RFS4_COMPOUND = 1 */
13557c478bd9Sstevel@tonic-gate 	COMPOUND4res nfs4_compound_res;
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate };
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate static struct rpc_disptable rfs_disptable[] = {
13607c478bd9Sstevel@tonic-gate 	{sizeof (rfsdisptab_v2) / sizeof (rfsdisptab_v2[0]),
13617c478bd9Sstevel@tonic-gate 	    rfscallnames_v2,
13620dfe541eSEvan Layton 	    rfsdisptab_v2},
13637c478bd9Sstevel@tonic-gate 	{sizeof (rfsdisptab_v3) / sizeof (rfsdisptab_v3[0]),
13647c478bd9Sstevel@tonic-gate 	    rfscallnames_v3,
13650dfe541eSEvan Layton 	    rfsdisptab_v3},
13667c478bd9Sstevel@tonic-gate 	{sizeof (rfsdisptab_v4) / sizeof (rfsdisptab_v4[0]),
13677c478bd9Sstevel@tonic-gate 	    rfscallnames_v4,
13680dfe541eSEvan Layton 	    rfsdisptab_v4},
13697c478bd9Sstevel@tonic-gate };
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate /*
13727c478bd9Sstevel@tonic-gate  * If nfs_portmon is set, then clients are required to use privileged
13737c478bd9Sstevel@tonic-gate  * ports (ports < IPPORT_RESERVED) in order to get NFS services.
13747c478bd9Sstevel@tonic-gate  *
13757c478bd9Sstevel@tonic-gate  * N.B.: this attempt to carry forward the already ill-conceived notion
13767c478bd9Sstevel@tonic-gate  * of privileged ports for TCP/UDP is really quite ineffectual.  Not only
13777c478bd9Sstevel@tonic-gate  * is it transport-dependent, it's laughably easy to spoof.  If you're
13787c478bd9Sstevel@tonic-gate  * really interested in security, you must start with secure RPC instead.
13797c478bd9Sstevel@tonic-gate  */
13807c478bd9Sstevel@tonic-gate static int nfs_portmon = 0;
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate #ifdef DEBUG
13837c478bd9Sstevel@tonic-gate /*
13847c478bd9Sstevel@tonic-gate  * Debug code to allow disabling of rfs_dispatch() use of
13857c478bd9Sstevel@tonic-gate  * fastxdrargs() and fastxdrres() calls for testing purposes.
13867c478bd9Sstevel@tonic-gate  */
13877c478bd9Sstevel@tonic-gate static int rfs_no_fast_xdrargs = 0;
13887c478bd9Sstevel@tonic-gate static int rfs_no_fast_xdrres = 0;
13897c478bd9Sstevel@tonic-gate #endif
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate union acl_args {
13927c478bd9Sstevel@tonic-gate 	/*
13937c478bd9Sstevel@tonic-gate 	 * ACL VERSION 2
13947c478bd9Sstevel@tonic-gate 	 */
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	/* ACL2_NULL = 0 */
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	/* ACL2_GETACL = 1 */
13997c478bd9Sstevel@tonic-gate 	GETACL2args acl2_getacl_args;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	/* ACL2_SETACL = 2 */
14027c478bd9Sstevel@tonic-gate 	SETACL2args acl2_setacl_args;
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	/* ACL2_GETATTR = 3 */
14057c478bd9Sstevel@tonic-gate 	GETATTR2args acl2_getattr_args;
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	/* ACL2_ACCESS = 4 */
14087c478bd9Sstevel@tonic-gate 	ACCESS2args acl2_access_args;
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	/* ACL2_GETXATTRDIR = 5 */
14117c478bd9Sstevel@tonic-gate 	GETXATTRDIR2args acl2_getxattrdir_args;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	/*
14147c478bd9Sstevel@tonic-gate 	 * ACL VERSION 3
14157c478bd9Sstevel@tonic-gate 	 */
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	/* ACL3_NULL = 0 */
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 	/* ACL3_GETACL = 1 */
14207c478bd9Sstevel@tonic-gate 	GETACL3args acl3_getacl_args;
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	/* ACL3_SETACL = 2 */
14237c478bd9Sstevel@tonic-gate 	SETACL3args acl3_setacl;
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	/* ACL3_GETXATTRDIR = 3 */
14267c478bd9Sstevel@tonic-gate 	GETXATTRDIR3args acl3_getxattrdir_args;
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate };
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate union acl_res {
14317c478bd9Sstevel@tonic-gate 	/*
14327c478bd9Sstevel@tonic-gate 	 * ACL VERSION 2
14337c478bd9Sstevel@tonic-gate 	 */
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	/* ACL2_NULL = 0 */
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	/* ACL2_GETACL = 1 */
14387c478bd9Sstevel@tonic-gate 	GETACL2res acl2_getacl_res;
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 	/* ACL2_SETACL = 2 */
14417c478bd9Sstevel@tonic-gate 	SETACL2res acl2_setacl_res;
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	/* ACL2_GETATTR = 3 */
14447c478bd9Sstevel@tonic-gate 	GETATTR2res acl2_getattr_res;
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 	/* ACL2_ACCESS = 4 */
14477c478bd9Sstevel@tonic-gate 	ACCESS2res acl2_access_res;
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	/* ACL2_GETXATTRDIR = 5 */
14507c478bd9Sstevel@tonic-gate 	GETXATTRDIR2args acl2_getxattrdir_res;
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 	/*
14537c478bd9Sstevel@tonic-gate 	 * ACL VERSION 3
14547c478bd9Sstevel@tonic-gate 	 */
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	/* ACL3_NULL = 0 */
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 	/* ACL3_GETACL = 1 */
14597c478bd9Sstevel@tonic-gate 	GETACL3res acl3_getacl_res;
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	/* ACL3_SETACL = 2 */
14627c478bd9Sstevel@tonic-gate 	SETACL3res acl3_setacl_res;
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 	/* ACL3_GETXATTRDIR = 3 */
14657c478bd9Sstevel@tonic-gate 	GETXATTRDIR3res acl3_getxattrdir_res;
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate };
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate static bool_t
auth_tooweak(struct svc_req * req,char * res)14707c478bd9Sstevel@tonic-gate auth_tooweak(struct svc_req *req, char *res)
14717c478bd9Sstevel@tonic-gate {
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 	if (req->rq_vers == NFS_VERSION && req->rq_proc == RFS_LOOKUP) {
14747c478bd9Sstevel@tonic-gate 		struct nfsdiropres *dr = (struct nfsdiropres *)res;
14752c2d21e9SRichard Lowe 		if ((enum wnfsstat)dr->dr_status == WNFSERR_CLNT_FLAVOR)
14767c478bd9Sstevel@tonic-gate 			return (TRUE);
14777c478bd9Sstevel@tonic-gate 	} else if (req->rq_vers == NFS_V3 && req->rq_proc == NFSPROC3_LOOKUP) {
14787c478bd9Sstevel@tonic-gate 		LOOKUP3res *resp = (LOOKUP3res *)res;
14792c2d21e9SRichard Lowe 		if ((enum wnfsstat)resp->status == WNFSERR_CLNT_FLAVOR)
14807c478bd9Sstevel@tonic-gate 			return (TRUE);
14817c478bd9Sstevel@tonic-gate 	}
14827c478bd9Sstevel@tonic-gate 	return (FALSE);
14837c478bd9Sstevel@tonic-gate }
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate static void
common_dispatch(struct svc_req * req,SVCXPRT * xprt,rpcvers_t min_vers,rpcvers_t max_vers,char * pgmname,struct rpc_disptable * disptable)14867c478bd9Sstevel@tonic-gate common_dispatch(struct svc_req *req, SVCXPRT *xprt, rpcvers_t min_vers,
14870dfe541eSEvan Layton     rpcvers_t max_vers, char *pgmname, struct rpc_disptable *disptable)
14887c478bd9Sstevel@tonic-gate {
14897c478bd9Sstevel@tonic-gate 	int which;
14907c478bd9Sstevel@tonic-gate 	rpcvers_t vers;
14917c478bd9Sstevel@tonic-gate 	char *args;
14927c478bd9Sstevel@tonic-gate 	union {
14937c478bd9Sstevel@tonic-gate 			union rfs_args ra;
14947c478bd9Sstevel@tonic-gate 			union acl_args aa;
14957c478bd9Sstevel@tonic-gate 		} args_buf;
14967c478bd9Sstevel@tonic-gate 	char *res;
14977c478bd9Sstevel@tonic-gate 	union {
14987c478bd9Sstevel@tonic-gate 			union rfs_res rr;
14997c478bd9Sstevel@tonic-gate 			union acl_res ar;
15007c478bd9Sstevel@tonic-gate 		} res_buf;
15017c478bd9Sstevel@tonic-gate 	struct rpcdisp *disp = NULL;
15027c478bd9Sstevel@tonic-gate 	int dis_flags = 0;
15037c478bd9Sstevel@tonic-gate 	cred_t *cr;
15047c478bd9Sstevel@tonic-gate 	int error = 0;
15057c478bd9Sstevel@tonic-gate 	int anon_ok;
15067c478bd9Sstevel@tonic-gate 	struct exportinfo *exi = NULL;
15077c478bd9Sstevel@tonic-gate 	unsigned int nfslog_rec_id;
15087c478bd9Sstevel@tonic-gate 	int dupstat;
15097c478bd9Sstevel@tonic-gate 	struct dupreq *dr;
15107c478bd9Sstevel@tonic-gate 	int authres;
15117c478bd9Sstevel@tonic-gate 	bool_t publicfh_ok = FALSE;
15127c478bd9Sstevel@tonic-gate 	enum_t auth_flavor;
15137c478bd9Sstevel@tonic-gate 	bool_t dupcached = FALSE;
15147c478bd9Sstevel@tonic-gate 	struct netbuf	nb;
15157c478bd9Sstevel@tonic-gate 	bool_t logging_enabled = FALSE;
15167c478bd9Sstevel@tonic-gate 	struct exportinfo *nfslog_exi = NULL;
1517eac3aab7Srobinson 	char **procnames;
1518eac3aab7Srobinson 	char cbuf[INET6_ADDRSTRLEN];	/* to hold both IPv4 and IPv6 addr */
15195cb0d679SMarcel Telka 	bool_t ro = FALSE;
15200dfe541eSEvan Layton 	nfs_globals_t *ng = nfs_srv_getzg();
15210dfe541eSEvan Layton 	nfs_export_t *ne = ng->nfs_export;
15220dfe541eSEvan Layton 	kstat_named_t *svstat, *procstat;
15230dfe541eSEvan Layton 
15240dfe541eSEvan Layton 	ASSERT(req->rq_prog == NFS_PROGRAM || req->rq_prog == NFS_ACL_PROGRAM);
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	vers = req->rq_vers;
15277c478bd9Sstevel@tonic-gate 
15280dfe541eSEvan Layton 	svstat = ng->svstat[req->rq_vers];
15290dfe541eSEvan Layton 	procstat = (req->rq_prog == NFS_PROGRAM) ?
15300dfe541eSEvan Layton 	    ng->rfsproccnt[vers] : ng->aclproccnt[vers];
15310dfe541eSEvan Layton 
15327c478bd9Sstevel@tonic-gate 	if (vers < min_vers || vers > max_vers) {
15337c478bd9Sstevel@tonic-gate 		svcerr_progvers(req->rq_xprt, min_vers, max_vers);
15347c478bd9Sstevel@tonic-gate 		error++;
15357c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "%s: bad version number %u", pgmname, vers);
15367c478bd9Sstevel@tonic-gate 		goto done;
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 	vers -= min_vers;
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 	which = req->rq_proc;
15417c478bd9Sstevel@tonic-gate 	if (which < 0 || which >= disptable[(int)vers].dis_nprocs) {
15427c478bd9Sstevel@tonic-gate 		svcerr_noproc(req->rq_xprt);
15437c478bd9Sstevel@tonic-gate 		error++;
15447c478bd9Sstevel@tonic-gate 		goto done;
15457c478bd9Sstevel@tonic-gate 	}
15467c478bd9Sstevel@tonic-gate 
15470dfe541eSEvan Layton 	procstat[which].value.ui64++;
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	disp = &disptable[(int)vers].dis_table[which];
1550eac3aab7Srobinson 	procnames = disptable[(int)vers].dis_procnames;
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 	auth_flavor = req->rq_cred.oa_flavor;
1553eac3aab7Srobinson 
15547c478bd9Sstevel@tonic-gate 	/*
15557c478bd9Sstevel@tonic-gate 	 * Deserialize into the args struct.
15567c478bd9Sstevel@tonic-gate 	 */
15577c478bd9Sstevel@tonic-gate 	args = (char *)&args_buf;
1558d9ad96c1Srg 
15597c478bd9Sstevel@tonic-gate #ifdef DEBUG
15607c478bd9Sstevel@tonic-gate 	if (rfs_no_fast_xdrargs || (auth_flavor == RPCSEC_GSS) ||
15617c478bd9Sstevel@tonic-gate 	    disp->dis_fastxdrargs == NULL_xdrproc_t ||
156227242a7cSthurlow 	    !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args))
15637c478bd9Sstevel@tonic-gate #else
15647c478bd9Sstevel@tonic-gate 	if ((auth_flavor == RPCSEC_GSS) ||
15657c478bd9Sstevel@tonic-gate 	    disp->dis_fastxdrargs == NULL_xdrproc_t ||
156627242a7cSthurlow 	    !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args))
15677c478bd9Sstevel@tonic-gate #endif
156827242a7cSthurlow 	{
15697c478bd9Sstevel@tonic-gate 		bzero(args, disp->dis_argsz);
15707c478bd9Sstevel@tonic-gate 		if (!SVC_GETARGS(xprt, disp->dis_xdrargs, args)) {
15717c478bd9Sstevel@tonic-gate 			error++;
15727d12f3bcSmaheshvs 			/*
15737d12f3bcSmaheshvs 			 * Check if we are outside our capabilities.
15747d12f3bcSmaheshvs 			 */
15757d12f3bcSmaheshvs 			if (rfs4_minorvers_mismatch(req, xprt, (void *)args))
15767d12f3bcSmaheshvs 				goto done;
15777d12f3bcSmaheshvs 
15787d12f3bcSmaheshvs 			svcerr_decode(xprt);
1579eac3aab7Srobinson 			cmn_err(CE_NOTE,
1580eac3aab7Srobinson 			    "Failed to decode arguments for %s version %u "
1581eac3aab7Srobinson 			    "procedure %s client %s%s",
1582eac3aab7Srobinson 			    pgmname, vers + min_vers, procnames[which],
1583eac3aab7Srobinson 			    client_name(req), client_addr(req, cbuf));
15847c478bd9Sstevel@tonic-gate 			goto done;
15857c478bd9Sstevel@tonic-gate 		}
15867c478bd9Sstevel@tonic-gate 	}
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 	/*
1589d9ad96c1Srg 	 * If Version 4 use that specific dispatch function.
15907c478bd9Sstevel@tonic-gate 	 */
1591d9ad96c1Srg 	if (req->rq_vers == 4) {
1592f7877f5dSDan McDonald 		error += rfs4_dispatch(disp, req, xprt, args);
1593d9ad96c1Srg 		goto done;
1594d9ad96c1Srg 	}
15957c478bd9Sstevel@tonic-gate 
1596d9ad96c1Srg 	dis_flags = disp->dis_flags;
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	/*
15997c478bd9Sstevel@tonic-gate 	 * Find export information and check authentication,
16007c478bd9Sstevel@tonic-gate 	 * setting the credential if everything is ok.
16017c478bd9Sstevel@tonic-gate 	 */
16027c478bd9Sstevel@tonic-gate 	if (disp->dis_getfh != NULL) {
160327242a7cSthurlow 		void *fh;
160427242a7cSthurlow 		fsid_t *fsid;
160527242a7cSthurlow 		fid_t *fid, *xfid;
160627242a7cSthurlow 		fhandle_t *fh2;
160727242a7cSthurlow 		nfs_fh3 *fh3;
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 		fh = (*disp->dis_getfh)(args);
161027242a7cSthurlow 		switch (req->rq_vers) {
161127242a7cSthurlow 		case NFS_VERSION:
161227242a7cSthurlow 			fh2 = (fhandle_t *)fh;
161327242a7cSthurlow 			fsid = &fh2->fh_fsid;
161427242a7cSthurlow 			fid = (fid_t *)&fh2->fh_len;
161527242a7cSthurlow 			xfid = (fid_t *)&fh2->fh_xlen;
161627242a7cSthurlow 			break;
161727242a7cSthurlow 		case NFS_V3:
161827242a7cSthurlow 			fh3 = (nfs_fh3 *)fh;
161927242a7cSthurlow 			fsid = &fh3->fh3_fsid;
162027242a7cSthurlow 			fid = FH3TOFIDP(fh3);
162127242a7cSthurlow 			xfid = FH3TOXFIDP(fh3);
162227242a7cSthurlow 			break;
162327242a7cSthurlow 		}
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate 		/*
16267c478bd9Sstevel@tonic-gate 		 * Fix for bug 1038302 - corbin
16277c478bd9Sstevel@tonic-gate 		 * There is a problem here if anonymous access is
16287c478bd9Sstevel@tonic-gate 		 * disallowed.  If the current request is part of the
16297c478bd9Sstevel@tonic-gate 		 * client's mount process for the requested filesystem,
16307c478bd9Sstevel@tonic-gate 		 * then it will carry root (uid 0) credentials on it, and
16317c478bd9Sstevel@tonic-gate 		 * will be denied by checkauth if that client does not
16327c478bd9Sstevel@tonic-gate 		 * have explicit root=0 permission.  This will cause the
16337c478bd9Sstevel@tonic-gate 		 * client's mount operation to fail.  As a work-around,
16347c478bd9Sstevel@tonic-gate 		 * we check here to see if the request is a getattr or
16357c478bd9Sstevel@tonic-gate 		 * statfs operation on the exported vnode itself, and
16367c478bd9Sstevel@tonic-gate 		 * pass a flag to checkauth with the result of this test.
16377c478bd9Sstevel@tonic-gate 		 *
16387c478bd9Sstevel@tonic-gate 		 * The filehandle refers to the mountpoint itself if
16397c478bd9Sstevel@tonic-gate 		 * the fh_data and fh_xdata portions of the filehandle
16407c478bd9Sstevel@tonic-gate 		 * are equal.
16417c478bd9Sstevel@tonic-gate 		 *
16427c478bd9Sstevel@tonic-gate 		 * Added anon_ok argument to checkauth().
16437c478bd9Sstevel@tonic-gate 		 */
16447c478bd9Sstevel@tonic-gate 
164527242a7cSthurlow 		if ((dis_flags & RPC_ALLOWANON) && EQFID(fid, xfid))
16467c478bd9Sstevel@tonic-gate 			anon_ok = 1;
16477c478bd9Sstevel@tonic-gate 		else
16487c478bd9Sstevel@tonic-gate 			anon_ok = 0;
16497c478bd9Sstevel@tonic-gate 
1650214d537cSVitaliy Gusev 		cr = svc_xprt_cred(xprt);
16517c478bd9Sstevel@tonic-gate 
165227242a7cSthurlow 		exi = checkexport(fsid, xfid);
1653d9ad96c1Srg 
16547c478bd9Sstevel@tonic-gate 		if (exi != NULL) {
16550dfe541eSEvan Layton 			publicfh_ok = PUBLICFH_CHECK(ne, disp, exi, fsid, xfid);
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 			/*
16587c478bd9Sstevel@tonic-gate 			 * Don't allow non-V4 clients access
16597c478bd9Sstevel@tonic-gate 			 * to pseudo exports
16607c478bd9Sstevel@tonic-gate 			 */
16617c478bd9Sstevel@tonic-gate 			if (PSEUDO(exi)) {
16627c478bd9Sstevel@tonic-gate 				svcerr_weakauth(xprt);
16637c478bd9Sstevel@tonic-gate 				error++;
16647c478bd9Sstevel@tonic-gate 				goto done;
16657c478bd9Sstevel@tonic-gate 			}
16667c478bd9Sstevel@tonic-gate 
16675cb0d679SMarcel Telka 			authres = checkauth(exi, req, cr, anon_ok, publicfh_ok,
16685cb0d679SMarcel Telka 			    &ro);
16697c478bd9Sstevel@tonic-gate 			/*
16707c478bd9Sstevel@tonic-gate 			 * authres >  0: authentication OK - proceed
16717c478bd9Sstevel@tonic-gate 			 * authres == 0: authentication weak - return error
16727c478bd9Sstevel@tonic-gate 			 * authres <  0: authentication timeout - drop
16737c478bd9Sstevel@tonic-gate 			 */
16747c478bd9Sstevel@tonic-gate 			if (authres <= 0) {
16757c478bd9Sstevel@tonic-gate 				if (authres == 0) {
16767c478bd9Sstevel@tonic-gate 					svcerr_weakauth(xprt);
16777c478bd9Sstevel@tonic-gate 					error++;
16787c478bd9Sstevel@tonic-gate 				}
16797c478bd9Sstevel@tonic-gate 				goto done;
16807c478bd9Sstevel@tonic-gate 			}
16817c478bd9Sstevel@tonic-gate 		}
16827c478bd9Sstevel@tonic-gate 	} else
16837c478bd9Sstevel@tonic-gate 		cr = NULL;
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 	if ((dis_flags & RPC_MAPRESP) && (auth_flavor != RPCSEC_GSS)) {
16867c478bd9Sstevel@tonic-gate 		res = (char *)SVC_GETRES(xprt, disp->dis_ressz);
16877c478bd9Sstevel@tonic-gate 		if (res == NULL)
16887c478bd9Sstevel@tonic-gate 			res = (char *)&res_buf;
16897c478bd9Sstevel@tonic-gate 	} else
16907c478bd9Sstevel@tonic-gate 		res = (char *)&res_buf;
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 	if (!(dis_flags & RPC_IDEMPOTENT)) {
16937c478bd9Sstevel@tonic-gate 		dupstat = SVC_DUP_EXT(xprt, req, res, disp->dis_ressz, &dr,
1694b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    &dupcached);
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 		switch (dupstat) {
16977c478bd9Sstevel@tonic-gate 		case DUP_ERROR:
16987c478bd9Sstevel@tonic-gate 			svcerr_systemerr(xprt);
16997c478bd9Sstevel@tonic-gate 			error++;
17007c478bd9Sstevel@tonic-gate 			goto done;
17017c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
17027c478bd9Sstevel@tonic-gate 		case DUP_INPROGRESS:
17037c478bd9Sstevel@tonic-gate 			if (res != (char *)&res_buf)
17047c478bd9Sstevel@tonic-gate 				SVC_FREERES(xprt);
17057c478bd9Sstevel@tonic-gate 			error++;
17067c478bd9Sstevel@tonic-gate 			goto done;
17077c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
17087c478bd9Sstevel@tonic-gate 		case DUP_NEW:
17097c478bd9Sstevel@tonic-gate 		case DUP_DROP:
17107c478bd9Sstevel@tonic-gate 			curthread->t_flag |= T_DONTPEND;
1711d9ad96c1Srg 
17125cb0d679SMarcel Telka 			(*disp->dis_proc)(args, res, exi, req, cr, ro);
1713d9ad96c1Srg 
17147c478bd9Sstevel@tonic-gate 			curthread->t_flag &= ~T_DONTPEND;
17157c478bd9Sstevel@tonic-gate 			if (curthread->t_flag & T_WOULDBLOCK) {
17167c478bd9Sstevel@tonic-gate 				curthread->t_flag &= ~T_WOULDBLOCK;
17177c478bd9Sstevel@tonic-gate 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
1718b89a8333Snatalie li - Sun Microsystems - Irvine United States 				    disp->dis_ressz, DUP_DROP);
17197c478bd9Sstevel@tonic-gate 				if (res != (char *)&res_buf)
17207c478bd9Sstevel@tonic-gate 					SVC_FREERES(xprt);
17217c478bd9Sstevel@tonic-gate 				error++;
17227c478bd9Sstevel@tonic-gate 				goto done;
17237c478bd9Sstevel@tonic-gate 			}
17247c478bd9Sstevel@tonic-gate 			if (dis_flags & RPC_AVOIDWORK) {
17257c478bd9Sstevel@tonic-gate 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
1726b89a8333Snatalie li - Sun Microsystems - Irvine United States 				    disp->dis_ressz, DUP_DROP);
17277c478bd9Sstevel@tonic-gate 			} else {
17287c478bd9Sstevel@tonic-gate 				SVC_DUPDONE_EXT(xprt, dr, res,
1729b89a8333Snatalie li - Sun Microsystems - Irvine United States 				    disp->dis_resfree == nullfree ? NULL :
1730b89a8333Snatalie li - Sun Microsystems - Irvine United States 				    disp->dis_resfree,
1731b89a8333Snatalie li - Sun Microsystems - Irvine United States 				    disp->dis_ressz, DUP_DONE);
17327c478bd9Sstevel@tonic-gate 				dupcached = TRUE;
17337c478bd9Sstevel@tonic-gate 			}
17347c478bd9Sstevel@tonic-gate 			break;
17357c478bd9Sstevel@tonic-gate 		case DUP_DONE:
17367c478bd9Sstevel@tonic-gate 			break;
17377c478bd9Sstevel@tonic-gate 		}
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	} else {
17407c478bd9Sstevel@tonic-gate 		curthread->t_flag |= T_DONTPEND;
1741d9ad96c1Srg 
17425cb0d679SMarcel Telka 		(*disp->dis_proc)(args, res, exi, req, cr, ro);
1743d9ad96c1Srg 
17447c478bd9Sstevel@tonic-gate 		curthread->t_flag &= ~T_DONTPEND;
17457c478bd9Sstevel@tonic-gate 		if (curthread->t_flag & T_WOULDBLOCK) {
17467c478bd9Sstevel@tonic-gate 			curthread->t_flag &= ~T_WOULDBLOCK;
17477c478bd9Sstevel@tonic-gate 			if (res != (char *)&res_buf)
17487c478bd9Sstevel@tonic-gate 				SVC_FREERES(xprt);
17497c478bd9Sstevel@tonic-gate 			error++;
17507c478bd9Sstevel@tonic-gate 			goto done;
17517c478bd9Sstevel@tonic-gate 		}
17527c478bd9Sstevel@tonic-gate 	}
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 	if (auth_tooweak(req, res)) {
17557c478bd9Sstevel@tonic-gate 		svcerr_weakauth(xprt);
17567c478bd9Sstevel@tonic-gate 		error++;
17577c478bd9Sstevel@tonic-gate 		goto done;
17587c478bd9Sstevel@tonic-gate 	}
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	/*
17617c478bd9Sstevel@tonic-gate 	 * Check to see if logging has been enabled on the server.
17627c478bd9Sstevel@tonic-gate 	 * If so, then obtain the export info struct to be used for
17637c478bd9Sstevel@tonic-gate 	 * the later writing of the log record.  This is done for
17647c478bd9Sstevel@tonic-gate 	 * the case that a lookup is done across a non-logged public
17657c478bd9Sstevel@tonic-gate 	 * file system.
17667c478bd9Sstevel@tonic-gate 	 */
17677c478bd9Sstevel@tonic-gate 	if (nfslog_buffer_list != NULL) {
17680dfe541eSEvan Layton 		nfslog_exi = nfslog_get_exi(ne, exi, req, res, &nfslog_rec_id);
17697c478bd9Sstevel@tonic-gate 		/*
17707c478bd9Sstevel@tonic-gate 		 * Is logging enabled?
17717c478bd9Sstevel@tonic-gate 		 */
17727c478bd9Sstevel@tonic-gate 		logging_enabled = (nfslog_exi != NULL);
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate 		/*
17757c478bd9Sstevel@tonic-gate 		 * Copy the netbuf for logging purposes, before it is
17767c478bd9Sstevel@tonic-gate 		 * freed by svc_sendreply().
17777c478bd9Sstevel@tonic-gate 		 */
17787c478bd9Sstevel@tonic-gate 		if (logging_enabled) {
17797c478bd9Sstevel@tonic-gate 			NFSLOG_COPY_NETBUF(nfslog_exi, xprt, &nb);
17807c478bd9Sstevel@tonic-gate 			/*
17817c478bd9Sstevel@tonic-gate 			 * If RPC_MAPRESP flag set (i.e. in V2 ops) the
17827c478bd9Sstevel@tonic-gate 			 * res gets copied directly into the mbuf and
17837c478bd9Sstevel@tonic-gate 			 * may be freed soon after the sendreply. So we
17847c478bd9Sstevel@tonic-gate 			 * must copy it here to a safe place...
17857c478bd9Sstevel@tonic-gate 			 */
17867c478bd9Sstevel@tonic-gate 			if (res != (char *)&res_buf) {
17877c478bd9Sstevel@tonic-gate 				bcopy(res, (char *)&res_buf, disp->dis_ressz);
17887c478bd9Sstevel@tonic-gate 			}
17897c478bd9Sstevel@tonic-gate 		}
17907c478bd9Sstevel@tonic-gate 	}
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 	/*
17937c478bd9Sstevel@tonic-gate 	 * Serialize and send results struct
17947c478bd9Sstevel@tonic-gate 	 */
17957c478bd9Sstevel@tonic-gate #ifdef DEBUG
179627242a7cSthurlow 	if (rfs_no_fast_xdrres == 0 && res != (char *)&res_buf)
17977c478bd9Sstevel@tonic-gate #else
179827242a7cSthurlow 	if (res != (char *)&res_buf)
17997c478bd9Sstevel@tonic-gate #endif
180027242a7cSthurlow 	{
18017c478bd9Sstevel@tonic-gate 		if (!svc_sendreply(xprt, disp->dis_fastxdrres, res)) {
18027c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
18030a4b0810SKaren Rochford 			svcerr_systemerr(xprt);
18047c478bd9Sstevel@tonic-gate 			error++;
18057c478bd9Sstevel@tonic-gate 		}
18067c478bd9Sstevel@tonic-gate 	} else {
18077c478bd9Sstevel@tonic-gate 		if (!svc_sendreply(xprt, disp->dis_xdrres, res)) {
18087c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
18090a4b0810SKaren Rochford 			svcerr_systemerr(xprt);
18107c478bd9Sstevel@tonic-gate 			error++;
18117c478bd9Sstevel@tonic-gate 		}
18127c478bd9Sstevel@tonic-gate 	}
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	/*
18157c478bd9Sstevel@tonic-gate 	 * Log if needed
18167c478bd9Sstevel@tonic-gate 	 */
18177c478bd9Sstevel@tonic-gate 	if (logging_enabled) {
18187c478bd9Sstevel@tonic-gate 		nfslog_write_record(nfslog_exi, req, args, (char *)&res_buf,
1819b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    cr, &nb, nfslog_rec_id, NFSLOG_ONE_BUFFER);
18207c478bd9Sstevel@tonic-gate 		exi_rele(nfslog_exi);
18217c478bd9Sstevel@tonic-gate 		kmem_free((&nb)->buf, (&nb)->len);
18227c478bd9Sstevel@tonic-gate 	}
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 	/*
18257c478bd9Sstevel@tonic-gate 	 * Free results struct. With the addition of NFS V4 we can
18267c478bd9Sstevel@tonic-gate 	 * have non-idempotent procedures with functions.
18277c478bd9Sstevel@tonic-gate 	 */
18287c478bd9Sstevel@tonic-gate 	if (disp->dis_resfree != nullfree && dupcached == FALSE) {
18297c478bd9Sstevel@tonic-gate 		(*disp->dis_resfree)(res);
18307c478bd9Sstevel@tonic-gate 	}
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate done:
18337c478bd9Sstevel@tonic-gate 	/*
18347c478bd9Sstevel@tonic-gate 	 * Free arguments struct
18357c478bd9Sstevel@tonic-gate 	 */
18367c478bd9Sstevel@tonic-gate 	if (disp) {
18377c478bd9Sstevel@tonic-gate 		if (!SVC_FREEARGS(xprt, disp->dis_xdrargs, args)) {
18387c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
18397c478bd9Sstevel@tonic-gate 			error++;
18407c478bd9Sstevel@tonic-gate 		}
18417c478bd9Sstevel@tonic-gate 	} else {
18427c478bd9Sstevel@tonic-gate 		if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) {
18437c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
18447c478bd9Sstevel@tonic-gate 			error++;
18457c478bd9Sstevel@tonic-gate 		}
18467c478bd9Sstevel@tonic-gate 	}
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 	if (exi != NULL)
18497c478bd9Sstevel@tonic-gate 		exi_rele(exi);
18507c478bd9Sstevel@tonic-gate 
18510dfe541eSEvan Layton 	svstat[NFS_BADCALLS].value.ui64 += error;
18520dfe541eSEvan Layton 	svstat[NFS_CALLS].value.ui64++;
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate static void
rfs_dispatch(struct svc_req * req,SVCXPRT * xprt)18567c478bd9Sstevel@tonic-gate rfs_dispatch(struct svc_req *req, SVCXPRT *xprt)
18577c478bd9Sstevel@tonic-gate {
18587c478bd9Sstevel@tonic-gate 	common_dispatch(req, xprt, NFS_VERSMIN, NFS_VERSMAX,
1859b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    "NFS", rfs_disptable);
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate static char *aclcallnames_v2[] = {
18637c478bd9Sstevel@tonic-gate 	"ACL2_NULL",
18647c478bd9Sstevel@tonic-gate 	"ACL2_GETACL",
18657c478bd9Sstevel@tonic-gate 	"ACL2_SETACL",
18667c478bd9Sstevel@tonic-gate 	"ACL2_GETATTR",
18677c478bd9Sstevel@tonic-gate 	"ACL2_ACCESS",
18687c478bd9Sstevel@tonic-gate 	"ACL2_GETXATTRDIR"
18697c478bd9Sstevel@tonic-gate };
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate static struct rpcdisp acldisptab_v2[] = {
18727c478bd9Sstevel@tonic-gate 	/*
18737c478bd9Sstevel@tonic-gate 	 * ACL VERSION 2
18747c478bd9Sstevel@tonic-gate 	 */
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 	/* ACL2_NULL = 0 */
18777c478bd9Sstevel@tonic-gate 	{rpc_null,
18787c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
18797c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
18807c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
18817c478bd9Sstevel@tonic-gate 	    0},
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	/* ACL2_GETACL = 1 */
18847c478bd9Sstevel@tonic-gate 	{acl2_getacl,
18857c478bd9Sstevel@tonic-gate 	    xdr_GETACL2args, xdr_fastGETACL2args, sizeof (GETACL2args),
18867c478bd9Sstevel@tonic-gate 	    xdr_GETACL2res, NULL_xdrproc_t, sizeof (GETACL2res),
18877c478bd9Sstevel@tonic-gate 	    acl2_getacl_free, RPC_IDEMPOTENT,
18887c478bd9Sstevel@tonic-gate 	    acl2_getacl_getfh},
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 	/* ACL2_SETACL = 2 */
18917c478bd9Sstevel@tonic-gate 	{acl2_setacl,
18927c478bd9Sstevel@tonic-gate 	    xdr_SETACL2args, NULL_xdrproc_t, sizeof (SETACL2args),
18937c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
18947c478bd9Sstevel@tonic-gate 	    xdr_SETACL2res, xdr_fastSETACL2res, sizeof (SETACL2res),
18957c478bd9Sstevel@tonic-gate #else
18967c478bd9Sstevel@tonic-gate 	    xdr_SETACL2res, NULL_xdrproc_t, sizeof (SETACL2res),
18977c478bd9Sstevel@tonic-gate #endif
18987c478bd9Sstevel@tonic-gate 	    nullfree, RPC_MAPRESP,
18997c478bd9Sstevel@tonic-gate 	    acl2_setacl_getfh},
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	/* ACL2_GETATTR = 3 */
19027c478bd9Sstevel@tonic-gate 	{acl2_getattr,
19037c478bd9Sstevel@tonic-gate 	    xdr_GETATTR2args, xdr_fastGETATTR2args, sizeof (GETATTR2args),
19047c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
19057c478bd9Sstevel@tonic-gate 	    xdr_GETATTR2res, xdr_fastGETATTR2res, sizeof (GETATTR2res),
19067c478bd9Sstevel@tonic-gate #else
19077c478bd9Sstevel@tonic-gate 	    xdr_GETATTR2res, NULL_xdrproc_t, sizeof (GETATTR2res),
19087c478bd9Sstevel@tonic-gate #endif
19097c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
19107c478bd9Sstevel@tonic-gate 	    acl2_getattr_getfh},
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	/* ACL2_ACCESS = 4 */
19137c478bd9Sstevel@tonic-gate 	{acl2_access,
19147c478bd9Sstevel@tonic-gate 	    xdr_ACCESS2args, xdr_fastACCESS2args, sizeof (ACCESS2args),
19157c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
19167c478bd9Sstevel@tonic-gate 	    xdr_ACCESS2res, xdr_fastACCESS2res, sizeof (ACCESS2res),
19177c478bd9Sstevel@tonic-gate #else
19187c478bd9Sstevel@tonic-gate 	    xdr_ACCESS2res, NULL_xdrproc_t, sizeof (ACCESS2res),
19197c478bd9Sstevel@tonic-gate #endif
19207c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT|RPC_MAPRESP,
19217c478bd9Sstevel@tonic-gate 	    acl2_access_getfh},
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 	/* ACL2_GETXATTRDIR = 5 */
19247c478bd9Sstevel@tonic-gate 	{acl2_getxattrdir,
19257c478bd9Sstevel@tonic-gate 	    xdr_GETXATTRDIR2args, NULL_xdrproc_t, sizeof (GETXATTRDIR2args),
19267c478bd9Sstevel@tonic-gate 	    xdr_GETXATTRDIR2res, NULL_xdrproc_t, sizeof (GETXATTRDIR2res),
19277c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
19287c478bd9Sstevel@tonic-gate 	    acl2_getxattrdir_getfh},
19297c478bd9Sstevel@tonic-gate };
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate static char *aclcallnames_v3[] = {
19327c478bd9Sstevel@tonic-gate 	"ACL3_NULL",
19337c478bd9Sstevel@tonic-gate 	"ACL3_GETACL",
19347c478bd9Sstevel@tonic-gate 	"ACL3_SETACL",
19357c478bd9Sstevel@tonic-gate 	"ACL3_GETXATTRDIR"
19367c478bd9Sstevel@tonic-gate };
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate static struct rpcdisp acldisptab_v3[] = {
19397c478bd9Sstevel@tonic-gate 	/*
19407c478bd9Sstevel@tonic-gate 	 * ACL VERSION 3
19417c478bd9Sstevel@tonic-gate 	 */
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 	/* ACL3_NULL = 0 */
19447c478bd9Sstevel@tonic-gate 	{rpc_null,
19457c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
19467c478bd9Sstevel@tonic-gate 	    xdr_void, NULL_xdrproc_t, 0,
19477c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
19487c478bd9Sstevel@tonic-gate 	    0},
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	/* ACL3_GETACL = 1 */
19517c478bd9Sstevel@tonic-gate 	{acl3_getacl,
19527c478bd9Sstevel@tonic-gate 	    xdr_GETACL3args, NULL_xdrproc_t, sizeof (GETACL3args),
19537c478bd9Sstevel@tonic-gate 	    xdr_GETACL3res, NULL_xdrproc_t, sizeof (GETACL3res),
19547c478bd9Sstevel@tonic-gate 	    acl3_getacl_free, RPC_IDEMPOTENT,
19557c478bd9Sstevel@tonic-gate 	    acl3_getacl_getfh},
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	/* ACL3_SETACL = 2 */
19587c478bd9Sstevel@tonic-gate 	{acl3_setacl,
19597c478bd9Sstevel@tonic-gate 	    xdr_SETACL3args, NULL_xdrproc_t, sizeof (SETACL3args),
19607c478bd9Sstevel@tonic-gate 	    xdr_SETACL3res, NULL_xdrproc_t, sizeof (SETACL3res),
19617c478bd9Sstevel@tonic-gate 	    nullfree, 0,
19627c478bd9Sstevel@tonic-gate 	    acl3_setacl_getfh},
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	/* ACL3_GETXATTRDIR = 3 */
19657c478bd9Sstevel@tonic-gate 	{acl3_getxattrdir,
19667c478bd9Sstevel@tonic-gate 	    xdr_GETXATTRDIR3args, NULL_xdrproc_t, sizeof (GETXATTRDIR3args),
19677c478bd9Sstevel@tonic-gate 	    xdr_GETXATTRDIR3res, NULL_xdrproc_t, sizeof (GETXATTRDIR3res),
19687c478bd9Sstevel@tonic-gate 	    nullfree, RPC_IDEMPOTENT,
19697c478bd9Sstevel@tonic-gate 	    acl3_getxattrdir_getfh},
19707c478bd9Sstevel@tonic-gate };
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate static struct rpc_disptable acl_disptable[] = {
19737c478bd9Sstevel@tonic-gate 	{sizeof (acldisptab_v2) / sizeof (acldisptab_v2[0]),
19747c478bd9Sstevel@tonic-gate 		aclcallnames_v2,
19750dfe541eSEvan Layton 		acldisptab_v2},
19767c478bd9Sstevel@tonic-gate 	{sizeof (acldisptab_v3) / sizeof (acldisptab_v3[0]),
19777c478bd9Sstevel@tonic-gate 		aclcallnames_v3,
19780dfe541eSEvan Layton 		acldisptab_v3},
19797c478bd9Sstevel@tonic-gate };
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate static void
acl_dispatch(struct svc_req * req,SVCXPRT * xprt)19827c478bd9Sstevel@tonic-gate acl_dispatch(struct svc_req *req, SVCXPRT *xprt)
19837c478bd9Sstevel@tonic-gate {
19847c478bd9Sstevel@tonic-gate 	common_dispatch(req, xprt, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,
1985b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    "ACL", acl_disptable);
19867c478bd9Sstevel@tonic-gate }
19877c478bd9Sstevel@tonic-gate 
19887c478bd9Sstevel@tonic-gate int
checkwin(int flavor,int window,struct svc_req * req)19897c478bd9Sstevel@tonic-gate checkwin(int flavor, int window, struct svc_req *req)
19907c478bd9Sstevel@tonic-gate {
19917c478bd9Sstevel@tonic-gate 	struct authdes_cred *adc;
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	switch (flavor) {
19947c478bd9Sstevel@tonic-gate 	case AUTH_DES:
19957c478bd9Sstevel@tonic-gate 		adc = (struct authdes_cred *)req->rq_clntcred;
1996b1cdc720SAlex Wilson 		CTASSERT(sizeof (struct authdes_cred) <= RQCRED_SIZE);
19977c478bd9Sstevel@tonic-gate 		if (adc->adc_fullname.window > window)
19987c478bd9Sstevel@tonic-gate 			return (0);
19997c478bd9Sstevel@tonic-gate 		break;
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 	default:
20027c478bd9Sstevel@tonic-gate 		break;
20037c478bd9Sstevel@tonic-gate 	}
20047c478bd9Sstevel@tonic-gate 	return (1);
20057c478bd9Sstevel@tonic-gate }
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate 
20087c478bd9Sstevel@tonic-gate /*
20097c478bd9Sstevel@tonic-gate  * checkauth() will check the access permission against the export
20107c478bd9Sstevel@tonic-gate  * information.  Then map root uid/gid to appropriate uid/gid.
20117c478bd9Sstevel@tonic-gate  *
20127c478bd9Sstevel@tonic-gate  * This routine is used by NFS V3 and V2 code.
20137c478bd9Sstevel@tonic-gate  */
20147c478bd9Sstevel@tonic-gate static int
checkauth(struct exportinfo * exi,struct svc_req * req,cred_t * cr,int anon_ok,bool_t publicfh_ok,bool_t * ro)20157c478bd9Sstevel@tonic-gate checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok,
20165cb0d679SMarcel Telka     bool_t publicfh_ok, bool_t *ro)
20177c478bd9Sstevel@tonic-gate {
20187c478bd9Sstevel@tonic-gate 	int i, nfsflavor, rpcflavor, stat, access;
20197c478bd9Sstevel@tonic-gate 	struct secinfo *secp;
20207c478bd9Sstevel@tonic-gate 	caddr_t principal;
20217c478bd9Sstevel@tonic-gate 	char buf[INET6_ADDRSTRLEN]; /* to hold both IPv4 and IPv6 addr */
20227c478bd9Sstevel@tonic-gate 	int anon_res = 0;
20237c478bd9Sstevel@tonic-gate 
20245cb0d679SMarcel Telka 	uid_t uid;
20255cb0d679SMarcel Telka 	gid_t gid;
202689621fe1SMarcel Telka 	uint_t ngids;
202789621fe1SMarcel Telka 	gid_t *gids;
20285cb0d679SMarcel Telka 
20297c478bd9Sstevel@tonic-gate 	/*
2030b4ff7163SThomas Haynes 	 * Check for privileged port number
2031b4ff7163SThomas Haynes 	 * N.B.:  this assumes that we know the format of a netbuf.
20327c478bd9Sstevel@tonic-gate 	 */
20337c478bd9Sstevel@tonic-gate 	if (nfs_portmon) {
20347c478bd9Sstevel@tonic-gate 		struct sockaddr *ca;
20357c478bd9Sstevel@tonic-gate 		ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 		if (ca == NULL)
20387c478bd9Sstevel@tonic-gate 			return (0);
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 		if ((ca->sa_family == AF_INET &&
20417c478bd9Sstevel@tonic-gate 		    ntohs(((struct sockaddr_in *)ca)->sin_port) >=
20427c478bd9Sstevel@tonic-gate 		    IPPORT_RESERVED) ||
20437c478bd9Sstevel@tonic-gate 		    (ca->sa_family == AF_INET6 &&
20447c478bd9Sstevel@tonic-gate 		    ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >=
20457c478bd9Sstevel@tonic-gate 		    IPPORT_RESERVED)) {
20467c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
20477c478bd9Sstevel@tonic-gate 			    "nfs_server: client %s%ssent NFS request from "
20487c478bd9Sstevel@tonic-gate 			    "unprivileged port",
20497c478bd9Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf));
20507c478bd9Sstevel@tonic-gate 			return (0);
20517c478bd9Sstevel@tonic-gate 		}
20527c478bd9Sstevel@tonic-gate 	}
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 	/*
20557c478bd9Sstevel@tonic-gate 	 *  return 1 on success or 0 on failure
20567c478bd9Sstevel@tonic-gate 	 */
20577c478bd9Sstevel@tonic-gate 	stat = sec_svc_getcred(req, cr, &principal, &nfsflavor);
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	/*
20605cb0d679SMarcel Telka 	 * A failed AUTH_UNIX sec_svc_getcred() implies we couldn't set
20617c478bd9Sstevel@tonic-gate 	 * the credentials; below we map that to anonymous.
20627c478bd9Sstevel@tonic-gate 	 */
20637c478bd9Sstevel@tonic-gate 	if (!stat && nfsflavor != AUTH_UNIX) {
20647c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
20657c478bd9Sstevel@tonic-gate 		    "nfs_server: couldn't get unix cred for %s",
20667c478bd9Sstevel@tonic-gate 		    client_name(req));
20677c478bd9Sstevel@tonic-gate 		return (0);
20687c478bd9Sstevel@tonic-gate 	}
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 	/*
20717c478bd9Sstevel@tonic-gate 	 * Short circuit checkauth() on operations that support the
20727c478bd9Sstevel@tonic-gate 	 * public filehandle, and if the request for that operation
20737c478bd9Sstevel@tonic-gate 	 * is using the public filehandle. Note that we must call
20747c478bd9Sstevel@tonic-gate 	 * sec_svc_getcred() first so that xp_cookie is set to the
20757c478bd9Sstevel@tonic-gate 	 * right value. Normally xp_cookie is just the RPC flavor
20767c478bd9Sstevel@tonic-gate 	 * of the the request, but in the case of RPCSEC_GSS it
20777c478bd9Sstevel@tonic-gate 	 * could be a pseudo flavor.
20787c478bd9Sstevel@tonic-gate 	 */
20797c478bd9Sstevel@tonic-gate 	if (publicfh_ok)
20807c478bd9Sstevel@tonic-gate 		return (1);
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 	rpcflavor = req->rq_cred.oa_flavor;
20837c478bd9Sstevel@tonic-gate 	/*
20847c478bd9Sstevel@tonic-gate 	 * Check if the auth flavor is valid for this export
20857c478bd9Sstevel@tonic-gate 	 */
208689621fe1SMarcel Telka 	access = nfsauth_access(exi, req, cr, &uid, &gid, &ngids, &gids);
20877c478bd9Sstevel@tonic-gate 	if (access & NFSAUTH_DROP)
20887c478bd9Sstevel@tonic-gate 		return (-1);	/* drop the request */
20897c478bd9Sstevel@tonic-gate 
20905cb0d679SMarcel Telka 	if (access & NFSAUTH_RO)
20915cb0d679SMarcel Telka 		*ro = TRUE;
20925cb0d679SMarcel Telka 
20937c478bd9Sstevel@tonic-gate 	if (access & NFSAUTH_DENIED) {
20947c478bd9Sstevel@tonic-gate 		/*
20957c478bd9Sstevel@tonic-gate 		 * If anon_ok == 1 and we got NFSAUTH_DENIED, it was
20965cb0d679SMarcel Telka 		 * probably due to the flavor not matching during
20977c478bd9Sstevel@tonic-gate 		 * the mount attempt. So map the flavor to AUTH_NONE
20987c478bd9Sstevel@tonic-gate 		 * so that the credentials get mapped to the anonymous
20997c478bd9Sstevel@tonic-gate 		 * user.
21007c478bd9Sstevel@tonic-gate 		 */
21017c478bd9Sstevel@tonic-gate 		if (anon_ok == 1)
21027c478bd9Sstevel@tonic-gate 			rpcflavor = AUTH_NONE;
21037c478bd9Sstevel@tonic-gate 		else
21047c478bd9Sstevel@tonic-gate 			return (0);	/* deny access */
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 	} else if (access & NFSAUTH_MAPNONE) {
21077c478bd9Sstevel@tonic-gate 		/*
21087c478bd9Sstevel@tonic-gate 		 * Access was granted even though the flavor mismatched
21097c478bd9Sstevel@tonic-gate 		 * because AUTH_NONE was one of the exported flavors.
21107c478bd9Sstevel@tonic-gate 		 */
21117c478bd9Sstevel@tonic-gate 		rpcflavor = AUTH_NONE;
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 	} else if (access & NFSAUTH_WRONGSEC) {
21147c478bd9Sstevel@tonic-gate 		/*
2115829eb6b7SThomas Haynes 		 * NFSAUTH_WRONGSEC is used for NFSv4. If we get here,
2116829eb6b7SThomas Haynes 		 * it means a client ignored the list of allowed flavors
2117829eb6b7SThomas Haynes 		 * returned via the MOUNT protocol. So we just disallow it!
21187c478bd9Sstevel@tonic-gate 		 */
2119829eb6b7SThomas Haynes 		return (0);
21207c478bd9Sstevel@tonic-gate 	}
21217c478bd9Sstevel@tonic-gate 
212289621fe1SMarcel Telka 	if (rpcflavor != AUTH_SYS)
212389621fe1SMarcel Telka 		kmem_free(gids, ngids * sizeof (gid_t));
212489621fe1SMarcel Telka 
21257c478bd9Sstevel@tonic-gate 	switch (rpcflavor) {
21267c478bd9Sstevel@tonic-gate 	case AUTH_NONE:
21277c478bd9Sstevel@tonic-gate 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2128b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    exi->exi_export.ex_anon);
21297c478bd9Sstevel@tonic-gate 		(void) crsetgroups(cr, 0, NULL);
21307c478bd9Sstevel@tonic-gate 		break;
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	case AUTH_UNIX:
2133bd3561fbSToomas Soome 		if (!stat || (crgetuid(cr) == 0 &&
2134bd3561fbSToomas Soome 		    !(access & NFSAUTH_UIDMAP))) {
21357c478bd9Sstevel@tonic-gate 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2136b89a8333Snatalie li - Sun Microsystems - Irvine United States 			    exi->exi_export.ex_anon);
21377c478bd9Sstevel@tonic-gate 			(void) crsetgroups(cr, 0, NULL);
21385cb0d679SMarcel Telka 		} else if (crgetuid(cr) == 0 && access & NFSAUTH_ROOT) {
2139b89a8333Snatalie li - Sun Microsystems - Irvine United States 			/*
2140b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * It is root, so apply rootid to get real UID
2141b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * Find the secinfo structure.  We should be able
2142b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * to find it by the time we reach here.
2143b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * nfsauth_access() has done the checking.
2144b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 */
2145b89a8333Snatalie li - Sun Microsystems - Irvine United States 			secp = NULL;
2146b89a8333Snatalie li - Sun Microsystems - Irvine United States 			for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2147b89a8333Snatalie li - Sun Microsystems - Irvine United States 				struct secinfo *sptr;
2148b89a8333Snatalie li - Sun Microsystems - Irvine United States 				sptr = &exi->exi_export.ex_secinfo[i];
2149b89a8333Snatalie li - Sun Microsystems - Irvine United States 				if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
2150b89a8333Snatalie li - Sun Microsystems - Irvine United States 					secp = sptr;
2151b89a8333Snatalie li - Sun Microsystems - Irvine United States 					break;
2152b89a8333Snatalie li - Sun Microsystems - Irvine United States 				}
2153b89a8333Snatalie li - Sun Microsystems - Irvine United States 			}
2154b89a8333Snatalie li - Sun Microsystems - Irvine United States 			if (secp != NULL) {
2155b89a8333Snatalie li - Sun Microsystems - Irvine United States 				(void) crsetugid(cr, secp->s_rootid,
2156b89a8333Snatalie li - Sun Microsystems - Irvine United States 				    secp->s_rootid);
2157b89a8333Snatalie li - Sun Microsystems - Irvine United States 				(void) crsetgroups(cr, 0, NULL);
2158b89a8333Snatalie li - Sun Microsystems - Irvine United States 			}
21595cb0d679SMarcel Telka 		} else if (crgetuid(cr) != uid || crgetgid(cr) != gid) {
21605cb0d679SMarcel Telka 			if (crsetugid(cr, uid, gid) != 0)
21615cb0d679SMarcel Telka 				anon_res = crsetugid(cr,
21625cb0d679SMarcel Telka 				    exi->exi_export.ex_anon,
21635cb0d679SMarcel Telka 				    exi->exi_export.ex_anon);
21645cb0d679SMarcel Telka 			(void) crsetgroups(cr, 0, NULL);
216589621fe1SMarcel Telka 		} else if (access & NFSAUTH_GROUPS) {
216689621fe1SMarcel Telka 			(void) crsetgroups(cr, ngids, gids);
21677c478bd9Sstevel@tonic-gate 		}
21685cb0d679SMarcel Telka 
216989621fe1SMarcel Telka 		kmem_free(gids, ngids * sizeof (gid_t));
217089621fe1SMarcel Telka 
21717c478bd9Sstevel@tonic-gate 		break;
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	case AUTH_DES:
21747c478bd9Sstevel@tonic-gate 	case RPCSEC_GSS:
21757c478bd9Sstevel@tonic-gate 		/*
21767c478bd9Sstevel@tonic-gate 		 *  Find the secinfo structure.  We should be able
21777c478bd9Sstevel@tonic-gate 		 *  to find it by the time we reach here.
21787c478bd9Sstevel@tonic-gate 		 *  nfsauth_access() has done the checking.
21797c478bd9Sstevel@tonic-gate 		 */
21807c478bd9Sstevel@tonic-gate 		secp = NULL;
21817c478bd9Sstevel@tonic-gate 		for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
21827c478bd9Sstevel@tonic-gate 			if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
21837c478bd9Sstevel@tonic-gate 			    nfsflavor) {
21847c478bd9Sstevel@tonic-gate 				secp = &exi->exi_export.ex_secinfo[i];
21857c478bd9Sstevel@tonic-gate 				break;
21867c478bd9Sstevel@tonic-gate 			}
21877c478bd9Sstevel@tonic-gate 		}
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 		if (!secp) {
21907c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "nfs_server: client %s%shad "
21917c478bd9Sstevel@tonic-gate 			    "no secinfo data for flavor %d",
21927c478bd9Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf),
21937c478bd9Sstevel@tonic-gate 			    nfsflavor);
21947c478bd9Sstevel@tonic-gate 			return (0);
21957c478bd9Sstevel@tonic-gate 		}
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 		if (!checkwin(rpcflavor, secp->s_window, req)) {
21987c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
21997c478bd9Sstevel@tonic-gate 			    "nfs_server: client %s%sused invalid "
22007c478bd9Sstevel@tonic-gate 			    "auth window value",
22017c478bd9Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf));
22027c478bd9Sstevel@tonic-gate 			return (0);
22037c478bd9Sstevel@tonic-gate 		}
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 		/*
22067c478bd9Sstevel@tonic-gate 		 * Map root principals listed in the share's root= list to root,
22077c478bd9Sstevel@tonic-gate 		 * and map any others principals that were mapped to root by RPC
22087c478bd9Sstevel@tonic-gate 		 * to anon.
22097c478bd9Sstevel@tonic-gate 		 */
22107c478bd9Sstevel@tonic-gate 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
2211b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    secp->s_rootcnt, secp->s_rootnames)) {
2212b89a8333Snatalie li - Sun Microsystems - Irvine United States 			if (crgetuid(cr) == 0 && secp->s_rootid == 0)
22137c478bd9Sstevel@tonic-gate 				return (1);
22147c478bd9Sstevel@tonic-gate 
2215b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2216b89a8333Snatalie li - Sun Microsystems - Irvine United States 			(void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 			/*
22197c478bd9Sstevel@tonic-gate 			 * NOTE: If and when kernel-land privilege tracing is
22207c478bd9Sstevel@tonic-gate 			 * added this may have to be replaced with code that
22217c478bd9Sstevel@tonic-gate 			 * retrieves root's supplementary groups (e.g., using
22227c478bd9Sstevel@tonic-gate 			 * kgss_get_group_info().  In the meantime principals
22237c478bd9Sstevel@tonic-gate 			 * mapped to uid 0 get all privileges, so setting cr's
22247c478bd9Sstevel@tonic-gate 			 * supplementary groups for them does nothing.
22257c478bd9Sstevel@tonic-gate 			 */
22267c478bd9Sstevel@tonic-gate 			(void) crsetgroups(cr, 0, NULL);
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 			return (1);
22297c478bd9Sstevel@tonic-gate 		}
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 		/*
22327c478bd9Sstevel@tonic-gate 		 * Not a root princ, or not in root list, map UID 0/nobody to
22337c478bd9Sstevel@tonic-gate 		 * the anon ID for the share.  (RPC sets cr's UIDs and GIDs to
22347c478bd9Sstevel@tonic-gate 		 * UID_NOBODY and GID_NOBODY, respectively.)
22357c478bd9Sstevel@tonic-gate 		 */
22367c478bd9Sstevel@tonic-gate 		if (crgetuid(cr) != 0 &&
22377c478bd9Sstevel@tonic-gate 		    (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
22387c478bd9Sstevel@tonic-gate 			return (1);
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2241b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    exi->exi_export.ex_anon);
22427c478bd9Sstevel@tonic-gate 		(void) crsetgroups(cr, 0, NULL);
22437c478bd9Sstevel@tonic-gate 		break;
22447c478bd9Sstevel@tonic-gate 	default:
22457c478bd9Sstevel@tonic-gate 		return (0);
22467c478bd9Sstevel@tonic-gate 	} /* switch on rpcflavor */
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	/*
22497c478bd9Sstevel@tonic-gate 	 * Even if anon access is disallowed via ex_anon == -1, we allow
22507c478bd9Sstevel@tonic-gate 	 * this access if anon_ok is set.  So set creds to the default
22517c478bd9Sstevel@tonic-gate 	 * "nobody" id.
22527c478bd9Sstevel@tonic-gate 	 */
22537c478bd9Sstevel@tonic-gate 	if (anon_res != 0) {
22547c478bd9Sstevel@tonic-gate 		if (anon_ok == 0) {
22557c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
22567c478bd9Sstevel@tonic-gate 			    "nfs_server: client %s%ssent wrong "
22577c478bd9Sstevel@tonic-gate 			    "authentication for %s",
22587c478bd9Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf),
22597c478bd9Sstevel@tonic-gate 			    exi->exi_export.ex_path ?
22607c478bd9Sstevel@tonic-gate 			    exi->exi_export.ex_path : "?");
22617c478bd9Sstevel@tonic-gate 			return (0);
22627c478bd9Sstevel@tonic-gate 		}
22637c478bd9Sstevel@tonic-gate 
22647c478bd9Sstevel@tonic-gate 		if (crsetugid(cr, UID_NOBODY, GID_NOBODY) != 0)
22657c478bd9Sstevel@tonic-gate 			return (0);
22667c478bd9Sstevel@tonic-gate 	}
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 	return (1);
22697c478bd9Sstevel@tonic-gate }
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate /*
22727c478bd9Sstevel@tonic-gate  * returns 0 on failure, -1 on a drop, -2 on wrong security flavor,
22737c478bd9Sstevel@tonic-gate  * and 1 on success
22747c478bd9Sstevel@tonic-gate  */
22757c478bd9Sstevel@tonic-gate int
checkauth4(struct compound_state * cs,struct svc_req * req)22767c478bd9Sstevel@tonic-gate checkauth4(struct compound_state *cs, struct svc_req *req)
22777c478bd9Sstevel@tonic-gate {
22787c478bd9Sstevel@tonic-gate 	int i, rpcflavor, access;
22797c478bd9Sstevel@tonic-gate 	struct secinfo *secp;
22807c478bd9Sstevel@tonic-gate 	char buf[MAXHOST + 1];
22817c478bd9Sstevel@tonic-gate 	int anon_res = 0, nfsflavor;
22827c478bd9Sstevel@tonic-gate 	struct exportinfo *exi;
22837c478bd9Sstevel@tonic-gate 	cred_t	*cr;
22847c478bd9Sstevel@tonic-gate 	caddr_t	principal;
22857c478bd9Sstevel@tonic-gate 
22865cb0d679SMarcel Telka 	uid_t uid;
22875cb0d679SMarcel Telka 	gid_t gid;
228889621fe1SMarcel Telka 	uint_t ngids;
228989621fe1SMarcel Telka 	gid_t *gids;
22905cb0d679SMarcel Telka 
22917c478bd9Sstevel@tonic-gate 	exi = cs->exi;
22927c478bd9Sstevel@tonic-gate 	cr = cs->cr;
22937c478bd9Sstevel@tonic-gate 	principal = cs->principal;
22947c478bd9Sstevel@tonic-gate 	nfsflavor = cs->nfsflavor;
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 	ASSERT(cr != NULL);
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 	rpcflavor = req->rq_cred.oa_flavor;
22997c478bd9Sstevel@tonic-gate 	cs->access &= ~CS_ACCESS_LIMITED;
23007c478bd9Sstevel@tonic-gate 
2301b4ff7163SThomas Haynes 	/*
2302b4ff7163SThomas Haynes 	 * Check for privileged port number
2303b4ff7163SThomas Haynes 	 * N.B.:  this assumes that we know the format of a netbuf.
2304b4ff7163SThomas Haynes 	 */
2305b4ff7163SThomas Haynes 	if (nfs_portmon) {
2306b4ff7163SThomas Haynes 		struct sockaddr *ca;
2307b4ff7163SThomas Haynes 		ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2308b4ff7163SThomas Haynes 
2309b4ff7163SThomas Haynes 		if (ca == NULL)
2310b4ff7163SThomas Haynes 			return (0);
2311b4ff7163SThomas Haynes 
2312b4ff7163SThomas Haynes 		if ((ca->sa_family == AF_INET &&
2313b4ff7163SThomas Haynes 		    ntohs(((struct sockaddr_in *)ca)->sin_port) >=
2314b4ff7163SThomas Haynes 		    IPPORT_RESERVED) ||
2315b4ff7163SThomas Haynes 		    (ca->sa_family == AF_INET6 &&
2316b4ff7163SThomas Haynes 		    ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >=
2317b4ff7163SThomas Haynes 		    IPPORT_RESERVED)) {
2318b4ff7163SThomas Haynes 			cmn_err(CE_NOTE,
2319b4ff7163SThomas Haynes 			    "nfs_server: client %s%ssent NFSv4 request from "
2320b4ff7163SThomas Haynes 			    "unprivileged port",
2321b4ff7163SThomas Haynes 			    client_name(req), client_addr(req, buf));
2322b4ff7163SThomas Haynes 			return (0);
2323b4ff7163SThomas Haynes 		}
2324b4ff7163SThomas Haynes 	}
2325b4ff7163SThomas Haynes 
23267c478bd9Sstevel@tonic-gate 	/*
23277c478bd9Sstevel@tonic-gate 	 * Check the access right per auth flavor on the vnode of
23287c478bd9Sstevel@tonic-gate 	 * this export for the given request.
23297c478bd9Sstevel@tonic-gate 	 */
233089621fe1SMarcel Telka 	access = nfsauth4_access(cs->exi, cs->vp, req, cr, &uid, &gid, &ngids,
233189621fe1SMarcel Telka 	    &gids);
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 	if (access & NFSAUTH_WRONGSEC)
23347c478bd9Sstevel@tonic-gate 		return (-2);	/* no access for this security flavor */
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate 	if (access & NFSAUTH_DROP)
23377c478bd9Sstevel@tonic-gate 		return (-1);	/* drop the request */
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate 	if (access & NFSAUTH_DENIED) {
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate 		if (exi->exi_export.ex_seccnt > 0)
23427c478bd9Sstevel@tonic-gate 			return (0);	/* deny access */
23437c478bd9Sstevel@tonic-gate 
23447c478bd9Sstevel@tonic-gate 	} else if (access & NFSAUTH_LIMITED) {
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 		cs->access |= CS_ACCESS_LIMITED;
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 	} else if (access & NFSAUTH_MAPNONE) {
23497c478bd9Sstevel@tonic-gate 		/*
23507c478bd9Sstevel@tonic-gate 		 * Access was granted even though the flavor mismatched
23517c478bd9Sstevel@tonic-gate 		 * because AUTH_NONE was one of the exported flavors.
23527c478bd9Sstevel@tonic-gate 		 */
23537c478bd9Sstevel@tonic-gate 		rpcflavor = AUTH_NONE;
23547c478bd9Sstevel@tonic-gate 	}
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 	/*
23577c478bd9Sstevel@tonic-gate 	 * XXX probably need to redo some of it for nfsv4?
23587c478bd9Sstevel@tonic-gate 	 * return 1 on success or 0 on failure
23597c478bd9Sstevel@tonic-gate 	 */
23607c478bd9Sstevel@tonic-gate 
236189621fe1SMarcel Telka 	if (rpcflavor != AUTH_SYS)
236289621fe1SMarcel Telka 		kmem_free(gids, ngids * sizeof (gid_t));
236389621fe1SMarcel Telka 
23647c478bd9Sstevel@tonic-gate 	switch (rpcflavor) {
23657c478bd9Sstevel@tonic-gate 	case AUTH_NONE:
23667c478bd9Sstevel@tonic-gate 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2367b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    exi->exi_export.ex_anon);
23687c478bd9Sstevel@tonic-gate 		(void) crsetgroups(cr, 0, NULL);
23697c478bd9Sstevel@tonic-gate 		break;
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	case AUTH_UNIX:
23725cb0d679SMarcel Telka 		if (crgetuid(cr) == 0 && !(access & NFSAUTH_UIDMAP)) {
23737c478bd9Sstevel@tonic-gate 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2374b89a8333Snatalie li - Sun Microsystems - Irvine United States 			    exi->exi_export.ex_anon);
23757c478bd9Sstevel@tonic-gate 			(void) crsetgroups(cr, 0, NULL);
2376b89a8333Snatalie li - Sun Microsystems - Irvine United States 		} else if (crgetuid(cr) == 0 && access & NFSAUTH_ROOT) {
2377b89a8333Snatalie li - Sun Microsystems - Irvine United States 			/*
2378b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * It is root, so apply rootid to get real UID
2379b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * Find the secinfo structure.  We should be able
2380b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * to find it by the time we reach here.
2381b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * nfsauth_access() has done the checking.
2382b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 */
2383b89a8333Snatalie li - Sun Microsystems - Irvine United States 			secp = NULL;
2384b89a8333Snatalie li - Sun Microsystems - Irvine United States 			for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2385b89a8333Snatalie li - Sun Microsystems - Irvine United States 				struct secinfo *sptr;
2386b89a8333Snatalie li - Sun Microsystems - Irvine United States 				sptr = &exi->exi_export.ex_secinfo[i];
2387b89a8333Snatalie li - Sun Microsystems - Irvine United States 				if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
2388b89a8333Snatalie li - Sun Microsystems - Irvine United States 					secp = &exi->exi_export.ex_secinfo[i];
2389b89a8333Snatalie li - Sun Microsystems - Irvine United States 					break;
2390b89a8333Snatalie li - Sun Microsystems - Irvine United States 				}
2391b89a8333Snatalie li - Sun Microsystems - Irvine United States 			}
2392b89a8333Snatalie li - Sun Microsystems - Irvine United States 			if (secp != NULL) {
2393b89a8333Snatalie li - Sun Microsystems - Irvine United States 				(void) crsetugid(cr, secp->s_rootid,
2394b89a8333Snatalie li - Sun Microsystems - Irvine United States 				    secp->s_rootid);
2395b89a8333Snatalie li - Sun Microsystems - Irvine United States 				(void) crsetgroups(cr, 0, NULL);
2396b89a8333Snatalie li - Sun Microsystems - Irvine United States 			}
23975cb0d679SMarcel Telka 		} else if (crgetuid(cr) != uid || crgetgid(cr) != gid) {
23985cb0d679SMarcel Telka 			if (crsetugid(cr, uid, gid) != 0)
23995cb0d679SMarcel Telka 				anon_res = crsetugid(cr,
24005cb0d679SMarcel Telka 				    exi->exi_export.ex_anon,
24015cb0d679SMarcel Telka 				    exi->exi_export.ex_anon);
24025cb0d679SMarcel Telka 			(void) crsetgroups(cr, 0, NULL);
240389621fe1SMarcel Telka 		} if (access & NFSAUTH_GROUPS) {
240489621fe1SMarcel Telka 			(void) crsetgroups(cr, ngids, gids);
24057c478bd9Sstevel@tonic-gate 		}
24065cb0d679SMarcel Telka 
240789621fe1SMarcel Telka 		kmem_free(gids, ngids * sizeof (gid_t));
240889621fe1SMarcel Telka 
24097c478bd9Sstevel@tonic-gate 		break;
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate 	default:
24127c478bd9Sstevel@tonic-gate 		/*
24137c478bd9Sstevel@tonic-gate 		 *  Find the secinfo structure.  We should be able
24147c478bd9Sstevel@tonic-gate 		 *  to find it by the time we reach here.
24157c478bd9Sstevel@tonic-gate 		 *  nfsauth_access() has done the checking.
24167c478bd9Sstevel@tonic-gate 		 */
24177c478bd9Sstevel@tonic-gate 		secp = NULL;
24187c478bd9Sstevel@tonic-gate 		for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
24197c478bd9Sstevel@tonic-gate 			if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
24207c478bd9Sstevel@tonic-gate 			    nfsflavor) {
24217c478bd9Sstevel@tonic-gate 				secp = &exi->exi_export.ex_secinfo[i];
24227c478bd9Sstevel@tonic-gate 				break;
24237c478bd9Sstevel@tonic-gate 			}
24247c478bd9Sstevel@tonic-gate 		}
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 		if (!secp) {
24277c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "nfs_server: client %s%shad "
24287c478bd9Sstevel@tonic-gate 			    "no secinfo data for flavor %d",
24297c478bd9Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf),
24307c478bd9Sstevel@tonic-gate 			    nfsflavor);
24317c478bd9Sstevel@tonic-gate 			return (0);
24327c478bd9Sstevel@tonic-gate 		}
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate 		if (!checkwin(rpcflavor, secp->s_window, req)) {
24357c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
24367c478bd9Sstevel@tonic-gate 			    "nfs_server: client %s%sused invalid "
24377c478bd9Sstevel@tonic-gate 			    "auth window value",
24387c478bd9Sstevel@tonic-gate 			    client_name(req), client_addr(req, buf));
24397c478bd9Sstevel@tonic-gate 			return (0);
24407c478bd9Sstevel@tonic-gate 		}
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 		/*
24437c478bd9Sstevel@tonic-gate 		 * Map root principals listed in the share's root= list to root,
24447c478bd9Sstevel@tonic-gate 		 * and map any others principals that were mapped to root by RPC
2445b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * to anon. If not going to anon, set to rootid (root_mapping).
24467c478bd9Sstevel@tonic-gate 		 */
24477c478bd9Sstevel@tonic-gate 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
2448b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    secp->s_rootcnt, secp->s_rootnames)) {
2449b89a8333Snatalie li - Sun Microsystems - Irvine United States 			if (crgetuid(cr) == 0 && secp->s_rootid == 0)
24507c478bd9Sstevel@tonic-gate 				return (1);
24517c478bd9Sstevel@tonic-gate 
2452b89a8333Snatalie li - Sun Microsystems - Irvine United States 			(void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 			/*
24557c478bd9Sstevel@tonic-gate 			 * NOTE: If and when kernel-land privilege tracing is
24567c478bd9Sstevel@tonic-gate 			 * added this may have to be replaced with code that
24577c478bd9Sstevel@tonic-gate 			 * retrieves root's supplementary groups (e.g., using
24587c478bd9Sstevel@tonic-gate 			 * kgss_get_group_info().  In the meantime principals
24597c478bd9Sstevel@tonic-gate 			 * mapped to uid 0 get all privileges, so setting cr's
24607c478bd9Sstevel@tonic-gate 			 * supplementary groups for them does nothing.
24617c478bd9Sstevel@tonic-gate 			 */
24627c478bd9Sstevel@tonic-gate 			(void) crsetgroups(cr, 0, NULL);
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate 			return (1);
24657c478bd9Sstevel@tonic-gate 		}
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 		/*
24687c478bd9Sstevel@tonic-gate 		 * Not a root princ, or not in root list, map UID 0/nobody to
24697c478bd9Sstevel@tonic-gate 		 * the anon ID for the share.  (RPC sets cr's UIDs and GIDs to
24707c478bd9Sstevel@tonic-gate 		 * UID_NOBODY and GID_NOBODY, respectively.)
24717c478bd9Sstevel@tonic-gate 		 */
24727c478bd9Sstevel@tonic-gate 		if (crgetuid(cr) != 0 &&
24737c478bd9Sstevel@tonic-gate 		    (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
24747c478bd9Sstevel@tonic-gate 			return (1);
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2477b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    exi->exi_export.ex_anon);
24787c478bd9Sstevel@tonic-gate 		(void) crsetgroups(cr, 0, NULL);
24797c478bd9Sstevel@tonic-gate 		break;
24807c478bd9Sstevel@tonic-gate 	} /* switch on rpcflavor */
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	/*
24837c478bd9Sstevel@tonic-gate 	 * Even if anon access is disallowed via ex_anon == -1, we allow
24847c478bd9Sstevel@tonic-gate 	 * this access if anon_ok is set.  So set creds to the default
24857c478bd9Sstevel@tonic-gate 	 * "nobody" id.
24867c478bd9Sstevel@tonic-gate 	 */
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate 	if (anon_res != 0) {
24897c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
2490b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    "nfs_server: client %s%ssent wrong "
2491b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    "authentication for %s",
2492b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    client_name(req), client_addr(req, buf),
2493b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    exi->exi_export.ex_path ?
2494b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    exi->exi_export.ex_path : "?");
24957c478bd9Sstevel@tonic-gate 		return (0);
24967c478bd9Sstevel@tonic-gate 	}
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 	return (1);
24997c478bd9Sstevel@tonic-gate }
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate static char *
client_name(struct svc_req * req)25037c478bd9Sstevel@tonic-gate client_name(struct svc_req *req)
25047c478bd9Sstevel@tonic-gate {
25057c478bd9Sstevel@tonic-gate 	char *hostname = NULL;
25067c478bd9Sstevel@tonic-gate 
25077c478bd9Sstevel@tonic-gate 	/*
25087c478bd9Sstevel@tonic-gate 	 * If it's a Unix cred then use the
25097c478bd9Sstevel@tonic-gate 	 * hostname from the credential.
25107c478bd9Sstevel@tonic-gate 	 */
25117c478bd9Sstevel@tonic-gate 	if (req->rq_cred.oa_flavor == AUTH_UNIX) {
25127c478bd9Sstevel@tonic-gate 		hostname = ((struct authunix_parms *)
25137c478bd9Sstevel@tonic-gate 		    req->rq_clntcred)->aup_machname;
25147c478bd9Sstevel@tonic-gate 	}
25157c478bd9Sstevel@tonic-gate 	if (hostname == NULL)
25167c478bd9Sstevel@tonic-gate 		hostname = "";
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 	return (hostname);
25197c478bd9Sstevel@tonic-gate }
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate static char *
client_addr(struct svc_req * req,char * buf)25227c478bd9Sstevel@tonic-gate client_addr(struct svc_req *req, char *buf)
25237c478bd9Sstevel@tonic-gate {
25247c478bd9Sstevel@tonic-gate 	struct sockaddr *ca;
25257c478bd9Sstevel@tonic-gate 	uchar_t *b;
25267c478bd9Sstevel@tonic-gate 	char *frontspace = "";
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate 	/*
25297c478bd9Sstevel@tonic-gate 	 * We assume we are called in tandem with client_name and the
25307c478bd9Sstevel@tonic-gate 	 * format string looks like "...client %s%sblah blah..."
25317c478bd9Sstevel@tonic-gate 	 *
25327c478bd9Sstevel@tonic-gate 	 * If it's a Unix cred then client_name returned
25337c478bd9Sstevel@tonic-gate 	 * a host name, so we need insert a space between host name
25347c478bd9Sstevel@tonic-gate 	 * and IP address.
25357c478bd9Sstevel@tonic-gate 	 */
25367c478bd9Sstevel@tonic-gate 	if (req->rq_cred.oa_flavor == AUTH_UNIX)
25377c478bd9Sstevel@tonic-gate 		frontspace = " ";
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 	/*
25407c478bd9Sstevel@tonic-gate 	 * Convert the caller's IP address to a dotted string
25417c478bd9Sstevel@tonic-gate 	 */
25427c478bd9Sstevel@tonic-gate 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	if (ca->sa_family == AF_INET) {
2545b89a8333Snatalie li - Sun Microsystems - Irvine United States 		b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr;
2546b89a8333Snatalie li - Sun Microsystems - Irvine United States 		(void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace,
2547b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF);
25487c478bd9Sstevel@tonic-gate 	} else if (ca->sa_family == AF_INET6) {
25497c478bd9Sstevel@tonic-gate 		struct sockaddr_in6 *sin6;
25507c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)ca;
25517c478bd9Sstevel@tonic-gate 		(void) kinet_ntop6((uchar_t *)&sin6->sin6_addr,
2552b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    buf, INET6_ADDRSTRLEN);
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	} else {
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate 		/*
25577c478bd9Sstevel@tonic-gate 		 * No IP address to print. If there was a host name
25587c478bd9Sstevel@tonic-gate 		 * printed, then we print a space.
25597c478bd9Sstevel@tonic-gate 		 */
25607c478bd9Sstevel@tonic-gate 		(void) sprintf(buf, frontspace);
25617c478bd9Sstevel@tonic-gate 	}
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 	return (buf);
25647c478bd9Sstevel@tonic-gate }
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate /*
25677c478bd9Sstevel@tonic-gate  * NFS Server initialization routine.  This routine should only be called
25687c478bd9Sstevel@tonic-gate  * once.  It performs the following tasks:
25697c478bd9Sstevel@tonic-gate  *	- Call sub-initialization routines (localize access to variables)
25707c478bd9Sstevel@tonic-gate  *	- Initialize all locks
25717c478bd9Sstevel@tonic-gate  *	- initialize the version 3 write verifier
25727c478bd9Sstevel@tonic-gate  */
25730dfe541eSEvan Layton void
nfs_srvinit(void)25747c478bd9Sstevel@tonic-gate nfs_srvinit(void)
25757c478bd9Sstevel@tonic-gate {
25767c478bd9Sstevel@tonic-gate 
25770dfe541eSEvan Layton 	/* Truly global stuff in this module (not per zone) */
25780dfe541eSEvan Layton 	rw_init(&nfssrv_globals_rwl, NULL, RW_DEFAULT, NULL);
25790dfe541eSEvan Layton 	list_create(&nfssrv_globals_list, sizeof (nfs_globals_t),
25800dfe541eSEvan Layton 	    offsetof(nfs_globals_t, nfs_g_link));
25810dfe541eSEvan Layton 	tsd_create(&nfs_server_tsd_key, NULL);
25820dfe541eSEvan Layton 
25830dfe541eSEvan Layton 	/* The order here is important */
25840dfe541eSEvan Layton 	nfs_exportinit();
25857c478bd9Sstevel@tonic-gate 	rfs_srvrinit();
25867c478bd9Sstevel@tonic-gate 	rfs3_srvrinit();
25870dfe541eSEvan Layton 	rfs4_srvrinit();
25887c478bd9Sstevel@tonic-gate 	nfsauth_init();
25897c478bd9Sstevel@tonic-gate 
25900dfe541eSEvan Layton 	/*
25910dfe541eSEvan Layton 	 * NFS server zone-specific global variables
25920dfe541eSEvan Layton 	 * Note the zone_init is called for the GZ here.
25930dfe541eSEvan Layton 	 */
25940dfe541eSEvan Layton 	zone_key_create(&nfssrv_zone_key, nfs_server_zone_init,
25950dfe541eSEvan Layton 	    nfs_server_zone_shutdown, nfs_server_zone_fini);
25967c478bd9Sstevel@tonic-gate }
25977c478bd9Sstevel@tonic-gate 
25987c478bd9Sstevel@tonic-gate /*
25997c478bd9Sstevel@tonic-gate  * NFS Server finalization routine. This routine is called to cleanup the
26007c478bd9Sstevel@tonic-gate  * initialization work previously performed if the NFS server module could
26017c478bd9Sstevel@tonic-gate  * not be loaded correctly.
26027c478bd9Sstevel@tonic-gate  */
26037c478bd9Sstevel@tonic-gate void
nfs_srvfini(void)26047c478bd9Sstevel@tonic-gate nfs_srvfini(void)
26057c478bd9Sstevel@tonic-gate {
26060dfe541eSEvan Layton 
26070dfe541eSEvan Layton 	/*
26080dfe541eSEvan Layton 	 * NFS server zone-specific global variables
26090dfe541eSEvan Layton 	 * Note the zone_fini is called for the GZ here.
26100dfe541eSEvan Layton 	 */
26110dfe541eSEvan Layton 	(void) zone_key_delete(nfssrv_zone_key);
26120dfe541eSEvan Layton 
26130dfe541eSEvan Layton 	/* The order here is important (reverse of init) */
26147c478bd9Sstevel@tonic-gate 	nfsauth_fini();
26150dfe541eSEvan Layton 	rfs4_srvrfini();
26167c478bd9Sstevel@tonic-gate 	rfs3_srvrfini();
26177c478bd9Sstevel@tonic-gate 	rfs_srvrfini();
26187c478bd9Sstevel@tonic-gate 	nfs_exportfini();
26197c478bd9Sstevel@tonic-gate 
26200dfe541eSEvan Layton 	/* Truly global stuff in this module (not per zone) */
26210dfe541eSEvan Layton 	tsd_destroy(&nfs_server_tsd_key);
26220dfe541eSEvan Layton 	list_destroy(&nfssrv_globals_list);
26230dfe541eSEvan Layton 	rw_destroy(&nfssrv_globals_rwl);
26247c478bd9Sstevel@tonic-gate }
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate /*
26270dfe541eSEvan Layton  * Zone init, shutdown, fini functions for the NFS server
26280dfe541eSEvan Layton  *
26290dfe541eSEvan Layton  * This design is careful to create the entire hierarhcy of
26300dfe541eSEvan Layton  * NFS server "globals" (including those created by various
26310dfe541eSEvan Layton  * per-module *_zone_init functions, etc.) so that all these
26320dfe541eSEvan Layton  * objects have exactly the same lifetime.
26330dfe541eSEvan Layton  *
26340dfe541eSEvan Layton  * These objects are also kept on a list for two reasons:
26350dfe541eSEvan Layton  * 1: It makes finding these in mdb _much_ easier.
26360dfe541eSEvan Layton  * 2: It allows operating across all zone globals for
26370dfe541eSEvan Layton  *    functions like nfs_auth.c:exi_cache_reclaim
26387c478bd9Sstevel@tonic-gate  */
26390dfe541eSEvan Layton static void *
nfs_server_zone_init(zoneid_t zoneid)26400dfe541eSEvan Layton nfs_server_zone_init(zoneid_t zoneid)
26410dfe541eSEvan Layton {
26420dfe541eSEvan Layton 	nfs_globals_t *ng;
26430dfe541eSEvan Layton 
26440dfe541eSEvan Layton 	ng = kmem_zalloc(sizeof (*ng), KM_SLEEP);
26450dfe541eSEvan Layton 
2646*f44e1126SVitaliy Gusev 	ng->nfs_versmin = NFS_SRV_VERSMIN_DEFAULT;
2647*f44e1126SVitaliy Gusev 	ng->nfs_versmax = NFS_SRV_VERSMAX_DEFAULT;
26480dfe541eSEvan Layton 
26490dfe541eSEvan Layton 	/* Init the stuff to control start/stop */
26500dfe541eSEvan Layton 	ng->nfs_server_upordown = NFS_SERVER_STOPPED;
26510dfe541eSEvan Layton 	mutex_init(&ng->nfs_server_upordown_lock, NULL, MUTEX_DEFAULT, NULL);
26520dfe541eSEvan Layton 	cv_init(&ng->nfs_server_upordown_cv, NULL, CV_DEFAULT, NULL);
26530dfe541eSEvan Layton 	mutex_init(&ng->rdma_wait_mutex, NULL, MUTEX_DEFAULT, NULL);
26540dfe541eSEvan Layton 	cv_init(&ng->rdma_wait_cv, NULL, CV_DEFAULT, NULL);
26550dfe541eSEvan Layton 
26560dfe541eSEvan Layton 	ng->nfs_zoneid = zoneid;
26570dfe541eSEvan Layton 
26580dfe541eSEvan Layton 	/*
26590dfe541eSEvan Layton 	 * Order here is important.
26600dfe541eSEvan Layton 	 * export init must precede srv init calls.
26610dfe541eSEvan Layton 	 */
26620dfe541eSEvan Layton 	nfs_export_zone_init(ng);
26630dfe541eSEvan Layton 	rfs_stat_zone_init(ng);
26640dfe541eSEvan Layton 	rfs_srv_zone_init(ng);
26650dfe541eSEvan Layton 	rfs3_srv_zone_init(ng);
26660dfe541eSEvan Layton 	rfs4_srv_zone_init(ng);
26670dfe541eSEvan Layton 	nfsauth_zone_init(ng);
26680dfe541eSEvan Layton 
26690dfe541eSEvan Layton 	rw_enter(&nfssrv_globals_rwl, RW_WRITER);
26700dfe541eSEvan Layton 	list_insert_tail(&nfssrv_globals_list, ng);
26710dfe541eSEvan Layton 	rw_exit(&nfssrv_globals_rwl);
26720dfe541eSEvan Layton 
26730dfe541eSEvan Layton 	return (ng);
26740dfe541eSEvan Layton }
26757c478bd9Sstevel@tonic-gate 
26760dfe541eSEvan Layton /* ARGSUSED */
26770dfe541eSEvan Layton static void
nfs_server_zone_shutdown(zoneid_t zoneid,void * data)26780dfe541eSEvan Layton nfs_server_zone_shutdown(zoneid_t zoneid, void *data)
26790dfe541eSEvan Layton {
26800dfe541eSEvan Layton 	nfs_globals_t *ng;
26810dfe541eSEvan Layton 
26820dfe541eSEvan Layton 	ng = (nfs_globals_t *)data;
26830dfe541eSEvan Layton 
26840dfe541eSEvan Layton 	/*
26850dfe541eSEvan Layton 	 * Order is like _fini, but only
26860dfe541eSEvan Layton 	 * some modules need this hook.
26870dfe541eSEvan Layton 	 */
26880dfe541eSEvan Layton 	nfsauth_zone_shutdown(ng);
26890dfe541eSEvan Layton 	nfs_export_zone_shutdown(ng);
26900dfe541eSEvan Layton }
26910dfe541eSEvan Layton 
26920dfe541eSEvan Layton /* ARGSUSED */
26930dfe541eSEvan Layton static void
nfs_server_zone_fini(zoneid_t zoneid,void * data)26940dfe541eSEvan Layton nfs_server_zone_fini(zoneid_t zoneid, void *data)
26950dfe541eSEvan Layton {
26960dfe541eSEvan Layton 	nfs_globals_t *ng;
26970dfe541eSEvan Layton 
26980dfe541eSEvan Layton 	ng = (nfs_globals_t *)data;
26990dfe541eSEvan Layton 
27000dfe541eSEvan Layton 	rw_enter(&nfssrv_globals_rwl, RW_WRITER);
27010dfe541eSEvan Layton 	list_remove(&nfssrv_globals_list, ng);
27020dfe541eSEvan Layton 	rw_exit(&nfssrv_globals_rwl);
27030dfe541eSEvan Layton 
27040dfe541eSEvan Layton 	/*
27050dfe541eSEvan Layton 	 * Order here is important.
27060dfe541eSEvan Layton 	 * reverse order from init
27070dfe541eSEvan Layton 	 */
27080dfe541eSEvan Layton 	nfsauth_zone_fini(ng);
27090dfe541eSEvan Layton 	rfs4_srv_zone_fini(ng);
27100dfe541eSEvan Layton 	rfs3_srv_zone_fini(ng);
27110dfe541eSEvan Layton 	rfs_srv_zone_fini(ng);
27120dfe541eSEvan Layton 	rfs_stat_zone_fini(ng);
27130dfe541eSEvan Layton 	nfs_export_zone_fini(ng);
27140dfe541eSEvan Layton 
27150dfe541eSEvan Layton 	mutex_destroy(&ng->nfs_server_upordown_lock);
27160dfe541eSEvan Layton 	cv_destroy(&ng->nfs_server_upordown_cv);
27170dfe541eSEvan Layton 	mutex_destroy(&ng->rdma_wait_mutex);
27180dfe541eSEvan Layton 	cv_destroy(&ng->rdma_wait_cv);
27190dfe541eSEvan Layton 
27200dfe541eSEvan Layton 	kmem_free(ng, sizeof (*ng));
27210dfe541eSEvan Layton }
27220dfe541eSEvan Layton 
27230dfe541eSEvan Layton /*
27240dfe541eSEvan Layton  * Set up an iovec array of up to cnt pointers.
27250dfe541eSEvan Layton  */
27267c478bd9Sstevel@tonic-gate void
mblk_to_iov(mblk_t * m,int cnt,struct iovec * iovp)27277c478bd9Sstevel@tonic-gate mblk_to_iov(mblk_t *m, int cnt, struct iovec *iovp)
27287c478bd9Sstevel@tonic-gate {
27297c478bd9Sstevel@tonic-gate 	while (m != NULL && cnt-- > 0) {
27307c478bd9Sstevel@tonic-gate 		iovp->iov_base = (caddr_t)m->b_rptr;
27317c478bd9Sstevel@tonic-gate 		iovp->iov_len = (m->b_wptr - m->b_rptr);
27327c478bd9Sstevel@tonic-gate 		iovp++;
27337c478bd9Sstevel@tonic-gate 		m = m->b_cont;
27347c478bd9Sstevel@tonic-gate 	}
27357c478bd9Sstevel@tonic-gate }
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate /*
27387c478bd9Sstevel@tonic-gate  * Common code between NFS Version 2 and NFS Version 3 for the public
27397c478bd9Sstevel@tonic-gate  * filehandle multicomponent lookups.
27407c478bd9Sstevel@tonic-gate  */
27417c478bd9Sstevel@tonic-gate 
27427c478bd9Sstevel@tonic-gate /*
27437c478bd9Sstevel@tonic-gate  * Public filehandle evaluation of a multi-component lookup, following
27447c478bd9Sstevel@tonic-gate  * symbolic links, if necessary. This may result in a vnode in another
27457c478bd9Sstevel@tonic-gate  * filesystem, which is OK as long as the other filesystem is exported.
27467c478bd9Sstevel@tonic-gate  *
27477c478bd9Sstevel@tonic-gate  * Note that the exi will be set either to NULL or a new reference to the
27487c478bd9Sstevel@tonic-gate  * exportinfo struct that corresponds to the vnode of the multi-component path.
27497c478bd9Sstevel@tonic-gate  * It is the callers responsibility to release this reference.
27507c478bd9Sstevel@tonic-gate  */
27517c478bd9Sstevel@tonic-gate int
rfs_publicfh_mclookup(char * p,vnode_t * dvp,cred_t * cr,vnode_t ** vpp,struct exportinfo ** exi,struct sec_ol * sec)27527c478bd9Sstevel@tonic-gate rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
27537c478bd9Sstevel@tonic-gate     struct exportinfo **exi, struct sec_ol *sec)
27547c478bd9Sstevel@tonic-gate {
27557c478bd9Sstevel@tonic-gate 	int pathflag;
27567c478bd9Sstevel@tonic-gate 	vnode_t *mc_dvp = NULL;
27577c478bd9Sstevel@tonic-gate 	vnode_t *realvp;
27587c478bd9Sstevel@tonic-gate 	int error;
27597c478bd9Sstevel@tonic-gate 
27607c478bd9Sstevel@tonic-gate 	*exi = NULL;
27617c478bd9Sstevel@tonic-gate 
27627c478bd9Sstevel@tonic-gate 	/*
27637c478bd9Sstevel@tonic-gate 	 * check if the given path is a url or native path. Since p is
27647c478bd9Sstevel@tonic-gate 	 * modified by MCLpath(), it may be empty after returning from
27657c478bd9Sstevel@tonic-gate 	 * there, and should be checked.
27667c478bd9Sstevel@tonic-gate 	 */
27677c478bd9Sstevel@tonic-gate 	if ((pathflag = MCLpath(&p)) == -1)
27687c478bd9Sstevel@tonic-gate 		return (EIO);
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate 	/*
27717c478bd9Sstevel@tonic-gate 	 * If pathflag is SECURITY_QUERY, turn the SEC_QUERY bit
27727c478bd9Sstevel@tonic-gate 	 * on in sec->sec_flags. This bit will later serve as an
27737c478bd9Sstevel@tonic-gate 	 * indication in makefh_ol() or makefh3_ol() to overload the
27747c478bd9Sstevel@tonic-gate 	 * filehandle to contain the sec modes used by the server for
27757c478bd9Sstevel@tonic-gate 	 * the path.
27767c478bd9Sstevel@tonic-gate 	 */
27777c478bd9Sstevel@tonic-gate 	if (pathflag == SECURITY_QUERY) {
27787c478bd9Sstevel@tonic-gate 		if ((sec->sec_index = (uint_t)(*p)) > 0) {
27797c478bd9Sstevel@tonic-gate 			sec->sec_flags |= SEC_QUERY;
27807c478bd9Sstevel@tonic-gate 			p++;
27817c478bd9Sstevel@tonic-gate 			if ((pathflag = MCLpath(&p)) == -1)
27827c478bd9Sstevel@tonic-gate 				return (EIO);
27837c478bd9Sstevel@tonic-gate 		} else {
27847c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
27857c478bd9Sstevel@tonic-gate 			    "nfs_server: invalid security index %d, "
27867c478bd9Sstevel@tonic-gate 			    "violating WebNFS SNEGO protocol.", sec->sec_index);
27877c478bd9Sstevel@tonic-gate 			return (EIO);
27887c478bd9Sstevel@tonic-gate 		}
27897c478bd9Sstevel@tonic-gate 	}
27907c478bd9Sstevel@tonic-gate 
27917c478bd9Sstevel@tonic-gate 	if (p[0] == '\0') {
27927c478bd9Sstevel@tonic-gate 		error = ENOENT;
27937c478bd9Sstevel@tonic-gate 		goto publicfh_done;
27947c478bd9Sstevel@tonic-gate 	}
27957c478bd9Sstevel@tonic-gate 
27967c478bd9Sstevel@tonic-gate 	error = rfs_pathname(p, &mc_dvp, vpp, dvp, cr, pathflag);
27977c478bd9Sstevel@tonic-gate 
27987c478bd9Sstevel@tonic-gate 	/*
27997c478bd9Sstevel@tonic-gate 	 * If name resolves to "/" we get EINVAL since we asked for
28007c478bd9Sstevel@tonic-gate 	 * the vnode of the directory that the file is in. Try again
28017c478bd9Sstevel@tonic-gate 	 * with NULL directory vnode.
28027c478bd9Sstevel@tonic-gate 	 */
28037c478bd9Sstevel@tonic-gate 	if (error == EINVAL) {
28047c478bd9Sstevel@tonic-gate 		error = rfs_pathname(p, NULL, vpp, dvp, cr, pathflag);
28057c478bd9Sstevel@tonic-gate 		if (!error) {
28067c478bd9Sstevel@tonic-gate 			ASSERT(*vpp != NULL);
28077c478bd9Sstevel@tonic-gate 			if ((*vpp)->v_type == VDIR) {
28087c478bd9Sstevel@tonic-gate 				VN_HOLD(*vpp);
28097c478bd9Sstevel@tonic-gate 				mc_dvp = *vpp;
28107c478bd9Sstevel@tonic-gate 			} else {
28117c478bd9Sstevel@tonic-gate 				/*
28127c478bd9Sstevel@tonic-gate 				 * This should not happen, the filesystem is
28137c478bd9Sstevel@tonic-gate 				 * in an inconsistent state. Fail the lookup
28147c478bd9Sstevel@tonic-gate 				 * at this point.
28157c478bd9Sstevel@tonic-gate 				 */
28167c478bd9Sstevel@tonic-gate 				VN_RELE(*vpp);
28177c478bd9Sstevel@tonic-gate 				error = EINVAL;
28187c478bd9Sstevel@tonic-gate 			}
28197c478bd9Sstevel@tonic-gate 		}
28207c478bd9Sstevel@tonic-gate 	}
28217c478bd9Sstevel@tonic-gate 
28227c478bd9Sstevel@tonic-gate 	if (error)
28237c478bd9Sstevel@tonic-gate 		goto publicfh_done;
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate 	if (*vpp == NULL) {
28267c478bd9Sstevel@tonic-gate 		error = ENOENT;
28277c478bd9Sstevel@tonic-gate 		goto publicfh_done;
28287c478bd9Sstevel@tonic-gate 	}
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 	ASSERT(mc_dvp != NULL);
28317c478bd9Sstevel@tonic-gate 	ASSERT(*vpp != NULL);
28327c478bd9Sstevel@tonic-gate 
28337c478bd9Sstevel@tonic-gate 	if ((*vpp)->v_type == VDIR) {
28347c478bd9Sstevel@tonic-gate 		do {
28357c478bd9Sstevel@tonic-gate 			/*
28367c478bd9Sstevel@tonic-gate 			 * *vpp may be an AutoFS node, so we perform
28377c478bd9Sstevel@tonic-gate 			 * a VOP_ACCESS() to trigger the mount of the intended
28387c478bd9Sstevel@tonic-gate 			 * filesystem, so we can perform the lookup in the
28397c478bd9Sstevel@tonic-gate 			 * intended filesystem.
28407c478bd9Sstevel@tonic-gate 			 */
2841da6c28aaSamw 			(void) VOP_ACCESS(*vpp, 0, 0, cr, NULL);
28427c478bd9Sstevel@tonic-gate 
28437c478bd9Sstevel@tonic-gate 			/*
28447c478bd9Sstevel@tonic-gate 			 * If vnode is covered, get the
28457c478bd9Sstevel@tonic-gate 			 * the topmost vnode.
28467c478bd9Sstevel@tonic-gate 			 */
28477c478bd9Sstevel@tonic-gate 			if (vn_mountedvfs(*vpp) != NULL) {
28487c478bd9Sstevel@tonic-gate 				error = traverse(vpp);
28497c478bd9Sstevel@tonic-gate 				if (error) {
28507c478bd9Sstevel@tonic-gate 					VN_RELE(*vpp);
28517c478bd9Sstevel@tonic-gate 					goto publicfh_done;
28527c478bd9Sstevel@tonic-gate 				}
28537c478bd9Sstevel@tonic-gate 			}
28547c478bd9Sstevel@tonic-gate 
2855da6c28aaSamw 			if (VOP_REALVP(*vpp, &realvp, NULL) == 0 &&
2856da6c28aaSamw 			    realvp != *vpp) {
28577c478bd9Sstevel@tonic-gate 				/*
28587c478bd9Sstevel@tonic-gate 				 * If realvp is different from *vpp
28597c478bd9Sstevel@tonic-gate 				 * then release our reference on *vpp, so that
28607c478bd9Sstevel@tonic-gate 				 * the export access check be performed on the
28617c478bd9Sstevel@tonic-gate 				 * real filesystem instead.
28627c478bd9Sstevel@tonic-gate 				 */
28637c478bd9Sstevel@tonic-gate 				VN_HOLD(realvp);
28647c478bd9Sstevel@tonic-gate 				VN_RELE(*vpp);
28657c478bd9Sstevel@tonic-gate 				*vpp = realvp;
2866b89a8333Snatalie li - Sun Microsystems - Irvine United States 			} else {
2867b89a8333Snatalie li - Sun Microsystems - Irvine United States 				break;
2868b89a8333Snatalie li - Sun Microsystems - Irvine United States 			}
28697c478bd9Sstevel@tonic-gate 		/* LINTED */
28707c478bd9Sstevel@tonic-gate 		} while (TRUE);
28717c478bd9Sstevel@tonic-gate 
28727c478bd9Sstevel@tonic-gate 		/*
28737c478bd9Sstevel@tonic-gate 		 * Let nfs_vptexi() figure what the real parent is.
28747c478bd9Sstevel@tonic-gate 		 */
28757c478bd9Sstevel@tonic-gate 		VN_RELE(mc_dvp);
28767c478bd9Sstevel@tonic-gate 		mc_dvp = NULL;
28777c478bd9Sstevel@tonic-gate 
28787c478bd9Sstevel@tonic-gate 	} else {
28797c478bd9Sstevel@tonic-gate 		/*
28807c478bd9Sstevel@tonic-gate 		 * If vnode is covered, get the
28817c478bd9Sstevel@tonic-gate 		 * the topmost vnode.
28827c478bd9Sstevel@tonic-gate 		 */
28837c478bd9Sstevel@tonic-gate 		if (vn_mountedvfs(mc_dvp) != NULL) {
28847c478bd9Sstevel@tonic-gate 			error = traverse(&mc_dvp);
28857c478bd9Sstevel@tonic-gate 			if (error) {
2886b89a8333Snatalie li - Sun Microsystems - Irvine United States 				VN_RELE(*vpp);
2887b89a8333Snatalie li - Sun Microsystems - Irvine United States 				goto publicfh_done;
28887c478bd9Sstevel@tonic-gate 			}
28897c478bd9Sstevel@tonic-gate 		}
28907c478bd9Sstevel@tonic-gate 
2891da6c28aaSamw 		if (VOP_REALVP(mc_dvp, &realvp, NULL) == 0 &&
2892da6c28aaSamw 		    realvp != mc_dvp) {
28937c478bd9Sstevel@tonic-gate 			/*
28947c478bd9Sstevel@tonic-gate 			 * *vpp is a file, obtain realvp of the parent
28957c478bd9Sstevel@tonic-gate 			 * directory vnode.
28967c478bd9Sstevel@tonic-gate 			 */
28977c478bd9Sstevel@tonic-gate 			VN_HOLD(realvp);
28987c478bd9Sstevel@tonic-gate 			VN_RELE(mc_dvp);
28997c478bd9Sstevel@tonic-gate 			mc_dvp = realvp;
29007c478bd9Sstevel@tonic-gate 		}
29017c478bd9Sstevel@tonic-gate 	}
29027c478bd9Sstevel@tonic-gate 
29037c478bd9Sstevel@tonic-gate 	/*
29047c478bd9Sstevel@tonic-gate 	 * The pathname may take us from the public filesystem to another.
29057c478bd9Sstevel@tonic-gate 	 * If that's the case then just set the exportinfo to the new export
29067c478bd9Sstevel@tonic-gate 	 * and build filehandle for it. Thanks to per-access checking there's
29077c478bd9Sstevel@tonic-gate 	 * no security issues with doing this. If the client is not allowed
29087c478bd9Sstevel@tonic-gate 	 * access to this new export then it will get an access error when it
29097c478bd9Sstevel@tonic-gate 	 * tries to use the filehandle
29107c478bd9Sstevel@tonic-gate 	 */
2911bd3561fbSToomas Soome 	error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi);
2912bd3561fbSToomas Soome 	if (error != 0) {
29137c478bd9Sstevel@tonic-gate 		VN_RELE(*vpp);
29147c478bd9Sstevel@tonic-gate 		goto publicfh_done;
29157c478bd9Sstevel@tonic-gate 	}
29167c478bd9Sstevel@tonic-gate 
29177c478bd9Sstevel@tonic-gate 	/*
29187c478bd9Sstevel@tonic-gate 	 * Not allowed access to pseudo exports.
29197c478bd9Sstevel@tonic-gate 	 */
29207c478bd9Sstevel@tonic-gate 	if (PSEUDO(*exi)) {
29217c478bd9Sstevel@tonic-gate 		error = ENOENT;
29227c478bd9Sstevel@tonic-gate 		VN_RELE(*vpp);
29237c478bd9Sstevel@tonic-gate 		goto publicfh_done;
29247c478bd9Sstevel@tonic-gate 	}
29257c478bd9Sstevel@tonic-gate 
29267c478bd9Sstevel@tonic-gate 	/*
29277c478bd9Sstevel@tonic-gate 	 * Do a lookup for the index file. We know the index option doesn't
29287c478bd9Sstevel@tonic-gate 	 * allow paths through handling in the share command, so mc_dvp will
29297c478bd9Sstevel@tonic-gate 	 * be the parent for the index file vnode, if its present. Use
29307c478bd9Sstevel@tonic-gate 	 * temporary pointers to preserve and reuse the vnode pointers of the
29317c478bd9Sstevel@tonic-gate 	 * original directory in case there's no index file. Note that the
29327c478bd9Sstevel@tonic-gate 	 * index file is a native path, and should not be interpreted by
29337c478bd9Sstevel@tonic-gate 	 * the URL parser in rfs_pathname()
29347c478bd9Sstevel@tonic-gate 	 */
29357c478bd9Sstevel@tonic-gate 	if (((*exi)->exi_export.ex_flags & EX_INDEX) &&
29367c478bd9Sstevel@tonic-gate 	    ((*vpp)->v_type == VDIR) && (pathflag == URLPATH)) {
29377c478bd9Sstevel@tonic-gate 		vnode_t *tvp, *tmc_dvp;	/* temporary vnode pointers */
29387c478bd9Sstevel@tonic-gate 
29397c478bd9Sstevel@tonic-gate 		tmc_dvp = mc_dvp;
29407c478bd9Sstevel@tonic-gate 		mc_dvp = tvp = *vpp;
29417c478bd9Sstevel@tonic-gate 
29427c478bd9Sstevel@tonic-gate 		error = rfs_pathname((*exi)->exi_export.ex_index, NULL, vpp,
29437c478bd9Sstevel@tonic-gate 		    mc_dvp, cr, NATIVEPATH);
29447c478bd9Sstevel@tonic-gate 
29457c478bd9Sstevel@tonic-gate 		if (error == ENOENT) {
29467c478bd9Sstevel@tonic-gate 			*vpp = tvp;
29477c478bd9Sstevel@tonic-gate 			mc_dvp = tmc_dvp;
29487c478bd9Sstevel@tonic-gate 			error = 0;
29497c478bd9Sstevel@tonic-gate 		} else {	/* ok or error other than ENOENT */
29507c478bd9Sstevel@tonic-gate 			if (tmc_dvp)
29517c478bd9Sstevel@tonic-gate 				VN_RELE(tmc_dvp);
29527c478bd9Sstevel@tonic-gate 			if (error)
29537c478bd9Sstevel@tonic-gate 				goto publicfh_done;
29547c478bd9Sstevel@tonic-gate 
29557c478bd9Sstevel@tonic-gate 			/*
29567c478bd9Sstevel@tonic-gate 			 * Found a valid vp for index "filename". Sanity check
29577c478bd9Sstevel@tonic-gate 			 * for odd case where a directory is provided as index
29587c478bd9Sstevel@tonic-gate 			 * option argument and leads us to another filesystem
29597c478bd9Sstevel@tonic-gate 			 */
29607c478bd9Sstevel@tonic-gate 
29617c478bd9Sstevel@tonic-gate 			/* Release the reference on the old exi value */
2962596bc239SMarcel Telka 			ASSERT(*exi != NULL);
29637c478bd9Sstevel@tonic-gate 			exi_rele(*exi);
29640dfe541eSEvan Layton 			*exi = NULL;
29657c478bd9Sstevel@tonic-gate 
2966bd3561fbSToomas Soome 			error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi);
2967bd3561fbSToomas Soome 			if (error != 0) {
29687c478bd9Sstevel@tonic-gate 				VN_RELE(*vpp);
29697c478bd9Sstevel@tonic-gate 				goto publicfh_done;
29707c478bd9Sstevel@tonic-gate 			}
29710dfe541eSEvan Layton 			/* Have a new *exi */
29727c478bd9Sstevel@tonic-gate 		}
29737c478bd9Sstevel@tonic-gate 	}
29747c478bd9Sstevel@tonic-gate 
29757c478bd9Sstevel@tonic-gate publicfh_done:
29767c478bd9Sstevel@tonic-gate 	if (mc_dvp)
29777c478bd9Sstevel@tonic-gate 		VN_RELE(mc_dvp);
29787c478bd9Sstevel@tonic-gate 
29797c478bd9Sstevel@tonic-gate 	return (error);
29807c478bd9Sstevel@tonic-gate }
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate /*
29837c478bd9Sstevel@tonic-gate  * Evaluate a multi-component path
29847c478bd9Sstevel@tonic-gate  */
29857c478bd9Sstevel@tonic-gate int
rfs_pathname(char * path,vnode_t ** dirvpp,vnode_t ** compvpp,vnode_t * startdvp,cred_t * cr,int pathflag)29867c478bd9Sstevel@tonic-gate rfs_pathname(
29877c478bd9Sstevel@tonic-gate 	char *path,			/* pathname to evaluate */
29887c478bd9Sstevel@tonic-gate 	vnode_t **dirvpp,		/* ret for ptr to parent dir vnode */
29897c478bd9Sstevel@tonic-gate 	vnode_t **compvpp,		/* ret for ptr to component vnode */
29907c478bd9Sstevel@tonic-gate 	vnode_t *startdvp,		/* starting vnode */
29917c478bd9Sstevel@tonic-gate 	cred_t *cr,			/* user's credential */
29927c478bd9Sstevel@tonic-gate 	int pathflag)			/* flag to identify path, e.g. URL */
29937c478bd9Sstevel@tonic-gate {
29947c478bd9Sstevel@tonic-gate 	char namebuf[TYPICALMAXPATHLEN];
29957c478bd9Sstevel@tonic-gate 	struct pathname pn;
29967c478bd9Sstevel@tonic-gate 	int error;
29977c478bd9Sstevel@tonic-gate 
29980dfe541eSEvan Layton 	ASSERT3U(crgetzoneid(cr), ==, curzone->zone_id);
29990dfe541eSEvan Layton 
30007c478bd9Sstevel@tonic-gate 	/*
30017c478bd9Sstevel@tonic-gate 	 * If pathname starts with '/', then set startdvp to root.
30027c478bd9Sstevel@tonic-gate 	 */
30037c478bd9Sstevel@tonic-gate 	if (*path == '/') {
30047c478bd9Sstevel@tonic-gate 		while (*path == '/')
30057c478bd9Sstevel@tonic-gate 			path++;
30067c478bd9Sstevel@tonic-gate 
30070dfe541eSEvan Layton 		startdvp = ZONE_ROOTVP();
30087c478bd9Sstevel@tonic-gate 	}
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 	error = pn_get_buf(path, UIO_SYSSPACE, &pn, namebuf, sizeof (namebuf));
30117c478bd9Sstevel@tonic-gate 	if (error == 0) {
30127c478bd9Sstevel@tonic-gate 		/*
30137c478bd9Sstevel@tonic-gate 		 * Call the URL parser for URL paths to modify the original
30147c478bd9Sstevel@tonic-gate 		 * string to handle any '%' encoded characters that exist.
30157c478bd9Sstevel@tonic-gate 		 * Done here to avoid an extra bcopy in the lookup.
30167c478bd9Sstevel@tonic-gate 		 * We need to be careful about pathlen's. We know that
30177c478bd9Sstevel@tonic-gate 		 * rfs_pathname() is called with a non-empty path. However,
30187c478bd9Sstevel@tonic-gate 		 * it could be emptied due to the path simply being all /'s,
30197c478bd9Sstevel@tonic-gate 		 * which is valid to proceed with the lookup, or due to the
30207c478bd9Sstevel@tonic-gate 		 * URL parser finding an encoded null character at the
30217c478bd9Sstevel@tonic-gate 		 * beginning of path which should not proceed with the lookup.
30227c478bd9Sstevel@tonic-gate 		 */
30237c478bd9Sstevel@tonic-gate 		if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
30247c478bd9Sstevel@tonic-gate 			URLparse(pn.pn_path);
30257c478bd9Sstevel@tonic-gate 			if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0)
30267c478bd9Sstevel@tonic-gate 				return (ENOENT);
30277c478bd9Sstevel@tonic-gate 		}
30287c478bd9Sstevel@tonic-gate 		VN_HOLD(startdvp);
30297c478bd9Sstevel@tonic-gate 		error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
30300dfe541eSEvan Layton 		    ZONE_ROOTVP(), startdvp, cr);
30317c478bd9Sstevel@tonic-gate 	}
30327c478bd9Sstevel@tonic-gate 	if (error == ENAMETOOLONG) {
30337c478bd9Sstevel@tonic-gate 		/*
30347c478bd9Sstevel@tonic-gate 		 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
30357c478bd9Sstevel@tonic-gate 		 */
3036bd3561fbSToomas Soome 		error = pn_get(path, UIO_SYSSPACE, &pn);
3037bd3561fbSToomas Soome 		if (error != 0)
30387c478bd9Sstevel@tonic-gate 			return (error);
30397c478bd9Sstevel@tonic-gate 		if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
30407c478bd9Sstevel@tonic-gate 			URLparse(pn.pn_path);
30417c478bd9Sstevel@tonic-gate 			if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0) {
30427c478bd9Sstevel@tonic-gate 				pn_free(&pn);
30437c478bd9Sstevel@tonic-gate 				return (ENOENT);
30447c478bd9Sstevel@tonic-gate 			}
30457c478bd9Sstevel@tonic-gate 		}
30467c478bd9Sstevel@tonic-gate 		VN_HOLD(startdvp);
30477c478bd9Sstevel@tonic-gate 		error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
30480dfe541eSEvan Layton 		    ZONE_ROOTVP(), startdvp, cr);
30497c478bd9Sstevel@tonic-gate 		pn_free(&pn);
30507c478bd9Sstevel@tonic-gate 	}
30517c478bd9Sstevel@tonic-gate 
30527c478bd9Sstevel@tonic-gate 	return (error);
30537c478bd9Sstevel@tonic-gate }
30547c478bd9Sstevel@tonic-gate 
30557c478bd9Sstevel@tonic-gate /*
30567c478bd9Sstevel@tonic-gate  * Adapt the multicomponent lookup path depending on the pathtype
30577c478bd9Sstevel@tonic-gate  */
30587c478bd9Sstevel@tonic-gate static int
MCLpath(char ** path)30597c478bd9Sstevel@tonic-gate MCLpath(char **path)
30607c478bd9Sstevel@tonic-gate {
30617c478bd9Sstevel@tonic-gate 	unsigned char c = (unsigned char)**path;
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate 	/*
30647c478bd9Sstevel@tonic-gate 	 * If the MCL path is between 0x20 and 0x7E (graphic printable
30657c478bd9Sstevel@tonic-gate 	 * character of the US-ASCII coded character set), its a URL path,
30667c478bd9Sstevel@tonic-gate 	 * per RFC 1738.
30677c478bd9Sstevel@tonic-gate 	 */
30687c478bd9Sstevel@tonic-gate 	if (c >= 0x20 && c <= 0x7E)
30697c478bd9Sstevel@tonic-gate 		return (URLPATH);
30707c478bd9Sstevel@tonic-gate 
30717c478bd9Sstevel@tonic-gate 	/*
30727c478bd9Sstevel@tonic-gate 	 * If the first octet of the MCL path is not an ASCII character
30737c478bd9Sstevel@tonic-gate 	 * then it must be interpreted as a tag value that describes the
30747c478bd9Sstevel@tonic-gate 	 * format of the remaining octets of the MCL path.
30757c478bd9Sstevel@tonic-gate 	 *
30767c478bd9Sstevel@tonic-gate 	 * If the first octet of the MCL path is 0x81 it is a query
30777c478bd9Sstevel@tonic-gate 	 * for the security info.
30787c478bd9Sstevel@tonic-gate 	 */
30797c478bd9Sstevel@tonic-gate 	switch (c) {
30807c478bd9Sstevel@tonic-gate 	case 0x80:	/* native path, i.e. MCL via mount protocol */
30817c478bd9Sstevel@tonic-gate 		(*path)++;
30827c478bd9Sstevel@tonic-gate 		return (NATIVEPATH);
30837c478bd9Sstevel@tonic-gate 	case 0x81:	/* security query */
30847c478bd9Sstevel@tonic-gate 		(*path)++;
30857c478bd9Sstevel@tonic-gate 		return (SECURITY_QUERY);
30867c478bd9Sstevel@tonic-gate 	default:
30877c478bd9Sstevel@tonic-gate 		return (-1);
30887c478bd9Sstevel@tonic-gate 	}
30897c478bd9Sstevel@tonic-gate }
30907c478bd9Sstevel@tonic-gate 
30917c478bd9Sstevel@tonic-gate #define	fromhex(c)  ((c >= '0' && c <= '9') ? (c - '0') : \
30927c478bd9Sstevel@tonic-gate 			((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\
30937c478bd9Sstevel@tonic-gate 			((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
30947c478bd9Sstevel@tonic-gate 
30957c478bd9Sstevel@tonic-gate /*
3096da6c28aaSamw  * The implementation of URLparse guarantees that the final string will
30977c478bd9Sstevel@tonic-gate  * fit in the original one. Replaces '%' occurrences followed by 2 characters
30987c478bd9Sstevel@tonic-gate  * with its corresponding hexadecimal character.
30997c478bd9Sstevel@tonic-gate  */
31007c478bd9Sstevel@tonic-gate static void
URLparse(char * str)31017c478bd9Sstevel@tonic-gate URLparse(char *str)
31027c478bd9Sstevel@tonic-gate {
31037c478bd9Sstevel@tonic-gate 	char *p, *q;
31047c478bd9Sstevel@tonic-gate 
31057c478bd9Sstevel@tonic-gate 	p = q = str;
31067c478bd9Sstevel@tonic-gate 	while (*p) {
31077c478bd9Sstevel@tonic-gate 		*q = *p;
31087c478bd9Sstevel@tonic-gate 		if (*p++ == '%') {
31097c478bd9Sstevel@tonic-gate 			if (*p) {
31107c478bd9Sstevel@tonic-gate 				*q = fromhex(*p) * 16;
31117c478bd9Sstevel@tonic-gate 				p++;
31127c478bd9Sstevel@tonic-gate 				if (*p) {
31137c478bd9Sstevel@tonic-gate 					*q += fromhex(*p);
31147c478bd9Sstevel@tonic-gate 					p++;
31157c478bd9Sstevel@tonic-gate 				}
31167c478bd9Sstevel@tonic-gate 			}
31177c478bd9Sstevel@tonic-gate 		}
31187c478bd9Sstevel@tonic-gate 		q++;
31197c478bd9Sstevel@tonic-gate 	}
31207c478bd9Sstevel@tonic-gate 	*q = '\0';
31217c478bd9Sstevel@tonic-gate }
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate 
31247c478bd9Sstevel@tonic-gate /*
31257c478bd9Sstevel@tonic-gate  * Get the export information for the lookup vnode, and verify its
31267c478bd9Sstevel@tonic-gate  * useable.
31277c478bd9Sstevel@tonic-gate  */
31287c478bd9Sstevel@tonic-gate int
nfs_check_vpexi(vnode_t * mc_dvp,vnode_t * vp,cred_t * cr,struct exportinfo ** exi)31297c478bd9Sstevel@tonic-gate nfs_check_vpexi(vnode_t *mc_dvp, vnode_t *vp, cred_t *cr,
3130596bc239SMarcel Telka     struct exportinfo **exi)
31317c478bd9Sstevel@tonic-gate {
31327c478bd9Sstevel@tonic-gate 	int walk;
31337c478bd9Sstevel@tonic-gate 	int error = 0;
31347c478bd9Sstevel@tonic-gate 
3135596bc239SMarcel Telka 	*exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
3136596bc239SMarcel Telka 	if (*exi == NULL)
31377c478bd9Sstevel@tonic-gate 		error = EACCES;
31387c478bd9Sstevel@tonic-gate 	else {
31397c478bd9Sstevel@tonic-gate 		/*
31407c478bd9Sstevel@tonic-gate 		 * If nosub is set for this export then
31417c478bd9Sstevel@tonic-gate 		 * a lookup relative to the public fh
31427c478bd9Sstevel@tonic-gate 		 * must not terminate below the
31437c478bd9Sstevel@tonic-gate 		 * exported directory.
31447c478bd9Sstevel@tonic-gate 		 */
3145596bc239SMarcel Telka 		if ((*exi)->exi_export.ex_flags & EX_NOSUB && walk > 0)
31467c478bd9Sstevel@tonic-gate 			error = EACCES;
31477c478bd9Sstevel@tonic-gate 	}
3148596bc239SMarcel Telka 
31497c478bd9Sstevel@tonic-gate 	return (error);
31507c478bd9Sstevel@tonic-gate }
3151cee86682Scalum 
3152bd6f1640SJarrett Lu /*
3153bd6f1640SJarrett Lu  * Used by NFSv3 and NFSv4 server to query label of
3154bd6f1640SJarrett Lu  * a pathname component during lookup/access ops.
3155bd6f1640SJarrett Lu  */
3156bd6f1640SJarrett Lu ts_label_t *
nfs_getflabel(vnode_t * vp,struct exportinfo * exi)3157bd6f1640SJarrett Lu nfs_getflabel(vnode_t *vp, struct exportinfo *exi)
3158bd6f1640SJarrett Lu {
3159bd6f1640SJarrett Lu 	zone_t *zone;
3160bd6f1640SJarrett Lu 	ts_label_t *zone_label;
3161bd6f1640SJarrett Lu 	char *path;
3162bd6f1640SJarrett Lu 
3163bd6f1640SJarrett Lu 	mutex_enter(&vp->v_lock);
3164e2fc3408SPatrick Mooney 	if (vp->v_path != vn_vpath_empty) {
3165bd6f1640SJarrett Lu 		zone = zone_find_by_any_path(vp->v_path, B_FALSE);
3166bd6f1640SJarrett Lu 		mutex_exit(&vp->v_lock);
3167bd6f1640SJarrett Lu 	} else {
3168bd6f1640SJarrett Lu 		/*
3169bd6f1640SJarrett Lu 		 * v_path not cached. Fall back on pathname of exported
3170bd6f1640SJarrett Lu 		 * file system as we rely on pathname from which we can
3171bd6f1640SJarrett Lu 		 * derive a label. The exported file system portion of
3172bd6f1640SJarrett Lu 		 * path is sufficient to obtain a label.
3173bd6f1640SJarrett Lu 		 */
3174bd6f1640SJarrett Lu 		path = exi->exi_export.ex_path;
3175bd6f1640SJarrett Lu 		if (path == NULL) {
3176bd6f1640SJarrett Lu 			mutex_exit(&vp->v_lock);
3177bd6f1640SJarrett Lu 			return (NULL);
3178bd6f1640SJarrett Lu 		}
3179bd6f1640SJarrett Lu 		zone = zone_find_by_any_path(path, B_FALSE);
3180bd6f1640SJarrett Lu 		mutex_exit(&vp->v_lock);
3181bd6f1640SJarrett Lu 	}
3182bd6f1640SJarrett Lu 	/*
3183bd6f1640SJarrett Lu 	 * Caller has verified that the file is either
3184bd6f1640SJarrett Lu 	 * exported or visible. So if the path falls in
3185bd6f1640SJarrett Lu 	 * global zone, admin_low is returned; otherwise
3186bd6f1640SJarrett Lu 	 * the zone's label is returned.
3187bd6f1640SJarrett Lu 	 */
3188bd6f1640SJarrett Lu 	zone_label = zone->zone_slabel;
3189bd6f1640SJarrett Lu 	label_hold(zone_label);
3190bd6f1640SJarrett Lu 	zone_rele(zone);
3191bd6f1640SJarrett Lu 	return (zone_label);
3192bd6f1640SJarrett Lu }
3193bd6f1640SJarrett Lu 
3194bd6f1640SJarrett Lu /*
3195bd6f1640SJarrett Lu  * TX NFS routine used by NFSv3 and NFSv4 to do label check
3196bd6f1640SJarrett Lu  * on client label and server's file object lable.
3197bd6f1640SJarrett Lu  */
3198bd6f1640SJarrett Lu boolean_t
do_rfs_label_check(bslabel_t * clabel,vnode_t * vp,int flag,struct exportinfo * exi)3199bd6f1640SJarrett Lu do_rfs_label_check(bslabel_t *clabel, vnode_t *vp, int flag,
3200bd6f1640SJarrett Lu     struct exportinfo *exi)
3201bd6f1640SJarrett Lu {
3202bd6f1640SJarrett Lu 	bslabel_t *slabel;
3203bd6f1640SJarrett Lu 	ts_label_t *tslabel;
3204bd6f1640SJarrett Lu 	boolean_t result;
3205bd6f1640SJarrett Lu 
3206bd6f1640SJarrett Lu 	if ((tslabel = nfs_getflabel(vp, exi)) == NULL) {
3207bd6f1640SJarrett Lu 		return (B_FALSE);
3208bd6f1640SJarrett Lu 	}
3209bd6f1640SJarrett Lu 	slabel = label2bslabel(tslabel);
3210bd6f1640SJarrett Lu 	DTRACE_PROBE4(tx__rfs__log__info__labelcheck, char *,
3211bd6f1640SJarrett Lu 	    "comparing server's file label(1) with client label(2) (vp(3))",
3212bd6f1640SJarrett Lu 	    bslabel_t *, slabel, bslabel_t *, clabel, vnode_t *, vp);
3213bd6f1640SJarrett Lu 
3214bd6f1640SJarrett Lu 	if (flag == EQUALITY_CHECK)
3215bd6f1640SJarrett Lu 		result = blequal(clabel, slabel);
3216bd6f1640SJarrett Lu 	else
3217bd6f1640SJarrett Lu 		result = bldominates(clabel, slabel);
3218bd6f1640SJarrett Lu 	label_rele(tslabel);
3219bd6f1640SJarrett Lu 	return (result);
3220bd6f1640SJarrett Lu }
3221c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3222c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /*
3223c242f9a0Schunli zhang - Sun Microsystems - Irvine United States  * Callback function to return the loaned buffers.
3224c242f9a0Schunli zhang - Sun Microsystems - Irvine United States  * Calls VOP_RETZCBUF() only after all uio_iov[]
3225c242f9a0Schunli zhang - Sun Microsystems - Irvine United States  * buffers are returned. nu_ref maintains the count.
3226c242f9a0Schunli zhang - Sun Microsystems - Irvine United States  */
3227c242f9a0Schunli zhang - Sun Microsystems - Irvine United States void
rfs_free_xuio(void * free_arg)3228c242f9a0Schunli zhang - Sun Microsystems - Irvine United States rfs_free_xuio(void *free_arg)
3229c242f9a0Schunli zhang - Sun Microsystems - Irvine United States {
3230c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	uint_t ref;
3231c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfs_xuio_t *nfsuiop = (nfs_xuio_t *)free_arg;
3232c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3233c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	ref = atomic_dec_uint_nv(&nfsuiop->nu_ref);
3234c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3235c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	/*
3236c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	 * Call VOP_RETZCBUF() only when all the iov buffers
3237c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	 * are sent OTW.
3238c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	 */
3239c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (ref != 0)
3240c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		return;
3241c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3242c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (((uio_t *)nfsuiop)->uio_extflg & UIO_XUIO) {
3243c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		(void) VOP_RETZCBUF(nfsuiop->nu_vp, (xuio_t *)free_arg, NULL,
3244c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		    NULL);
3245c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		VN_RELE(nfsuiop->nu_vp);
3246c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	}
3247c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3248c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	kmem_cache_free(nfs_xuio_cache, free_arg);
3249c242f9a0Schunli zhang - Sun Microsystems - Irvine United States }
3250c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3251c242f9a0Schunli zhang - Sun Microsystems - Irvine United States xuio_t *
rfs_setup_xuio(vnode_t * vp)3252c242f9a0Schunli zhang - Sun Microsystems - Irvine United States rfs_setup_xuio(vnode_t *vp)
3253c242f9a0Schunli zhang - Sun Microsystems - Irvine United States {
3254c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfs_xuio_t *nfsuiop;
3255c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3256c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfsuiop = kmem_cache_alloc(nfs_xuio_cache, KM_SLEEP);
3257c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3258c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	bzero(nfsuiop, sizeof (nfs_xuio_t));
3259c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfsuiop->nu_vp = vp;
3260c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3261c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	/*
3262c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	 * ref count set to 1. more may be added
3263c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	 * if multiple mblks refer to multiple iov's.
3264c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	 * This is done in uio_to_mblk().
3265c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	 */
3266c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3267c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfsuiop->nu_ref = 1;
3268c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3269c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfsuiop->nu_frtn.free_func = rfs_free_xuio;
3270c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfsuiop->nu_frtn.free_arg = (char *)nfsuiop;
3271c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3272c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfsuiop->nu_uio.xu_type = UIOTYPE_ZEROCOPY;
3273c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3274c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	return (&nfsuiop->nu_uio);
3275c242f9a0Schunli zhang - Sun Microsystems - Irvine United States }
3276c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3277c242f9a0Schunli zhang - Sun Microsystems - Irvine United States mblk_t *
uio_to_mblk(uio_t * uiop)3278c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uio_to_mblk(uio_t *uiop)
3279c242f9a0Schunli zhang - Sun Microsystems - Irvine United States {
3280c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	struct iovec *iovp;
3281c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	int i;
3282c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	mblk_t *mp, *mp1;
3283c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfs_xuio_t *nfsuiop = (nfs_xuio_t *)uiop;
3284c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3285c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (uiop->uio_iovcnt == 0)
3286c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		return (NULL);
3287c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3288c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	iovp = uiop->uio_iov;
3289c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	mp = mp1 = esballoca((uchar_t *)iovp->iov_base, iovp->iov_len,
3290c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	    BPRI_MED, &nfsuiop->nu_frtn);
3291c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	ASSERT(mp != NULL);
3292c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3293c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	mp->b_wptr += iovp->iov_len;
3294c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	mp->b_datap->db_type = M_DATA;
3295c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3296c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	for (i = 1; i < uiop->uio_iovcnt; i++) {
3297c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		iovp = (uiop->uio_iov + i);
3298c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3299c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		mp1->b_cont = esballoca(
3300c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		    (uchar_t *)iovp->iov_base, iovp->iov_len, BPRI_MED,
3301c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		    &nfsuiop->nu_frtn);
3302c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3303c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		mp1 = mp1->b_cont;
3304c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		ASSERT(mp1 != NULL);
3305c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		mp1->b_wptr += iovp->iov_len;
3306c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		mp1->b_datap->db_type = M_DATA;
3307c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	}
3308c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3309c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	nfsuiop->nu_ref = uiop->uio_iovcnt;
3310c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3311c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	return (mp);
3312c242f9a0Schunli zhang - Sun Microsystems - Irvine United States }
3313c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3314e36d7b11SSebastien Roy /*
3315e36d7b11SSebastien Roy  * Allocate memory to hold data for a read request of len bytes.
3316e36d7b11SSebastien Roy  *
3317e36d7b11SSebastien Roy  * We don't allocate buffers greater than kmem_max_cached in size to avoid
3318e36d7b11SSebastien Roy  * allocating memory from the kmem_oversized arena.  If we allocate oversized
3319e36d7b11SSebastien Roy  * buffers, we incur heavy cross-call activity when freeing these large buffers
3320e36d7b11SSebastien Roy  * in the TCP receive path. Note that we can't set b_wptr here since the
3321e36d7b11SSebastien Roy  * length of the data returned may differ from the length requested when
3322e36d7b11SSebastien Roy  * reading the end of a file; we set b_wptr in rfs_rndup_mblks() once the
3323e36d7b11SSebastien Roy  * length of the read is known.
3324e36d7b11SSebastien Roy  */
3325e36d7b11SSebastien Roy mblk_t *
rfs_read_alloc(uint_t len,struct iovec ** iov,int * iovcnt)3326e36d7b11SSebastien Roy rfs_read_alloc(uint_t len, struct iovec **iov, int *iovcnt)
3327e36d7b11SSebastien Roy {
3328e36d7b11SSebastien Roy 	struct iovec *iovarr;
3329e36d7b11SSebastien Roy 	mblk_t *mp, **mpp = &mp;
3330e36d7b11SSebastien Roy 	size_t mpsize;
3331e36d7b11SSebastien Roy 	uint_t remain = len;
3332e36d7b11SSebastien Roy 	int i, err = 0;
3333e36d7b11SSebastien Roy 
3334e36d7b11SSebastien Roy 	*iovcnt = howmany(len, kmem_max_cached);
3335e36d7b11SSebastien Roy 
3336e36d7b11SSebastien Roy 	iovarr = kmem_alloc(*iovcnt * sizeof (struct iovec), KM_SLEEP);
3337e36d7b11SSebastien Roy 	*iov = iovarr;
3338e36d7b11SSebastien Roy 
3339e36d7b11SSebastien Roy 	for (i = 0; i < *iovcnt; remain -= mpsize, i++) {
3340e36d7b11SSebastien Roy 		ASSERT(remain <= len);
3341e36d7b11SSebastien Roy 		/*
3342e36d7b11SSebastien Roy 		 * We roundup the size we allocate to a multiple of
3343e36d7b11SSebastien Roy 		 * BYTES_PER_XDR_UNIT (4 bytes) so that the call to
3344e36d7b11SSebastien Roy 		 * xdrmblk_putmblk() never fails.
3345e36d7b11SSebastien Roy 		 */
3346e36d7b11SSebastien Roy 		ASSERT(kmem_max_cached % BYTES_PER_XDR_UNIT == 0);
3347e36d7b11SSebastien Roy 		mpsize = MIN(kmem_max_cached, remain);
3348e36d7b11SSebastien Roy 		*mpp = allocb_wait(RNDUP(mpsize), BPRI_MED, STR_NOSIG, &err);
3349e36d7b11SSebastien Roy 		ASSERT(*mpp != NULL);
3350e36d7b11SSebastien Roy 		ASSERT(err == 0);
3351e36d7b11SSebastien Roy 
3352e36d7b11SSebastien Roy 		iovarr[i].iov_base = (caddr_t)(*mpp)->b_rptr;
3353e36d7b11SSebastien Roy 		iovarr[i].iov_len = mpsize;
3354e36d7b11SSebastien Roy 		mpp = &(*mpp)->b_cont;
3355e36d7b11SSebastien Roy 	}
3356e36d7b11SSebastien Roy 	return (mp);
3357e36d7b11SSebastien Roy }
3358e36d7b11SSebastien Roy 
3359c242f9a0Schunli zhang - Sun Microsystems - Irvine United States void
rfs_rndup_mblks(mblk_t * mp,uint_t len,int buf_loaned)3360c242f9a0Schunli zhang - Sun Microsystems - Irvine United States rfs_rndup_mblks(mblk_t *mp, uint_t len, int buf_loaned)
3361c242f9a0Schunli zhang - Sun Microsystems - Irvine United States {
3362e36d7b11SSebastien Roy 	int i;
3363c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	int alloc_err = 0;
3364c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	mblk_t *rmp;
3365e36d7b11SSebastien Roy 	uint_t mpsize, remainder;
3366c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3367e36d7b11SSebastien Roy 	remainder = P2NPHASE(len, BYTES_PER_XDR_UNIT);
3368c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3369e36d7b11SSebastien Roy 	/*
3370e36d7b11SSebastien Roy 	 * Non copy-reduction case.  This function assumes that blocks were
3371e36d7b11SSebastien Roy 	 * allocated in multiples of BYTES_PER_XDR_UNIT bytes, which makes this
3372e36d7b11SSebastien Roy 	 * padding safe without bounds checking.
3373e36d7b11SSebastien Roy 	 */
3374c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	if (!buf_loaned) {
3375e36d7b11SSebastien Roy 		/*
3376e36d7b11SSebastien Roy 		 * Set the size of each mblk in the chain until we've consumed
3377e36d7b11SSebastien Roy 		 * the specified length for all but the last one.
3378e36d7b11SSebastien Roy 		 */
3379e36d7b11SSebastien Roy 		while ((mpsize = MBLKSIZE(mp)) < len) {
3380e36d7b11SSebastien Roy 			ASSERT(mpsize % BYTES_PER_XDR_UNIT == 0);
3381e36d7b11SSebastien Roy 			mp->b_wptr += mpsize;
3382e36d7b11SSebastien Roy 			len -= mpsize;
3383e36d7b11SSebastien Roy 			mp = mp->b_cont;
3384e36d7b11SSebastien Roy 			ASSERT(mp != NULL);
3385c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		}
3386e36d7b11SSebastien Roy 
3387e36d7b11SSebastien Roy 		ASSERT(len + remainder <= mpsize);
3388e36d7b11SSebastien Roy 		mp->b_wptr += len;
3389e36d7b11SSebastien Roy 		for (i = 0; i < remainder; i++)
3390e36d7b11SSebastien Roy 			*mp->b_wptr++ = '\0';
3391c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		return;
3392c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	}
3393c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3394e36d7b11SSebastien Roy 	/*
3395e36d7b11SSebastien Roy 	 * No remainder mblk required.
3396e36d7b11SSebastien Roy 	 */
3397e36d7b11SSebastien Roy 	if (remainder == 0)
3398c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		return;
3399c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3400e36d7b11SSebastien Roy 	/*
3401e36d7b11SSebastien Roy 	 * Get to the last mblk in the chain.
3402e36d7b11SSebastien Roy 	 */
3403e36d7b11SSebastien Roy 	while (mp->b_cont != NULL)
3404c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		mp = mp->b_cont;
3405c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3406c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	/*
3407e36d7b11SSebastien Roy 	 * In case of copy-reduction mblks, the size of the mblks are fixed
3408e36d7b11SSebastien Roy 	 * and are of the size of the loaned buffers.  Allocate a remainder
3409e36d7b11SSebastien Roy 	 * mblk and chain it to the data buffers. This is sub-optimal, but not
3410e36d7b11SSebastien Roy 	 * expected to happen commonly.
3411c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	 */
3412e36d7b11SSebastien Roy 	rmp = allocb_wait(remainder, BPRI_MED, STR_NOSIG, &alloc_err);
3413c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	ASSERT(rmp != NULL);
3414c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	ASSERT(alloc_err == 0);
3415c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3416e36d7b11SSebastien Roy 	for (i = 0; i < remainder; i++)
3417c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 		*rmp->b_wptr++ = '\0';
3418c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 
3419c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	rmp->b_datap->db_type = M_DATA;
3420c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 	mp->b_cont = rmp;
3421c242f9a0Schunli zhang - Sun Microsystems - Irvine United States }
3422