Home | History | Annotate | Download | only in nfs
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  1610   thurlow  * Common Development and Distribution License (the "License").
      6  1610   thurlow  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21     0    stevel /*
     22  8695  Rajkumar  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23     0    stevel  * Use is subject to license terms.
     24     0    stevel  */
     25     0    stevel 
     26     0    stevel /*
     27     0    stevel  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
     28     0    stevel  *	All rights reserved.
     29     0    stevel  *	Use is subject to license terms.
     30     0    stevel  */
     31     0    stevel 
     32     0    stevel #include <sys/param.h>
     33     0    stevel #include <sys/types.h>
     34     0    stevel #include <sys/systm.h>
     35     0    stevel #include <sys/cred.h>
     36     0    stevel #include <sys/proc.h>
     37     0    stevel #include <sys/user.h>
     38     0    stevel #include <sys/buf.h>
     39     0    stevel #include <sys/vfs.h>
     40     0    stevel #include <sys/vnode.h>
     41     0    stevel #include <sys/pathname.h>
     42     0    stevel #include <sys/uio.h>
     43     0    stevel #include <sys/file.h>
     44     0    stevel #include <sys/stat.h>
     45     0    stevel #include <sys/errno.h>
     46     0    stevel #include <sys/socket.h>
     47     0    stevel #include <sys/sysmacros.h>
     48     0    stevel #include <sys/siginfo.h>
     49     0    stevel #include <sys/tiuser.h>
     50     0    stevel #include <sys/statvfs.h>
     51     0    stevel #include <sys/stream.h>
     52     0    stevel #include <sys/strsubr.h>
     53     0    stevel #include <sys/stropts.h>
     54     0    stevel #include <sys/timod.h>
     55     0    stevel #include <sys/t_kuser.h>
     56     0    stevel #include <sys/kmem.h>
     57     0    stevel #include <sys/kstat.h>
     58     0    stevel #include <sys/dirent.h>
     59     0    stevel #include <sys/cmn_err.h>
     60     0    stevel #include <sys/debug.h>
     61     0    stevel #include <sys/unistd.h>
     62     0    stevel #include <sys/vtrace.h>
     63     0    stevel #include <sys/mode.h>
     64     0    stevel #include <sys/acl.h>
     65     0    stevel #include <sys/sdt.h>
     66     0    stevel 
     67     0    stevel #include <rpc/types.h>
     68     0    stevel #include <rpc/auth.h>
     69     0    stevel #include <rpc/auth_unix.h>
     70     0    stevel #include <rpc/auth_des.h>
     71     0    stevel #include <rpc/svc.h>
     72     0    stevel #include <rpc/xdr.h>
     73  8695  Rajkumar #include <rpc/rpc_rdma.h>
     74     0    stevel 
     75     0    stevel #include <nfs/nfs.h>
     76     0    stevel #include <nfs/export.h>
     77     0    stevel #include <nfs/nfssys.h>
     78     0    stevel #include <nfs/nfs_clnt.h>
     79     0    stevel #include <nfs/nfs_acl.h>
     80     0    stevel #include <nfs/nfs_log.h>
     81  7961   Natalie #include <nfs/nfs_cmd.h>
     82     0    stevel #include <nfs/lm.h>
     83    74  rg137905 #include <nfs/nfs_dispatch.h>
     84    74  rg137905 #include <nfs/nfs4_drc.h>
     85     0    stevel 
     86     0    stevel #include <sys/modctl.h>
     87     0    stevel #include <sys/cladm.h>
     88     0    stevel #include <sys/clconf.h>
     89  9871   Jarrett 
     90  9871   Jarrett #include <sys/tsol/label.h>
     91     0    stevel 
     92     0    stevel #define	MAXHOST 32
     93     0    stevel const char *kinet_ntop6(uchar_t *, char *, size_t);
     94     0    stevel 
     95     0    stevel /*
     96     0    stevel  * Module linkage information.
     97     0    stevel  */
     98     0    stevel 
     99     0    stevel static struct modlmisc modlmisc = {
    100     0    stevel 	&mod_miscops, "NFS server module"
    101     0    stevel };
    102     0    stevel 
    103     0    stevel static struct modlinkage modlinkage = {
    104     0    stevel 	MODREV_1, (void *)&modlmisc, NULL
    105     0    stevel };
    106     0    stevel 
    107     0    stevel char _depends_on[] = "misc/klmmod";
    108  2035     calum 
    109     0    stevel int
    110     0    stevel _init(void)
    111     0    stevel {
    112     0    stevel 	int status;
    113     0    stevel 
    114     0    stevel 	if ((status = nfs_srvinit()) != 0) {
    115     0    stevel 		cmn_err(CE_WARN, "_init: nfs_srvinit failed");
    116     0    stevel 		return (status);
    117     0    stevel 	}
    118     0    stevel 
    119     0    stevel 	status = mod_install((struct modlinkage *)&modlinkage);
    120     0    stevel 	if (status != 0) {
    121     0    stevel 		/*
    122     0    stevel 		 * Could not load module, cleanup previous
    123     0    stevel 		 * initialization work.
    124     0    stevel 		 */
    125     0    stevel 		nfs_srvfini();
    126     0    stevel 	}
    127     0    stevel 
    128  2035     calum 	/*
    129  2035     calum 	 * Initialise some placeholders for nfssys() calls. These have
    130  2035     calum 	 * to be declared by the nfs module, since that handles nfssys()
    131  2035     calum 	 * calls - also used by NFS clients - but are provided by this
    132  2035     calum 	 * nfssrv module. These also then serve as confirmation to the
    133  2035     calum 	 * relevant code in nfs that nfssrv has been loaded, as they're
    134  2035     calum 	 * initially NULL.
    135  2035     calum 	 */
    136     0    stevel 	nfs_srv_quiesce_func = nfs_srv_quiesce_all;
    137  2035     calum 	nfs_srv_dss_func = rfs4_dss_setpaths;
    138  2035     calum 
    139  2035     calum 	/* setup DSS paths here; must be done before initial server startup */
    140  2035     calum 	rfs4_dss_paths = rfs4_dss_oldpaths = NULL;
    141     0    stevel 
    142     0    stevel 	return (status);
    143     0    stevel }
    144     0    stevel 
    145     0    stevel int
    146     0    stevel _fini()
    147     0    stevel {
    148     0    stevel 	return (EBUSY);
    149     0    stevel }
    150     0    stevel 
    151     0    stevel int
    152     0    stevel _info(struct modinfo *modinfop)
    153     0    stevel {
    154     0    stevel 	return (mod_info(&modlinkage, modinfop));
    155     0    stevel }
    156     0    stevel 
    157     0    stevel /*
    158     0    stevel  * PUBLICFH_CHECK() checks if the dispatch routine supports
    159     0    stevel  * RPC_PUBLICFH_OK, if the filesystem is exported public, and if the
    160     0    stevel  * incoming request is using the public filehandle. The check duplicates
    161     0    stevel  * the exportmatch() call done in checkexport(), and we should consider
    162     0    stevel  * modifying those routines to avoid the duplication. For now, we optimize
    163     0    stevel  * by calling exportmatch() only after checking that the dispatch routine
    164     0    stevel  * supports RPC_PUBLICFH_OK, and if the filesystem is explicitly exported
    165     0    stevel  * public (i.e., not the placeholder).
    166     0    stevel  */
    167  1610   thurlow #define	PUBLICFH_CHECK(disp, exi, fsid, xfid) \
    168     0    stevel 		((disp->dis_flags & RPC_PUBLICFH_OK) && \
    169     0    stevel 		((exi->exi_export.ex_flags & EX_PUBLIC) || \
    170     0    stevel 		(exi == exi_public && exportmatch(exi_root, \
    171  1610   thurlow 		fsid, xfid))))
    172     0    stevel 
    173     0    stevel static void	nfs_srv_shutdown_all(int);
    174     0    stevel static void	rfs4_server_start(int);
    175     0    stevel static void	nullfree(void);
    176     0    stevel static void	rfs_dispatch(struct svc_req *, SVCXPRT *);
    177     0    stevel static void	acl_dispatch(struct svc_req *, SVCXPRT *);
    178     0    stevel static void	common_dispatch(struct svc_req *, SVCXPRT *,
    179     0    stevel 		rpcvers_t, rpcvers_t, char *,
    180     0    stevel 		struct rpc_disptable *);
    181  2035     calum static void	hanfsv4_failover(void);
    182     0    stevel static	int	checkauth(struct exportinfo *, struct svc_req *, cred_t *, int,
    183     0    stevel 			bool_t);
    184     0    stevel static char	*client_name(struct svc_req *req);
    185     0    stevel static char	*client_addr(struct svc_req *req, char *buf);
    186     0    stevel extern	int	sec_svc_getcred(struct svc_req *, cred_t *cr, char **, int *);
    187     0    stevel extern	bool_t	sec_svc_inrootlist(int, caddr_t, int, caddr_t *);
    188     0    stevel 
    189     0    stevel #define	NFSLOG_COPY_NETBUF(exi, xprt, nb)	{		\
    190     0    stevel 	(nb)->maxlen = (xprt)->xp_rtaddr.maxlen;		\
    191     0    stevel 	(nb)->len = (xprt)->xp_rtaddr.len;			\
    192     0    stevel 	(nb)->buf = kmem_alloc((nb)->len, KM_SLEEP);		\
    193     0    stevel 	bcopy((xprt)->xp_rtaddr.buf, (nb)->buf, (nb)->len);	\
    194     0    stevel 	}
    195     0    stevel 
    196     0    stevel /*
    197     0    stevel  * Public Filehandle common nfs routines
    198     0    stevel  */
    199     0    stevel static int	MCLpath(char **);
    200     0    stevel static void	URLparse(char *);
    201     0    stevel 
    202     0    stevel /*
    203     0    stevel  * NFS callout table.
    204     0    stevel  * This table is used by svc_getreq() to dispatch a request with
    205     0    stevel  * a given prog/vers pair to an appropriate service provider
    206     0    stevel  * dispatch routine.
    207     0    stevel  *
    208     0    stevel  * NOTE: ordering is relied upon below when resetting the version min/max
    209     0    stevel  * for NFS_PROGRAM.  Careful, if this is ever changed.
    210     0    stevel  */
    211     0    stevel static SVC_CALLOUT __nfs_sc_clts[] = {
    212     0    stevel 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
    213     0    stevel 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
    214     0    stevel };
    215     0    stevel 
    216     0    stevel static SVC_CALLOUT_TABLE nfs_sct_clts = {
    217     0    stevel 	sizeof (__nfs_sc_clts) / sizeof (__nfs_sc_clts[0]), FALSE,
    218     0    stevel 	__nfs_sc_clts
    219     0    stevel };
    220     0    stevel 
    221     0    stevel static SVC_CALLOUT __nfs_sc_cots[] = {
    222     0    stevel 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
    223     0    stevel 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
    224     0    stevel };
    225     0    stevel 
    226     0    stevel static SVC_CALLOUT_TABLE nfs_sct_cots = {
    227     0    stevel 	sizeof (__nfs_sc_cots) / sizeof (__nfs_sc_cots[0]), FALSE, __nfs_sc_cots
    228     0    stevel };
    229     0    stevel 
    230     0    stevel static SVC_CALLOUT __nfs_sc_rdma[] = {
    231     0    stevel 	{ NFS_PROGRAM,	   NFS_VERSMIN,	    NFS_VERSMAX,	rfs_dispatch },
    232     0    stevel 	{ NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,	acl_dispatch }
    233     0    stevel };
    234     0    stevel 
    235     0    stevel static SVC_CALLOUT_TABLE nfs_sct_rdma = {
    236     0    stevel 	sizeof (__nfs_sc_rdma) / sizeof (__nfs_sc_rdma[0]), FALSE, __nfs_sc_rdma
    237     0    stevel };
    238     0    stevel rpcvers_t nfs_versmin = NFS_VERSMIN_DEFAULT;
    239     0    stevel rpcvers_t nfs_versmax = NFS_VERSMAX_DEFAULT;
    240     0    stevel 
    241     0    stevel /*
    242     0    stevel  * Used to track the state of the server so that initialization
    243     0    stevel  * can be done properly.
    244     0    stevel  */
    245     0    stevel typedef enum {
    246     0    stevel 	NFS_SERVER_STOPPED,	/* server state destroyed */
    247     0    stevel 	NFS_SERVER_STOPPING,	/* server state being destroyed */
    248     0    stevel 	NFS_SERVER_RUNNING,
    249     0    stevel 	NFS_SERVER_QUIESCED,	/* server state preserved */
    250     0    stevel 	NFS_SERVER_OFFLINE	/* server pool offline */
    251     0    stevel } nfs_server_running_t;
    252     0    stevel 
    253     0    stevel static nfs_server_running_t nfs_server_upordown;
    254     0    stevel static kmutex_t nfs_server_upordown_lock;
    255     0    stevel static	kcondvar_t nfs_server_upordown_cv;
    256     0    stevel 
    257  2035     calum /*
    258  2035     calum  * DSS: distributed stable storage
    259  2035     calum  * lists of all DSS paths: current, and before last warmstart
    260  2035     calum  */
    261  2035     calum nvlist_t *rfs4_dss_paths, *rfs4_dss_oldpaths;
    262  2035     calum 
    263    74  rg137905 int rfs4_dispatch(struct rpcdisp *, struct svc_req *, SVCXPRT *, char *);
    264  4635  maheshvs bool_t rfs4_minorvers_mismatch(struct svc_req *, SVCXPRT *, void *);
    265    74  rg137905 
    266     0    stevel /*
    267     0    stevel  * RDMA wait variables.
    268     0    stevel  */
    269     0    stevel static kcondvar_t rdma_wait_cv;
    270     0    stevel static kmutex_t rdma_wait_mutex;
    271     0    stevel 
    272     0    stevel /*
    273     0    stevel  * Will be called at the point the server pool is being unregistered
    274     0    stevel  * from the pool list. From that point onwards, the pool is waiting
    275     0    stevel  * to be drained and as such the server state is stale and pertains
    276     0    stevel  * to the old instantiation of the NFS server pool.
    277     0    stevel  */
    278     0    stevel void
    279     0    stevel nfs_srv_offline(void)
    280     0    stevel {
    281     0    stevel 	mutex_enter(&nfs_server_upordown_lock);
    282     0    stevel 	if (nfs_server_upordown == NFS_SERVER_RUNNING) {
    283     0    stevel 		nfs_server_upordown = NFS_SERVER_OFFLINE;
    284     0    stevel 	}
    285     0    stevel 	mutex_exit(&nfs_server_upordown_lock);
    286     0    stevel }
    287     0    stevel 
    288     0    stevel /*
    289     0    stevel  * Will be called at the point the server pool is being destroyed so
    290     0    stevel  * all transports have been closed and no service threads are in
    291     0    stevel  * existence.
    292     0    stevel  *
    293     0    stevel  * If we quiesce the server, we're shutting it down without destroying the
    294     0    stevel  * server state. This allows it to warm start subsequently.
    295     0    stevel  */
    296     0    stevel void
    297     0    stevel nfs_srv_stop_all(void)
    298     0    stevel {
    299     0    stevel 	int quiesce = 0;
    300     0    stevel 	nfs_srv_shutdown_all(quiesce);
    301     0    stevel }
    302     0    stevel 
    303     0    stevel /*
    304     0    stevel  * This alternative shutdown routine can be requested via nfssys()
    305     0    stevel  */
    306     0    stevel void
    307     0    stevel nfs_srv_quiesce_all(void)
    308     0    stevel {
    309     0    stevel 	int quiesce = 1;
    310     0    stevel 	nfs_srv_shutdown_all(quiesce);
    311     0    stevel }
    312     0    stevel 
    313     0    stevel static void
    314     0    stevel nfs_srv_shutdown_all(int quiesce) {
    315     0    stevel 	mutex_enter(&nfs_server_upordown_lock);
    316     0    stevel 	if (quiesce) {
    317     0    stevel 		if (nfs_server_upordown == NFS_SERVER_RUNNING ||
    318     0    stevel 			nfs_server_upordown == NFS_SERVER_OFFLINE) {
    319     0    stevel 			nfs_server_upordown = NFS_SERVER_QUIESCED;
    320     0    stevel 			cv_signal(&nfs_server_upordown_cv);
    321  2035     calum 
    322  2035     calum 			/* reset DSS state, for subsequent warm restart */
    323  2035     calum 			rfs4_dss_numnewpaths = 0;
    324  2035     calum 			rfs4_dss_newpaths = NULL;
    325  2035     calum 
    326     0    stevel 			cmn_err(CE_NOTE, "nfs_server: server is now quiesced; "
    327     0    stevel 			    "NFSv4 state has been preserved");
    328     0    stevel 		}
    329     0    stevel 	} else {
    330     0    stevel 		if (nfs_server_upordown == NFS_SERVER_OFFLINE) {
    331     0    stevel 			nfs_server_upordown = NFS_SERVER_STOPPING;
    332     0    stevel 			mutex_exit(&nfs_server_upordown_lock);
    333     0    stevel 			rfs4_state_fini();
    334    74  rg137905 			rfs4_fini_drc(nfs4_drc);
    335     0    stevel 			mutex_enter(&nfs_server_upordown_lock);
    336     0    stevel 			nfs_server_upordown = NFS_SERVER_STOPPED;
    337     0    stevel 			cv_signal(&nfs_server_upordown_cv);
    338     0    stevel 		}
    339     0    stevel 	}
    340     0    stevel 	mutex_exit(&nfs_server_upordown_lock);
    341     0    stevel }
    342     0    stevel 
    343     0    stevel static int
    344     0    stevel nfs_srv_set_sc_versions(struct file *fp, SVC_CALLOUT_TABLE **sctpp,
    345     0    stevel 			rpcvers_t versmin, rpcvers_t versmax)
    346     0    stevel {
    347     0    stevel 	struct strioctl strioc;
    348     0    stevel 	struct T_info_ack tinfo;
    349     0    stevel 	int		error, retval;
    350     0    stevel 
    351     0    stevel 	/*
    352     0    stevel 	 * Find out what type of transport this is.
    353     0    stevel 	 */
    354     0    stevel 	strioc.ic_cmd = TI_GETINFO;
    355     0    stevel 	strioc.ic_timout = -1;
    356     0    stevel 	strioc.ic_len = sizeof (tinfo);
    357     0    stevel 	strioc.ic_dp = (char *)&tinfo;
    358     0    stevel 	tinfo.PRIM_type = T_INFO_REQ;
    359     0    stevel 
    360     0    stevel 	error = strioctl(fp->f_vnode, I_STR, (intptr_t)&strioc, 0, K_TO_K,
    361     0    stevel 	    CRED(), &retval);
    362     0    stevel 	if (error || retval)
    363     0    stevel 		return (error);
    364     0    stevel 
    365     0    stevel 	/*
    366     0    stevel 	 * Based on our query of the transport type...
    367     0    stevel 	 *
    368     0    stevel 	 * Reset the min/max versions based on the caller's request
    369     0    stevel 	 * NOTE: This assumes that NFS_PROGRAM is first in the array!!
    370     0    stevel 	 * And the second entry is the NFS_ACL_PROGRAM.
    371     0    stevel 	 */
    372     0    stevel 	switch (tinfo.SERV_type) {
    373     0    stevel 	case T_CLTS:
    374     0    stevel 		if (versmax == NFS_V4)
    375     0    stevel 			return (EINVAL);
    376     0    stevel 		__nfs_sc_clts[0].sc_versmin = versmin;
    377     0    stevel 		__nfs_sc_clts[0].sc_versmax = versmax;
    378     0    stevel 		__nfs_sc_clts[1].sc_versmin = versmin;
    379     0    stevel 		__nfs_sc_clts[1].sc_versmax = versmax;
    380     0    stevel 		*sctpp = &nfs_sct_clts;
    381     0    stevel 		break;
    382     0    stevel 	case T_COTS:
    383     0    stevel 	case T_COTS_ORD:
    384     0    stevel 		__nfs_sc_cots[0].sc_versmin = versmin;
    385     0    stevel 		__nfs_sc_cots[0].sc_versmax = versmax;
    386     0    stevel 		/* For the NFS_ACL program, check the max version */
    387     0    stevel 		if (versmax > NFS_ACL_VERSMAX)
    388     0    stevel 			versmax = NFS_ACL_VERSMAX;
    389     0    stevel 		__nfs_sc_cots[1].sc_versmin = versmin;
    390     0    stevel 		__nfs_sc_cots[1].sc_versmax = versmax;
    391     0    stevel 		*sctpp = &nfs_sct_cots;
    392     0    stevel 		break;
    393     0    stevel 	default:
    394     0    stevel 		error = EINVAL;
    395     0    stevel 	}
    396     0    stevel 
    397     0    stevel 	return (error);
    398     0    stevel }
    399     0    stevel 
    400     0    stevel /*
    401     0    stevel  * NFS Server system call.
    402     0    stevel  * Does all of the work of running a NFS server.
    403     0    stevel  * uap->fd is the fd of an open transport provider
    404     0    stevel  */
    405     0    stevel int
    406     0    stevel nfs_svc(struct nfs_svc_args *arg, model_t model)
    407     0    stevel {
    408     0    stevel 	file_t *fp;
    409     0    stevel 	SVCMASTERXPRT *xprt;
    410     0    stevel 	int error;
    411     0    stevel 	int readsize;
    412     0    stevel 	char buf[KNC_STRSIZE];
    413     0    stevel 	size_t len;
    414     0    stevel 	STRUCT_HANDLE(nfs_svc_args, uap);
    415     0    stevel 	struct netbuf addrmask;
    416     0    stevel 	SVC_CALLOUT_TABLE *sctp = NULL;
    417     0    stevel 
    418     0    stevel #ifdef lint
    419     0    stevel 	model = model;		/* STRUCT macros don't always refer to it */
    420     0    stevel #endif
    421     0    stevel 
    422     0    stevel 	STRUCT_SET_HANDLE(uap, model, arg);
    423     0    stevel 
    424     0    stevel 	/* Check privileges in nfssys() */
    425     0    stevel 
    426     0    stevel 	if ((fp = getf(STRUCT_FGET(uap, fd))) == NULL)
    427     0    stevel 		return (EBADF);
    428     0    stevel 
    429     0    stevel 	/*
    430     0    stevel 	 * Set read buffer size to rsize
    431     0    stevel 	 * and add room for RPC headers.
    432     0    stevel 	 */
    433     0    stevel 	readsize = nfs3tsize() + (RPC_MAXDATASIZE - NFS_MAXDATA);
    434     0    stevel 	if (readsize < RPC_MAXDATASIZE)
    435     0    stevel 		readsize = RPC_MAXDATASIZE;
    436     0    stevel 
    437     0    stevel 	error = copyinstr((const char *)STRUCT_FGETP(uap, netid), buf,
    438     0    stevel 	    KNC_STRSIZE, &len);
    439     0    stevel 	if (error) {
    440     0    stevel 		releasef(STRUCT_FGET(uap, fd));
    441     0    stevel 		return (error);
    442     0    stevel 	}
    443     0    stevel 
    444     0    stevel 	addrmask.len = STRUCT_FGET(uap, addrmask.len);
    445     0    stevel 	addrmask.maxlen = STRUCT_FGET(uap, addrmask.maxlen);
    446     0    stevel 	addrmask.buf = kmem_alloc(addrmask.maxlen, KM_SLEEP);
    447     0    stevel 	error = copyin(STRUCT_FGETP(uap, addrmask.buf), addrmask.buf,
    448     0    stevel 	    addrmask.len);
    449     0    stevel 	if (error) {
    450     0    stevel 		releasef(STRUCT_FGET(uap, fd));
    451     0    stevel 		kmem_free(addrmask.buf, addrmask.maxlen);
    452     0    stevel 		return (error);
    453     0    stevel 	}
    454     0    stevel 
    455     0    stevel 	nfs_versmin = STRUCT_FGET(uap, versmin);
    456     0    stevel 	nfs_versmax = STRUCT_FGET(uap, versmax);
    457     0    stevel 
    458     0    stevel 	/* Double check the vers min/max ranges */
    459     0    stevel 	if ((nfs_versmin > nfs_versmax) ||
    460  7961   Natalie 	    (nfs_versmin < NFS_VERSMIN) ||
    461  7961   Natalie 	    (nfs_versmax > NFS_VERSMAX)) {
    462     0    stevel 		nfs_versmin = NFS_VERSMIN_DEFAULT;
    463     0    stevel 		nfs_versmax = NFS_VERSMAX_DEFAULT;
    464     0    stevel 	}
    465     0    stevel 
    466     0    stevel 	if (error =
    467     0    stevel 	    nfs_srv_set_sc_versions(fp, &sctp, nfs_versmin, nfs_versmax)) {
    468     0    stevel 		releasef(STRUCT_FGET(uap, fd));
    469     0    stevel 		kmem_free(addrmask.buf, addrmask.maxlen);
    470     0    stevel 		return (error);
    471     0    stevel 	}
    472     0    stevel 
    473     0    stevel 	/* Initialize nfsv4 server */
    474     0    stevel 	if (nfs_versmax == (rpcvers_t)NFS_V4)
    475     0    stevel 		rfs4_server_start(STRUCT_FGET(uap, delegation));
    476     0    stevel 
    477     0    stevel 	/* Create a transport handle. */
    478     0    stevel 	error = svc_tli_kcreate(fp, readsize, buf, &addrmask, &xprt,
    479  7961   Natalie 	    sctp, NULL, NFS_SVCPOOL_ID, TRUE);
    480     0    stevel 
    481     0    stevel 	if (error)
    482     0    stevel 		kmem_free(addrmask.buf, addrmask.maxlen);
    483     0    stevel 
    484     0    stevel 	releasef(STRUCT_FGET(uap, fd));
    485     0    stevel 
    486  2035     calum 	/* HA-NFSv4: save the cluster nodeid */
    487     0    stevel 	if (cluster_bootflags & CLUSTER_BOOTED)
    488     0    stevel 		lm_global_nlmid = clconf_get_nodeid();
    489     0    stevel 
    490     0    stevel 	return (error);
    491     0    stevel }
    492     0    stevel 
    493     0    stevel static void
    494     0    stevel rfs4_server_start(int nfs4_srv_delegation)
    495     0    stevel {
    496     0    stevel 	/*
    497     0    stevel 	 * Determine if the server has previously been "started" and
    498     0    stevel 	 * if not, do the per instance initialization
    499     0    stevel 	 */
    500     0    stevel 	mutex_enter(&nfs_server_upordown_lock);
    501     0    stevel 
    502     0    stevel 	if (nfs_server_upordown != NFS_SERVER_RUNNING) {
    503     0    stevel 		/* Do we need to stop and wait on the previous server? */
    504     0    stevel 		while (nfs_server_upordown == NFS_SERVER_STOPPING ||
    505  7961   Natalie 		    nfs_server_upordown == NFS_SERVER_OFFLINE)
    506     0    stevel 			cv_wait(&nfs_server_upordown_cv,
    507     0    stevel 			    &nfs_server_upordown_lock);
    508     0    stevel 
    509     0    stevel 		if (nfs_server_upordown != NFS_SERVER_RUNNING) {
    510     0    stevel 			(void) svc_pool_control(NFS_SVCPOOL_ID,
    511     0    stevel 			    SVCPSET_UNREGISTER_PROC, (void *)&nfs_srv_offline);
    512     0    stevel 			(void) svc_pool_control(NFS_SVCPOOL_ID,
    513     0    stevel 			    SVCPSET_SHUTDOWN_PROC, (void *)&nfs_srv_stop_all);
    514     0    stevel 
    515     0    stevel 			/* is this an nfsd warm start? */
    516     0    stevel 			if (nfs_server_upordown == NFS_SERVER_QUIESCED) {
    517     0    stevel 				cmn_err(CE_NOTE, "nfs_server: "
    518     0    stevel 				    "server was previously quiesced; "
    519     0    stevel 				    "existing NFSv4 state will be re-used");
    520     0    stevel 
    521     0    stevel 				/*
    522  2035     calum 				 * HA-NFSv4: this is also the signal
    523  2035     calum 				 * that a Resource Group failover has
    524  2035     calum 				 * occurred.
    525     0    stevel 				 */
    526  2390     calum 				if (cluster_bootflags & CLUSTER_BOOTED)
    527  2035     calum 					hanfsv4_failover();
    528     0    stevel 			} else {
    529  2035     calum 				/* cold start */
    530     0    stevel 				rfs4_state_init();
    531    74  rg137905 				nfs4_drc = rfs4_init_drc(nfs4_drc_max,
    532  7961   Natalie 				    nfs4_drc_hash);
    533     0    stevel 			}
    534     0    stevel 
    535     0    stevel 			/*
    536     0    stevel 			 * Check to see if delegation is to be
    537     0    stevel 			 * enabled at the server
    538     0    stevel 			 */
    539     0    stevel 			if (nfs4_srv_delegation != FALSE)
    540     0    stevel 				rfs4_set_deleg_policy(SRV_NORMAL_DELEGATE);
    541     0    stevel 
    542     0    stevel 			nfs_server_upordown = NFS_SERVER_RUNNING;
    543     0    stevel 		}
    544     0    stevel 		cv_signal(&nfs_server_upordown_cv);
    545     0    stevel 	}
    546     0    stevel 	mutex_exit(&nfs_server_upordown_lock);
    547     0    stevel }
    548     0    stevel 
    549     0    stevel /*
    550     0    stevel  * If RDMA device available,
    551     0    stevel  * start RDMA listener.
    552     0    stevel  */
    553     0    stevel int
    554     0    stevel rdma_start(struct rdma_svc_args *rsa)
    555     0    stevel {
    556     0    stevel 	int error;
    557     0    stevel 	rdma_xprt_group_t started_rdma_xprts;
    558  8695  Rajkumar 	rdma_stat stat;
    559  8695  Rajkumar 	int svc_state = 0;
    560     0    stevel 
    561     0    stevel 	/* Double check the vers min/max ranges */
    562     0    stevel 	if ((rsa->nfs_versmin > rsa->nfs_versmax) ||
    563  7961   Natalie 	    (rsa->nfs_versmin < NFS_VERSMIN) ||
    564  7961   Natalie 	    (rsa->nfs_versmax > NFS_VERSMAX)) {
    565     0    stevel 		rsa->nfs_versmin = NFS_VERSMIN_DEFAULT;
    566     0    stevel 		rsa->nfs_versmax = NFS_VERSMAX_DEFAULT;
    567     0    stevel 	}
    568     0    stevel 	nfs_versmin = rsa->nfs_versmin;
    569     0    stevel 	nfs_versmax = rsa->nfs_versmax;
    570     0    stevel 
    571     0    stevel 	/* Set the versions in the callout table */
    572     0    stevel 	__nfs_sc_rdma[0].sc_versmin = rsa->nfs_versmin;
    573     0    stevel 	__nfs_sc_rdma[0].sc_versmax = rsa->nfs_versmax;
    574     0    stevel 	/* For the NFS_ACL program, check the max version */
    575     0    stevel 	__nfs_sc_rdma[1].sc_versmin = rsa->nfs_versmin;
    576     0    stevel 	if (rsa->nfs_versmax > NFS_ACL_VERSMAX)
    577     0    stevel 		__nfs_sc_rdma[1].sc_versmax = NFS_ACL_VERSMAX;
    578     0    stevel 	else
    579     0    stevel 		__nfs_sc_rdma[1].sc_versmax = rsa->nfs_versmax;
    580     0    stevel 
    581     0    stevel 	/* Initialize nfsv4 server */
    582     0    stevel 	if (rsa->nfs_versmax == (rpcvers_t)NFS_V4)
    583     0    stevel 		rfs4_server_start(rsa->delegation);
    584     0    stevel 
    585     0    stevel 	started_rdma_xprts.rtg_count = 0;
    586     0    stevel 	started_rdma_xprts.rtg_listhead = NULL;
    587     0    stevel 	started_rdma_xprts.rtg_poolid = rsa->poolid;
    588  8695  Rajkumar 
    589  8695  Rajkumar restart:
    590     0    stevel 	error = svc_rdma_kcreate(rsa->netid, &nfs_sct_rdma, rsa->poolid,
    591     0    stevel 	    &started_rdma_xprts);
    592     0    stevel 
    593  8695  Rajkumar 	svc_state = !error;
    594  8695  Rajkumar 
    595  8695  Rajkumar 	while (!error) {
    596  8695  Rajkumar 
    597  8695  Rajkumar 		/*
    598  8695  Rajkumar 		 * wait till either interrupted by a signal on
    599  8695  Rajkumar 		 * nfs service stop/restart or signalled by a
    600  8695  Rajkumar 		 * rdma plugin attach/detatch.
    601  8695  Rajkumar 		 */
    602  8695  Rajkumar 
    603  8695  Rajkumar 		stat = rdma_kwait();
    604  8695  Rajkumar 
    605  8695  Rajkumar 		/*
    606  8695  Rajkumar 		 * stop services if running -- either on a HCA detach event
    607  8695  Rajkumar 		 * or if the nfs service is stopped/restarted.
    608  8695  Rajkumar 		 */
    609  8695  Rajkumar 
    610  8695  Rajkumar 		if ((stat == RDMA_HCA_DETACH || stat == RDMA_INTR) &&
    611  8695  Rajkumar 		    svc_state) {
    612  8695  Rajkumar 			rdma_stop(&started_rdma_xprts);
    613  8695  Rajkumar 			svc_state = 0;
    614     0    stevel 		}
    615  8695  Rajkumar 
    616  8695  Rajkumar 		/*
    617  8695  Rajkumar 		 * nfs service stop/restart, break out of the
    618  8695  Rajkumar 		 * wait loop and return;
    619  8695  Rajkumar 		 */
    620  8695  Rajkumar 		if (stat == RDMA_INTR)
    621  8695  Rajkumar 			return (0);
    622  8695  Rajkumar 
    623  8695  Rajkumar 		/*
    624  8695  Rajkumar 		 * restart stopped services on a HCA attach event
    625  8695  Rajkumar 		 * (if not already running)
    626  8695  Rajkumar 		 */
    627  8695  Rajkumar 
    628  8695  Rajkumar 		if ((stat == RDMA_HCA_ATTACH) && (svc_state == 0))
    629  8695  Rajkumar 			goto restart;
    630  8695  Rajkumar 
    631  8695  Rajkumar 		/*
    632  8695  Rajkumar 		 * loop until a nfs service stop/restart
    633  8695  Rajkumar 		 */
    634     0    stevel 	}
    635     0    stevel 
    636     0    stevel 	return (error);
    637     0    stevel }
    638     0    stevel 
    639     0    stevel /* ARGSUSED */
    640    74  rg137905 void
    641     0    stevel rpc_null(caddr_t *argp, caddr_t *resp)
    642     0    stevel {
    643     0    stevel }
    644     0    stevel 
    645     0    stevel /* ARGSUSED */
    646  5982       ahl void
    647  5982       ahl rpc_null_v3(caddr_t *argp, caddr_t *resp, struct exportinfo *exi,
    648  5982       ahl     struct svc_req *req, cred_t *cr)
    649  5982       ahl {
    650  5982       ahl 	DTRACE_NFSV3_3(op__null__start, struct svc_req *, req,
    651  5982       ahl 	    cred_t *, cr, vnode_t *, NULL);
    652  5982       ahl 	DTRACE_NFSV3_3(op__null__done, struct svc_req *, req,
    653  5982       ahl 	    cred_t *, cr, vnode_t *, NULL);
    654  5982       ahl }
    655  5982       ahl 
    656  5982       ahl /* ARGSUSED */
    657     0    stevel static void
    658     0    stevel rfs_error(caddr_t *argp, caddr_t *resp)
    659     0    stevel {
    660     0    stevel 	/* return (EOPNOTSUPP); */
    661     0    stevel }
    662     0    stevel 
    663     0    stevel static void
    664     0    stevel nullfree(void)
    665     0    stevel {
    666     0    stevel }
    667     0    stevel 
    668     0    stevel static char *rfscallnames_v2[] = {
    669     0    stevel 	"RFS2_NULL",
    670     0    stevel 	"RFS2_GETATTR",
    671     0    stevel 	"RFS2_SETATTR",
    672     0    stevel 	"RFS2_ROOT",
    673     0    stevel 	"RFS2_LOOKUP",
    674     0    stevel 	"RFS2_READLINK",
    675     0    stevel 	"RFS2_READ",
    676     0    stevel 	"RFS2_WRITECACHE",
    677     0    stevel 	"RFS2_WRITE",
    678     0    stevel 	"RFS2_CREATE",
    679     0    stevel 	"RFS2_REMOVE",
    680     0    stevel 	"RFS2_RENAME",
    681     0    stevel 	"RFS2_LINK",
    682     0    stevel 	"RFS2_SYMLINK",
    683     0    stevel 	"RFS2_MKDIR",
    684     0    stevel 	"RFS2_RMDIR",
    685     0    stevel 	"RFS2_READDIR",
    686     0    stevel 	"RFS2_STATFS"
    687     0    stevel };
    688     0    stevel 
    689     0    stevel static struct rpcdisp rfsdisptab_v2[] = {
    690     0    stevel 	/*
    691     0    stevel 	 * NFS VERSION 2
    692     0    stevel 	 */
    693     0    stevel 
    694     0    stevel 	/* RFS_NULL = 0 */
    695     0    stevel 	{rpc_null,
    696     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
    697     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
    698     0    stevel 	    nullfree, RPC_IDEMPOTENT,
    699    74  rg137905 	    0},
    700     0    stevel 
    701     0    stevel 	/* RFS_GETATTR = 1 */
    702     0    stevel 	{rfs_getattr,
    703     0    stevel 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
    704     0    stevel 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
    705     0    stevel 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
    706    74  rg137905 	    rfs_getattr_getfh},
    707     0    stevel 
    708     0    stevel 	/* RFS_SETATTR = 2 */
    709     0    stevel 	{rfs_setattr,
    710     0    stevel 	    xdr_saargs, NULL_xdrproc_t, sizeof (struct nfssaargs),
    711     0    stevel 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
    712     0    stevel 	    nullfree, RPC_MAPRESP,
    713    74  rg137905 	    rfs_setattr_getfh},
    714     0    stevel 
    715     0    stevel 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
    716     0    stevel 	{rfs_error,
    717     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
    718     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
    719     0    stevel 	    nullfree, RPC_IDEMPOTENT,
    720    74  rg137905 	    0},
    721     0    stevel 
    722     0    stevel 	/* RFS_LOOKUP = 4 */
    723     0    stevel 	{rfs_lookup,
    724     0    stevel 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
    725     0    stevel 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
    726     0    stevel 	    nullfree, RPC_IDEMPOTENT|RPC_MAPRESP|RPC_PUBLICFH_OK,
    727    74  rg137905 	    rfs_lookup_getfh},
    728     0    stevel 
    729     0    stevel 	/* RFS_READLINK = 5 */
    730     0    stevel 	{rfs_readlink,
    731     0    stevel 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
    732     0    stevel 	    xdr_rdlnres, NULL_xdrproc_t, sizeof (struct nfsrdlnres),
    733     0    stevel 	    rfs_rlfree, RPC_IDEMPOTENT,
    734    74  rg137905 	    rfs_readlink_getfh},
    735     0    stevel 
    736     0    stevel 	/* RFS_READ = 6 */
    737     0    stevel 	{rfs_read,
    738     0    stevel 	    xdr_readargs, NULL_xdrproc_t, sizeof (struct nfsreadargs),
    739     0    stevel 	    xdr_rdresult, NULL_xdrproc_t, sizeof (struct nfsrdresult),
    740     0    stevel 	    rfs_rdfree, RPC_IDEMPOTENT,
    741    74  rg137905 	    rfs_read_getfh},
    742     0    stevel 
    743     0    stevel 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
    744     0    stevel 	{rfs_error,
    745     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
    746     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
    747     0    stevel 	    nullfree, RPC_IDEMPOTENT,
    748    74  rg137905 	    0},
    749     0    stevel 
    750     0    stevel 	/* RFS_WRITE = 8 */
    751     0    stevel 	{rfs_write,
    752     0    stevel 	    xdr_writeargs, NULL_xdrproc_t, sizeof (struct nfswriteargs),
    753     0    stevel 	    xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
    754     0    stevel 	    nullfree, RPC_MAPRESP,
    755    74  rg137905 	    rfs_write_getfh},
    756     0    stevel 
    757     0    stevel 	/* RFS_CREATE = 9 */
    758     0    stevel 	{rfs_create,
    759     0    stevel 	    xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
    760     0    stevel 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
    761     0    stevel 	    nullfree, RPC_MAPRESP,
    762    74  rg137905 	    rfs_create_getfh},
    763     0    stevel 
    764     0    stevel 	/* RFS_REMOVE = 10 */
    765     0    stevel 	{rfs_remove,
    766     0    stevel 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
    767     0    stevel #ifdef _LITTLE_ENDIAN
    768     0    stevel 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
    769     0    stevel #else
    770     0    stevel 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
    771     0    stevel #endif
    772     0    stevel 	    nullfree, RPC_MAPRESP,
    773    74  rg137905 	    rfs_remove_getfh},
    774     0    stevel 
    775     0    stevel 	/* RFS_RENAME = 11 */
    776     0    stevel 	{rfs_rename,
    777     0    stevel 	    xdr_rnmargs, NULL_xdrproc_t, sizeof (struct nfsrnmargs),
    778     0    stevel #ifdef _LITTLE_ENDIAN
    779     0    stevel 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
    780     0    stevel #else
    781     0    stevel 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
    782     0    stevel #endif
    783     0    stevel 	    nullfree, RPC_MAPRESP,
    784    74  rg137905 	    rfs_rename_getfh},
    785     0    stevel 
    786     0    stevel 	/* RFS_LINK = 12 */
    787     0    stevel 	{rfs_link,
    788     0    stevel 	    xdr_linkargs, NULL_xdrproc_t, sizeof (struct nfslinkargs),
    789     0    stevel #ifdef _LITTLE_ENDIAN
    790     0    stevel 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
    791     0    stevel #else
    792     0    stevel 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
    793     0    stevel #endif
    794     0    stevel 	    nullfree, RPC_MAPRESP,
    795    74  rg137905 	    rfs_link_getfh},
    796     0    stevel 
    797     0    stevel 	/* RFS_SYMLINK = 13 */
    798     0    stevel 	{rfs_symlink,
    799     0    stevel 	    xdr_slargs, NULL_xdrproc_t, sizeof (struct nfsslargs),
    800     0    stevel #ifdef _LITTLE_ENDIAN
    801     0    stevel 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
    802     0    stevel #else
    803     0    stevel 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
    804     0    stevel #endif
    805     0    stevel 	    nullfree, RPC_MAPRESP,
    806    74  rg137905 	    rfs_symlink_getfh},
    807     0    stevel 
    808     0    stevel 	/* RFS_MKDIR = 14 */
    809     0    stevel 	{rfs_mkdir,
    810     0    stevel 	    xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
    811     0    stevel 	    xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
    812     0    stevel 	    nullfree, RPC_MAPRESP,
    813    74  rg137905 	    rfs_mkdir_getfh},
    814     0    stevel 
    815     0    stevel 	/* RFS_RMDIR = 15 */
    816     0    stevel 	{rfs_rmdir,
    817     0    stevel 	    xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
    818     0    stevel #ifdef _LITTLE_ENDIAN
    819     0    stevel 	    xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
    820     0    stevel #else
    821     0    stevel 	    xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
    822     0    stevel #endif
    823     0    stevel 	    nullfree, RPC_MAPRESP,
    824    74  rg137905 	    rfs_rmdir_getfh},
    825     0    stevel 
    826     0    stevel 	/* RFS_READDIR = 16 */
    827     0    stevel 	{rfs_readdir,
    828     0    stevel 	    xdr_rddirargs, NULL_xdrproc_t, sizeof (struct nfsrddirargs),
    829     0    stevel 	    xdr_putrddirres, NULL_xdrproc_t, sizeof (struct nfsrddirres),
    830     0    stevel 	    rfs_rddirfree, RPC_IDEMPOTENT,
    831    74  rg137905 	    rfs_readdir_getfh},
    832     0    stevel 
    833     0    stevel 	/* RFS_STATFS = 17 */
    834     0    stevel 	{rfs_statfs,
    835     0    stevel 	    xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
    836     0    stevel 	    xdr_statfs, xdr_faststatfs, sizeof (struct nfsstatfs),
    837     0    stevel 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
    838    74  rg137905 	    rfs_statfs_getfh},
    839     0    stevel };
    840     0    stevel 
    841     0    stevel static char *rfscallnames_v3[] = {
    842     0    stevel 	"RFS3_NULL",
    843     0    stevel 	"RFS3_GETATTR",
    844     0    stevel 	"RFS3_SETATTR",
    845     0    stevel 	"RFS3_LOOKUP",
    846     0    stevel 	"RFS3_ACCESS",
    847     0    stevel 	"RFS3_READLINK",
    848     0    stevel 	"RFS3_READ",
    849     0    stevel 	"RFS3_WRITE",
    850     0    stevel 	"RFS3_CREATE",
    851     0    stevel 	"RFS3_MKDIR",
    852     0    stevel 	"RFS3_SYMLINK",
    853     0    stevel 	"RFS3_MKNOD",
    854     0    stevel 	"RFS3_REMOVE",
    855     0    stevel 	"RFS3_RMDIR",
    856     0    stevel 	"RFS3_RENAME",
    857     0    stevel 	"RFS3_LINK",
    858     0    stevel 	"RFS3_READDIR",
    859     0    stevel 	"RFS3_READDIRPLUS",
    860     0    stevel 	"RFS3_FSSTAT",
    861     0    stevel 	"RFS3_FSINFO",
    862     0    stevel 	"RFS3_PATHCONF",
    863     0    stevel 	"RFS3_COMMIT"
    864     0    stevel };
    865     0    stevel 
    866     0    stevel static struct rpcdisp rfsdisptab_v3[] = {
    867     0    stevel 	/*
    868     0    stevel 	 * NFS VERSION 3
    869     0    stevel 	 */
    870     0    stevel 
    871     0    stevel 	/* RFS_NULL = 0 */
    872  5982       ahl 	{rpc_null_v3,
    873     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
    874     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
    875     0    stevel 	    nullfree, RPC_IDEMPOTENT,
    876    74  rg137905 	    0},
    877     0    stevel 
    878     0    stevel 	/* RFS3_GETATTR = 1 */
    879     0    stevel 	{rfs3_getattr,
    880  1610   thurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (GETATTR3args),
    881     0    stevel 	    xdr_GETATTR3res, NULL_xdrproc_t, sizeof (GETATTR3res),
    882     0    stevel 	    nullfree, (RPC_IDEMPOTENT | RPC_ALLOWANON),
    883    74  rg137905 	    rfs3_getattr_getfh},
    884     0    stevel 
    885     0    stevel 	/* RFS3_SETATTR = 2 */
    886     0    stevel 	{rfs3_setattr,
    887     0    stevel 	    xdr_SETATTR3args, NULL_xdrproc_t, sizeof (SETATTR3args),
    888     0    stevel 	    xdr_SETATTR3res, NULL_xdrproc_t, sizeof (SETATTR3res),
    889     0    stevel 	    nullfree, 0,
    890    74  rg137905 	    rfs3_setattr_getfh},
    891     0    stevel 
    892     0    stevel 	/* RFS3_LOOKUP = 3 */
    893     0    stevel 	{rfs3_lookup,
    894     0    stevel 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (LOOKUP3args),
    895     0    stevel 	    xdr_LOOKUP3res, NULL_xdrproc_t, sizeof (LOOKUP3res),
    896     0    stevel 	    nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK),
    897    74  rg137905 	    rfs3_lookup_getfh},
    898     0    stevel 
    899     0    stevel 	/* RFS3_ACCESS = 4 */
    900     0    stevel 	{rfs3_access,
    901     0    stevel 	    xdr_ACCESS3args, NULL_xdrproc_t, sizeof (ACCESS3args),
    902     0    stevel 	    xdr_ACCESS3res, NULL_xdrproc_t, sizeof (ACCESS3res),
    903     0    stevel 	    nullfree, RPC_IDEMPOTENT,
    904    74  rg137905 	    rfs3_access_getfh},
    905     0    stevel 
    906     0    stevel 	/* RFS3_READLINK = 5 */
    907     0    stevel 	{rfs3_readlink,
    908  1610   thurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (READLINK3args),
    909     0    stevel 	    xdr_READLINK3res, NULL_xdrproc_t, sizeof (READLINK3res),
    910     0    stevel 	    rfs3_readlink_free, RPC_IDEMPOTENT,
    911    74  rg137905 	    rfs3_readlink_getfh},
    912     0    stevel 
    913     0    stevel 	/* RFS3_READ = 6 */
    914     0    stevel 	{rfs3_read,
    915     0    stevel 	    xdr_READ3args, NULL_xdrproc_t, sizeof (READ3args),
    916     0    stevel 	    xdr_READ3res, NULL_xdrproc_t, sizeof (READ3res),
    917     0    stevel 	    rfs3_read_free, RPC_IDEMPOTENT,
    918    74  rg137905 	    rfs3_read_getfh},
    919     0    stevel 
    920     0    stevel 	/* RFS3_WRITE = 7 */
    921     0    stevel 	{rfs3_write,
    922     0    stevel 	    xdr_WRITE3args, NULL_xdrproc_t, sizeof (WRITE3args),
    923     0    stevel 	    xdr_WRITE3res, NULL_xdrproc_t, sizeof (WRITE3res),
    924     0    stevel 	    nullfree, 0,
    925    74  rg137905 	    rfs3_write_getfh},
    926     0    stevel 
    927     0    stevel 	/* RFS3_CREATE = 8 */
    928     0    stevel 	{rfs3_create,
    929     0    stevel 	    xdr_CREATE3args, NULL_xdrproc_t, sizeof (CREATE3args),
    930     0    stevel 	    xdr_CREATE3res, NULL_xdrproc_t, sizeof (CREATE3res),
    931     0    stevel 	    nullfree, 0,
    932    74  rg137905 	    rfs3_create_getfh},
    933     0    stevel 
    934     0    stevel 	/* RFS3_MKDIR = 9 */
    935     0    stevel 	{rfs3_mkdir,
    936     0    stevel 	    xdr_MKDIR3args, NULL_xdrproc_t, sizeof (MKDIR3args),
    937     0    stevel 	    xdr_MKDIR3res, NULL_xdrproc_t, sizeof (MKDIR3res),
    938     0    stevel 	    nullfree, 0,
    939    74  rg137905 	    rfs3_mkdir_getfh},
    940     0    stevel 
    941     0    stevel 	/* RFS3_SYMLINK = 10 */
    942     0    stevel 	{rfs3_symlink,
    943     0    stevel 	    xdr_SYMLINK3args, NULL_xdrproc_t, sizeof (SYMLINK3args),
    944     0    stevel 	    xdr_SYMLINK3res, NULL_xdrproc_t, sizeof (SYMLINK3res),
    945     0    stevel 	    nullfree, 0,
    946    74  rg137905 	    rfs3_symlink_getfh},
    947     0    stevel 
    948     0    stevel 	/* RFS3_MKNOD = 11 */
    949     0    stevel 	{rfs3_mknod,
    950     0    stevel 	    xdr_MKNOD3args, NULL_xdrproc_t, sizeof (MKNOD3args),
    951     0    stevel 	    xdr_MKNOD3res, NULL_xdrproc_t, sizeof (MKNOD3res),
    952     0    stevel 	    nullfree, 0,
    953    74  rg137905 	    rfs3_mknod_getfh},
    954     0    stevel 
    955     0    stevel 	/* RFS3_REMOVE = 12 */
    956     0    stevel 	{rfs3_remove,
    957     0    stevel 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (REMOVE3args),
    958     0    stevel 	    xdr_REMOVE3res, NULL_xdrproc_t, sizeof (REMOVE3res),
    959     0    stevel 	    nullfree, 0,
    960    74  rg137905 	    rfs3_remove_getfh},
    961     0    stevel 
    962     0    stevel 	/* RFS3_RMDIR = 13 */
    963     0    stevel 	{rfs3_rmdir,
    964     0    stevel 	    xdr_diropargs3, NULL_xdrproc_t, sizeof (RMDIR3args),
    965     0    stevel 	    xdr_RMDIR3res, NULL_xdrproc_t, sizeof (RMDIR3res),
    966     0    stevel 	    nullfree, 0,
    967    74  rg137905 	    rfs3_rmdir_getfh},
    968     0    stevel 
    969     0    stevel 	/* RFS3_RENAME = 14 */
    970     0    stevel 	{rfs3_rename,
    971     0    stevel 	    xdr_RENAME3args, NULL_xdrproc_t, sizeof (RENAME3args),
    972     0    stevel 	    xdr_RENAME3res, NULL_xdrproc_t, sizeof (RENAME3res),
    973     0    stevel 	    nullfree, 0,
    974    74  rg137905 	    rfs3_rename_getfh},
    975     0    stevel 
    976     0    stevel 	/* RFS3_LINK = 15 */
    977     0    stevel 	{rfs3_link,
    978     0    stevel 	    xdr_LINK3args, NULL_xdrproc_t, sizeof (LINK3args),
    979     0    stevel 	    xdr_LINK3res, NULL_xdrproc_t, sizeof (LINK3res),
    980     0    stevel 	    nullfree, 0,
    981    74  rg137905 	    rfs3_link_getfh},
    982     0    stevel 
    983     0    stevel 	/* RFS3_READDIR = 16 */
    984     0    stevel 	{rfs3_readdir,
    985     0    stevel 	    xdr_READDIR3args, NULL_xdrproc_t, sizeof (READDIR3args),
    986     0    stevel 	    xdr_READDIR3res, NULL_xdrproc_t, sizeof (READDIR3res),
    987     0    stevel 	    rfs3_readdir_free, RPC_IDEMPOTENT,
    988    74  rg137905 	    rfs3_readdir_getfh},
    989     0    stevel 
    990     0    stevel 	/* RFS3_READDIRPLUS = 17 */
    991     0    stevel 	{rfs3_readdirplus,
    992     0    stevel 	    xdr_READDIRPLUS3args, NULL_xdrproc_t, sizeof (READDIRPLUS3args),
    993     0    stevel 	    xdr_READDIRPLUS3res, NULL_xdrproc_t, sizeof (READDIRPLUS3res),
    994     0    stevel 	    rfs3_readdirplus_free, RPC_AVOIDWORK,
    995    74  rg137905 	    rfs3_readdirplus_getfh},
    996     0    stevel 
    997     0    stevel 	/* RFS3_FSSTAT = 18 */
    998     0    stevel 	{rfs3_fsstat,
    999  1610   thurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSSTAT3args),
   1000     0    stevel 	    xdr_FSSTAT3res, NULL_xdrproc_t, sizeof (FSSTAT3res),
   1001     0    stevel 	    nullfree, RPC_IDEMPOTENT,
   1002    74  rg137905 	    rfs3_fsstat_getfh},
   1003     0    stevel 
   1004     0    stevel 	/* RFS3_FSINFO = 19 */
   1005     0    stevel 	{rfs3_fsinfo,
   1006  1610   thurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSINFO3args),
   1007     0    stevel 	    xdr_FSINFO3res, NULL_xdrproc_t, sizeof (FSINFO3res),
   1008     0    stevel 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON,
   1009    74  rg137905 	    rfs3_fsinfo_getfh},
   1010     0    stevel 
   1011     0    stevel 	/* RFS3_PATHCONF = 20 */
   1012     0    stevel 	{rfs3_pathconf,
   1013  1610   thurlow 	    xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (PATHCONF3args),
   1014     0    stevel 	    xdr_PATHCONF3res, NULL_xdrproc_t, sizeof (PATHCONF3res),
   1015     0    stevel 	    nullfree, RPC_IDEMPOTENT,
   1016    74  rg137905 	    rfs3_pathconf_getfh},
   1017     0    stevel 
   1018     0    stevel 	/* RFS3_COMMIT = 21 */
   1019     0    stevel 	{rfs3_commit,
   1020     0    stevel 	    xdr_COMMIT3args, NULL_xdrproc_t, sizeof (COMMIT3args),
   1021     0    stevel 	    xdr_COMMIT3res, NULL_xdrproc_t, sizeof (COMMIT3res),
   1022     0    stevel 	    nullfree, RPC_IDEMPOTENT,
   1023    74  rg137905 	    rfs3_commit_getfh},
   1024     0    stevel };
   1025     0    stevel 
   1026     0    stevel static char *rfscallnames_v4[] = {
   1027     0    stevel 	"RFS4_NULL",
   1028     0    stevel 	"RFS4_COMPOUND",
   1029     0    stevel 	"RFS4_NULL",
   1030     0    stevel 	"RFS4_NULL",
   1031     0    stevel 	"RFS4_NULL",
   1032     0    stevel 	"RFS4_NULL",
   1033     0    stevel 	"RFS4_NULL",
   1034     0    stevel 	"RFS4_NULL",
   1035     0    stevel 	"RFS4_CREATE"
   1036     0    stevel };
   1037     0    stevel 
   1038     0    stevel static struct rpcdisp rfsdisptab_v4[] = {
   1039     0    stevel 	/*
   1040     0    stevel 	 * NFS VERSION 4
   1041     0    stevel 	 */
   1042     0    stevel 
   1043     0    stevel 	/* RFS_NULL = 0 */
   1044     0    stevel 	{rpc_null,
   1045     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
   1046     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
   1047    74  rg137905 	    nullfree, RPC_IDEMPOTENT, 0},
   1048     0    stevel 
   1049     0    stevel 	/* RFS4_compound = 1 */
   1050     0    stevel 	{rfs4_compound,
   1051   806  ek110237 	    xdr_COMPOUND4args_srv, NULL_xdrproc_t, sizeof (COMPOUND4args),
   1052   806  ek110237 	    xdr_COMPOUND4res_srv, NULL_xdrproc_t, sizeof (COMPOUND4res),
   1053    74  rg137905 	    rfs4_compound_free, 0, 0},
   1054     0    stevel };
   1055     0    stevel 
   1056     0    stevel union rfs_args {
   1057     0    stevel 	/*
   1058     0    stevel 	 * NFS VERSION 2
   1059     0    stevel 	 */
   1060     0    stevel 
   1061     0    stevel 	/* RFS_NULL = 0 */
   1062     0    stevel 
   1063     0    stevel 	/* RFS_GETATTR = 1 */
   1064     0    stevel 	fhandle_t nfs2_getattr_args;
   1065     0    stevel 
   1066     0    stevel 	/* RFS_SETATTR = 2 */
   1067     0    stevel 	struct nfssaargs nfs2_setattr_args;
   1068     0    stevel 
   1069     0    stevel 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
   1070     0    stevel 
   1071     0    stevel 	/* RFS_LOOKUP = 4 */
   1072     0    stevel 	struct nfsdiropargs nfs2_lookup_args;
   1073     0    stevel 
   1074     0    stevel 	/* RFS_READLINK = 5 */
   1075     0    stevel 	fhandle_t nfs2_readlink_args;
   1076     0    stevel 
   1077     0    stevel 	/* RFS_READ = 6 */
   1078     0    stevel 	struct nfsreadargs nfs2_read_args;
   1079     0    stevel 
   1080     0    stevel 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
   1081     0    stevel 
   1082     0    stevel 	/* RFS_WRITE = 8 */
   1083     0    stevel 	struct nfswriteargs nfs2_write_args;
   1084     0    stevel 
   1085     0    stevel 	/* RFS_CREATE = 9 */
   1086     0    stevel 	struct nfscreatargs nfs2_create_args;
   1087     0    stevel 
   1088     0    stevel 	/* RFS_REMOVE = 10 */
   1089     0    stevel 	struct nfsdiropargs nfs2_remove_args;
   1090     0    stevel 
   1091     0    stevel 	/* RFS_RENAME = 11 */
   1092     0    stevel 	struct nfsrnmargs nfs2_rename_args;
   1093     0    stevel 
   1094     0    stevel 	/* RFS_LINK = 12 */
   1095     0    stevel 	struct nfslinkargs nfs2_link_args;
   1096     0    stevel 
   1097     0    stevel 	/* RFS_SYMLINK = 13 */
   1098     0    stevel 	struct nfsslargs nfs2_symlink_args;
   1099     0    stevel 
   1100     0    stevel 	/* RFS_MKDIR = 14 */
   1101     0    stevel 	struct nfscreatargs nfs2_mkdir_args;
   1102     0    stevel 
   1103     0    stevel 	/* RFS_RMDIR = 15 */
   1104     0    stevel 	struct nfsdiropargs nfs2_rmdir_args;
   1105     0    stevel 
   1106     0    stevel 	/* RFS_READDIR = 16 */
   1107     0    stevel 	struct nfsrddirargs nfs2_readdir_args;
   1108     0    stevel 
   1109     0    stevel 	/* RFS_STATFS = 17 */
   1110     0    stevel 	fhandle_t nfs2_statfs_args;
   1111     0    stevel 
   1112     0    stevel 	/*
   1113     0    stevel 	 * NFS VERSION 3
   1114     0    stevel 	 */
   1115     0    stevel 
   1116     0    stevel 	/* RFS_NULL = 0 */
   1117     0    stevel 
   1118     0    stevel 	/* RFS3_GETATTR = 1 */
   1119     0    stevel 	GETATTR3args nfs3_getattr_args;
   1120     0    stevel 
   1121     0    stevel 	/* RFS3_SETATTR = 2 */
   1122     0    stevel 	SETATTR3args nfs3_setattr_args;
   1123     0    stevel 
   1124     0    stevel 	/* RFS3_LOOKUP = 3 */
   1125     0    stevel 	LOOKUP3args nfs3_lookup_args;
   1126     0    stevel 
   1127     0    stevel 	/* RFS3_ACCESS = 4 */
   1128     0    stevel 	ACCESS3args nfs3_access_args;
   1129     0    stevel 
   1130     0    stevel 	/* RFS3_READLINK = 5 */
   1131     0    stevel 	READLINK3args nfs3_readlink_args;
   1132     0    stevel 
   1133     0    stevel 	/* RFS3_READ = 6 */
   1134     0    stevel 	READ3args nfs3_read_args;
   1135     0    stevel 
   1136     0    stevel 	/* RFS3_WRITE = 7 */
   1137     0    stevel 	WRITE3args nfs3_write_args;
   1138     0    stevel 
   1139     0    stevel 	/* RFS3_CREATE = 8 */
   1140     0    stevel 	CREATE3args nfs3_create_args;
   1141     0    stevel 
   1142     0    stevel 	/* RFS3_MKDIR = 9 */
   1143     0    stevel 	MKDIR3args nfs3_mkdir_args;
   1144     0    stevel 
   1145     0    stevel 	/* RFS3_SYMLINK = 10 */
   1146     0    stevel 	SYMLINK3args nfs3_symlink_args;
   1147     0    stevel 
   1148     0    stevel 	/* RFS3_MKNOD = 11 */
   1149     0    stevel 	MKNOD3args nfs3_mknod_args;
   1150     0    stevel 
   1151     0    stevel 	/* RFS3_REMOVE = 12 */
   1152     0    stevel 	REMOVE3args nfs3_remove_args;
   1153     0    stevel 
   1154     0    stevel 	/* RFS3_RMDIR = 13 */
   1155     0    stevel 	RMDIR3args nfs3_rmdir_args;
   1156     0    stevel 
   1157     0    stevel 	/* RFS3_RENAME = 14 */
   1158     0    stevel 	RENAME3args nfs3_rename_args;
   1159     0    stevel 
   1160     0    stevel 	/* RFS3_LINK = 15 */
   1161     0    stevel 	LINK3args nfs3_link_args;
   1162     0    stevel 
   1163     0    stevel 	/* RFS3_READDIR = 16 */
   1164     0    stevel 	READDIR3args nfs3_readdir_args;
   1165     0    stevel 
   1166     0    stevel 	/* RFS3_READDIRPLUS = 17 */
   1167     0    stevel 	READDIRPLUS3args nfs3_readdirplus_args;
   1168     0    stevel 
   1169     0    stevel 	/* RFS3_FSSTAT = 18 */
   1170     0    stevel 	FSSTAT3args nfs3_fsstat_args;
   1171     0    stevel 
   1172     0    stevel 	/* RFS3_FSINFO = 19 */
   1173     0    stevel 	FSINFO3args nfs3_fsinfo_args;
   1174     0    stevel 
   1175     0    stevel 	/* RFS3_PATHCONF = 20 */
   1176     0    stevel 	PATHCONF3args nfs3_pathconf_args;
   1177     0    stevel 
   1178     0    stevel 	/* RFS3_COMMIT = 21 */
   1179     0    stevel 	COMMIT3args nfs3_commit_args;
   1180     0    stevel 
   1181     0    stevel 	/*
   1182     0    stevel 	 * NFS VERSION 4
   1183     0    stevel 	 */
   1184     0    stevel 
   1185     0    stevel 	/* RFS_NULL = 0 */
   1186     0    stevel 
   1187     0    stevel 	/* COMPUND = 1 */
   1188     0    stevel 	COMPOUND4args nfs4_compound_args;
   1189     0    stevel };
   1190     0    stevel 
   1191     0    stevel union rfs_res {
   1192     0    stevel 	/*
   1193     0    stevel 	 * NFS VERSION 2
   1194     0    stevel 	 */
   1195     0    stevel 
   1196     0    stevel 	/* RFS_NULL = 0 */
   1197     0    stevel 
   1198     0    stevel 	/* RFS_GETATTR = 1 */
   1199     0    stevel 	struct nfsattrstat nfs2_getattr_res;
   1200     0    stevel 
   1201     0    stevel 	/* RFS_SETATTR = 2 */
   1202     0    stevel 	struct nfsattrstat nfs2_setattr_res;
   1203     0    stevel 
   1204     0    stevel 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
   1205     0    stevel 
   1206     0    stevel 	/* RFS_LOOKUP = 4 */
   1207     0    stevel 	struct nfsdiropres nfs2_lookup_res;
   1208     0    stevel 
   1209     0    stevel 	/* RFS_READLINK = 5 */
   1210     0    stevel 	struct nfsrdlnres nfs2_readlink_res;
   1211     0    stevel 
   1212     0    stevel 	/* RFS_READ = 6 */
   1213     0    stevel 	struct nfsrdresult nfs2_read_res;
   1214     0    stevel 
   1215     0    stevel 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
   1216     0    stevel 
   1217     0    stevel 	/* RFS_WRITE = 8 */
   1218     0    stevel 	struct nfsattrstat nfs2_write_res;
   1219     0    stevel 
   1220     0    stevel 	/* RFS_CREATE = 9 */
   1221     0    stevel 	struct nfsdiropres nfs2_create_res;
   1222     0    stevel 
   1223     0    stevel 	/* RFS_REMOVE = 10 */
   1224     0    stevel 	enum nfsstat nfs2_remove_res;
   1225     0    stevel 
   1226     0    stevel 	/* RFS_RENAME = 11 */
   1227     0    stevel 	enum nfsstat nfs2_rename_res;
   1228     0    stevel 
   1229     0    stevel 	/* RFS_LINK = 12 */
   1230     0    stevel 	enum nfsstat nfs2_link_res;
   1231     0    stevel 
   1232     0    stevel 	/* RFS_SYMLINK = 13 */
   1233     0    stevel 	enum nfsstat nfs2_symlink_res;
   1234     0    stevel 
   1235     0    stevel 	/* RFS_MKDIR = 14 */
   1236     0    stevel 	struct nfsdiropres nfs2_mkdir_res;
   1237     0    stevel 
   1238     0    stevel 	/* RFS_RMDIR = 15 */
   1239     0    stevel 	enum nfsstat nfs2_rmdir_res;
   1240     0    stevel 
   1241     0    stevel 	/* RFS_READDIR = 16 */
   1242     0    stevel 	struct nfsrddirres nfs2_readdir_res;
   1243     0    stevel 
   1244     0    stevel 	/* RFS_STATFS = 17 */
   1245     0    stevel 	struct nfsstatfs nfs2_statfs_res;
   1246     0    stevel 
   1247     0    stevel 	/*
   1248     0    stevel 	 * NFS VERSION 3
   1249     0    stevel 	 */
   1250     0    stevel 
   1251     0    stevel 	/* RFS_NULL = 0 */
   1252     0    stevel 
   1253     0    stevel 	/* RFS3_GETATTR = 1 */
   1254     0    stevel 	GETATTR3res nfs3_getattr_res;
   1255     0    stevel 
   1256     0    stevel 	/* RFS3_SETATTR = 2 */
   1257     0    stevel 	SETATTR3res nfs3_setattr_res;
   1258     0    stevel 
   1259     0    stevel 	/* RFS3_LOOKUP = 3 */
   1260     0    stevel 	LOOKUP3res nfs3_lookup_res;
   1261     0    stevel 
   1262     0    stevel 	/* RFS3_ACCESS = 4 */
   1263     0    stevel 	ACCESS3res nfs3_access_res;
   1264     0    stevel 
   1265     0    stevel 	/* RFS3_READLINK = 5 */
   1266     0    stevel 	READLINK3res nfs3_readlink_res;
   1267     0    stevel 
   1268     0    stevel 	/* RFS3_READ = 6 */
   1269     0    stevel 	READ3res nfs3_read_res;
   1270     0    stevel 
   1271     0    stevel 	/* RFS3_WRITE = 7 */
   1272     0    stevel 	WRITE3res nfs3_write_res;
   1273     0    stevel 
   1274     0    stevel 	/* RFS3_CREATE = 8 */
   1275     0    stevel 	CREATE3res nfs3_create_res;
   1276     0    stevel 
   1277     0    stevel 	/* RFS3_MKDIR = 9 */
   1278     0    stevel 	MKDIR3res nfs3_mkdir_res;
   1279     0    stevel 
   1280     0    stevel 	/* RFS3_SYMLINK = 10 */
   1281     0    stevel 	SYMLINK3res nfs3_symlink_res;
   1282     0    stevel 
   1283     0    stevel 	/* RFS3_MKNOD = 11 */
   1284     0    stevel 	MKNOD3res nfs3_mknod_res;
   1285     0    stevel 
   1286     0    stevel 	/* RFS3_REMOVE = 12 */
   1287     0    stevel 	REMOVE3res nfs3_remove_res;
   1288     0    stevel 
   1289     0    stevel 	/* RFS3_RMDIR = 13 */
   1290     0    stevel 	RMDIR3res nfs3_rmdir_res;
   1291     0    stevel 
   1292     0    stevel 	/* RFS3_RENAME = 14 */
   1293     0    stevel 	RENAME3res nfs3_rename_res;
   1294     0    stevel 
   1295     0    stevel 	/* RFS3_LINK = 15 */
   1296     0    stevel 	LINK3res nfs3_link_res;
   1297     0    stevel 
   1298     0    stevel 	/* RFS3_READDIR = 16 */
   1299     0    stevel 	READDIR3res nfs3_readdir_res;
   1300     0    stevel 
   1301     0    stevel 	/* RFS3_READDIRPLUS = 17 */
   1302     0    stevel 	READDIRPLUS3res nfs3_readdirplus_res;
   1303     0    stevel 
   1304     0    stevel 	/* RFS3_FSSTAT = 18 */
   1305     0    stevel 	FSSTAT3res nfs3_fsstat_res;
   1306     0    stevel 
   1307     0    stevel 	/* RFS3_FSINFO = 19 */
   1308     0    stevel 	FSINFO3res nfs3_fsinfo_res;
   1309     0    stevel 
   1310     0    stevel 	/* RFS3_PATHCONF = 20 */
   1311     0    stevel 	PATHCONF3res nfs3_pathconf_res;
   1312     0    stevel 
   1313     0    stevel 	/* RFS3_COMMIT = 21 */
   1314     0    stevel 	COMMIT3res nfs3_commit_res;
   1315     0    stevel 
   1316     0    stevel 	/*
   1317     0    stevel 	 * NFS VERSION 4
   1318     0    stevel 	 */
   1319     0    stevel 
   1320     0    stevel 	/* RFS_NULL = 0 */
   1321     0    stevel 
   1322     0    stevel 	/* RFS4_COMPOUND = 1 */
   1323     0    stevel 	COMPOUND4res nfs4_compound_res;
   1324     0    stevel 
   1325     0    stevel };
   1326     0    stevel 
   1327     0    stevel static struct rpc_disptable rfs_disptable[] = {
   1328     0    stevel 	{sizeof (rfsdisptab_v2) / sizeof (rfsdisptab_v2[0]),
   1329     0    stevel 	    rfscallnames_v2,
   1330     0    stevel 	    &rfsproccnt_v2_ptr, rfsdisptab_v2},
   1331     0    stevel 	{sizeof (rfsdisptab_v3) / sizeof (rfsdisptab_v3[0]),
   1332     0    stevel 	    rfscallnames_v3,
   1333     0    stevel 	    &rfsproccnt_v3_ptr, rfsdisptab_v3},
   1334     0    stevel 	{sizeof (rfsdisptab_v4) / sizeof (rfsdisptab_v4[0]),
   1335     0    stevel 	    rfscallnames_v4,
   1336     0    stevel 	    &rfsproccnt_v4_ptr, rfsdisptab_v4},
   1337     0    stevel };
   1338     0    stevel 
   1339     0    stevel /*
   1340     0    stevel  * If nfs_portmon is set, then clients are required to use privileged
   1341     0    stevel  * ports (ports < IPPORT_RESERVED) in order to get NFS services.
   1342     0    stevel  *
   1343     0    stevel  * N.B.: this attempt to carry forward the already ill-conceived notion
   1344     0    stevel  * of privileged ports for TCP/UDP is really quite ineffectual.  Not only
   1345     0    stevel  * is it transport-dependent, it's laughably easy to spoof.  If you're
   1346     0    stevel  * really interested in security, you must start with secure RPC instead.
   1347     0    stevel  */
   1348     0    stevel static int nfs_portmon = 0;
   1349     0    stevel 
   1350     0    stevel #ifdef DEBUG
   1351     0    stevel static int cred_hits = 0;
   1352     0    stevel static int cred_misses = 0;
   1353     0    stevel #endif
   1354     0    stevel 
   1355     0    stevel 
   1356     0    stevel #ifdef DEBUG
   1357     0    stevel /*
   1358     0    stevel  * Debug code to allow disabling of rfs_dispatch() use of
   1359     0    stevel  * fastxdrargs() and fastxdrres() calls for testing purposes.
   1360     0    stevel  */
   1361     0    stevel static int rfs_no_fast_xdrargs = 0;
   1362     0    stevel static int rfs_no_fast_xdrres = 0;
   1363     0    stevel #endif
   1364     0    stevel 
   1365     0    stevel union acl_args {
   1366     0    stevel 	/*
   1367     0    stevel 	 * ACL VERSION 2
   1368     0    stevel 	 */
   1369     0    stevel 
   1370     0    stevel 	/* ACL2_NULL = 0 */
   1371     0    stevel 
   1372     0    stevel 	/* ACL2_GETACL = 1 */
   1373     0    stevel 	GETACL2args acl2_getacl_args;
   1374     0    stevel 
   1375     0    stevel 	/* ACL2_SETACL = 2 */
   1376     0    stevel 	SETACL2args acl2_setacl_args;
   1377     0    stevel 
   1378     0    stevel 	/* ACL2_GETATTR = 3 */
   1379     0    stevel 	GETATTR2args acl2_getattr_args;
   1380     0    stevel 
   1381     0    stevel 	/* ACL2_ACCESS = 4 */
   1382     0    stevel 	ACCESS2args acl2_access_args;
   1383     0    stevel 
   1384     0    stevel 	/* ACL2_GETXATTRDIR = 5 */
   1385     0    stevel 	GETXATTRDIR2args acl2_getxattrdir_args;
   1386     0    stevel 
   1387     0    stevel 	/*
   1388     0    stevel 	 * ACL VERSION 3
   1389     0    stevel 	 */
   1390     0    stevel 
   1391     0    stevel 	/* ACL3_NULL = 0 */
   1392     0    stevel 
   1393     0    stevel 	/* ACL3_GETACL = 1 */
   1394     0    stevel 	GETACL3args acl3_getacl_args;
   1395     0    stevel 
   1396     0    stevel 	/* ACL3_SETACL = 2 */
   1397     0    stevel 	SETACL3args acl3_setacl;
   1398     0    stevel 
   1399     0    stevel 	/* ACL3_GETXATTRDIR = 3 */
   1400     0    stevel 	GETXATTRDIR3args acl3_getxattrdir_args;
   1401     0    stevel 
   1402     0    stevel };
   1403     0    stevel 
   1404     0    stevel union acl_res {
   1405     0    stevel 	/*
   1406     0    stevel 	 * ACL VERSION 2
   1407     0    stevel 	 */
   1408     0    stevel 
   1409     0    stevel 	/* ACL2_NULL = 0 */
   1410     0    stevel 
   1411     0    stevel 	/* ACL2_GETACL = 1 */
   1412     0    stevel 	GETACL2res acl2_getacl_res;
   1413     0    stevel 
   1414     0    stevel 	/* ACL2_SETACL = 2 */
   1415     0    stevel 	SETACL2res acl2_setacl_res;
   1416     0    stevel 
   1417     0    stevel 	/* ACL2_GETATTR = 3 */
   1418     0    stevel 	GETATTR2res acl2_getattr_res;
   1419     0    stevel 
   1420     0    stevel 	/* ACL2_ACCESS = 4 */
   1421     0    stevel 	ACCESS2res acl2_access_res;
   1422     0    stevel 
   1423     0    stevel 	/* ACL2_GETXATTRDIR = 5 */
   1424     0    stevel 	GETXATTRDIR2args acl2_getxattrdir_res;
   1425     0    stevel 
   1426     0    stevel 	/*
   1427     0    stevel 	 * ACL VERSION 3
   1428     0    stevel 	 */
   1429     0    stevel 
   1430     0    stevel 	/* ACL3_NULL = 0 */
   1431     0    stevel 
   1432     0    stevel 	/* ACL3_GETACL = 1 */
   1433     0    stevel 	GETACL3res acl3_getacl_res;
   1434     0    stevel 
   1435     0    stevel 	/* ACL3_SETACL = 2 */
   1436     0    stevel 	SETACL3res acl3_setacl_res;
   1437     0    stevel 
   1438     0    stevel 	/* ACL3_GETXATTRDIR = 3 */
   1439     0    stevel 	GETXATTRDIR3res acl3_getxattrdir_res;
   1440     0    stevel 
   1441     0    stevel };
   1442     0    stevel 
   1443     0    stevel static bool_t
   1444     0    stevel auth_tooweak(struct svc_req *req, char *res)
   1445     0    stevel {
   1446     0    stevel 
   1447     0    stevel 	if (req->rq_vers == NFS_VERSION && req->rq_proc == RFS_LOOKUP) {
   1448     0    stevel 		struct nfsdiropres *dr = (struct nfsdiropres *)res;
   1449     0    stevel 		if (dr->dr_status == WNFSERR_CLNT_FLAVOR)
   1450     0    stevel 			return (TRUE);
   1451     0    stevel 	} else if (req->rq_vers == NFS_V3 && req->rq_proc == NFSPROC3_LOOKUP) {
   1452     0    stevel 		LOOKUP3res *resp = (LOOKUP3res *)res;
   1453     0    stevel 		if (resp->status == WNFSERR_CLNT_FLAVOR)
   1454     0    stevel 			return (TRUE);
   1455     0    stevel 	}
   1456     0    stevel 	return (FALSE);
   1457     0    stevel }
   1458     0    stevel 
   1459    74  rg137905 
   1460     0    stevel static void
   1461     0    stevel common_dispatch(struct svc_req *req, SVCXPRT *xprt, rpcvers_t min_vers,
   1462     0    stevel 		rpcvers_t max_vers, char *pgmname,
   1463     0    stevel 		struct rpc_disptable *disptable)
   1464     0    stevel {
   1465     0    stevel 	int which;
   1466     0    stevel 	rpcvers_t vers;
   1467     0    stevel 	char *args;
   1468     0    stevel 	union {
   1469     0    stevel 			union rfs_args ra;
   1470     0    stevel 			union acl_args aa;
   1471     0    stevel 		} args_buf;
   1472     0    stevel 	char *res;
   1473     0    stevel 	union {
   1474     0    stevel 			union rfs_res rr;
   1475     0    stevel 			union acl_res ar;
   1476     0    stevel 		} res_buf;
   1477     0    stevel 	struct rpcdisp *disp = NULL;
   1478     0    stevel 	int dis_flags = 0;
   1479     0    stevel 	cred_t *cr;
   1480     0    stevel 	int error = 0;
   1481     0    stevel 	int anon_ok;
   1482     0    stevel 	struct exportinfo *exi = NULL;
   1483     0    stevel 	unsigned int nfslog_rec_id;
   1484     0    stevel 	int dupstat;
   1485     0    stevel 	struct dupreq *dr;
   1486     0    stevel 	int authres;
   1487     0    stevel 	bool_t publicfh_ok = FALSE;
   1488     0    stevel 	enum_t auth_flavor;
   1489     0    stevel 	bool_t dupcached = FALSE;
   1490     0    stevel 	struct netbuf	nb;
   1491     0    stevel 	bool_t logging_enabled = FALSE;
   1492     0    stevel 	struct exportinfo *nfslog_exi = NULL;
   1493  1232  robinson 	char **procnames;
   1494  1232  robinson 	char cbuf[INET6_ADDRSTRLEN];	/* to hold both IPv4 and IPv6 addr */
   1495     0    stevel 
   1496     0    stevel 	vers = req->rq_vers;
   1497     0    stevel 
   1498     0    stevel 	if (vers < min_vers || vers > max_vers) {
   1499     0    stevel 		svcerr_progvers(req->rq_xprt, min_vers, max_vers);
   1500     0    stevel 		error++;
   1501     0    stevel 		cmn_err(CE_NOTE, "%s: bad version number %u", pgmname, vers);
   1502     0    stevel 		goto done;
   1503     0    stevel 	}
   1504     0    stevel 	vers -= min_vers;
   1505     0    stevel 
   1506     0    stevel 	which = req->rq_proc;
   1507     0    stevel 	if (which < 0 || which >= disptable[(int)vers].dis_nprocs) {
   1508     0    stevel 		svcerr_noproc(req->rq_xprt);
   1509     0    stevel 		error++;
   1510     0    stevel 		goto done;
   1511     0    stevel 	}
   1512     0    stevel 
   1513     0    stevel 	(*(disptable[(int)vers].dis_proccntp))[which].value.ui64++;
   1514     0    stevel 
   1515     0    stevel 	disp = &disptable[(int)vers].dis_table[which];
   1516  1232  robinson 	procnames = disptable[(int)vers].dis_procnames;
   1517     0    stevel 
   1518     0    stevel 	auth_flavor = req->rq_cred.oa_flavor;
   1519  1232  robinson 
   1520     0    stevel 	/*
   1521     0    stevel 	 * Deserialize into the args struct.
   1522     0    stevel 	 */
   1523     0    stevel 	args = (char *)&args_buf;
   1524    74  rg137905 
   1525     0    stevel #ifdef DEBUG
   1526     0    stevel 	if (rfs_no_fast_xdrargs || (auth_flavor == RPCSEC_GSS) ||
   1527     0    stevel 	    disp->dis_fastxdrargs == NULL_xdrproc_t ||
   1528  1610   thurlow 	    !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args))
   1529     0    stevel #else
   1530     0    stevel 	if ((auth_flavor == RPCSEC_GSS) ||
   1531     0    stevel 	    disp->dis_fastxdrargs == NULL_xdrproc_t ||
   1532  1610   thurlow 	    !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args))
   1533     0    stevel #endif
   1534  1610   thurlow 	{
   1535     0    stevel 		bzero(args, disp->dis_argsz);
   1536     0    stevel 		if (!SVC_GETARGS(xprt, disp->dis_xdrargs, args)) {
   1537  4635  maheshvs 			error++;
   1538  4635  maheshvs 			/*
   1539  4635  maheshvs 			 * Check if we are outside our capabilities.
   1540  4635  maheshvs 			 */
   1541  4635  maheshvs 			if (rfs4_minorvers_mismatch(req, xprt, (void *)args))
   1542  4635  maheshvs 				goto done;
   1543  4635  maheshvs 
   1544     0    stevel 			svcerr_decode(xprt);
   1545  1232  robinson 			cmn_err(CE_NOTE,
   1546  1232  robinson 			    "Failed to decode arguments for %s version %u "
   1547  1232  robinson 			    "procedure %s client %s%s",
   1548  1232  robinson 			    pgmname, vers + min_vers, procnames[which],
   1549  1232  robinson 			    client_name(req), client_addr(req, cbuf));
   1550     0    stevel 			goto done;
   1551     0    stevel 		}
   1552     0    stevel 	}
   1553     0    stevel 
   1554     0    stevel 	/*
   1555    74  rg137905 	 * If Version 4 use that specific dispatch function.
   1556     0    stevel 	 */
   1557    74  rg137905 	if (req->rq_vers == 4) {
   1558    74  rg137905 		error += rfs4_dispatch(disp, req, xprt, args);
   1559    74  rg137905 		goto done;
   1560    74  rg137905 	}
   1561     0    stevel 
   1562    74  rg137905 	dis_flags = disp->dis_flags;
   1563     0    stevel 
   1564     0    stevel 	/*
   1565     0    stevel 	 * Find export information and check authentication,
   1566     0    stevel 	 * setting the credential if everything is ok.
   1567     0    stevel 	 */
   1568     0    stevel 	if (disp->dis_getfh != NULL) {
   1569  1610   thurlow 		void *fh;
   1570  1610   thurlow 		fsid_t *fsid;
   1571  1610   thurlow 		fid_t *fid, *xfid;
   1572  1610   thurlow 		fhandle_t *fh2;
   1573  1610   thurlow 		nfs_fh3 *fh3;
   1574     0    stevel 
   1575     0    stevel 		fh = (*disp->dis_getfh)(args);
   1576  1610   thurlow 		switch (req->rq_vers) {
   1577  1610   thurlow 		case NFS_VERSION:
   1578  1610   thurlow 			fh2 = (fhandle_t *)fh;
   1579  1610   thurlow 			fsid = &fh2->fh_fsid;
   1580  1610   thurlow 			fid = (fid_t *)&fh2->fh_len;
   1581  1610   thurlow 			xfid = (fid_t *)&fh2->fh_xlen;
   1582  1610   thurlow 			break;
   1583  1610   thurlow 		case NFS_V3:
   1584  1610   thurlow 			fh3 = (nfs_fh3 *)fh;
   1585  1610   thurlow 			fsid = &fh3->fh3_fsid;
   1586  1610   thurlow 			fid = FH3TOFIDP(fh3);
   1587  1610   thurlow 			xfid = FH3TOXFIDP(fh3);
   1588  1610   thurlow 			break;
   1589  1610   thurlow 		}
   1590     0    stevel 
   1591     0    stevel 		/*
   1592     0    stevel 		 * Fix for bug 1038302 - corbin
   1593     0    stevel 		 * There is a problem here if anonymous access is
   1594     0    stevel 		 * disallowed.  If the current request is part of the
   1595     0    stevel 		 * client's mount process for the requested filesystem,
   1596     0    stevel 		 * then it will carry root (uid 0) credentials on it, and
   1597     0    stevel 		 * will be denied by checkauth if that client does not
   1598     0    stevel 		 * have explicit root=0 permission.  This will cause the
   1599     0    stevel 		 * client's mount operation to fail.  As a work-around,
   1600     0    stevel 		 * we check here to see if the request is a getattr or
   1601     0    stevel 		 * statfs operation on the exported vnode itself, and
   1602     0    stevel 		 * pass a flag to checkauth with the result of this test.
   1603     0    stevel 		 *
   1604     0    stevel 		 * The filehandle refers to the mountpoint itself if
   1605     0    stevel 		 * the fh_data and fh_xdata portions of the filehandle
   1606     0    stevel 		 * are equal.
   1607     0    stevel 		 *
   1608     0    stevel 		 * Added anon_ok argument to checkauth().
   1609     0    stevel 		 */
   1610     0    stevel 
   1611  1610   thurlow 		if ((dis_flags & RPC_ALLOWANON) && EQFID(fid, xfid))
   1612     0    stevel 			anon_ok = 1;
   1613     0    stevel 		else
   1614     0    stevel 			anon_ok = 0;
   1615     0    stevel 
   1616     0    stevel 		cr = xprt->xp_cred;
   1617     0    stevel 		ASSERT(cr != NULL);
   1618     0    stevel #ifdef DEBUG
   1619     0    stevel 		if (crgetref(cr) != 1) {
   1620     0    stevel 			crfree(cr);
   1621     0    stevel 			cr = crget();
   1622     0    stevel 			xprt->xp_cred = cr;
   1623     0    stevel 			cred_misses++;
   1624     0    stevel 		} else
   1625     0    stevel 			cred_hits++;
   1626     0    stevel #else
   1627     0    stevel 		if (crgetref(cr) != 1) {
   1628     0    stevel 			crfree(cr);
   1629     0    stevel 			cr = crget();
   1630     0    stevel 			xprt->xp_cred = cr;
   1631     0    stevel 		}
   1632     0    stevel #endif
   1633     0    stevel 
   1634  1610   thurlow 		exi = checkexport(fsid, xfid);
   1635    74  rg137905 
   1636     0    stevel 		if (exi != NULL) {
   1637  1610   thurlow 			publicfh_ok = PUBLICFH_CHECK(disp, exi, fsid, xfid);
   1638     0    stevel 
   1639     0    stevel 			/*
   1640     0    stevel 			 * Don't allow non-V4 clients access
   1641     0    stevel 			 * to pseudo exports
   1642     0    stevel 			 */
   1643     0    stevel 			if (PSEUDO(exi)) {
   1644     0    stevel 				svcerr_weakauth(xprt);
   1645     0    stevel 				error++;
   1646     0    stevel 				goto done;
   1647     0    stevel 			}
   1648     0    stevel 
   1649     0    stevel 			authres = checkauth(exi, req, cr, anon_ok, publicfh_ok);
   1650     0    stevel 			/*
   1651     0    stevel 			 * authres >  0: authentication OK - proceed
   1652     0    stevel 			 * authres == 0: authentication weak - return error
   1653     0    stevel 			 * authres <  0: authentication timeout - drop
   1654     0    stevel 			 */
   1655     0    stevel 			if (authres <= 0) {
   1656     0    stevel 				if (authres == 0) {
   1657     0    stevel 					svcerr_weakauth(xprt);
   1658     0    stevel 					error++;
   1659     0    stevel 				}
   1660     0    stevel 				goto done;
   1661     0    stevel 			}
   1662  7961   Natalie 
   1663  7961   Natalie 			/* check to see if we might need charmap */
   1664  7961   Natalie 			if (exi->exi_export.ex_flags & EX_CHARMAP) {
   1665  7961   Natalie 				struct sockaddr *ca;
   1666  7961   Natalie 				ca =  (struct sockaddr *)
   1667  7961   Natalie 				    svc_getrpccaller(req->rq_xprt)->buf;
   1668  7961   Natalie 				(void) nfscmd_charmap(exi, ca);
   1669  7961   Natalie 			}
   1670     0    stevel 		}
   1671     0    stevel 	} else
   1672     0    stevel 		cr = NULL;
   1673     0    stevel 
   1674     0    stevel 	if ((dis_flags & RPC_MAPRESP) && (auth_flavor != RPCSEC_GSS)) {
   1675     0    stevel 		res = (char *)SVC_GETRES(xprt, disp->dis_ressz);
   1676     0    stevel 		if (res == NULL)
   1677     0    stevel 			res = (char *)&res_buf;
   1678     0    stevel 	} else
   1679     0    stevel 		res = (char *)&res_buf;
   1680     0    stevel 
   1681     0    stevel 	if (!(dis_flags & RPC_IDEMPOTENT)) {
   1682     0    stevel 		dupstat = SVC_DUP_EXT(xprt, req, res, disp->dis_ressz, &dr,
   1683  7961   Natalie 		    &dupcached);
   1684     0    stevel 
   1685     0    stevel 		switch (dupstat) {
   1686     0    stevel 		case DUP_ERROR:
   1687     0    stevel 			svcerr_systemerr(xprt);
   1688     0    stevel 			error++;
   1689     0    stevel 			goto done;
   1690     0    stevel 			/* NOTREACHED */
   1691     0    stevel 		case DUP_INPROGRESS:
   1692     0    stevel 			if (res != (char *)&res_buf)
   1693     0    stevel 				SVC_FREERES(xprt);
   1694     0    stevel 			error++;
   1695     0    stevel 			goto done;
   1696     0    stevel 			/* NOTREACHED */
   1697     0    stevel 		case DUP_NEW:
   1698     0    stevel 		case DUP_DROP:
   1699     0    stevel 			curthread->t_flag |= T_DONTPEND;
   1700    74  rg137905 
   1701     0    stevel 			(*disp->dis_proc)(args, res, exi, req, cr);
   1702    74  rg137905 
   1703     0    stevel 			curthread->t_flag &= ~T_DONTPEND;
   1704     0    stevel 			if (curthread->t_flag & T_WOULDBLOCK) {
   1705     0    stevel 				curthread->t_flag &= ~T_WOULDBLOCK;
   1706     0    stevel 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
   1707  7961   Natalie 				    disp->dis_ressz, DUP_DROP);
   1708     0    stevel 				if (res != (char *)&res_buf)
   1709     0    stevel 					SVC_FREERES(xprt);
   1710     0    stevel 				error++;
   1711     0    stevel 				goto done;
   1712     0    stevel 			}
   1713     0    stevel 			if (dis_flags & RPC_AVOIDWORK) {
   1714     0    stevel 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
   1715  7961   Natalie 				    disp->dis_ressz, DUP_DROP);
   1716     0    stevel 			} else {
   1717     0    stevel 				SVC_DUPDONE_EXT(xprt, dr, res,
   1718  7961   Natalie 				    disp->dis_resfree == nullfree ? NULL :
   1719  7961   Natalie 				    disp->dis_resfree,
   1720  7961   Natalie 				    disp->dis_ressz, DUP_DONE);
   1721     0    stevel 				dupcached = TRUE;
   1722     0    stevel 			}
   1723     0    stevel 			break;
   1724     0    stevel 		case DUP_DONE:
   1725     0    stevel 			break;
   1726     0    stevel 		}
   1727     0    stevel 
   1728     0    stevel 	} else {
   1729     0    stevel 		curthread->t_flag |= T_DONTPEND;
   1730    74  rg137905 
   1731     0    stevel 		(*disp->dis_proc)(args, res, exi, req, cr);
   1732    74  rg137905 
   1733     0    stevel 		curthread->t_flag &= ~T_DONTPEND;
   1734     0    stevel 		if (curthread->t_flag & T_WOULDBLOCK) {
   1735     0    stevel 			curthread->t_flag &= ~T_WOULDBLOCK;
   1736     0    stevel 			if (res != (char *)&res_buf)
   1737     0    stevel 				SVC_FREERES(xprt);
   1738     0    stevel 			error++;
   1739     0    stevel 			goto done;
   1740     0    stevel 		}
   1741     0    stevel 	}
   1742     0    stevel 
   1743     0    stevel 	if (auth_tooweak(req, res)) {
   1744     0    stevel 		svcerr_weakauth(xprt);
   1745     0    stevel 		error++;
   1746     0    stevel 		goto done;
   1747     0    stevel 	}
   1748     0    stevel 
   1749     0    stevel 	/*
   1750     0    stevel 	 * Check to see if logging has been enabled on the server.
   1751     0    stevel 	 * If so, then obtain the export info struct to be used for
   1752     0    stevel 	 * the later writing of the log record.  This is done for
   1753     0    stevel 	 * the case that a lookup is done across a non-logged public
   1754     0    stevel 	 * file system.
   1755     0    stevel 	 */
   1756     0    stevel 	if (nfslog_buffer_list != NULL) {
   1757     0    stevel 		nfslog_exi = nfslog_get_exi(exi, req, res, &nfslog_rec_id);
   1758     0    stevel 		/*
   1759     0    stevel 		 * Is logging enabled?
   1760     0    stevel 		 */
   1761     0    stevel 		logging_enabled = (nfslog_exi != NULL);
   1762     0    stevel 
   1763     0    stevel 		/*
   1764     0    stevel 		 * Copy the netbuf for logging purposes, before it is
   1765     0    stevel 		 * freed by svc_sendreply().
   1766     0    stevel 		 */
   1767     0    stevel 		if (logging_enabled) {
   1768     0    stevel 			NFSLOG_COPY_NETBUF(nfslog_exi, xprt, &nb);
   1769     0    stevel 			/*
   1770     0    stevel 			 * If RPC_MAPRESP flag set (i.e. in V2 ops) the
   1771     0    stevel 			 * res gets copied directly into the mbuf and
   1772     0    stevel 			 * may be freed soon after the sendreply. So we
   1773     0    stevel 			 * must copy it here to a safe place...
   1774     0    stevel 			 */
   1775     0    stevel 			if (res != (char *)&res_buf) {
   1776     0    stevel 				bcopy(res, (char *)&res_buf, disp->dis_ressz);
   1777     0    stevel 			}
   1778     0    stevel 		}
   1779     0    stevel 	}
   1780     0    stevel 
   1781     0    stevel 	/*
   1782     0    stevel 	 * Serialize and send results struct
   1783     0    stevel 	 */
   1784     0    stevel #ifdef DEBUG
   1785  1610   thurlow 	if (rfs_no_fast_xdrres == 0 && res != (char *)&res_buf)
   1786     0    stevel #else
   1787  1610   thurlow 	if (res != (char *)&res_buf)
   1788     0    stevel #endif
   1789  1610   thurlow 	{
   1790     0    stevel 		if (!svc_sendreply(xprt, disp->dis_fastxdrres, res)) {
   1791     0    stevel 			cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
   1792     0    stevel 			error++;
   1793     0    stevel 		}
   1794     0    stevel 	} else {
   1795     0    stevel 		if (!svc_sendreply(xprt, disp->dis_xdrres, res)) {
   1796     0    stevel 			cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
   1797     0    stevel 			error++;
   1798     0    stevel 		}
   1799     0    stevel 	}
   1800     0    stevel 
   1801     0    stevel 	/*
   1802     0    stevel 	 * Log if needed
   1803     0    stevel 	 */
   1804     0    stevel 	if (logging_enabled) {
   1805     0    stevel 		nfslog_write_record(nfslog_exi, req, args, (char *)&res_buf,
   1806  7961   Natalie 		    cr, &nb, nfslog_rec_id, NFSLOG_ONE_BUFFER);
   1807     0    stevel 		exi_rele(nfslog_exi);
   1808     0    stevel 		kmem_free((&nb)->buf, (&nb)->len);
   1809     0    stevel 	}
   1810     0    stevel 
   1811     0    stevel 	/*
   1812     0    stevel 	 * Free results struct. With the addition of NFS V4 we can
   1813     0    stevel 	 * have non-idempotent procedures with functions.
   1814     0    stevel 	 */
   1815     0    stevel 	if (disp->dis_resfree != nullfree && dupcached == FALSE) {
   1816     0    stevel 		(*disp->dis_resfree)(res);
   1817     0    stevel 	}
   1818     0    stevel 
   1819     0    stevel done:
   1820     0    stevel 	/*
   1821     0    stevel 	 * Free arguments struct
   1822     0    stevel 	 */
   1823     0    stevel 	if (disp) {
   1824     0    stevel 		if (!SVC_FREEARGS(xprt, disp->dis_xdrargs, args)) {
   1825     0    stevel 			cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
   1826     0    stevel 			error++;
   1827     0    stevel 		}
   1828     0    stevel 	} else {
   1829     0    stevel 		if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) {
   1830     0    stevel 			cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
   1831     0    stevel 			error++;
   1832     0    stevel 		}
   1833     0    stevel 	}
   1834     0    stevel 
   1835     0    stevel 	if (exi != NULL)
   1836     0    stevel 		exi_rele(exi);
   1837     0    stevel 
   1838     0    stevel 	global_svstat_ptr[req->rq_vers][NFS_BADCALLS].value.ui64 += error;
   1839     0    stevel 
   1840     0    stevel 	global_svstat_ptr[req->rq_vers][NFS_CALLS].value.ui64++;
   1841     0    stevel }
   1842     0    stevel 
   1843     0    stevel static void
   1844     0    stevel rfs_dispatch(struct svc_req *req, SVCXPRT *xprt)
   1845     0    stevel {
   1846     0    stevel 	common_dispatch(req, xprt, NFS_VERSMIN, NFS_VERSMAX,
   1847  7961   Natalie 	    "NFS", rfs_disptable);
   1848     0    stevel }
   1849     0    stevel 
   1850     0    stevel static char *aclcallnames_v2[] = {
   1851     0    stevel 	"ACL2_NULL",
   1852     0    stevel 	"ACL2_GETACL",
   1853     0    stevel 	"ACL2_SETACL",
   1854     0    stevel 	"ACL2_GETATTR",
   1855     0    stevel 	"ACL2_ACCESS",
   1856     0    stevel 	"ACL2_GETXATTRDIR"
   1857     0    stevel };
   1858     0    stevel 
   1859     0    stevel static struct rpcdisp acldisptab_v2[] = {
   1860     0    stevel 	/*
   1861     0    stevel 	 * ACL VERSION 2
   1862     0    stevel 	 */
   1863     0    stevel 
   1864     0    stevel 	/* ACL2_NULL = 0 */
   1865     0    stevel 	{rpc_null,
   1866     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
   1867     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
   1868     0    stevel 	    nullfree, RPC_IDEMPOTENT,
   1869     0    stevel 	    0},
   1870     0    stevel 
   1871     0    stevel 	/* ACL2_GETACL = 1 */
   1872     0    stevel 	{acl2_getacl,
   1873     0    stevel 	    xdr_GETACL2args, xdr_fastGETACL2args, sizeof (GETACL2args),
   1874     0    stevel 	    xdr_GETACL2res, NULL_xdrproc_t, sizeof (GETACL2res),
   1875     0    stevel 	    acl2_getacl_free, RPC_IDEMPOTENT,
   1876     0    stevel 	    acl2_getacl_getfh},
   1877     0    stevel 
   1878     0    stevel 	/* ACL2_SETACL = 2 */
   1879     0    stevel 	{acl2_setacl,
   1880     0    stevel 	    xdr_SETACL2args, NULL_xdrproc_t, sizeof (SETACL2args),
   1881     0    stevel #ifdef _LITTLE_ENDIAN
   1882     0    stevel 	    xdr_SETACL2res, xdr_fastSETACL2res, sizeof (SETACL2res),
   1883     0    stevel #else
   1884     0    stevel 	    xdr_SETACL2res, NULL_xdrproc_t, sizeof (SETACL2res),
   1885     0    stevel #endif
   1886     0    stevel 	    nullfree, RPC_MAPRESP,
   1887     0    stevel 	    acl2_setacl_getfh},
   1888     0    stevel 
   1889     0    stevel 	/* ACL2_GETATTR = 3 */
   1890     0    stevel 	{acl2_getattr,
   1891     0    stevel 	    xdr_GETATTR2args, xdr_fastGETATTR2args, sizeof (GETATTR2args),
   1892     0    stevel #ifdef _LITTLE_ENDIAN
   1893     0    stevel 	    xdr_GETATTR2res, xdr_fastGETATTR2res, sizeof (GETATTR2res),
   1894     0    stevel #else
   1895     0    stevel 	    xdr_GETATTR2res, NULL_xdrproc_t, sizeof (GETATTR2res),
   1896     0    stevel #endif
   1897     0    stevel 	    nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
   1898     0    stevel 	    acl2_getattr_getfh},
   1899     0    stevel 
   1900     0    stevel 	/* ACL2_ACCESS = 4 */
   1901     0    stevel 	{acl2_access,
   1902     0    stevel 	    xdr_ACCESS2args, xdr_fastACCESS2args, sizeof (ACCESS2args),
   1903     0    stevel #ifdef _LITTLE_ENDIAN
   1904     0    stevel 	    xdr_ACCESS2res, xdr_fastACCESS2res, sizeof (ACCESS2res),
   1905     0    stevel #else
   1906     0    stevel 	    xdr_ACCESS2res, NULL_xdrproc_t, sizeof (ACCESS2res),
   1907     0    stevel #endif
   1908     0    stevel 	    nullfree, RPC_IDEMPOTENT|RPC_MAPRESP,
   1909     0    stevel 	    acl2_access_getfh},
   1910     0    stevel 
   1911     0    stevel 	/* ACL2_GETXATTRDIR = 5 */
   1912     0    stevel 	{acl2_getxattrdir,
   1913     0    stevel 	    xdr_GETXATTRDIR2args, NULL_xdrproc_t, sizeof (GETXATTRDIR2args),
   1914     0    stevel 	    xdr_GETXATTRDIR2res, NULL_xdrproc_t, sizeof (GETXATTRDIR2res),
   1915     0    stevel 	    nullfree, RPC_IDEMPOTENT,
   1916     0    stevel 	    acl2_getxattrdir_getfh},
   1917     0    stevel };
   1918     0    stevel 
   1919     0    stevel static char *aclcallnames_v3[] = {
   1920     0    stevel 	"ACL3_NULL",
   1921     0    stevel 	"ACL3_GETACL",
   1922     0    stevel 	"ACL3_SETACL",
   1923     0    stevel 	"ACL3_GETXATTRDIR"
   1924     0    stevel };
   1925     0    stevel 
   1926     0    stevel static struct rpcdisp acldisptab_v3[] = {
   1927     0    stevel 	/*
   1928     0    stevel 	 * ACL VERSION 3
   1929     0    stevel 	 */
   1930     0    stevel 
   1931     0    stevel 	/* ACL3_NULL = 0 */
   1932     0    stevel 	{rpc_null,
   1933     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
   1934     0    stevel 	    xdr_void, NULL_xdrproc_t, 0,
   1935     0    stevel 	    nullfree, RPC_IDEMPOTENT,
   1936     0    stevel 	    0},
   1937     0    stevel 
   1938     0    stevel 	/* ACL3_GETACL = 1 */
   1939     0    stevel 	{acl3_getacl,
   1940     0    stevel 	    xdr_GETACL3args, NULL_xdrproc_t, sizeof (GETACL3args),
   1941     0    stevel 	    xdr_GETACL3res, NULL_xdrproc_t, sizeof (GETACL3res),
   1942     0    stevel 	    acl3_getacl_free, RPC_IDEMPOTENT,
   1943     0    stevel 	    acl3_getacl_getfh},
   1944     0    stevel 
   1945     0    stevel 	/* ACL3_SETACL = 2 */
   1946     0    stevel 	{acl3_setacl,
   1947     0    stevel 	    xdr_SETACL3args, NULL_xdrproc_t, sizeof (SETACL3args),
   1948     0    stevel 	    xdr_SETACL3res, NULL_xdrproc_t, sizeof (SETACL3res),
   1949     0    stevel 	    nullfree, 0,
   1950     0    stevel 	    acl3_setacl_getfh},
   1951     0    stevel 
   1952     0    stevel 	/* ACL3_GETXATTRDIR = 3 */
   1953     0    stevel 	{acl3_getxattrdir,
   1954     0    stevel 	    xdr_GETXATTRDIR3args, NULL_xdrproc_t, sizeof (GETXATTRDIR3args),
   1955     0    stevel 	    xdr_GETXATTRDIR3res, NULL_xdrproc_t, sizeof (GETXATTRDIR3res),
   1956     0    stevel 	    nullfree, RPC_IDEMPOTENT,
   1957     0    stevel 	    acl3_getxattrdir_getfh},
   1958     0    stevel };
   1959     0    stevel 
   1960     0    stevel static struct rpc_disptable acl_disptable[] = {
   1961     0    stevel 	{sizeof (acldisptab_v2) / sizeof (acldisptab_v2[0]),
   1962     0    stevel 		aclcallnames_v2,
   1963     0    stevel 		&aclproccnt_v2_ptr, acldisptab_v2},
   1964     0    stevel 	{sizeof (acldisptab_v3) / sizeof (acldisptab_v3[0]),
   1965     0    stevel 		aclcallnames_v3,
   1966     0    stevel 		&aclproccnt_v3_ptr, acldisptab_v3},
   1967     0    stevel };
   1968     0    stevel 
   1969     0    stevel static void
   1970     0    stevel acl_dispatch(struct svc_req *req, SVCXPRT *xprt)
   1971     0    stevel {
   1972     0    stevel 	common_dispatch(req, xprt, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,
   1973  7961   Natalie 	    "ACL", acl_disptable);
   1974     0    stevel }
   1975     0    stevel 
   1976     0    stevel int
   1977     0    stevel checkwin(int flavor, int window, struct svc_req *req)
   1978     0    stevel {
   1979     0    stevel 	struct authdes_cred *adc;
   1980     0    stevel 
   1981     0    stevel 	switch (flavor) {
   1982     0    stevel 	case AUTH_DES:
   1983     0    stevel 		adc = (struct authdes_cred *)req->rq_clntcred;
   1984     0    stevel 		if (adc->adc_fullname.window > window)
   1985     0    stevel 			return (0);
   1986     0    stevel 		break;
   1987     0    stevel 
   1988     0    stevel 	default:
   1989     0    stevel 		break;
   1990     0    stevel 	}
   1991     0    stevel 	return (1);
   1992     0    stevel }
   1993     0    stevel 
   1994     0    stevel 
   1995     0    stevel /*
   1996     0    stevel  * checkauth() will check the access permission against the export
   1997     0    stevel  * information.  Then map root uid/gid to appropriate uid/gid.
   1998     0    stevel  *
   1999     0    stevel  * This routine is used by NFS V3 and V2 code.
   2000     0    stevel  */
   2001     0    stevel static int
   2002     0    stevel checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok,
   2003     0    stevel     bool_t publicfh_ok)
   2004     0    stevel {
   2005     0    stevel 	int i, nfsflavor, rpcflavor, stat, access;
   2006     0    stevel 	struct secinfo *secp;
   2007     0    stevel 	caddr_t principal;
   2008     0    stevel 	char buf[INET6_ADDRSTRLEN]; /* to hold both IPv4 and IPv6 addr */
   2009     0    stevel 	int anon_res = 0;
   2010     0    stevel 
   2011     0    stevel 	/*
   2012  9987    Thomas 	 * Check for privileged port number
   2013  9987    Thomas 	 * N.B.:  this assumes that we know the format of a netbuf.
   2014     0    stevel 	 */
   2015     0    stevel 	if (nfs_portmon) {
   2016     0    stevel 		struct sockaddr *ca;
   2017     0    stevel 		ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
   2018     0    stevel 
   2019     0    stevel 		if (ca == NULL)
   2020     0    stevel 			return (0);
   2021     0    stevel 
   2022     0    stevel 		if ((ca->sa_family == AF_INET &&
   2023     0    stevel 		    ntohs(((struct sockaddr_in *)ca)->sin_port) >=
   2024     0    stevel 		    IPPORT_RESERVED) ||
   2025     0    stevel 		    (ca->sa_family == AF_INET6 &&
   2026     0    stevel 		    ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >=
   2027     0    stevel 		    IPPORT_RESERVED)) {
   2028     0    stevel 			cmn_err(CE_NOTE,
   2029     0    stevel 			    "nfs_server: client %s%ssent NFS request from "
   2030     0    stevel 			    "unprivileged port",
   2031     0    stevel 			    client_name(req), client_addr(req, buf));
   2032     0    stevel 			return (0);
   2033     0    stevel 		}
   2034     0    stevel 	}
   2035     0    stevel 
   2036     0    stevel 	/*
   2037     0    stevel 	 *  return 1 on success or 0 on failure
   2038     0    stevel 	 */
   2039     0    stevel 	stat = sec_svc_getcred(req, cr, &principal, &nfsflavor);
   2040     0    stevel 
   2041     0    stevel 	/*
   2042     0    stevel 	 * A failed AUTH_UNIX svc_get_cred() implies we couldn't set
   2043     0    stevel 	 * the credentials; below we map that to anonymous.
   2044     0    stevel 	 */
   2045     0    stevel 	if (!stat && nfsflavor != AUTH_UNIX) {
   2046     0    stevel 		cmn_err(CE_NOTE,
   2047     0    stevel 		    "nfs_server: couldn't get unix cred for %s",
   2048     0    stevel 		    client_name(req));
   2049     0    stevel 		return (0);
   2050     0    stevel 	}
   2051     0    stevel 
   2052     0    stevel 	/*
   2053     0    stevel 	 * Short circuit checkauth() on operations that support the
   2054     0    stevel 	 * public filehandle, and if the request for that operation
   2055     0    stevel 	 * is using the public filehandle. Note that we must call
   2056     0    stevel 	 * sec_svc_getcred() first so that xp_cookie is set to the
   2057     0    stevel 	 * right value. Normally xp_cookie is just the RPC flavor
   2058     0    stevel 	 * of the the request, but in the case of RPCSEC_GSS it
   2059     0    stevel 	 * could be a pseudo flavor.
   2060     0    stevel 	 */
   2061     0    stevel 	if (publicfh_ok)
   2062     0    stevel 		return (1);
   2063     0    stevel 
   2064     0    stevel 	rpcflavor = req->rq_cred.oa_flavor;
   2065     0    stevel 	/*
   2066     0    stevel 	 * Check if the auth flavor is valid for this export
   2067     0    stevel 	 */
   2068     0    stevel 	access = nfsauth_access(exi, req);
   2069     0    stevel 	if (access & NFSAUTH_DROP)
   2070     0    stevel 		return (-1);	/* drop the request */
   2071     0    stevel 
   2072     0    stevel 	if (access & NFSAUTH_DENIED) {
   2073     0    stevel 		/*
   2074     0    stevel 		 * If anon_ok == 1 and we got NFSAUTH_DENIED, it was
   2075     0    stevel 		 * probably due to the flavor not matching during the
   2076     0    stevel 		 * the mount attempt. So map the flavor to AUTH_NONE
   2077     0    stevel 		 * so that the credentials get mapped to the anonymous
   2078     0    stevel 		 * user.
   2079     0    stevel 		 */
   2080     0    stevel 		if (anon_ok == 1)
   2081     0    stevel 			rpcflavor = AUTH_NONE;
   2082     0    stevel 		else
   2083     0    stevel 			return (0);	/* deny access */
   2084     0    stevel 
   2085     0    stevel 	} else if (access & NFSAUTH_MAPNONE) {
   2086     0    stevel 		/*
   2087     0    stevel 		 * Access was granted even though the flavor mismatched
   2088     0    stevel 		 * because AUTH_NONE was one of the exported flavors.
   2089     0    stevel 		 */
   2090     0    stevel 		rpcflavor = AUTH_NONE;
   2091     0    stevel 
   2092     0    stevel 	} else if (access & NFSAUTH_WRONGSEC) {
   2093     0    stevel 		/*
   2094  8395    Thomas 		 * NFSAUTH_WRONGSEC is used for NFSv4. If we get here,
   2095  8395    Thomas 		 * it means a client ignored the list of allowed flavors
   2096  8395    Thomas 		 * returned via the MOUNT protocol. So we just disallow it!
   2097     0    stevel 		 */
   2098  8395    Thomas 		return (0);
   2099     0    stevel 	}
   2100     0    stevel 
   2101     0    stevel 	switch (rpcflavor) {
   2102     0    stevel 	case AUTH_NONE:
   2103     0    stevel 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
   2104  7961   Natalie 		    exi->exi_export.ex_anon);
   2105     0    stevel 		(void) crsetgroups(cr, 0, NULL);
   2106     0    stevel 		break;
   2107     0    stevel 
   2108     0    stevel 	case AUTH_UNIX:
   2109     0    stevel 		if (!stat || crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) {
   2110     0    stevel 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
   2111  7961   Natalie 			    exi->exi_export.ex_anon);
   2112     0    stevel 			(void) crsetgroups(cr, 0, NULL);
   2113  7961   Natalie 		} else if (!stat || crgetuid(cr) == 0 &&
   2114  7961   Natalie 		    access & NFSAUTH_ROOT) {
   2115  7961   Natalie 			/*
   2116  7961   Natalie 			 * It is root, so apply rootid to get real UID
   2117  7961   Natalie 			 * Find the secinfo structure.  We should be able
   2118  7961   Natalie 			 * to find it by the time we reach here.
   2119  7961   Natalie 			 * nfsauth_access() has done the checking.
   2120  7961   Natalie 			 */
   2121  7961   Natalie 			secp = NULL;
   2122  7961   Natalie 			for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
   2123  7961   Natalie 				struct secinfo *sptr;
   2124  7961   Natalie 				sptr = &exi->exi_export.ex_secinfo[i];
   2125  7961   Natalie 				if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
   2126  7961   Natalie 					secp = sptr;
   2127  7961   Natalie 					break;
   2128  7961   Natalie 				}
   2129  7961   Natalie 			}
   2130  7961   Natalie 			if (secp != NULL) {
   2131  7961   Natalie 				(void) crsetugid(cr, secp->s_rootid,
   2132  7961   Natalie 				    secp->s_rootid);
   2133  7961   Natalie 				(void) crsetgroups(cr, 0, NULL);
   2134  7961   Natalie 			}
   2135     0    stevel 		}
   2136     0    stevel 		break;
   2137     0    stevel 
   2138     0    stevel 	case AUTH_DES:
   2139     0    stevel 	case RPCSEC_GSS:
   2140     0    stevel 		/*
   2141     0    stevel 		 *  Find the secinfo structure.  We should be able
   2142     0    stevel 		 *  to find it by the time we reach here.
   2143     0    stevel 		 *  nfsauth_access() has done the checking.
   2144     0    stevel 		 */
   2145     0    stevel 		secp = NULL;
   2146     0    stevel 		for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
   2147     0    stevel 			if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
   2148     0    stevel 			    nfsflavor) {
   2149     0    stevel 				secp = &exi->exi_export.ex_secinfo[i];
   2150     0    stevel 				break;
   2151     0    stevel 			}
   2152     0    stevel 		}
   2153     0    stevel 
   2154     0    stevel 		if (!secp) {
   2155     0    stevel 			cmn_err(CE_NOTE, "nfs_server: client %s%shad "
   2156     0    stevel 			    "no secinfo data for flavor %d",
   2157     0    stevel 			    client_name(req), client_addr(req, buf),
   2158     0    stevel 			    nfsflavor);
   2159     0    stevel 			return (0);
   2160     0    stevel 		}
   2161     0    stevel 
   2162     0    stevel 		if (!checkwin(rpcflavor, secp->s_window, req)) {
   2163     0    stevel 			cmn_err(CE_NOTE,
   2164     0    stevel 			    "nfs_server: client %s%sused invalid "
   2165     0    stevel 			    "auth window value",
   2166     0    stevel 			    client_name(req), client_addr(req, buf));
   2167     0    stevel 			return (0);
   2168     0    stevel 		}
   2169     0    stevel 
   2170     0    stevel 		/*
   2171     0    stevel 		 * Map root principals listed in the share's root= list to root,
   2172     0    stevel 		 * and map any others principals that were mapped to root by RPC
   2173     0    stevel 		 * to anon.
   2174     0    stevel 		 */
   2175     0    stevel 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
   2176  7961   Natalie 		    secp->s_rootcnt, secp->s_rootnames)) {
   2177  7961   Natalie 			if (crgetuid(cr) == 0 && secp->s_rootid == 0)
   2178     0    stevel 				return (1);
   2179     0    stevel 
   2180  7961   Natalie 
   2181  7961   Natalie 			(void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
   2182     0    stevel 
   2183     0    stevel 			/*
   2184     0    stevel 			 * NOTE: If and when kernel-land privilege tracing is
   2185     0    stevel 			 * added this may have to be replaced with code that
   2186     0    stevel 			 * retrieves root's supplementary groups (e.g., using
   2187     0    stevel 			 * kgss_get_group_info().  In the meantime principals
   2188     0    stevel 			 * mapped to uid 0 get all privileges, so setting cr's
   2189     0    stevel 			 * supplementary groups for them does nothing.
   2190     0    stevel 			 */
   2191     0    stevel 			(void) crsetgroups(cr, 0, NULL);
   2192     0    stevel 
   2193     0    stevel 			return (1);
   2194     0    stevel 		}
   2195     0    stevel 
   2196     0    stevel 		/*
   2197     0    stevel 		 * Not a root princ, or not in root list, map UID 0/nobody to
   2198     0    stevel 		 * the anon ID for the share.  (RPC sets cr's UIDs and GIDs to
   2199     0    stevel 		 * UID_NOBODY and GID_NOBODY, respectively.)
   2200     0    stevel 		 */
   2201     0    stevel 		if (crgetuid(cr) != 0 &&
   2202     0    stevel 		    (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
   2203     0    stevel 			return (1);
   2204     0    stevel 
   2205     0    stevel 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
   2206  7961   Natalie 		    exi->exi_export.ex_anon);
   2207     0    stevel 		(void) crsetgroups(cr, 0, NULL);
   2208     0    stevel 		break;
   2209     0    stevel 	default:
   2210     0    stevel 		return (0);
   2211     0    stevel 	} /* switch on rpcflavor */
   2212     0    stevel 
   2213     0    stevel 	/*
   2214     0    stevel 	 * Even if anon access is disallowed via ex_anon == -1, we allow
   2215     0    stevel 	 * this access if anon_ok is set.  So set creds to the default
   2216     0    stevel 	 * "nobody" id.
   2217     0    stevel 	 */
   2218     0    stevel 	if (anon_res != 0) {
   2219     0    stevel 		if (anon_ok == 0) {
   2220     0    stevel 			cmn_err(CE_NOTE,
   2221     0    stevel 			    "nfs_server: client %s%ssent wrong "
   2222     0    stevel 			    "authentication for %s",
   2223     0    stevel 			    client_name(req), client_addr(req, buf),
   2224     0    stevel 			    exi->exi_export.ex_path ?
   2225     0    stevel 			    exi->exi_export.ex_path : "?");
   2226     0    stevel 			return (0);
   2227     0    stevel 		}
   2228     0    stevel 
   2229     0    stevel 		if (crsetugid(cr, UID_NOBODY, GID_NOBODY) != 0)
   2230     0    stevel 			return (0);
   2231     0    stevel 	}
   2232     0    stevel 
   2233     0    stevel 	return (1);
   2234     0    stevel }
   2235     0    stevel 
   2236     0    stevel /*
   2237     0    stevel  * returns 0 on failure, -1 on a drop, -2 on wrong security flavor,
   2238     0    stevel  * and 1 on success
   2239     0    stevel  */
   2240     0    stevel int
   2241     0    stevel checkauth4(struct compound_state *cs, struct svc_req *req)
   2242     0    stevel {
   2243     0    stevel 	int i, rpcflavor, access;
   2244     0    stevel 	struct secinfo *secp;
   2245     0    stevel 	char buf[MAXHOST + 1];
   2246     0    stevel 	int anon_res = 0, nfsflavor;
   2247     0    stevel 	struct exportinfo *exi;
   2248     0    stevel 	cred_t	*cr;
   2249     0    stevel 	caddr_t	principal;
   2250     0    stevel 
   2251     0    stevel 	exi = cs->exi;
   2252     0    stevel 	cr = cs->cr;
   2253     0    stevel 	principal = cs->principal;
   2254     0    stevel 	nfsflavor = cs->nfsflavor;
   2255     0    stevel 
   2256     0    stevel 	ASSERT(cr != NULL);
   2257     0    stevel 
   2258     0    stevel 	rpcflavor = req->rq_cred.oa_flavor;
   2259     0    stevel 	cs->access &= ~CS_ACCESS_LIMITED;
   2260  9987    Thomas 
   2261  9987    Thomas 	/*
   2262  9987    Thomas 	 * Check for privileged port number
   2263  9987    Thomas 	 * N.B.:  this assumes that we know the format of a netbuf.
   2264  9987    Thomas 	 */
   2265  9987    Thomas 	if (nfs_portmon) {
   2266  9987    Thomas 		struct sockaddr *ca;
   2267  9987    Thomas 		ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
   2268  9987    Thomas 
   2269  9987    Thomas 		if (ca == NULL)
   2270  9987    Thomas 			return (0);
   2271  9987    Thomas 
   2272  9987    Thomas 		if ((ca->sa_family == AF_INET &&
   2273  9987    Thomas 		    ntohs(((struct sockaddr_in *)ca)->sin_port) >=
   2274  9987    Thomas 		    IPPORT_RESERVED) ||
   2275  9987    Thomas 		    (ca->sa_family == AF_INET6 &&
   2276  9987    Thomas 		    ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >=
   2277  9987    Thomas 		    IPPORT_RESERVED)) {
   2278  9987    Thomas 			cmn_err(CE_NOTE,
   2279  9987    Thomas 			    "nfs_server: client %s%ssent NFSv4 request from "
   2280  9987    Thomas 			    "unprivileged port",
   2281  9987    Thomas 			    client_name(req), client_addr(req, buf));
   2282  9987    Thomas 			return (0);
   2283  9987    Thomas 		}
   2284  9987    Thomas 	}
   2285     0    stevel 
   2286     0    stevel 	/*
   2287     0    stevel 	 * Check the access right per auth flavor on the vnode of
   2288     0    stevel 	 * this export for the given request.
   2289     0    stevel 	 */
   2290     0    stevel 	access = nfsauth4_access(cs->exi, cs->vp, req);
   2291     0    stevel 
   2292     0    stevel 	if (access & NFSAUTH_WRONGSEC)
   2293     0    stevel 		return (-2);	/* no access for this security flavor */
   2294     0    stevel 
   2295     0    stevel 	if (access & NFSAUTH_DROP)
   2296     0    stevel 		return (-1);	/* drop the request */
   2297     0    stevel 
   2298     0    stevel 	if (access & NFSAUTH_DENIED) {
   2299     0    stevel 
   2300     0    stevel 		if (exi->exi_export.ex_seccnt > 0)
   2301     0    stevel 			return (0);	/* deny access */
   2302     0    stevel 
   2303     0    stevel 	} else if (access & NFSAUTH_LIMITED) {
   2304     0    stevel 
   2305     0    stevel 		cs->access |= CS_ACCESS_LIMITED;
   2306     0    stevel 
   2307     0    stevel 	} else if (access & NFSAUTH_MAPNONE) {
   2308     0    stevel 		/*
   2309     0    stevel 		 * Access was granted even though the flavor mismatched
   2310     0    stevel 		 * because AUTH_NONE was one of the exported flavors.
   2311     0    stevel 		 */
   2312     0    stevel 		rpcflavor = AUTH_NONE;
   2313     0    stevel 	}
   2314     0    stevel 
   2315     0    stevel 	/*
   2316     0    stevel 	 * XXX probably need to redo some of it for nfsv4?
   2317     0    stevel 	 * return 1 on success or 0 on failure
   2318     0    stevel 	 */
   2319     0    stevel 
   2320     0    stevel 	switch (rpcflavor) {
   2321     0    stevel 	case AUTH_NONE:
   2322     0    stevel 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
   2323  7961   Natalie 		    exi->exi_export.ex_anon);
   2324     0    stevel 		(void) crsetgroups(cr, 0, NULL);
   2325     0    stevel 		break;
   2326     0    stevel 
   2327     0    stevel 	case AUTH_UNIX:
   2328     0    stevel 		if (crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) {
   2329     0    stevel 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
   2330  7961   Natalie 			    exi->exi_export.ex_anon);
   2331     0    stevel 			(void) crsetgroups(cr, 0, NULL);
   2332  7961   Natalie 		} else if (crgetuid(cr) == 0 && access & NFSAUTH_ROOT) {
   2333  7961   Natalie 			/*
   2334  7961   Natalie 			 * It is root, so apply rootid to get real UID
   2335  7961   Natalie 			 * Find the secinfo structure.  We should be able
   2336  7961   Natalie 			 * to find it by the time we reach here.
   2337  7961   Natalie 			 * nfsauth_access() has done the checking.
   2338  7961   Natalie 			 */
   2339  7961   Natalie 			secp = NULL;
   2340  7961   Natalie 			for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
   2341  7961   Natalie 				struct secinfo *sptr;
   2342  7961   Natalie 				sptr = &exi->exi_export.ex_secinfo[i];
   2343  7961   Natalie 				if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
   2344  7961   Natalie 					secp = &exi->exi_export.ex_secinfo[i];
   2345  7961   Natalie 					break;
   2346  7961   Natalie 				}
   2347  7961   Natalie 			}
   2348  7961   Natalie 			if (secp != NULL) {
   2349  7961   Natalie 				(void) crsetugid(cr, secp->s_rootid,
   2350  7961   Natalie 				    secp->s_rootid);
   2351  7961   Natalie 				(void) crsetgroups(cr, 0, NULL);
   2352  7961   Natalie 			}
   2353     0    stevel 		}
   2354     0    stevel 		break;
   2355     0    stevel 
   2356     0    stevel 	default:
   2357     0    stevel 		/*
   2358     0    stevel 		 *  Find the secinfo structure.  We should be able
   2359     0    stevel 		 *  to find it by the time we reach here.
   2360     0    stevel 		 *  nfsauth_access() has done the checking.
   2361     0    stevel 		 */
   2362     0    stevel 		secp = NULL;
   2363     0    stevel 		for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
   2364     0    stevel 			if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
   2365     0    stevel 			    nfsflavor) {
   2366     0    stevel 				secp = &exi->exi_export.ex_secinfo[i];
   2367     0    stevel 				break;
   2368     0    stevel 			}
   2369     0    stevel 		}
   2370     0    stevel 
   2371     0    stevel 		if (!secp) {
   2372     0    stevel 			cmn_err(CE_NOTE, "nfs_server: client %s%shad "
   2373     0    stevel 			    "no secinfo data for flavor %d",
   2374     0    stevel 			    client_name(req), client_addr(req, buf),
   2375     0    stevel 			    nfsflavor);
   2376     0    stevel 			return (0);
   2377     0    stevel 		}
   2378     0    stevel 
   2379     0    stevel 		if (!checkwin(rpcflavor, secp->s_window, req)) {
   2380     0    stevel 			cmn_err(CE_NOTE,
   2381     0    stevel 			    "nfs_server: client %s%sused invalid "
   2382     0    stevel 			    "auth window value",
   2383     0    stevel 			    client_name(req), client_addr(req, buf));
   2384     0    stevel 			return (0);
   2385     0    stevel 		}
   2386     0    stevel 
   2387     0    stevel 		/*
   2388     0    stevel 		 * Map root principals listed in the share's root= list to root,
   2389     0    stevel 		 * and map any others principals that were mapped to root by RPC
   2390  7961   Natalie 		 * to anon. If not going to anon, set to rootid (root_mapping).
   2391     0    stevel 		 */
   2392     0    stevel 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
   2393  7961   Natalie 		    secp->s_rootcnt, secp->s_rootnames)) {
   2394  7961   Natalie 			if (crgetuid(cr) == 0 && secp->s_rootid == 0)
   2395     0    stevel 				return (1);
   2396     0    stevel 
   2397  7961   Natalie 			(void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
   2398     0    stevel 
   2399     0    stevel 			/*
   2400     0    stevel 			 * NOTE: If and when kernel-land privilege tracing is
   2401     0    stevel 			 * added this may have to be replaced with code that
   2402     0    stevel 			 * retrieves root's supplementary groups (e.g., using
   2403     0    stevel 			 * kgss_get_group_info().  In the meantime principals
   2404     0    stevel 			 * mapped to uid 0 get all privileges, so setting cr's
   2405     0    stevel 			 * supplementary groups for them does nothing.
   2406     0    stevel 			 */
   2407     0    stevel 			(void) crsetgroups(cr, 0, NULL);
   2408     0    stevel 
   2409     0    stevel 			return (1);
   2410     0    stevel 		}
   2411     0    stevel 
   2412     0    stevel 		/*
   2413     0    stevel 		 * Not a root princ, or not in root list, map UID 0/nobody to
   2414     0    stevel 		 * the anon ID for the share.  (RPC sets cr's UIDs and GIDs to
   2415     0    stevel 		 * UID_NOBODY and GID_NOBODY, respectively.)
   2416     0    stevel 		 */
   2417     0    stevel 		if (crgetuid(cr) != 0 &&
   2418     0    stevel 		    (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
   2419     0    stevel 			return (1);
   2420     0    stevel 
   2421     0    stevel 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
   2422  7961   Natalie 		    exi->exi_export.ex_anon);
   2423     0    stevel 		(void) crsetgroups(cr, 0, NULL);
   2424     0    stevel 		break;
   2425     0    stevel 	} /* switch on rpcflavor */
   2426     0    stevel 
   2427     0    stevel 	/*
   2428     0    stevel 	 * Even if anon access is disallowed via ex_anon == -1, we allow
   2429     0    stevel 	 * this access if anon_ok is set.  So set creds to the default
   2430     0    stevel 	 * "nobody" id.
   2431     0    stevel 	 */
   2432     0    stevel 
   2433     0    stevel 	if (anon_res != 0) {
   2434     0    stevel 		cmn_err(CE_NOTE,
   2435  7961   Natalie 		    "nfs_server: client %s%ssent wrong "
   2436  7961   Natalie 		    "authentication for %s",
   2437  7961   Natalie 		    client_name(req), client_addr(req, buf),
   2438  7961   Natalie 		    exi->exi_export.ex_path ?
   2439  7961   Natalie 		    exi->exi_export.ex_path : "?");
   2440     0    stevel 		return (0);
   2441     0    stevel 	}
   2442     0    stevel 
   2443     0    stevel 	return (1);
   2444     0    stevel }
   2445     0    stevel 
   2446     0    stevel 
   2447     0    stevel static char *
   2448     0    stevel client_name(struct svc_req *req)
   2449     0    stevel {
   2450     0    stevel 	char *hostname = NULL;
   2451     0    stevel 
   2452     0    stevel 	/*
   2453     0    stevel 	 * If it's a Unix cred then use the
   2454     0    stevel 	 * hostname from the credential.
   2455     0    stevel 	 */
   2456     0    stevel 	if (req->rq_cred.oa_flavor == AUTH_UNIX) {
   2457     0    stevel 		hostname = ((struct authunix_parms *)
   2458     0    stevel 		    req->rq_clntcred)->aup_machname;
   2459     0    stevel 	}
   2460     0    stevel 	if (hostname == NULL)
   2461     0    stevel 		hostname = "";
   2462     0    stevel 
   2463     0    stevel 	return (hostname);
   2464     0    stevel }
   2465     0    stevel 
   2466     0    stevel static char *
   2467     0    stevel client_addr(struct svc_req *req, char *buf)
   2468     0    stevel {
   2469     0    stevel 	struct sockaddr *ca;
   2470     0    stevel 	uchar_t *b;
   2471     0    stevel 	char *frontspace = "";
   2472     0    stevel 
   2473     0    stevel 	/*
   2474     0    stevel 	 * We assume we are called in tandem with client_name and the
   2475     0    stevel 	 * format string looks like "...client %s%sblah blah..."
   2476     0    stevel 	 *
   2477     0    stevel 	 * If it's a Unix cred then client_name returned
   2478     0    stevel 	 * a host name, so we need insert a space between host name
   2479     0    stevel 	 * and IP address.
   2480     0    stevel 	 */
   2481     0    stevel 	if (req->rq_cred.oa_flavor == AUTH_UNIX)
   2482     0    stevel 		frontspace = " ";
   2483     0    stevel 
   2484     0    stevel 	/*
   2485     0    stevel 	 * Convert the caller's IP address to a dotted string
   2486     0    stevel 	 */
   2487     0    stevel 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
   2488     0    stevel 
   2489     0    stevel 	if (ca->sa_family == AF_INET) {
   2490  7961   Natalie 		b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr;
   2491  7961   Natalie 		(void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace,
   2492  7961   Natalie 		    b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF);
   2493     0    stevel 	} else if (ca->sa_family == AF_INET6) {
   2494     0    stevel 		struct sockaddr_in6 *sin6;
   2495     0    stevel 		sin6 = (struct sockaddr_in6 *)ca;
   2496     0    stevel 		(void) kinet_ntop6((uchar_t *)&sin6->sin6_addr,
   2497  7961   Natalie 		    buf, INET6_ADDRSTRLEN);
   2498     0    stevel 
   2499     0    stevel 	} else {
   2500     0    stevel 
   2501     0    stevel 		/*
   2502     0    stevel 		 * No IP address to print. If there was a host name
   2503     0    stevel 		 * printed, then we print a space.
   2504     0    stevel 		 */
   2505     0    stevel 		(void) sprintf(buf, frontspace);
   2506     0    stevel 	}
   2507     0    stevel 
   2508     0    stevel 	return (buf);
   2509     0    stevel }
   2510     0    stevel 
   2511     0    stevel /*
   2512     0    stevel  * NFS Server initialization routine.  This routine should only be called
   2513     0    stevel  * once.  It performs the following tasks:
   2514     0    stevel  *	- Call sub-initialization routines (localize access to variables)
   2515     0    stevel  *	- Initialize all locks
   2516     0    stevel  *	- initialize the version 3 write verifier
   2517     0    stevel  */
   2518     0    stevel int
   2519     0    stevel nfs_srvinit(void)
   2520     0    stevel {
   2521     0    stevel 	int error;
   2522     0    stevel 
   2523     0    stevel 	error = nfs_exportinit();
   2524     0    stevel 	if (error != 0)
   2525     0    stevel 		return (error);
   2526     0    stevel 	error = rfs4_srvrinit();
   2527     0    stevel 	if (error != 0) {
   2528     0    stevel 		nfs_exportfini();
   2529     0    stevel 		return (error);
   2530     0    stevel 	}
   2531     0    stevel 	rfs_srvrinit();
   2532     0    stevel 	rfs3_srvrinit();
   2533     0    stevel 	nfsauth_init();
   2534     0    stevel 
   2535     0    stevel 	/* Init the stuff to control start/stop */
   2536     0    stevel 	nfs_server_upordown = NFS_SERVER_STOPPED;
   2537     0    stevel 	mutex_init(&nfs_server_upordown_lock, NULL, MUTEX_DEFAULT, NULL);
   2538     0    stevel 	cv_init(&nfs_server_upordown_cv, NULL, CV_DEFAULT, NULL);
   2539     0    stevel 	mutex_init(&rdma_wait_mutex, NULL, MUTEX_DEFAULT, NULL);
   2540     0    stevel 	cv_init(&rdma_wait_cv, NULL, CV_DEFAULT, NULL);
   2541     0    stevel 
   2542     0    stevel 	return (0);
   2543     0    stevel }
   2544     0    stevel 
   2545     0    stevel /*
   2546     0    stevel  * NFS Server finalization routine. This routine is called to cleanup the
   2547     0    stevel  * initialization work previously performed if the NFS server module could
   2548     0    stevel  * not be loaded correctly.
   2549     0    stevel  */
   2550     0    stevel void
   2551     0    stevel nfs_srvfini(void)
   2552     0    stevel {
   2553     0    stevel 	nfsauth_fini();
   2554     0    stevel 	rfs3_srvrfini();
   2555     0    stevel 	rfs_srvrfini();
   2556     0    stevel 	nfs_exportfini();
   2557     0    stevel 
   2558     0    stevel 	mutex_destroy(&nfs_server_upordown_lock);
   2559     0    stevel 	cv_destroy(&nfs_server_upordown_cv);
   2560     0    stevel 	mutex_destroy(&rdma_wait_mutex);
   2561     0    stevel 	cv_destroy(&rdma_wait_cv);
   2562     0    stevel }
   2563     0    stevel 
   2564     0    stevel /*
   2565     0    stevel  * Set up an iovec array of up to cnt pointers.
   2566     0    stevel  */
   2567     0    stevel 
   2568     0    stevel void
   2569     0    stevel mblk_to_iov(mblk_t *m, int cnt, struct iovec *iovp)
   2570     0    stevel {
   2571     0    stevel 	while (m != NULL && cnt-- > 0) {
   2572     0    stevel 		iovp->iov_base = (caddr_t)m->b_rptr;
   2573     0    stevel 		iovp->iov_len = (m->b_wptr - m->b_rptr);
   2574     0    stevel 		iovp++;
   2575     0    stevel 		m = m->b_cont;
   2576     0    stevel 	}
   2577     0    stevel }
   2578     0    stevel 
   2579     0    stevel /*
   2580     0    stevel  * Common code between NFS Version 2 and NFS Version 3 for the public
   2581     0    stevel  * filehandle multicomponent lookups.
   2582     0    stevel  */
   2583     0    stevel 
   2584     0    stevel /*
   2585     0    stevel  * Public filehandle evaluation of a multi-component lookup, following
   2586     0    stevel  * symbolic links, if necessary. This may result in a vnode in another
   2587     0    stevel  * filesystem, which is OK as long as the other filesystem is exported.
   2588     0    stevel  *
   2589     0    stevel  * Note that the exi will be set either to NULL or a new reference to the
   2590     0    stevel  * exportinfo struct that corresponds to the vnode of the multi-component path.
   2591     0    stevel  * It is the callers responsibility to release this reference.
   2592     0    stevel  */
   2593     0    stevel int
   2594     0    stevel rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
   2595     0    stevel     struct exportinfo **exi, struct sec_ol *sec)
   2596     0    stevel {
   2597     0    stevel 	int pathflag;
   2598     0    stevel 	vnode_t *mc_dvp = NULL;
   2599     0    stevel 	vnode_t *realvp;
   2600     0    stevel 	int error;
   2601     0    stevel 
   2602     0    stevel 	*exi = NULL;
   2603     0    stevel 
   2604     0    stevel 	/*
   2605     0    stevel 	 * check if the given path is a url or native path. Since p is
   2606     0    stevel 	 * modified by MCLpath(), it may be empty after returning from
   2607     0    stevel 	 * there, and should be checked.
   2608     0    stevel 	 */
   2609     0    stevel 	if ((pathflag = MCLpath(&p)) == -1)
   2610     0    stevel 		return (EIO);
   2611     0    stevel 
   2612     0    stevel 	/*
   2613     0    stevel 	 * If pathflag is SECURITY_QUERY, turn the SEC_QUERY bit
   2614     0    stevel 	 * on in sec->sec_flags. This bit will later serve as an
   2615     0    stevel 	 * indication in makefh_ol() or makefh3_ol() to overload the
   2616     0    stevel 	 * filehandle to contain the sec modes used by the server for
   2617     0    stevel 	 * the path.
   2618     0    stevel 	 */
   2619     0    stevel 	if (pathflag == SECURITY_QUERY) {
   2620     0    stevel 		if ((sec->sec_index = (uint_t)(*p)) > 0) {
   2621     0    stevel 			sec->sec_flags |= SEC_QUERY;
   2622     0    stevel 			p++;
   2623     0    stevel 			if ((pathflag = MCLpath(&p)) == -1)
   2624     0    stevel 				return (EIO);
   2625     0    stevel 		} else {
   2626     0    stevel 			cmn_err(CE_NOTE,
   2627     0    stevel 			    "nfs_server: invalid security index %d, "
   2628     0    stevel 			    "violating WebNFS SNEGO protocol.", sec->sec_index);
   2629     0    stevel 			return (EIO);
   2630     0    stevel 		}
   2631     0    stevel 	}
   2632     0    stevel 
   2633     0    stevel 	if (p[0] == '\0') {
   2634     0    stevel 		error = ENOENT;
   2635     0    stevel 		goto publicfh_done;
   2636     0    stevel 	}
   2637     0    stevel 
   2638     0    stevel 	error = rfs_pathname(p, &mc_dvp, vpp, dvp, cr, pathflag);
   2639     0    stevel 
   2640     0    stevel 	/*
   2641     0    stevel 	 * If name resolves to "/" we get EINVAL since we asked for
   2642     0    stevel 	 * the vnode of the directory that the file is in. Try again
   2643     0    stevel 	 * with NULL directory vnode.
   2644     0    stevel 	 */
   2645     0    stevel 	if (error == EINVAL) {
   2646     0    stevel 		error = rfs_pathname(p, NULL, vpp, dvp, cr, pathflag);
   2647     0    stevel 		if (!error) {
   2648     0    stevel 			ASSERT(*vpp != NULL);
   2649     0    stevel 			if ((*vpp)->v_type == VDIR) {
   2650     0    stevel 				VN_HOLD(*vpp);
   2651     0    stevel 				mc_dvp = *vpp;
   2652     0    stevel 			} else {
   2653     0    stevel 				/*
   2654     0    stevel 				 * This should not happen, the filesystem is
   2655     0    stevel 				 * in an inconsistent state. Fail the lookup
   2656     0    stevel 				 * at this point.
   2657     0    stevel 				 */
   2658     0    stevel 				VN_RELE(*vpp);
   2659     0    stevel 				error = EINVAL;
   2660     0    stevel 			}
   2661     0    stevel 		}
   2662     0    stevel 	}
   2663     0    stevel 
   2664     0    stevel 	if (error)
   2665     0    stevel 		goto publicfh_done;
   2666     0    stevel 
   2667     0    stevel 	if (*vpp == NULL) {
   2668     0    stevel 		error = ENOENT;
   2669     0    stevel 		goto publicfh_done;
   2670     0    stevel 	}
   2671     0    stevel 
   2672     0    stevel 	ASSERT(mc_dvp != NULL);
   2673     0    stevel 	ASSERT(*vpp != NULL);
   2674     0    stevel 
   2675     0    stevel 	if ((*vpp)->v_type == VDIR) {
   2676     0    stevel 		do {
   2677     0    stevel 			/*
   2678     0    stevel 			 * *vpp may be an AutoFS node, so we perform
   2679     0    stevel 			 * a VOP_ACCESS() to trigger the mount of the intended
   2680     0    stevel 			 * filesystem, so we can perform the lookup in the
   2681     0    stevel 			 * intended filesystem.
   2682     0    stevel 			 */
   2683  5331       amw 			(void) VOP_ACCESS(*vpp, 0, 0, cr, NULL);
   2684     0    stevel 
   2685     0    stevel 			/*
   2686     0    stevel 			 * If vnode is covered, get the
   2687     0    stevel 			 * the topmost vnode.
   2688     0    stevel 			 */
   2689     0    stevel 			if (vn_mountedvfs(*vpp) != NULL) {
   2690     0    stevel 				error = traverse(vpp);
   2691     0    stevel 				if (error) {
   2692     0    stevel 					VN_RELE(*vpp);
   2693     0    stevel 					goto publicfh_done;
   2694     0    stevel 				}
   2695     0    stevel 			}
   2696     0    stevel 
   2697  5331       amw 			if (VOP_REALVP(*vpp, &realvp, NULL) == 0 &&
   2698  5331       amw 			    realvp != *vpp) {
   2699     0    stevel 				/*
   2700     0    stevel 				 * If realvp is different from *vpp
   2701     0    stevel 				 * then release our reference on *vpp, so that
   2702     0    stevel 				 * the export access check be performed on the
   2703     0    stevel 				 * real filesystem instead.
   2704     0    stevel 				 */
   2705     0    stevel 				VN_HOLD(realvp);
   2706     0    stevel 				VN_RELE(*vpp);
   2707     0    stevel 				*vpp = realvp;
   2708  7961   Natalie 			} else {
   2709  7961   Natalie 				break;
   2710  7961   Natalie 			}
   2711     0    stevel 		/* LINTED */
   2712     0    stevel 		} while (TRUE);
   2713     0    stevel 
   2714     0    stevel 		/*
   2715     0    stevel 		 * Let nfs_vptexi() figure what the real parent is.
   2716     0    stevel 		 */
   2717     0    stevel 		VN_RELE(mc_dvp);
   2718     0    stevel 		mc_dvp = NULL;
   2719     0    stevel 
   2720     0    stevel 	} else {
   2721     0    stevel 		/*
   2722     0    stevel 		 * If vnode is covered, get the
   2723     0    stevel 		 * the topmost vnode.
   2724     0    stevel 		 */
   2725     0    stevel 		if (vn_mountedvfs(mc_dvp) != NULL) {
   2726     0    stevel 			error = traverse(&mc_dvp);
   2727     0    stevel 			if (error) {
   2728  7961   Natalie 				VN_RELE(*vpp);
   2729  7961   Natalie 				goto publicfh_done;
   2730     0    stevel 			}
   2731     0    stevel 		}
   2732     0    stevel 
   2733  5331       amw 		if (VOP_REALVP(mc_dvp, &realvp, NULL) == 0 &&
   2734  5331       amw 		    realvp != mc_dvp) {
   2735     0    stevel 			/*
   2736     0    stevel 			 * *vpp is a file, obtain realvp of the parent
   2737     0    stevel 			 * directory vnode.
   2738     0    stevel 			 */
   2739     0    stevel 			VN_HOLD(realvp);
   2740     0    stevel 			VN_RELE(mc_dvp);
   2741     0    stevel 			mc_dvp = realvp;
   2742     0    stevel 		}
   2743     0    stevel 	}
   2744     0    stevel 
   2745     0    stevel 	/*
   2746     0    stevel 	 * The pathname may take us from the public filesystem to another.
   2747     0    stevel 	 * If that's the case then just set the exportinfo to the new export
   2748     0    stevel 	 * and build filehandle for it. Thanks to per-access checking there's
   2749     0    stevel 	 * no security issues with doing this. If the client is not allowed
   2750     0    stevel 	 * access to this new export then it will get an access error when it
   2751     0    stevel 	 * tries to use the filehandle
   2752     0    stevel 	 */
   2753     0    stevel 	if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
   2754     0    stevel 		VN_RELE(*vpp);
   2755     0    stevel 		goto publicfh_done;
   2756     0    stevel 	}
   2757     0    stevel 
   2758     0    stevel 	/*
   2759     0    stevel 	 * Not allowed access to pseudo exports.
   2760     0    stevel 	 */
   2761     0    stevel 	if (PSEUDO(*exi)) {
   2762     0    stevel 		error = ENOENT;
   2763     0    stevel 		VN_RELE(*vpp);
   2764     0    stevel 		goto publicfh_done;
   2765     0    stevel 	}
   2766     0    stevel 
   2767     0    stevel 	/*
   2768     0    stevel 	 * Do a lookup for the index file. We know the index option doesn't
   2769     0    stevel 	 * allow paths through handling in the share command, so mc_dvp will
   2770     0    stevel 	 * be the parent for the index file vnode, if its present. Use
   2771     0    stevel 	 * temporary pointers to preserve and reuse the vnode pointers of the
   2772     0    stevel 	 * original directory in case there's no index file. Note that the
   2773     0    stevel 	 * index file is a native path, and should not be interpreted by
   2774     0    stevel 	 * the URL parser in rfs_pathname()
   2775     0    stevel 	 */
   2776     0    stevel 	if (((*exi)->exi_export.ex_flags & EX_INDEX) &&
   2777     0    stevel 	    ((*vpp)->v_type == VDIR) && (pathflag == URLPATH)) {
   2778     0    stevel 		vnode_t *tvp, *tmc_dvp;	/* temporary vnode pointers */
   2779     0    stevel 
   2780     0    stevel 		tmc_dvp = mc_dvp;
   2781     0    stevel 		mc_dvp = tvp = *vpp;
   2782     0    stevel 
   2783     0    stevel 		error = rfs_pathname((*exi)->exi_export.ex_index, NULL, vpp,
   2784     0    stevel 		    mc_dvp, cr, NATIVEPATH);
   2785     0    stevel 
   2786     0    stevel 		if (error == ENOENT) {
   2787     0    stevel 			*vpp = tvp;
   2788     0    stevel 			mc_dvp = tmc_dvp;
   2789     0    stevel 			error = 0;
   2790     0    stevel 		} else {	/* ok or error other than ENOENT */
   2791     0    stevel 			if (tmc_dvp)
   2792     0    stevel 				VN_RELE(tmc_dvp);
   2793     0    stevel 			if (error)
   2794     0    stevel 				goto publicfh_done;
   2795     0    stevel 
   2796     0    stevel 			/*
   2797     0    stevel 			 * Found a valid vp for index "filename". Sanity check
   2798     0    stevel 			 * for odd case where a directory is provided as index
   2799     0    stevel 			 * option argument and leads us to another filesystem
   2800     0    stevel 			 */
   2801     0    stevel 
   2802     0    stevel 			/* Release the reference on the old exi value */
   2803     0    stevel 			ASSERT(*exi != NULL);
   2804     0    stevel 			exi_rele(*exi);
   2805     0    stevel 
   2806     0    stevel 			if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
   2807     0    stevel 				VN_RELE(*vpp);
   2808     0    stevel 				goto publicfh_done;
   2809     0    stevel 			}
   2810     0    stevel 		}
   2811     0    stevel 	}
   2812     0    stevel 
   2813     0    stevel publicfh_done:
   2814     0    stevel 	if (mc_dvp)
   2815     0    stevel 		VN_RELE(mc_dvp);
   2816     0    stevel 
   2817     0    stevel 	return (error);
   2818     0    stevel }
   2819     0    stevel 
   2820     0    stevel /*
   2821     0    stevel  * Evaluate a multi-component path
   2822     0    stevel  */
   2823     0    stevel int
   2824     0    stevel rfs_pathname(
   2825     0    stevel 	char *path,			/* pathname to evaluate */
   2826     0    stevel 	vnode_t **dirvpp,		/* ret for ptr to parent dir vnode */
   2827     0    stevel 	vnode_t **compvpp,		/* ret for ptr to component vnode */
   2828     0    stevel 	vnode_t *startdvp,		/* starting vnode */
   2829     0    stevel 	cred_t *cr,			/* user's credential */
   2830     0    stevel 	int pathflag)			/* flag to identify path, e.g. URL */
   2831     0    stevel {
   2832     0    stevel 	char namebuf[TYPICALMAXPATHLEN];
   2833     0    stevel 	struct pathname pn;
   2834     0    stevel 	int error;
   2835     0    stevel 
   2836     0    stevel 	/*
   2837     0    stevel 	 * If pathname starts with '/', then set startdvp to root.
   2838     0    stevel 	 */
   2839     0    stevel 	if (*path == '/') {
   2840     0    stevel 		while (*path == '/')
   2841     0    stevel 			path++;
   2842     0    stevel 
   2843     0    stevel 		startdvp = rootdir;
   2844     0    stevel 	}
   2845     0    stevel 
   2846     0    stevel 	error = pn_get_buf(path, UIO_SYSSPACE, &pn, namebuf, sizeof (namebuf));
   2847     0    stevel 	if (error == 0) {
   2848     0    stevel 		/*
   2849     0    stevel 		 * Call the URL parser for URL paths to modify the original
   2850     0    stevel 		 * string to handle any '%' encoded characters that exist.
   2851     0    stevel 		 * Done here to avoid an extra bcopy in the lookup.
   2852     0    stevel 		 * We need to be careful about pathlen's. We know that
   2853     0    stevel 		 * rfs_pathname() is called with a non-empty path. However,
   2854     0    stevel 		 * it could be emptied due to the path simply being all /'s,
   2855     0    stevel 		 * which is valid to proceed with the lookup, or due to the
   2856     0    stevel 		 * URL parser finding an encoded null character at the
   2857     0    stevel 		 * beginning of path which should not proceed with the lookup.
   2858     0    stevel 		 */
   2859     0    stevel 		if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
   2860     0    stevel 			URLparse(pn.pn_path);
   2861     0    stevel 			if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0)
   2862     0    stevel 				return (ENOENT);
   2863     0    stevel 		}
   2864     0    stevel 		VN_HOLD(startdvp);
   2865     0    stevel 		error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
   2866     0    stevel 		    rootdir, startdvp, cr);
   2867     0    stevel 	}
   2868     0    stevel 	if (error == ENAMETOOLONG) {
   2869     0    stevel 		/*
   2870     0    stevel 		 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
   2871     0    stevel 		 */
   2872     0    stevel 		if (error = pn_get(path, UIO_SYSSPACE, &pn))
   2873     0    stevel 			return (error);
   2874     0    stevel 		if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
   2875     0    stevel 			URLparse(pn.pn_path);
   2876     0    stevel 			if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0) {
   2877     0    stevel 				pn_free(&pn);
   2878     0    stevel 				return (ENOENT);
   2879     0    stevel 			}
   2880     0    stevel 		}
   2881     0    stevel 		VN_HOLD(startdvp);
   2882     0    stevel 		error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
   2883     0    stevel 		    rootdir, startdvp, cr);
   2884     0    stevel 		pn_free(&pn);
   2885     0    stevel 	}
   2886     0    stevel 
   2887     0    stevel 	return (error);
   2888     0    stevel }
   2889     0    stevel 
   2890     0    stevel /*
   2891     0    stevel  * Adapt the multicomponent lookup path depending on the pathtype
   2892     0    stevel  */
   2893     0    stevel static int
   2894     0    stevel MCLpath(char **path)
   2895     0    stevel {
   2896     0    stevel 	unsigned char c = (unsigned char)**path;
   2897     0    stevel 
   2898     0    stevel 	/*
   2899     0    stevel 	 * If the MCL path is between 0x20 and 0x7E (graphic printable
   2900     0    stevel 	 * character of the US-ASCII coded character set), its a URL path,
   2901     0    stevel 	 * per RFC 1738.
   2902     0    stevel 	 */
   2903     0    stevel 	if (c >= 0x20 && c <= 0x7E)
   2904     0    stevel 		return (URLPATH);
   2905     0    stevel 
   2906     0    stevel 	/*
   2907     0    stevel 	 * If the first octet of the MCL path is not an ASCII character
   2908     0    stevel 	 * then it must be interpreted as a tag value that describes the
   2909     0    stevel 	 * format of the remaining octets of the MCL path.
   2910     0    stevel 	 *
   2911     0    stevel 	 * If the first octet of the MCL path is 0x81 it is a query
   2912     0    stevel 	 * for the security info.
   2913     0    stevel 	 */
   2914     0    stevel 	switch (c) {
   2915     0    stevel 	case 0x80:	/* native path, i.e. MCL via mount protocol */
   2916     0    stevel 		(*path)++;
   2917     0    stevel 		return (NATIVEPATH);
   2918     0    stevel 	case 0x81:	/* security query */
   2919     0    stevel 		(*path)++;
   2920     0    stevel 		return (SECURITY_QUERY);
   2921     0    stevel 	default:
   2922     0    stevel 		return (-1);
   2923     0    stevel 	}
   2924     0    stevel }
   2925     0    stevel 
   2926     0    stevel #define	fromhex(c)  ((c >= '0' && c <= '9') ? (c - '0') : \
   2927     0    stevel 			((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\
   2928     0    stevel 			((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
   2929     0    stevel 
   2930     0    stevel /*
   2931  5331       amw  * The implementation of URLparse guarantees that the final string will
   2932     0    stevel  * fit in the original one. Replaces '%' occurrences followed by 2 characters
   2933     0    stevel  * with its corresponding hexadecimal character.
   2934     0    stevel  */
   2935     0    stevel static void
   2936     0    stevel URLparse(char *str)
   2937     0    stevel {
   2938     0    stevel 	char *p, *q;
   2939     0    stevel 
   2940     0    stevel 	p = q = str;
   2941     0    stevel 	while (*p) {
   2942     0    stevel 		*q = *p;
   2943     0    stevel 		if (*p++ == '%') {
   2944     0    stevel 			if (*p) {
   2945     0    stevel 				*q = fromhex(*p) * 16;
   2946     0    stevel 				p++;
   2947     0    stevel 				if (*p) {
   2948     0    stevel 					*q += fromhex(*p);
   2949     0    stevel 					p++;
   2950     0    stevel 				}
   2951     0    stevel 			}
   2952     0    stevel 		}
   2953     0    stevel 		q++;
   2954     0    stevel 	}
   2955     0    stevel 	*q = '\0';
   2956     0    stevel }
   2957     0    stevel 
   2958     0    stevel 
   2959     0    stevel /*
   2960     0    stevel  * Get the export information for the lookup vnode, and verify its
   2961     0    stevel  * useable.
   2962     0    stevel  */
   2963     0    stevel int
   2964     0    stevel nfs_check_vpexi(vnode_t *mc_dvp, vnode_t *vp, cred_t *cr,
   2965     0    stevel     struct exportinfo **exi)
   2966     0    stevel {
   2967     0    stevel 	int walk;
   2968     0    stevel 	int error = 0;
   2969     0    stevel 
   2970     0    stevel 	*exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
   2971     0    stevel 	if (*exi == NULL)
   2972     0    stevel 		error = EACCES;
   2973     0    stevel 	else {
   2974     0    stevel 		/*
   2975     0    stevel 		 * If nosub is set for this export then
   2976     0    stevel 		 * a lookup relative to the public fh
   2977     0    stevel 		 * must not terminate below the
   2978     0    stevel 		 * exported directory.
   2979     0    stevel 		 */
   2980     0    stevel 		if ((*exi)->exi_export.ex_flags & EX_NOSUB && walk > 0)
   2981     0    stevel 			error = EACCES;
   2982     0    stevel 	}
   2983     0    stevel 
   2984     0    stevel 	return (error);
   2985     0    stevel }
   2986  2035     calum 
   2987  2035     calum /*
   2988  2035     calum  * Do the main work of handling HA-NFSv4 Resource Group failover on
   2989  2035     calum  * Sun Cluster.
   2990  2035     calum  * We need to detect whether any RG admin paths have been added or removed,
   2991  2035     calum  * and adjust resources accordingly.
   2992  2035     calum  * Currently we're using a very inefficient algorithm, ~ 2 * O(n**2). In
   2993  2035     calum  * order to scale, the list and array of paths need to be held in more
   2994  2035     calum  * suitable data structures.
   2995  2035     calum  */
   2996  2035     calum static void
   2997  2035     calum hanfsv4_failover(void)
   2998  2035     calum {
   2999  2035     calum 	int i, start_grace, numadded_paths = 0;
   3000  2035     calum 	char **added_paths = NULL;
   3001  2035     calum 	rfs4_dss_path_t *dss_path;
   3002  2035     calum 
   3003  2035     calum 	/*
   3004  2390     calum 	 * Note: currently, rfs4_dss_pathlist cannot be NULL, since
   3005  2390     calum 	 * it will always include an entry for NFS4_DSS_VAR_DIR. If we
   3006  2390     calum 	 * make the latter dynamically specified too, the following will
   3007  2390     calum 	 * need to be adjusted.
   3008  2390     calum 	 */
   3009  2390     calum 
   3010  2390     calum 	/*
   3011  2035     calum 	 * First, look for removed paths: RGs that have been failed-over
   3012  2035     calum 	 * away from this node.
   3013  2035     calum 	 * Walk the "currently-serving" rfs4_dss_pathlist and, for each
   3014  2035     calum 	 * path, check if it is on the "passed-in" rfs4_dss_newpaths array
   3015  2035     calum 	 * from nfsd. If not, that RG path has been removed.
   3016  2035     calum 	 *
   3017  2035     calum 	 * Note that nfsd has sorted rfs4_dss_newpaths for us, and removed
   3018  2035     calum 	 * any duplicates.
   3019  2035     calum 	 */
   3020  2035     calum 	dss_path = rfs4_dss_pathlist;
   3021  2035     calum 	do {
   3022  2035     calum 		int found = 0;
   3023  2035     calum 		char *path = dss_path->path;
   3024  2035     calum 
   3025  2035     calum 		/* used only for non-HA so may not be removed */
   3026  2035     calum 		if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) {
   3027  2035     calum 			dss_path = dss_path->next;
   3028  2035     calum 			continue;
   3029  2035     calum 		}
   3030  2035     calum 
   3031  2035     calum 		for (i = 0; i < rfs4_dss_numnewpaths; i++) {
   3032  2035     calum 			int cmpret;
   3033  2035     calum 			char *newpath = rfs4_dss_newpaths[i];
   3034  2035     calum 
   3035  2035     calum 			/*
   3036  2035     calum 			 * Since nfsd has sorted rfs4_dss_newpaths for us,
   3037  2390     calum 			 * once the return from strcmp is negative we know
   3038  2035     calum 			 * we've passed the point where "path" should be,
   3039  2035     calum 			 * and can stop searching: "path" has been removed.
   3040  2035     calum 			 */
   3041  2390     calum 			cmpret = strcmp(path, newpath);
   3042  2035     calum 			if (cmpret < 0)
   3043  2035     calum 				break;
   3044  2035     calum 			if (cmpret == 0) {
   3045  2035     calum 				found = 1;
   3046  2035     calum 				break;
   3047  2035     calum 			}
   3048  2035     calum 		}
   3049  2035     calum 
   3050  2035     calum 		if (found == 0) {
   3051  2035     calum 			unsigned index = dss_path->index;
   3052  2035     calum 			rfs4_servinst_t *sip = dss_path->sip;
   3053  2035     calum 			rfs4_dss_path_t *path_next = dss_path->next;
   3054  2035     calum 
   3055  2035     calum 			/*
   3056  2035     calum 			 * This path has been removed.
   3057  2035     calum 			 * We must clear out the servinst reference to
   3058  2035     calum 			 * it, since it's now owned by another
   3059  2035     calum 			 * node: we should not attempt to touch it.
   3060  2035     calum 			 */
   3061  2035     calum 			ASSERT(dss_path == sip->dss_paths[index]);
   3062  2035     calum 			sip->dss_paths[index] = NULL;
   3063  2035     calum 
   3064  2035     calum 			/* remove from "currently-serving" list, and destroy */
   3065  2035     calum 			remque(dss_path);
   3066  2390     calum 			/* allow for NUL */
   3067  2390     calum 			kmem_free(dss_path->path, strlen(dss_path->path) + 1);
   3068  2035     calum 			kmem_free(dss_path, sizeof (rfs4_dss_path_t));
   3069  2035     calum 
   3070  2035     calum 			dss_path = path_next;
   3071  2035     calum 		} else {
   3072  2035     calum 			/* path was found; not removed */
   3073  2035     calum 			dss_path = dss_path->next;
   3074  2035     calum 		}
   3075  2035     calum 	} while (dss_path != rfs4_dss_pathlist);
   3076  2035     calum 
   3077  2035     calum 	/*
   3078  2035     calum 	 * Now, look for added paths: RGs that have been failed-over
   3079  2035     calum 	 * to this node.
   3080  2035     calum 	 * Walk the "passed-in" rfs4_dss_newpaths array from nfsd and,
   3081  2035     calum 	 * for each path, check if it is on the "currently-serving"
   3082  2035     calum 	 * rfs4_dss_pathlist. If not, that RG path has been added.
   3083  2035     calum 	 *
   3084  2035     calum 	 * Note: we don't do duplicate detection here; nfsd does that for us.
   3085  2035     calum 	 *
   3086  2035     calum 	 * Note: numadded_paths <= rfs4_dss_numnewpaths, which gives us
   3087  2035     calum 	 * an upper bound for the size needed for added_paths[numadded_paths].
   3088  2035     calum 	 */
   3089  2035     calum 
   3090  2035     calum 	/* probably more space than we need, but guaranteed to be enough */
   3091  2035     calum 	if (rfs4_dss_numnewpaths > 0) {
   3092  2035     calum 		size_t sz = rfs4_dss_numnewpaths * sizeof (char *);
   3093  2035     calum 		added_paths = kmem_zalloc(sz, KM_SLEEP);
   3094  2035     calum 	}
   3095  2035     calum 
   3096  2035     calum 	/* walk the "passed-in" rfs4_dss_newpaths array from nfsd */
   3097  2035     calum 	for (i = 0; i < rfs4_dss_numnewpaths; i++) {
   3098  2035     calum 		int found = 0;
   3099  2035     calum 		char *newpath = rfs4_dss_newpaths[i];
   3100  2035     calum 
   3101  2035     calum 		dss_path = rfs4_dss_pathlist;
   3102  2035     calum 		do {
   3103  2035     calum 			char *path = dss_path->path;
   3104  2035     calum 
   3105  2035     calum 			/* used only for non-HA */
   3106  2035     calum 			if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) {
   3107  2035     calum 				dss_path = dss_path->next;
   3108  2035     calum 				continue;
   3109  2035     calum 			}
   3110  2035     calum 
   3111  2035     calum 			if (strncmp(path, newpath, strlen(path)) == 0) {
   3112  2035     calum 				found = 1;
   3113  2035     calum 				break;
   3114  2035     calum 			}
   3115  2035     calum 
   3116  2035     calum 			dss_path = dss_path->next;
   3117  2035     calum 		} while (dss_path != rfs4_dss_pathlist);
   3118  2035     calum 
   3119  2035     calum 		if (found == 0) {
   3120  2035     calum 			added_paths[numadded_paths] = newpath;
   3121  2035     calum 			numadded_paths++;
   3122  2035     calum 		}
   3123  2035     calum 	}
   3124  2035     calum 
   3125  2035     calum 	/* did we find any added paths? */
   3126  2035     calum 	if (numadded_paths > 0) {
   3127  2035     calum 		/* create a new server instance, and start its grace period */
   3128  2035     calum 		start_grace = 1;
   3129  2035     calum 		rfs4_servinst_create(start_grace, numadded_paths, added_paths);
   3130  2035     calum 
   3131  2035     calum 		/* read in the stable storage state from these paths */
   3132  2035     calum 		rfs4_dss_readstate(numadded_paths, added_paths);
   3133  2035     calum 
   3134  2035     calum 		/*
   3135  2035     calum 		 * Multiple failovers during a grace period will cause
   3136  2035     calum 		 * clients of the same resource group to be partitioned
   3137  2035     calum 		 * into different server instances, with different
   3138  2035     calum 		 * grace periods.  Since clients of the same resource
   3139  2035     calum 		 * group must be subject to the same grace period,
   3140  2035     calum 		 * we need to reset all currently active grace periods.
   3141  2035     calum 		 */
   3142  2035     calum 		rfs4_grace_reset_all();
   3143  2035     calum 	}
   3144  2035     calum 
   3145  2035     calum 	if (rfs4_dss_numnewpaths > 0)
   3146  2035     calum 		kmem_free(added_paths, rfs4_dss_numnewpaths * sizeof (char *));
   3147  2035     calum }
   3148  9871   Jarrett 
   3149  9871   Jarrett /*
   3150  9871   Jarrett  * Used by NFSv3 and NFSv4 server to query label of
   3151  9871   Jarrett  * a pathname component during lookup/access ops.
   3152  9871   Jarrett  */
   3153  9871   Jarrett ts_label_t *
   3154  9871   Jarrett nfs_getflabel(vnode_t *vp, struct exportinfo *exi)
   3155  9871   Jarrett {
   3156  9871   Jarrett 	zone_t *zone;
   3157  9871   Jarrett 	ts_label_t *zone_label;
   3158  9871   Jarrett 	char *path;
   3159  9871   Jarrett 
   3160  9871   Jarrett 	mutex_enter(&vp->v_lock);
   3161  9871   Jarrett 	if (vp->v_path != NULL) {
   3162  9871   Jarrett 		zone = zone_find_by_any_path(vp->v_path, B_FALSE);
   3163  9871   Jarrett 		mutex_exit(&vp->v_lock);
   3164  9871   Jarrett 	} else {
   3165  9871   Jarrett 		/*
   3166  9871   Jarrett 		 * v_path not cached. Fall back on pathname of exported
   3167  9871   Jarrett 		 * file system as we rely on pathname from which we can
   3168  9871   Jarrett 		 * derive a label. The exported file system portion of
   3169  9871   Jarrett 		 * path is sufficient to obtain a label.
   3170  9871   Jarrett 		 */
   3171  9871   Jarrett 		path = exi->exi_export.ex_path;
   3172  9871   Jarrett 		if (path == NULL) {
   3173  9871   Jarrett 			mutex_exit(&vp->v_lock);
   3174  9871   Jarrett 			return (NULL);
   3175  9871   Jarrett 		}
   3176  9871   Jarrett 		zone = zone_find_by_any_path(path, B_FALSE);
   3177  9871   Jarrett 		mutex_exit(&vp->v_lock);
   3178  9871   Jarrett 	}
   3179  9871   Jarrett 	/*
   3180  9871   Jarrett 	 * Caller has verified that the file is either
   3181  9871   Jarrett 	 * exported or visible. So if the path falls in
   3182  9871   Jarrett 	 * global zone, admin_low is returned; otherwise
   3183  9871   Jarrett 	 * the zone's label is returned.
   3184  9871   Jarrett 	 */
   3185  9871   Jarrett 	zone_label = zone->zone_slabel;
   3186  9871   Jarrett 	label_hold(zone_label);
   3187  9871   Jarrett 	zone_rele(zone);
   3188  9871   Jarrett 	return (zone_label);
   3189  9871   Jarrett }
   3190  9871   Jarrett 
   3191  9871   Jarrett /*
   3192  9871   Jarrett  * TX NFS routine used by NFSv3 and NFSv4 to do label check
   3193  9871   Jarrett  * on client label and server's file object lable.
   3194  9871   Jarrett  */
   3195  9871   Jarrett boolean_t
   3196  9871   Jarrett do_rfs_label_check(bslabel_t *clabel, vnode_t *vp, int flag,
   3197  9871   Jarrett     struct exportinfo *exi)
   3198  9871   Jarrett {
   3199  9871   Jarrett 	bslabel_t *slabel;
   3200  9871   Jarrett 	ts_label_t *tslabel;
   3201  9871   Jarrett 	boolean_t result;
   3202  9871   Jarrett 
   3203  9871   Jarrett 	if ((tslabel = nfs_getflabel(vp, exi)) == NULL) {
   3204  9871   Jarrett 		return (B_FALSE);
   3205  9871   Jarrett 	}
   3206  9871   Jarrett 	slabel = label2bslabel(tslabel);
   3