17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*45916cd2Sjpk  * Common Development and Distribution License (the "License").
6*45916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*45916cd2Sjpk  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
287c478bd9Sstevel@tonic-gate  *	All rights reserved.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/param.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/systm.h>
367c478bd9Sstevel@tonic-gate #include <sys/cred.h>
377c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
387c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
397c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
437c478bd9Sstevel@tonic-gate #include <sys/mount.h>
447c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
457c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
467c478bd9Sstevel@tonic-gate #include <sys/errno.h>
477c478bd9Sstevel@tonic-gate #include <sys/debug.h>
487c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
497c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
507c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
517c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
527c478bd9Sstevel@tonic-gate #include <sys/acl.h>
537c478bd9Sstevel@tonic-gate #include <sys/flock.h>
547c478bd9Sstevel@tonic-gate #include <sys/policy.h>
557c478bd9Sstevel@tonic-gate #include <sys/zone.h>
567c478bd9Sstevel@tonic-gate #include <sys/class.h>
577c478bd9Sstevel@tonic-gate #include <sys/socket.h>
587c478bd9Sstevel@tonic-gate #include <sys/netconfig.h>
59*45916cd2Sjpk #include <sys/tsol/tnet.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include <rpc/types.h>
627c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
637c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
667c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
677c478bd9Sstevel@tonic-gate #include <nfs/rnode.h>
687c478bd9Sstevel@tonic-gate #include <nfs/mount.h>
697c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h>
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * From rpcsec module (common/rpcsec).
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate extern int sec_clnt_loadinfo(struct sec_data *, struct sec_data **, model_t);
777c478bd9Sstevel@tonic-gate extern void sec_clnt_freeinfo(struct sec_data *);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * The order and contents of this structure must be kept in sync with that of
817c478bd9Sstevel@tonic-gate  * rfsreqcnt_v3_tmpl in nfs_stats.c
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate static char *rfsnames_v3[] = {
847c478bd9Sstevel@tonic-gate 	"null", "getattr", "setattr", "lookup", "access", "readlink", "read",
857c478bd9Sstevel@tonic-gate 	"write", "create", "mkdir", "symlink", "mknod", "remove", "rmdir",
867c478bd9Sstevel@tonic-gate 	"rename", "link", "readdir", "readdirplus", "fsstat", "fsinfo",
877c478bd9Sstevel@tonic-gate 	"pathconf", "commit"
887c478bd9Sstevel@tonic-gate };
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * This table maps from NFS protocol number into call type.
927c478bd9Sstevel@tonic-gate  * Zero means a "Lookup" type call
937c478bd9Sstevel@tonic-gate  * One  means a "Read" type call
947c478bd9Sstevel@tonic-gate  * Two  means a "Write" type call
957c478bd9Sstevel@tonic-gate  * This is used to select a default time-out.
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate static uchar_t call_type_v3[] = {
987c478bd9Sstevel@tonic-gate 	0, 0, 1, 0, 0, 0, 1,
997c478bd9Sstevel@tonic-gate 	2, 2, 2, 2, 2, 2, 2,
1007c478bd9Sstevel@tonic-gate 	2, 2, 1, 2, 0, 0, 0,
1017c478bd9Sstevel@tonic-gate 	2 };
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * Similar table, but to determine which timer to use
1057c478bd9Sstevel@tonic-gate  * (only real reads and writes!)
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate static uchar_t timer_type_v3[] = {
1087c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 1,
1097c478bd9Sstevel@tonic-gate 	2, 0, 0, 0, 0, 0, 0,
1107c478bd9Sstevel@tonic-gate 	0, 0, 1, 1, 0, 0, 0,
1117c478bd9Sstevel@tonic-gate 	0 };
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate  * This table maps from NFS protocol number into a call type
1157c478bd9Sstevel@tonic-gate  * for the semisoft mount option.
1167c478bd9Sstevel@tonic-gate  * Zero means do not repeat operation.
1177c478bd9Sstevel@tonic-gate  * One  means repeat.
1187c478bd9Sstevel@tonic-gate  */
1197c478bd9Sstevel@tonic-gate static uchar_t ss_call_type_v3[] = {
1207c478bd9Sstevel@tonic-gate 	0, 0, 1, 0, 0, 0, 0,
1217c478bd9Sstevel@tonic-gate 	1, 1, 1, 1, 1, 1, 1,
1227c478bd9Sstevel@tonic-gate 	1, 1, 0, 0, 0, 0, 0,
1237c478bd9Sstevel@tonic-gate 	1 };
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * nfs3 vfs operations.
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate static int	nfs3_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
1297c478bd9Sstevel@tonic-gate static int	nfs3_unmount(vfs_t *, int, cred_t *);
1307c478bd9Sstevel@tonic-gate static int	nfs3_root(vfs_t *, vnode_t **);
1317c478bd9Sstevel@tonic-gate static int	nfs3_statvfs(vfs_t *, struct statvfs64 *);
1327c478bd9Sstevel@tonic-gate static int	nfs3_sync(vfs_t *, short, cred_t *);
1337c478bd9Sstevel@tonic-gate static int	nfs3_vget(vfs_t *, vnode_t **, fid_t *);
1347c478bd9Sstevel@tonic-gate static int	nfs3_mountroot(vfs_t *, whymountroot_t);
1357c478bd9Sstevel@tonic-gate static void	nfs3_freevfs(vfs_t *);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static int	nfs3rootvp(vnode_t **, vfs_t *, struct servinfo *,
1387c478bd9Sstevel@tonic-gate 		    int, cred_t *, zone_t *);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /*
1417c478bd9Sstevel@tonic-gate  * Initialize the vfs structure
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate static int nfs3fstyp;
1457c478bd9Sstevel@tonic-gate vfsops_t *nfs3_vfsops;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * Debug variable to check for rdma based
1497c478bd9Sstevel@tonic-gate  * transport startup and cleanup. Controlled
1507c478bd9Sstevel@tonic-gate  * through /etc/system. Off by default.
1517c478bd9Sstevel@tonic-gate  */
1527c478bd9Sstevel@tonic-gate extern int rdma_debug;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate int
1557c478bd9Sstevel@tonic-gate nfs3init(int fstyp, char *name)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	static const fs_operation_def_t nfs3_vfsops_template[] = {
1587c478bd9Sstevel@tonic-gate 		VFSNAME_MOUNT, nfs3_mount,
1597c478bd9Sstevel@tonic-gate 		VFSNAME_UNMOUNT, nfs3_unmount,
1607c478bd9Sstevel@tonic-gate 		VFSNAME_ROOT, nfs3_root,
1617c478bd9Sstevel@tonic-gate 		VFSNAME_STATVFS, nfs3_statvfs,
1627c478bd9Sstevel@tonic-gate 		VFSNAME_SYNC, (fs_generic_func_p) nfs3_sync,
1637c478bd9Sstevel@tonic-gate 		VFSNAME_VGET, nfs3_vget,
1647c478bd9Sstevel@tonic-gate 		VFSNAME_MOUNTROOT, nfs3_mountroot,
1657c478bd9Sstevel@tonic-gate 		VFSNAME_FREEVFS, (fs_generic_func_p)nfs3_freevfs,
1667c478bd9Sstevel@tonic-gate 		NULL, NULL
1677c478bd9Sstevel@tonic-gate 	};
1687c478bd9Sstevel@tonic-gate 	int error;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	error = vfs_setfsops(fstyp, nfs3_vfsops_template, &nfs3_vfsops);
1717c478bd9Sstevel@tonic-gate 	if (error != 0) {
1727c478bd9Sstevel@tonic-gate 		zcmn_err(GLOBAL_ZONEID, CE_WARN,
1737c478bd9Sstevel@tonic-gate 		    "nfs3init: bad vfs ops template");
1747c478bd9Sstevel@tonic-gate 		return (error);
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	error = vn_make_ops(name, nfs3_vnodeops_template, &nfs3_vnodeops);
1787c478bd9Sstevel@tonic-gate 	if (error != 0) {
1797c478bd9Sstevel@tonic-gate 		(void) vfs_freevfsops_by_type(fstyp);
1807c478bd9Sstevel@tonic-gate 		zcmn_err(GLOBAL_ZONEID, CE_WARN,
1817c478bd9Sstevel@tonic-gate 		    "nfs3init: bad vnode ops template");
1827c478bd9Sstevel@tonic-gate 		return (error);
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	nfs3fstyp = fstyp;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	return (0);
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate void
1917c478bd9Sstevel@tonic-gate nfs3fini(void)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate  * nfs mount vfsop
1977c478bd9Sstevel@tonic-gate  * Set up mount info record and attach it to vfs struct.
1987c478bd9Sstevel@tonic-gate  */
1997c478bd9Sstevel@tonic-gate static int
2007c478bd9Sstevel@tonic-gate nfs3_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	char *data = uap->dataptr;
2037c478bd9Sstevel@tonic-gate 	int error;
2047c478bd9Sstevel@tonic-gate 	vnode_t *rtvp;			/* the server's root */
2057c478bd9Sstevel@tonic-gate 	mntinfo_t *mi;			/* mount info, pointed at by vfs */
2067c478bd9Sstevel@tonic-gate 	size_t hlen;			/* length of hostname */
2077c478bd9Sstevel@tonic-gate 	size_t nlen;			/* length of netname */
2087c478bd9Sstevel@tonic-gate 	char netname[SYS_NMLN];		/* server's netname */
2097c478bd9Sstevel@tonic-gate 	struct netbuf addr;		/* server's address */
2107c478bd9Sstevel@tonic-gate 	struct netbuf syncaddr;		/* AUTH_DES time sync addr */
2117c478bd9Sstevel@tonic-gate 	struct knetconfig *knconf;	/* transport knetconfig structure */
2127c478bd9Sstevel@tonic-gate 	struct knetconfig *rdma_knconf;	/* rdma transport structure */
2137c478bd9Sstevel@tonic-gate 	rnode_t *rp;
2147c478bd9Sstevel@tonic-gate 	struct servinfo *svp;		/* nfs server info */
2157c478bd9Sstevel@tonic-gate 	struct servinfo *svp_tail = NULL; /* previous nfs server info */
2167c478bd9Sstevel@tonic-gate 	struct servinfo *svp_head;	/* first nfs server info */
2177c478bd9Sstevel@tonic-gate 	struct servinfo *svp_2ndlast;	/* 2nd last in server info list */
2187c478bd9Sstevel@tonic-gate 	struct sec_data *secdata;	/* security data */
2197c478bd9Sstevel@tonic-gate 	STRUCT_DECL(nfs_args, args);	/* nfs mount arguments */
2207c478bd9Sstevel@tonic-gate 	STRUCT_DECL(knetconfig, knconf_tmp);
2217c478bd9Sstevel@tonic-gate 	STRUCT_DECL(netbuf, addr_tmp);
2227c478bd9Sstevel@tonic-gate 	int flags, addr_type;
2237c478bd9Sstevel@tonic-gate 	char *p, *pf;
224108322fbScarlsonj 	zone_t *zone = nfs_zone();
225*45916cd2Sjpk 	zone_t *mntzone = NULL;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
2287c478bd9Sstevel@tonic-gate 		return (EPERM);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if (mvp->v_type != VDIR)
2317c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/*
2347c478bd9Sstevel@tonic-gate 	 * get arguments
2357c478bd9Sstevel@tonic-gate 	 *
2367c478bd9Sstevel@tonic-gate 	 * nfs_args is now versioned and is extensible, so
2377c478bd9Sstevel@tonic-gate 	 * uap->datalen might be different from sizeof (args)
2387c478bd9Sstevel@tonic-gate 	 * in a compatible situation.
2397c478bd9Sstevel@tonic-gate 	 */
2407c478bd9Sstevel@tonic-gate more:
2417c478bd9Sstevel@tonic-gate 	STRUCT_INIT(args, get_udatamodel());
2427c478bd9Sstevel@tonic-gate 	bzero(STRUCT_BUF(args), SIZEOF_STRUCT(nfs_args, DATAMODEL_NATIVE));
2437c478bd9Sstevel@tonic-gate 	if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen,
2447c478bd9Sstevel@tonic-gate 	    STRUCT_SIZE(args))))
2457c478bd9Sstevel@tonic-gate 		return (EFAULT);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	flags = STRUCT_FGET(args, flags);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_REMOUNT) {
2507c478bd9Sstevel@tonic-gate 		size_t n;
2517c478bd9Sstevel@tonic-gate 		char name[FSTYPSZ];
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 		if (uap->flags & MS_SYSSPACE)
2547c478bd9Sstevel@tonic-gate 			error = copystr(uap->fstype, name, FSTYPSZ, &n);
2557c478bd9Sstevel@tonic-gate 		else
2567c478bd9Sstevel@tonic-gate 			error = copyinstr(uap->fstype, name, FSTYPSZ, &n);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 		if (error) {
2597c478bd9Sstevel@tonic-gate 			if (error == ENAMETOOLONG)
2607c478bd9Sstevel@tonic-gate 				return (EINVAL);
2617c478bd9Sstevel@tonic-gate 			return (error);
2627c478bd9Sstevel@tonic-gate 		}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		/*
2657c478bd9Sstevel@tonic-gate 		 * This check is to ensure that the request is a
2667c478bd9Sstevel@tonic-gate 		 * genuine nfs remount request.
2677c478bd9Sstevel@tonic-gate 		 */
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 		if (strncmp(name, "nfs", 3) != 0)
2707c478bd9Sstevel@tonic-gate 			return (EINVAL);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 		/*
2737c478bd9Sstevel@tonic-gate 		 * If the request changes the locking type, disallow the
2747c478bd9Sstevel@tonic-gate 		 * remount,
2757c478bd9Sstevel@tonic-gate 		 * because it's questionable whether we can transfer the
2767c478bd9Sstevel@tonic-gate 		 * locking state correctly.
2777c478bd9Sstevel@tonic-gate 		 */
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 		if ((mi = VFTOMI(vfsp)) != NULL) {
2807c478bd9Sstevel@tonic-gate 			uint_t new_mi_llock;
2817c478bd9Sstevel@tonic-gate 			uint_t old_mi_llock;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 			new_mi_llock = (flags & NFSMNT_LLOCK) ? 1 : 0;
2847c478bd9Sstevel@tonic-gate 			old_mi_llock = (mi->mi_flags & MI_LLOCK) ? 1 : 0;
2857c478bd9Sstevel@tonic-gate 			if (old_mi_llock != new_mi_llock)
2867c478bd9Sstevel@tonic-gate 				return (EBUSY);
2877c478bd9Sstevel@tonic-gate 		}
2887c478bd9Sstevel@tonic-gate 		return (0);
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	mutex_enter(&mvp->v_lock);
2927c478bd9Sstevel@tonic-gate 	if (!(uap->flags & MS_OVERLAY) &&
2937c478bd9Sstevel@tonic-gate 	    (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
2947c478bd9Sstevel@tonic-gate 		mutex_exit(&mvp->v_lock);
2957c478bd9Sstevel@tonic-gate 		return (EBUSY);
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 	mutex_exit(&mvp->v_lock);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/* make sure things are zeroed for errout: */
3007c478bd9Sstevel@tonic-gate 	rtvp = NULL;
3017c478bd9Sstevel@tonic-gate 	mi = NULL;
3027c478bd9Sstevel@tonic-gate 	addr.buf = NULL;
3037c478bd9Sstevel@tonic-gate 	syncaddr.buf = NULL;
3047c478bd9Sstevel@tonic-gate 	secdata = NULL;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	/*
3077c478bd9Sstevel@tonic-gate 	 * A valid knetconfig structure is required.
3087c478bd9Sstevel@tonic-gate 	 */
3097c478bd9Sstevel@tonic-gate 	if (!(flags & NFSMNT_KNCONF))
3107c478bd9Sstevel@tonic-gate 		return (EINVAL);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	/*
3137c478bd9Sstevel@tonic-gate 	 * Allocate a servinfo struct.
3147c478bd9Sstevel@tonic-gate 	 */
3157c478bd9Sstevel@tonic-gate 	svp = kmem_zalloc(sizeof (*svp), KM_SLEEP);
3167c478bd9Sstevel@tonic-gate 	mutex_init(&svp->sv_lock, NULL, MUTEX_DEFAULT, NULL);
3177c478bd9Sstevel@tonic-gate 	if (svp_tail) {
3187c478bd9Sstevel@tonic-gate 		svp_2ndlast = svp_tail;
3197c478bd9Sstevel@tonic-gate 		svp_tail->sv_next = svp;
3207c478bd9Sstevel@tonic-gate 	} else {
3217c478bd9Sstevel@tonic-gate 		svp_head = svp;
3227c478bd9Sstevel@tonic-gate 		svp_2ndlast = svp;
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	svp_tail = svp;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	/*
3287c478bd9Sstevel@tonic-gate 	 * Allocate space for a knetconfig structure and
3297c478bd9Sstevel@tonic-gate 	 * its strings and copy in from user-land.
3307c478bd9Sstevel@tonic-gate 	 */
3317c478bd9Sstevel@tonic-gate 	knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP);
3327c478bd9Sstevel@tonic-gate 	svp->sv_knconf = knconf;
3337c478bd9Sstevel@tonic-gate 	STRUCT_INIT(knconf_tmp, get_udatamodel());
3347c478bd9Sstevel@tonic-gate 	if (copyin(STRUCT_FGETP(args, knconf), STRUCT_BUF(knconf_tmp),
3357c478bd9Sstevel@tonic-gate 	    STRUCT_SIZE(knconf_tmp))) {
3367c478bd9Sstevel@tonic-gate 		sv_free(svp_head);
3377c478bd9Sstevel@tonic-gate 		return (EFAULT);
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics);
3417c478bd9Sstevel@tonic-gate 	knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly);
3427c478bd9Sstevel@tonic-gate 	knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto);
3437c478bd9Sstevel@tonic-gate 	if (get_udatamodel() != DATAMODEL_LP64) {
3447c478bd9Sstevel@tonic-gate 		knconf->knc_rdev = expldev(STRUCT_FGET(knconf_tmp, knc_rdev));
3457c478bd9Sstevel@tonic-gate 	} else {
3467c478bd9Sstevel@tonic-gate 		knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev);
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
3507c478bd9Sstevel@tonic-gate 	p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
3517c478bd9Sstevel@tonic-gate 	error = copyinstr(knconf->knc_protofmly, pf, KNC_STRSIZE, NULL);
3527c478bd9Sstevel@tonic-gate 	if (error) {
3537c478bd9Sstevel@tonic-gate 		kmem_free(pf, KNC_STRSIZE);
3547c478bd9Sstevel@tonic-gate 		kmem_free(p, KNC_STRSIZE);
3557c478bd9Sstevel@tonic-gate 		sv_free(svp_head);
3567c478bd9Sstevel@tonic-gate 		return (error);
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	error = copyinstr(knconf->knc_proto, p, KNC_STRSIZE, NULL);
3597c478bd9Sstevel@tonic-gate 	if (error) {
3607c478bd9Sstevel@tonic-gate 		kmem_free(pf, KNC_STRSIZE);
3617c478bd9Sstevel@tonic-gate 		kmem_free(p, KNC_STRSIZE);
3627c478bd9Sstevel@tonic-gate 		sv_free(svp_head);
3637c478bd9Sstevel@tonic-gate 		return (error);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 	knconf->knc_protofmly = pf;
3667c478bd9Sstevel@tonic-gate 	knconf->knc_proto = p;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	/*
3697c478bd9Sstevel@tonic-gate 	 * Get server address
3707c478bd9Sstevel@tonic-gate 	 */
3717c478bd9Sstevel@tonic-gate 	STRUCT_INIT(addr_tmp, get_udatamodel());
3727c478bd9Sstevel@tonic-gate 	if (copyin(STRUCT_FGETP(args, addr), STRUCT_BUF(addr_tmp),
3737c478bd9Sstevel@tonic-gate 	    STRUCT_SIZE(addr_tmp))) {
3747c478bd9Sstevel@tonic-gate 		addr.buf = NULL;
3757c478bd9Sstevel@tonic-gate 		error = EFAULT;
3767c478bd9Sstevel@tonic-gate 	} else {
3777c478bd9Sstevel@tonic-gate 		char *userbufptr;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 		userbufptr = addr.buf = STRUCT_FGETP(addr_tmp, buf);
3807c478bd9Sstevel@tonic-gate 		addr.len = STRUCT_FGET(addr_tmp, len);
3817c478bd9Sstevel@tonic-gate 		addr.buf = kmem_alloc(addr.len, KM_SLEEP);
3827c478bd9Sstevel@tonic-gate 		addr.maxlen = addr.len;
3837c478bd9Sstevel@tonic-gate 		if (copyin(userbufptr, addr.buf, addr.len))
3847c478bd9Sstevel@tonic-gate 			error = EFAULT;
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 	svp->sv_addr = addr;
3877c478bd9Sstevel@tonic-gate 	if (error)
3887c478bd9Sstevel@tonic-gate 		goto errout;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	/*
3917c478bd9Sstevel@tonic-gate 	 * Get the root fhandle
3927c478bd9Sstevel@tonic-gate 	 */
3937c478bd9Sstevel@tonic-gate 	if (copyin(STRUCT_FGETP(args, fh), &svp->sv_fhandle,
3947c478bd9Sstevel@tonic-gate 	    sizeof (svp->sv_fhandle))) {
3957c478bd9Sstevel@tonic-gate 		error = EFAULT;
3967c478bd9Sstevel@tonic-gate 		goto errout;
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/*
4007c478bd9Sstevel@tonic-gate 	 * Check the root fhandle length
4017c478bd9Sstevel@tonic-gate 	 */
40268458954Sssdevi 	if (svp->sv_fhandle.fh_len > NFS3_FHSIZE ||
40368458954Sssdevi 		svp->sv_fhandle.fh_len <= 0) {
4047c478bd9Sstevel@tonic-gate 		error = EINVAL;
4057c478bd9Sstevel@tonic-gate #ifdef DEBUG
4067c478bd9Sstevel@tonic-gate 		zcmn_err(getzoneid(), CE_WARN,
4077c478bd9Sstevel@tonic-gate 		    "nfs3_mount: got an invalid fhandle. fh_len = %d",
4087c478bd9Sstevel@tonic-gate 		    svp->sv_fhandle.fh_len);
4097c478bd9Sstevel@tonic-gate 		svp->sv_fhandle.fh_len = NFS_FHANDLE_LEN;
4107c478bd9Sstevel@tonic-gate 		nfs_printfhandle(&svp->sv_fhandle);
4117c478bd9Sstevel@tonic-gate #endif
4127c478bd9Sstevel@tonic-gate 		goto errout;
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/*
4167c478bd9Sstevel@tonic-gate 	 * Get server's hostname
4177c478bd9Sstevel@tonic-gate 	 */
4187c478bd9Sstevel@tonic-gate 	if (flags & NFSMNT_HOSTNAME) {
4197c478bd9Sstevel@tonic-gate 		error = copyinstr(STRUCT_FGETP(args, hostname),
4207c478bd9Sstevel@tonic-gate 		    netname, sizeof (netname), &hlen);
4217c478bd9Sstevel@tonic-gate 		if (error)
4227c478bd9Sstevel@tonic-gate 			goto errout;
4237c478bd9Sstevel@tonic-gate 	} else {
4247c478bd9Sstevel@tonic-gate 		char *p = "unknown-host";
4257c478bd9Sstevel@tonic-gate 		hlen = strlen(p) + 1;
4267c478bd9Sstevel@tonic-gate 		(void) strcpy(netname, p);
4277c478bd9Sstevel@tonic-gate 	}
4287c478bd9Sstevel@tonic-gate 	svp->sv_hostnamelen = hlen;
4297c478bd9Sstevel@tonic-gate 	svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP);
4307c478bd9Sstevel@tonic-gate 	(void) strcpy(svp->sv_hostname, netname);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	/*
4337c478bd9Sstevel@tonic-gate 	 * RDMA MOUNT SUPPORT FOR NFS v3:
4347c478bd9Sstevel@tonic-gate 	 * Establish, is it possible to use RDMA, if so overload the
4357c478bd9Sstevel@tonic-gate 	 * knconf with rdma specific knconf and free the orignal.
4367c478bd9Sstevel@tonic-gate 	 */
4377c478bd9Sstevel@tonic-gate 	if ((flags & NFSMNT_TRYRDMA) || (flags & NFSMNT_DORDMA)) {
4387c478bd9Sstevel@tonic-gate 		/*
4397c478bd9Sstevel@tonic-gate 		 * Determine the addr type for RDMA, IPv4 or v6.
4407c478bd9Sstevel@tonic-gate 		 */
4417c478bd9Sstevel@tonic-gate 		if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET) == 0)
4427c478bd9Sstevel@tonic-gate 			addr_type = AF_INET;
4437c478bd9Sstevel@tonic-gate 		else if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET6) == 0)
4447c478bd9Sstevel@tonic-gate 			addr_type = AF_INET6;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 		if (rdma_reachable(addr_type, &svp->sv_addr,
4477c478bd9Sstevel@tonic-gate 			&rdma_knconf) == 0) {
4487c478bd9Sstevel@tonic-gate 			/*
4497c478bd9Sstevel@tonic-gate 			 * If successful, hijack the orignal knconf and
4507c478bd9Sstevel@tonic-gate 			 * replace with a new one, depending on the flags.
4517c478bd9Sstevel@tonic-gate 			 */
4527c478bd9Sstevel@tonic-gate 			svp->sv_origknconf = svp->sv_knconf;
4537c478bd9Sstevel@tonic-gate 			svp->sv_knconf = rdma_knconf;
4547c478bd9Sstevel@tonic-gate 			knconf = rdma_knconf;
4557c478bd9Sstevel@tonic-gate 		} else {
4567c478bd9Sstevel@tonic-gate 			if (flags & NFSMNT_TRYRDMA) {
4577c478bd9Sstevel@tonic-gate #ifdef	DEBUG
4587c478bd9Sstevel@tonic-gate 				if (rdma_debug)
4597c478bd9Sstevel@tonic-gate 					zcmn_err(getzoneid(), CE_WARN,
4607c478bd9Sstevel@tonic-gate 					    "no RDMA onboard, revert\n");
4617c478bd9Sstevel@tonic-gate #endif
4627c478bd9Sstevel@tonic-gate 			}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 			if (flags & NFSMNT_DORDMA) {
4657c478bd9Sstevel@tonic-gate 				/*
4667c478bd9Sstevel@tonic-gate 				 * If proto=rdma is specified and no RDMA
4677c478bd9Sstevel@tonic-gate 				 * path to this server is avialable then
4687c478bd9Sstevel@tonic-gate 				 * ditch this server.
4697c478bd9Sstevel@tonic-gate 				 * This is not included in the mountable
4707c478bd9Sstevel@tonic-gate 				 * server list or the replica list.
4717c478bd9Sstevel@tonic-gate 				 * Check if more servers are specified;
4727c478bd9Sstevel@tonic-gate 				 * Failover case, otherwise bail out of mount.
4737c478bd9Sstevel@tonic-gate 				 */
4747c478bd9Sstevel@tonic-gate 				if (STRUCT_FGET(args, nfs_args_ext) ==
4757c478bd9Sstevel@tonic-gate 				    NFS_ARGS_EXTB && STRUCT_FGETP(args,
4767c478bd9Sstevel@tonic-gate 					nfs_ext_u.nfs_extB.next) != NULL) {
4777c478bd9Sstevel@tonic-gate 					if (uap->flags & MS_RDONLY &&
4787c478bd9Sstevel@tonic-gate 					    !(flags & NFSMNT_SOFT)) {
4797c478bd9Sstevel@tonic-gate 						data = (char *)
4807c478bd9Sstevel@tonic-gate 						    STRUCT_FGETP(args,
4817c478bd9Sstevel@tonic-gate 						nfs_ext_u.nfs_extB.next);
4827c478bd9Sstevel@tonic-gate 						if (svp_head->sv_next == NULL) {
4837c478bd9Sstevel@tonic-gate 							svp_tail = NULL;
4847c478bd9Sstevel@tonic-gate 							svp_2ndlast = NULL;
4857c478bd9Sstevel@tonic-gate 							sv_free(svp_head);
4867c478bd9Sstevel@tonic-gate 							goto more;
4877c478bd9Sstevel@tonic-gate 						} else {
4887c478bd9Sstevel@tonic-gate 							svp_tail = svp_2ndlast;
4897c478bd9Sstevel@tonic-gate 							svp_2ndlast->sv_next =
4907c478bd9Sstevel@tonic-gate 							    NULL;
4917c478bd9Sstevel@tonic-gate 							sv_free(svp);
4927c478bd9Sstevel@tonic-gate 							goto more;
4937c478bd9Sstevel@tonic-gate 						}
4947c478bd9Sstevel@tonic-gate 					}
4957c478bd9Sstevel@tonic-gate 				} else {
4967c478bd9Sstevel@tonic-gate 					/*
4977c478bd9Sstevel@tonic-gate 					 * This is the last server specified
4987c478bd9Sstevel@tonic-gate 					 * in the nfs_args list passed down
4997c478bd9Sstevel@tonic-gate 					 * and its not rdma capable.
5007c478bd9Sstevel@tonic-gate 					 */
5017c478bd9Sstevel@tonic-gate 					if (svp_head->sv_next == NULL) {
5027c478bd9Sstevel@tonic-gate 						/*
5037c478bd9Sstevel@tonic-gate 						 * Is this the only one
5047c478bd9Sstevel@tonic-gate 						 */
5057c478bd9Sstevel@tonic-gate 						error = EINVAL;
5067c478bd9Sstevel@tonic-gate #ifdef	DEBUG
5077c478bd9Sstevel@tonic-gate 						if (rdma_debug)
5087c478bd9Sstevel@tonic-gate 							zcmn_err(getzoneid(),
5097c478bd9Sstevel@tonic-gate 							    CE_WARN,
5107c478bd9Sstevel@tonic-gate 							    "No RDMA srv");
5117c478bd9Sstevel@tonic-gate #endif
5127c478bd9Sstevel@tonic-gate 						goto errout;
5137c478bd9Sstevel@tonic-gate 					} else {
5147c478bd9Sstevel@tonic-gate 						/*
5157c478bd9Sstevel@tonic-gate 						 * There is list, since some
5167c478bd9Sstevel@tonic-gate 						 * servers specified before
5177c478bd9Sstevel@tonic-gate 						 * this passed all requirements
5187c478bd9Sstevel@tonic-gate 						 */
5197c478bd9Sstevel@tonic-gate 						svp_tail = svp_2ndlast;
5207c478bd9Sstevel@tonic-gate 						svp_2ndlast->sv_next = NULL;
5217c478bd9Sstevel@tonic-gate 						sv_free(svp);
5227c478bd9Sstevel@tonic-gate 						goto proceed;
5237c478bd9Sstevel@tonic-gate 					}
5247c478bd9Sstevel@tonic-gate 				}
5257c478bd9Sstevel@tonic-gate 			}
5267c478bd9Sstevel@tonic-gate 		}
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	/*
5307c478bd9Sstevel@tonic-gate 	 * Get the extention data which has the new security data structure.
5317c478bd9Sstevel@tonic-gate 	 */
5327c478bd9Sstevel@tonic-gate 	if (flags & NFSMNT_NEWARGS) {
5337c478bd9Sstevel@tonic-gate 		switch (STRUCT_FGET(args, nfs_args_ext)) {
5347c478bd9Sstevel@tonic-gate 		case NFS_ARGS_EXTA:
5357c478bd9Sstevel@tonic-gate 		case NFS_ARGS_EXTB:
5367c478bd9Sstevel@tonic-gate 			/*
5377c478bd9Sstevel@tonic-gate 			 * Indicating the application is using the new
5387c478bd9Sstevel@tonic-gate 			 * sec_data structure to pass in the security
5397c478bd9Sstevel@tonic-gate 			 * data.
5407c478bd9Sstevel@tonic-gate 			 */
5417c478bd9Sstevel@tonic-gate 			if (STRUCT_FGETP(args,
5427c478bd9Sstevel@tonic-gate 			    nfs_ext_u.nfs_extA.secdata) == NULL) {
5437c478bd9Sstevel@tonic-gate 				error = EINVAL;
5447c478bd9Sstevel@tonic-gate 			} else {
5457c478bd9Sstevel@tonic-gate 				error = sec_clnt_loadinfo(
5467c478bd9Sstevel@tonic-gate 				    (struct sec_data *)STRUCT_FGETP(args,
5477c478bd9Sstevel@tonic-gate 					nfs_ext_u.nfs_extA.secdata),
5487c478bd9Sstevel@tonic-gate 				    &secdata, get_udatamodel());
5497c478bd9Sstevel@tonic-gate 			}
5507c478bd9Sstevel@tonic-gate 			break;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 		default:
5537c478bd9Sstevel@tonic-gate 			error = EINVAL;
5547c478bd9Sstevel@tonic-gate 			break;
5557c478bd9Sstevel@tonic-gate 		}
5567c478bd9Sstevel@tonic-gate 	} else if (flags & NFSMNT_SECURE) {
5577c478bd9Sstevel@tonic-gate 		/*
5587c478bd9Sstevel@tonic-gate 		 * Keep this for backward compatibility to support
5597c478bd9Sstevel@tonic-gate 		 * NFSMNT_SECURE/NFSMNT_RPCTIMESYNC flags.
5607c478bd9Sstevel@tonic-gate 		 */
5617c478bd9Sstevel@tonic-gate 		if (STRUCT_FGETP(args, syncaddr) == NULL) {
5627c478bd9Sstevel@tonic-gate 			error = EINVAL;
5637c478bd9Sstevel@tonic-gate 		} else {
5647c478bd9Sstevel@tonic-gate 			/*
5657c478bd9Sstevel@tonic-gate 			 * get time sync address.
5667c478bd9Sstevel@tonic-gate 			 */
5677c478bd9Sstevel@tonic-gate 			if (copyin(STRUCT_FGETP(args, syncaddr), &addr_tmp,
5687c478bd9Sstevel@tonic-gate 			    STRUCT_SIZE(addr_tmp))) {
5697c478bd9Sstevel@tonic-gate 				syncaddr.buf = NULL;
5707c478bd9Sstevel@tonic-gate 				error = EFAULT;
5717c478bd9Sstevel@tonic-gate 			} else {
5727c478bd9Sstevel@tonic-gate 				char *userbufptr;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 				userbufptr = syncaddr.buf =
5757c478bd9Sstevel@tonic-gate 				    STRUCT_FGETP(addr_tmp, buf);
5767c478bd9Sstevel@tonic-gate 				syncaddr.len =
5777c478bd9Sstevel@tonic-gate 				    STRUCT_FGET(addr_tmp, len);
5787c478bd9Sstevel@tonic-gate 				syncaddr.buf = kmem_alloc(syncaddr.len,
5797c478bd9Sstevel@tonic-gate 				    KM_SLEEP);
5807c478bd9Sstevel@tonic-gate 				syncaddr.maxlen = syncaddr.len;
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 				if (copyin(userbufptr, syncaddr.buf,
5837c478bd9Sstevel@tonic-gate 				    syncaddr.len))
5847c478bd9Sstevel@tonic-gate 					error = EFAULT;
5857c478bd9Sstevel@tonic-gate 			}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 			/*
5887c478bd9Sstevel@tonic-gate 			 * get server's netname
5897c478bd9Sstevel@tonic-gate 			 */
5907c478bd9Sstevel@tonic-gate 			if (!error) {
5917c478bd9Sstevel@tonic-gate 				error = copyinstr(STRUCT_FGETP(args, netname),
5927c478bd9Sstevel@tonic-gate 				    netname, sizeof (netname), &nlen);
5937c478bd9Sstevel@tonic-gate 				netname[nlen] = '\0';
5947c478bd9Sstevel@tonic-gate 			}
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 			if (error && syncaddr.buf != NULL) {
5977c478bd9Sstevel@tonic-gate 				kmem_free(syncaddr.buf, syncaddr.len);
5987c478bd9Sstevel@tonic-gate 				syncaddr.buf = NULL;
5997c478bd9Sstevel@tonic-gate 			}
6007c478bd9Sstevel@tonic-gate 		}
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 		/*
6037c478bd9Sstevel@tonic-gate 		 * Move security related data to the sec_data structure.
6047c478bd9Sstevel@tonic-gate 		 */
6057c478bd9Sstevel@tonic-gate 		if (!error) {
6067c478bd9Sstevel@tonic-gate 			dh_k4_clntdata_t *data;
6077c478bd9Sstevel@tonic-gate 			char *pf, *p;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 			secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP);
6107c478bd9Sstevel@tonic-gate 			if (flags & NFSMNT_RPCTIMESYNC)
6117c478bd9Sstevel@tonic-gate 				secdata->flags |= AUTH_F_RPCTIMESYNC;
6127c478bd9Sstevel@tonic-gate 			data = kmem_alloc(sizeof (*data), KM_SLEEP);
6137c478bd9Sstevel@tonic-gate 			data->syncaddr = syncaddr;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 			/*
6167c478bd9Sstevel@tonic-gate 			 * duplicate the knconf information for the
6177c478bd9Sstevel@tonic-gate 			 * new opaque data.
6187c478bd9Sstevel@tonic-gate 			 */
6197c478bd9Sstevel@tonic-gate 			data->knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP);
6207c478bd9Sstevel@tonic-gate 			*data->knconf = *knconf;
6217c478bd9Sstevel@tonic-gate 			pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
6227c478bd9Sstevel@tonic-gate 			p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
6237c478bd9Sstevel@tonic-gate 			bcopy(knconf->knc_protofmly, pf, KNC_STRSIZE);
6247c478bd9Sstevel@tonic-gate 			bcopy(knconf->knc_proto, pf, KNC_STRSIZE);
6257c478bd9Sstevel@tonic-gate 			data->knconf->knc_protofmly = pf;
6267c478bd9Sstevel@tonic-gate 			data->knconf->knc_proto = p;
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 			/* move server netname to the sec_data structure */
6297c478bd9Sstevel@tonic-gate 			if (nlen != 0) {
6307c478bd9Sstevel@tonic-gate 				data->netname = kmem_alloc(nlen, KM_SLEEP);
6317c478bd9Sstevel@tonic-gate 				bcopy(netname, data->netname, nlen);
6327c478bd9Sstevel@tonic-gate 				data->netnamelen = (int)nlen;
6337c478bd9Sstevel@tonic-gate 			}
6347c478bd9Sstevel@tonic-gate 			secdata->secmod = secdata->rpcflavor = AUTH_DES;
6357c478bd9Sstevel@tonic-gate 			secdata->data = (caddr_t)data;
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 	} else {
6387c478bd9Sstevel@tonic-gate 		secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP);
6397c478bd9Sstevel@tonic-gate 		secdata->secmod = secdata->rpcflavor = AUTH_UNIX;
6407c478bd9Sstevel@tonic-gate 		secdata->data = NULL;
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 	svp->sv_secdata = secdata;
6437c478bd9Sstevel@tonic-gate 	if (error)
6447c478bd9Sstevel@tonic-gate 		goto errout;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/*
6477c478bd9Sstevel@tonic-gate 	 * See bug 1180236.
6487c478bd9Sstevel@tonic-gate 	 * If mount secure failed, we will fall back to AUTH_NONE
6497c478bd9Sstevel@tonic-gate 	 * and try again.  nfs3rootvp() will turn this back off.
6507c478bd9Sstevel@tonic-gate 	 *
6517c478bd9Sstevel@tonic-gate 	 * The NFS Version 3 mount uses the FSINFO and GETATTR
6527c478bd9Sstevel@tonic-gate 	 * procedures.  The server should not care if these procedures
6537c478bd9Sstevel@tonic-gate 	 * have the proper security flavor, so if mount retries using
6547c478bd9Sstevel@tonic-gate 	 * AUTH_NONE that does not require a credential setup for root
6557c478bd9Sstevel@tonic-gate 	 * then the automounter would work without requiring root to be
6567c478bd9Sstevel@tonic-gate 	 * keylogged into AUTH_DES.
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 	if (secdata->rpcflavor != AUTH_UNIX &&
6597c478bd9Sstevel@tonic-gate 	    secdata->rpcflavor != AUTH_LOOPBACK)
6607c478bd9Sstevel@tonic-gate 		secdata->flags |= AUTH_F_TRYNONE;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	/*
6637c478bd9Sstevel@tonic-gate 	 * Failover support:
6647c478bd9Sstevel@tonic-gate 	 *
6657c478bd9Sstevel@tonic-gate 	 * We may have a linked list of nfs_args structures,
6667c478bd9Sstevel@tonic-gate 	 * which means the user is looking for failover.  If
6677c478bd9Sstevel@tonic-gate 	 * the mount is either not "read-only" or "soft",
6687c478bd9Sstevel@tonic-gate 	 * we want to bail out with EINVAL.
6697c478bd9Sstevel@tonic-gate 	 */
6707c478bd9Sstevel@tonic-gate 	if (STRUCT_FGET(args, nfs_args_ext) == NFS_ARGS_EXTB &&
6717c478bd9Sstevel@tonic-gate 	    STRUCT_FGETP(args, nfs_ext_u.nfs_extB.next) != NULL) {
6727c478bd9Sstevel@tonic-gate 		if (uap->flags & MS_RDONLY && !(flags & NFSMNT_SOFT)) {
6737c478bd9Sstevel@tonic-gate 			data = (char *)STRUCT_FGETP(args,
6747c478bd9Sstevel@tonic-gate 			    nfs_ext_u.nfs_extB.next);
6757c478bd9Sstevel@tonic-gate 			goto more;
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 		error = EINVAL;
6787c478bd9Sstevel@tonic-gate 		goto errout;
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	/*
6827c478bd9Sstevel@tonic-gate 	 * Determine the zone we're being mounted into.
6837c478bd9Sstevel@tonic-gate 	 */
684*45916cd2Sjpk 	zone_hold(mntzone = zone);		/* start with this assumption */
6857c478bd9Sstevel@tonic-gate 	if (getzoneid() == GLOBAL_ZONEID) {
686*45916cd2Sjpk 		zone_rele(mntzone);
6877c478bd9Sstevel@tonic-gate 		mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
6887c478bd9Sstevel@tonic-gate 		ASSERT(mntzone != NULL);
6897c478bd9Sstevel@tonic-gate 		if (mntzone != zone) {
6907c478bd9Sstevel@tonic-gate 			error = EBUSY;
6917c478bd9Sstevel@tonic-gate 			goto errout;
6927c478bd9Sstevel@tonic-gate 		}
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
695*45916cd2Sjpk 	if (is_system_labeled()) {
696*45916cd2Sjpk 		error = nfs_mount_label_policy(vfsp, &svp->sv_addr,
697*45916cd2Sjpk 		    svp->sv_knconf, cr);
698*45916cd2Sjpk 
699*45916cd2Sjpk 		if (error > 0)
700*45916cd2Sjpk 			goto errout;
701*45916cd2Sjpk 
702*45916cd2Sjpk 		if (error == -1) {
703*45916cd2Sjpk 			/* change mount to read-only to prevent write-down */
704*45916cd2Sjpk 			vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
705*45916cd2Sjpk 		}
706*45916cd2Sjpk 	}
707*45916cd2Sjpk 
7087c478bd9Sstevel@tonic-gate 	/*
7097c478bd9Sstevel@tonic-gate 	 * Stop the mount from going any further if the zone is going away.
7107c478bd9Sstevel@tonic-gate 	 */
711*45916cd2Sjpk 	if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) {
7127c478bd9Sstevel@tonic-gate 		error = EBUSY;
7137c478bd9Sstevel@tonic-gate 		goto errout;
7147c478bd9Sstevel@tonic-gate 	}
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	/*
7177c478bd9Sstevel@tonic-gate 	 * Get root vnode.
7187c478bd9Sstevel@tonic-gate 	 */
7197c478bd9Sstevel@tonic-gate proceed:
720*45916cd2Sjpk 	error = nfs3rootvp(&rtvp, vfsp, svp_head, flags, cr, mntzone);
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	if (error)
7237c478bd9Sstevel@tonic-gate 		goto errout;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/*
7267c478bd9Sstevel@tonic-gate 	 * Set option fields in the mount info record
7277c478bd9Sstevel@tonic-gate 	 */
7287c478bd9Sstevel@tonic-gate 	mi = VTOMI(rtvp);
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	if (svp_head->sv_next)
7317c478bd9Sstevel@tonic-gate 		mi->mi_flags |= MI_LLOCK;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	error = nfs_setopts(rtvp, get_udatamodel(), STRUCT_BUF(args));
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate errout:
7367c478bd9Sstevel@tonic-gate 	if (error) {
7377c478bd9Sstevel@tonic-gate 		if (rtvp != NULL) {
7387c478bd9Sstevel@tonic-gate 			rp = VTOR(rtvp);
7397c478bd9Sstevel@tonic-gate 			if (rp->r_flags & RHASHED)
7407c478bd9Sstevel@tonic-gate 				rp_rmhash(rp);
7417c478bd9Sstevel@tonic-gate 		}
7427c478bd9Sstevel@tonic-gate 		sv_free(svp_head);
7437c478bd9Sstevel@tonic-gate 		if (mi != NULL) {
7447c478bd9Sstevel@tonic-gate 			nfs_async_stop(vfsp);
7457c478bd9Sstevel@tonic-gate 			nfs_async_manager_stop(vfsp);
7467c478bd9Sstevel@tonic-gate 			if (mi->mi_io_kstats) {
7477c478bd9Sstevel@tonic-gate 				kstat_delete(mi->mi_io_kstats);
7487c478bd9Sstevel@tonic-gate 				mi->mi_io_kstats = NULL;
7497c478bd9Sstevel@tonic-gate 			}
7507c478bd9Sstevel@tonic-gate 			if (mi->mi_ro_kstats) {
7517c478bd9Sstevel@tonic-gate 				kstat_delete(mi->mi_ro_kstats);
7527c478bd9Sstevel@tonic-gate 				mi->mi_ro_kstats = NULL;
7537c478bd9Sstevel@tonic-gate 			}
7547c478bd9Sstevel@tonic-gate 			nfs_free_mi(mi);
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 	}
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if (rtvp != NULL)
7597c478bd9Sstevel@tonic-gate 		VN_RELE(rtvp);
7607c478bd9Sstevel@tonic-gate 
761*45916cd2Sjpk 	if (mntzone != NULL)
762*45916cd2Sjpk 		zone_rele(mntzone);
763*45916cd2Sjpk 
7647c478bd9Sstevel@tonic-gate 	return (error);
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate static int nfs3_dynamic = 0;	/* global variable to enable dynamic retrans. */
7687c478bd9Sstevel@tonic-gate static ushort_t nfs3_max_threads = 8;	/* max number of active async threads */
7697c478bd9Sstevel@tonic-gate static uint_t nfs3_bsize = 32 * 1024;	/* client `block' size */
7707c478bd9Sstevel@tonic-gate static uint_t nfs3_async_clusters = 1;	/* # of reqs from each async queue */
7717c478bd9Sstevel@tonic-gate static uint_t nfs3_cots_timeo = NFS_COTS_TIMEO;
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate static int
7747c478bd9Sstevel@tonic-gate nfs3rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo *svp,
7757c478bd9Sstevel@tonic-gate 	int flags, cred_t *cr, zone_t *zone)
7767c478bd9Sstevel@tonic-gate {
7777c478bd9Sstevel@tonic-gate 	vnode_t *rtvp;
7787c478bd9Sstevel@tonic-gate 	mntinfo_t *mi;
7797c478bd9Sstevel@tonic-gate 	dev_t nfs_dev;
7807c478bd9Sstevel@tonic-gate 	struct vattr va;
7817c478bd9Sstevel@tonic-gate 	struct FSINFO3args args;
7827c478bd9Sstevel@tonic-gate 	struct FSINFO3res res;
7837c478bd9Sstevel@tonic-gate 	int error;
7847c478bd9Sstevel@tonic-gate 	int douprintf;
7857c478bd9Sstevel@tonic-gate 	rnode_t *rp;
7867c478bd9Sstevel@tonic-gate 	int i;
7877c478bd9Sstevel@tonic-gate 	uint_t max_transfer_size;
7887c478bd9Sstevel@tonic-gate 	struct nfs_stats *nfsstatsp;
7897c478bd9Sstevel@tonic-gate 	cred_t *lcr = NULL, *tcr = cr;
7907c478bd9Sstevel@tonic-gate 
791108322fbScarlsonj 	nfsstatsp = zone_getspecific(nfsstat_zone_key, nfs_zone());
7927c478bd9Sstevel@tonic-gate 	ASSERT(nfsstatsp != NULL);
7937c478bd9Sstevel@tonic-gate 
794108322fbScarlsonj 	ASSERT(nfs_zone() == zone);
7957c478bd9Sstevel@tonic-gate 	/*
7967c478bd9Sstevel@tonic-gate 	 * Create a mount record and link it to the vfs struct.
7977c478bd9Sstevel@tonic-gate 	 */
7987c478bd9Sstevel@tonic-gate 	mi = kmem_zalloc(sizeof (*mi), KM_SLEEP);
7997c478bd9Sstevel@tonic-gate 	mutex_init(&mi->mi_lock, NULL, MUTEX_DEFAULT, NULL);
800e8dc3b7dSvv 	mutex_init(&mi->mi_remap_lock, NULL, MUTEX_DEFAULT, NULL);
8017c478bd9Sstevel@tonic-gate 	mi->mi_flags = MI_ACL | MI_EXTATTR;
8027c478bd9Sstevel@tonic-gate 	if (!(flags & NFSMNT_SOFT))
8037c478bd9Sstevel@tonic-gate 		mi->mi_flags |= MI_HARD;
8047c478bd9Sstevel@tonic-gate 	if ((flags & NFSMNT_SEMISOFT))
8057c478bd9Sstevel@tonic-gate 		mi->mi_flags |= MI_SEMISOFT;
8067c478bd9Sstevel@tonic-gate 	if ((flags & NFSMNT_NOPRINT))
8077c478bd9Sstevel@tonic-gate 		mi->mi_flags |= MI_NOPRINT;
8087c478bd9Sstevel@tonic-gate 	if (flags & NFSMNT_INT)
8097c478bd9Sstevel@tonic-gate 		mi->mi_flags |= MI_INT;
8107c478bd9Sstevel@tonic-gate 	mi->mi_retrans = NFS_RETRIES;
8117c478bd9Sstevel@tonic-gate 	if (svp->sv_knconf->knc_semantics == NC_TPI_COTS_ORD ||
8127c478bd9Sstevel@tonic-gate 	    svp->sv_knconf->knc_semantics == NC_TPI_COTS)
8137c478bd9Sstevel@tonic-gate 		mi->mi_timeo = nfs3_cots_timeo;
8147c478bd9Sstevel@tonic-gate 	else
8157c478bd9Sstevel@tonic-gate 		mi->mi_timeo = NFS_TIMEO;
8167c478bd9Sstevel@tonic-gate 	mi->mi_prog = NFS_PROGRAM;
8177c478bd9Sstevel@tonic-gate 	mi->mi_vers = NFS_V3;
8187c478bd9Sstevel@tonic-gate 	mi->mi_rfsnames = rfsnames_v3;
8197c478bd9Sstevel@tonic-gate 	mi->mi_reqs = nfsstatsp->nfs_stats_v3.rfsreqcnt_ptr;
8207c478bd9Sstevel@tonic-gate 	mi->mi_call_type = call_type_v3;
8217c478bd9Sstevel@tonic-gate 	mi->mi_ss_call_type = ss_call_type_v3;
8227c478bd9Sstevel@tonic-gate 	mi->mi_timer_type = timer_type_v3;
8237c478bd9Sstevel@tonic-gate 	mi->mi_aclnames = aclnames_v3;
8247c478bd9Sstevel@tonic-gate 	mi->mi_aclreqs = nfsstatsp->nfs_stats_v3.aclreqcnt_ptr;
8257c478bd9Sstevel@tonic-gate 	mi->mi_acl_call_type = acl_call_type_v3;
8267c478bd9Sstevel@tonic-gate 	mi->mi_acl_ss_call_type = acl_ss_call_type_v3;
8277c478bd9Sstevel@tonic-gate 	mi->mi_acl_timer_type = acl_timer_type_v3;
8287c478bd9Sstevel@tonic-gate 	cv_init(&mi->mi_failover_cv, NULL, CV_DEFAULT, NULL);
8297c478bd9Sstevel@tonic-gate 	mi->mi_servers = svp;
8307c478bd9Sstevel@tonic-gate 	mi->mi_curr_serv = svp;
8317c478bd9Sstevel@tonic-gate 	mi->mi_acregmin = SEC2HR(ACREGMIN);
8327c478bd9Sstevel@tonic-gate 	mi->mi_acregmax = SEC2HR(ACREGMAX);
8337c478bd9Sstevel@tonic-gate 	mi->mi_acdirmin = SEC2HR(ACDIRMIN);
8347c478bd9Sstevel@tonic-gate 	mi->mi_acdirmax = SEC2HR(ACDIRMAX);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	if (nfs3_dynamic)
8377c478bd9Sstevel@tonic-gate 		mi->mi_flags |= MI_DYNAMIC;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	if (flags & NFSMNT_DIRECTIO)
8407c478bd9Sstevel@tonic-gate 		mi->mi_flags |= MI_DIRECTIO;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	/*
8437c478bd9Sstevel@tonic-gate 	 * Make a vfs struct for nfs.  We do this here instead of below
8447c478bd9Sstevel@tonic-gate 	 * because rtvp needs a vfs before we can do a getattr on it.
8457c478bd9Sstevel@tonic-gate 	 *
8467c478bd9Sstevel@tonic-gate 	 * Assign a unique device id to the mount
8477c478bd9Sstevel@tonic-gate 	 */
8487c478bd9Sstevel@tonic-gate 	mutex_enter(&nfs_minor_lock);
8497c478bd9Sstevel@tonic-gate 	do {
8507c478bd9Sstevel@tonic-gate 		nfs_minor = (nfs_minor + 1) & MAXMIN32;
8517c478bd9Sstevel@tonic-gate 		nfs_dev = makedevice(nfs_major, nfs_minor);
8527c478bd9Sstevel@tonic-gate 	} while (vfs_devismounted(nfs_dev));
8537c478bd9Sstevel@tonic-gate 	mutex_exit(&nfs_minor_lock);
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	vfsp->vfs_dev = nfs_dev;
8567c478bd9Sstevel@tonic-gate 	vfs_make_fsid(&vfsp->vfs_fsid, nfs_dev, nfs3fstyp);
8577c478bd9Sstevel@tonic-gate 	vfsp->vfs_data = (caddr_t)mi;
8587c478bd9Sstevel@tonic-gate 	vfsp->vfs_fstype = nfsfstyp;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/*
8617c478bd9Sstevel@tonic-gate 	 * Verify that nfs3_bsize tuneable is set to an
8627c478bd9Sstevel@tonic-gate 	 * acceptable value.  It be a multiple of PAGESIZE or
8637c478bd9Sstevel@tonic-gate 	 * file corruption can occur.
8647c478bd9Sstevel@tonic-gate 	 */
8657c478bd9Sstevel@tonic-gate 	if (nfs3_bsize & PAGEOFFSET)
8667c478bd9Sstevel@tonic-gate 		nfs3_bsize &= PAGEMASK;
8677c478bd9Sstevel@tonic-gate 	if (nfs3_bsize < PAGESIZE)
8687c478bd9Sstevel@tonic-gate 		nfs3_bsize = PAGESIZE;
8697c478bd9Sstevel@tonic-gate 	vfsp->vfs_bsize = nfs3_bsize;
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	/*
8727c478bd9Sstevel@tonic-gate 	 * Initialize fields used to support async putpage operations.
8737c478bd9Sstevel@tonic-gate 	 */
8747c478bd9Sstevel@tonic-gate 	for (i = 0; i < NFS_ASYNC_TYPES; i++)
8757c478bd9Sstevel@tonic-gate 		mi->mi_async_clusters[i] = nfs3_async_clusters;
8767c478bd9Sstevel@tonic-gate 	mi->mi_async_init_clusters = nfs3_async_clusters;
8777c478bd9Sstevel@tonic-gate 	mi->mi_async_curr = &mi->mi_async_reqs[0];
8787c478bd9Sstevel@tonic-gate 	mi->mi_max_threads = nfs3_max_threads;
8797c478bd9Sstevel@tonic-gate 	mutex_init(&mi->mi_async_lock, NULL, MUTEX_DEFAULT, NULL);
8807c478bd9Sstevel@tonic-gate 	cv_init(&mi->mi_async_reqs_cv, NULL, CV_DEFAULT, NULL);
8817c478bd9Sstevel@tonic-gate 	cv_init(&mi->mi_async_work_cv, NULL, CV_DEFAULT, NULL);
8827c478bd9Sstevel@tonic-gate 	cv_init(&mi->mi_async_cv, NULL, CV_DEFAULT, NULL);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	mi->mi_vfsp = vfsp;
8857c478bd9Sstevel@tonic-gate 	zone_hold(mi->mi_zone = zone);
8867c478bd9Sstevel@tonic-gate 	nfs_mi_zonelist_add(mi);
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	/*
8897c478bd9Sstevel@tonic-gate 	 * Make the root vnode, use it to get attributes,
8907c478bd9Sstevel@tonic-gate 	 * then remake it with the attributes.
8917c478bd9Sstevel@tonic-gate 	 */
8927c478bd9Sstevel@tonic-gate 	rtvp = makenfs3node((nfs_fh3 *)&svp->sv_fhandle,
8937c478bd9Sstevel@tonic-gate 	    NULL, vfsp, gethrtime(), cr, NULL, NULL);
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	/*
8967c478bd9Sstevel@tonic-gate 	 * Make the FSINFO calls, primarily at this point to
8977c478bd9Sstevel@tonic-gate 	 * determine the transfer size.  For client failover,
8987c478bd9Sstevel@tonic-gate 	 * we'll want this to be the minimum bid from any
8997c478bd9Sstevel@tonic-gate 	 * server, so that we don't overrun stated limits.
9007c478bd9Sstevel@tonic-gate 	 *
9017c478bd9Sstevel@tonic-gate 	 * While we're looping, we'll turn off AUTH_F_TRYNONE,
9027c478bd9Sstevel@tonic-gate 	 * which is only for the mount operation.
9037c478bd9Sstevel@tonic-gate 	 */
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	mi->mi_tsize = nfs3_tsize(svp->sv_knconf);
9067c478bd9Sstevel@tonic-gate 	mi->mi_stsize = mi->mi_tsize;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	mi->mi_curread = nfs3_bsize;
9097c478bd9Sstevel@tonic-gate 	mi->mi_curwrite = mi->mi_curread;
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	/*
9127c478bd9Sstevel@tonic-gate 	 * If the uid is set then set the creds for secure mounts
9137c478bd9Sstevel@tonic-gate 	 * by proxy processes such as automountd.
9147c478bd9Sstevel@tonic-gate 	 */
9157c478bd9Sstevel@tonic-gate 	if (svp->sv_secdata->uid != 0 &&
9167c478bd9Sstevel@tonic-gate 	    svp->sv_secdata->rpcflavor == RPCSEC_GSS) {
9177c478bd9Sstevel@tonic-gate 		lcr = crdup(cr);
9187c478bd9Sstevel@tonic-gate 		(void) crsetugid(lcr, svp->sv_secdata->uid, crgetgid(cr));
9197c478bd9Sstevel@tonic-gate 		tcr = lcr;
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	for (svp = mi->mi_servers; svp != NULL; svp = svp->sv_next) {
9237c478bd9Sstevel@tonic-gate 		douprintf = 1;
9247c478bd9Sstevel@tonic-gate 		mi->mi_curr_serv = svp;
9257c478bd9Sstevel@tonic-gate 		max_transfer_size = nfs3_tsize(svp->sv_knconf);
9267c478bd9Sstevel@tonic-gate 		mi->mi_tsize = MIN(max_transfer_size, mi->mi_tsize);
9277c478bd9Sstevel@tonic-gate 		mi->mi_stsize = MIN(max_transfer_size, mi->mi_stsize);
9287c478bd9Sstevel@tonic-gate 		mi->mi_curread = MIN(max_transfer_size, mi->mi_curread);
9297c478bd9Sstevel@tonic-gate 		mi->mi_curwrite = MIN(max_transfer_size, mi->mi_curwrite);
9307c478bd9Sstevel@tonic-gate 		args.fsroot = *(nfs_fh3 *)&svp->sv_fhandle;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 		error = rfs3call(mi, NFSPROC3_FSINFO,
9337c478bd9Sstevel@tonic-gate 		    xdr_nfs_fh3, (caddr_t)&args,
9347c478bd9Sstevel@tonic-gate 		    xdr_FSINFO3res, (caddr_t)&res, tcr,
9357c478bd9Sstevel@tonic-gate 		    &douprintf, &res.status, 0, NULL);
9367c478bd9Sstevel@tonic-gate 		if (error)
9377c478bd9Sstevel@tonic-gate 			goto bad;
9387c478bd9Sstevel@tonic-gate 		error = geterrno3(res.status);
9397c478bd9Sstevel@tonic-gate 		if (error)
9407c478bd9Sstevel@tonic-gate 			goto bad;
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 		/* get type of root node */
9437c478bd9Sstevel@tonic-gate 		if (res.resok.obj_attributes.attributes) {
9447c478bd9Sstevel@tonic-gate 			if (res.resok.obj_attributes.attr.type < NF3REG ||
9457c478bd9Sstevel@tonic-gate 			    res.resok.obj_attributes.attr.type > NF3FIFO) {
9467c478bd9Sstevel@tonic-gate #ifdef DEBUG
9477c478bd9Sstevel@tonic-gate 				zcmn_err(getzoneid(), CE_WARN,
9487c478bd9Sstevel@tonic-gate 			    "NFS3 server %s returned a bad file type for root",
9497c478bd9Sstevel@tonic-gate 				    svp->sv_hostname);
9507c478bd9Sstevel@tonic-gate #else
9517c478bd9Sstevel@tonic-gate 				zcmn_err(getzoneid(), CE_WARN,
9527c478bd9Sstevel@tonic-gate 			    "NFS server %s returned a bad file type for root",
9537c478bd9Sstevel@tonic-gate 				    svp->sv_hostname);
9547c478bd9Sstevel@tonic-gate #endif
9557c478bd9Sstevel@tonic-gate 				error = EINVAL;
9567c478bd9Sstevel@tonic-gate 				goto bad;
9577c478bd9Sstevel@tonic-gate 			} else {
9587c478bd9Sstevel@tonic-gate 				if (rtvp->v_type != VNON &&
9597c478bd9Sstevel@tonic-gate 		rtvp->v_type != nf3_to_vt[res.resok.obj_attributes.attr.type]) {
9607c478bd9Sstevel@tonic-gate #ifdef DEBUG
9617c478bd9Sstevel@tonic-gate 					zcmn_err(getzoneid(), CE_WARN,
9627c478bd9Sstevel@tonic-gate 		"NFS3 server %s returned a different file type for root",
9637c478bd9Sstevel@tonic-gate 					    svp->sv_hostname);
9647c478bd9Sstevel@tonic-gate #else
9657c478bd9Sstevel@tonic-gate 					zcmn_err(getzoneid(), CE_WARN,
9667c478bd9Sstevel@tonic-gate 		"NFS server %s returned a different file type for root",
9677c478bd9Sstevel@tonic-gate 					    svp->sv_hostname);
9687c478bd9Sstevel@tonic-gate #endif
9697c478bd9Sstevel@tonic-gate 					error = EINVAL;
9707c478bd9Sstevel@tonic-gate 					goto bad;
9717c478bd9Sstevel@tonic-gate 				}
9727c478bd9Sstevel@tonic-gate 				rtvp->v_type =
9737c478bd9Sstevel@tonic-gate 				nf3_to_vt[res.resok.obj_attributes.attr.type];
9747c478bd9Sstevel@tonic-gate 			}
9757c478bd9Sstevel@tonic-gate 		}
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 		if (res.resok.rtmax != 0) {
9787c478bd9Sstevel@tonic-gate 			mi->mi_tsize = MIN(res.resok.rtmax, mi->mi_tsize);
9797c478bd9Sstevel@tonic-gate 			if (res.resok.rtpref != 0) {
9807c478bd9Sstevel@tonic-gate 				mi->mi_curread = MIN(res.resok.rtpref,
9817c478bd9Sstevel@tonic-gate 						    mi->mi_curread);
9827c478bd9Sstevel@tonic-gate 			} else {
9837c478bd9Sstevel@tonic-gate 				mi->mi_curread = MIN(res.resok.rtmax,
9847c478bd9Sstevel@tonic-gate 						    mi->mi_curread);
9857c478bd9Sstevel@tonic-gate 			}
9867c478bd9Sstevel@tonic-gate 		} else if (res.resok.rtpref != 0) {
9877c478bd9Sstevel@tonic-gate 			mi->mi_tsize = MIN(res.resok.rtpref, mi->mi_tsize);
9887c478bd9Sstevel@tonic-gate 			mi->mi_curread = MIN(res.resok.rtpref, mi->mi_curread);
9897c478bd9Sstevel@tonic-gate 		} else {
9907c478bd9Sstevel@tonic-gate #ifdef DEBUG
9917c478bd9Sstevel@tonic-gate 			zcmn_err(getzoneid(), CE_WARN,
9927c478bd9Sstevel@tonic-gate 			    "NFS3 server %s returned 0 for read transfer sizes",
9937c478bd9Sstevel@tonic-gate 			    svp->sv_hostname);
9947c478bd9Sstevel@tonic-gate #else
9957c478bd9Sstevel@tonic-gate 			zcmn_err(getzoneid(), CE_WARN,
9967c478bd9Sstevel@tonic-gate 			    "NFS server %s returned 0 for read transfer sizes",
9977c478bd9Sstevel@tonic-gate 			    svp->sv_hostname);
9987c478bd9Sstevel@tonic-gate #endif
9997c478bd9Sstevel@tonic-gate 			error = EIO;
10007c478bd9Sstevel@tonic-gate 			goto bad;
10017c478bd9Sstevel@tonic-gate 		}
10027c478bd9Sstevel@tonic-gate 		if (res.resok.wtmax != 0) {
10037c478bd9Sstevel@tonic-gate 			mi->mi_stsize = MIN(res.resok.wtmax, mi->mi_stsize);
10047c478bd9Sstevel@tonic-gate 			if (res.resok.wtpref != 0) {
10057c478bd9Sstevel@tonic-gate 				mi->mi_curwrite = MIN(res.resok.wtpref,
10067c478bd9Sstevel@tonic-gate 						    mi->mi_curwrite);
10077c478bd9Sstevel@tonic-gate 			} else {
10087c478bd9Sstevel@tonic-gate 				mi->mi_curwrite = MIN(res.resok.wtmax,
10097c478bd9Sstevel@tonic-gate 						    mi->mi_curwrite);
10107c478bd9Sstevel@tonic-gate 			}
10117c478bd9Sstevel@tonic-gate 		} else if (res.resok.wtpref != 0) {
10127c478bd9Sstevel@tonic-gate 			mi->mi_stsize = MIN(res.resok.wtpref, mi->mi_stsize);
10137c478bd9Sstevel@tonic-gate 			mi->mi_curwrite = MIN(res.resok.wtpref,
10147c478bd9Sstevel@tonic-gate 					    mi->mi_curwrite);
10157c478bd9Sstevel@tonic-gate 		} else {
10167c478bd9Sstevel@tonic-gate #ifdef DEBUG
10177c478bd9Sstevel@tonic-gate 			zcmn_err(getzoneid(), CE_WARN,
10187c478bd9Sstevel@tonic-gate 			"NFS3 server %s returned 0 for write transfer sizes",
10197c478bd9Sstevel@tonic-gate 			    svp->sv_hostname);
10207c478bd9Sstevel@tonic-gate #else
10217c478bd9Sstevel@tonic-gate 			zcmn_err(getzoneid(), CE_WARN,
10227c478bd9Sstevel@tonic-gate 			"NFS server %s returned 0 for write transfer sizes",
10237c478bd9Sstevel@tonic-gate 			    svp->sv_hostname);
10247c478bd9Sstevel@tonic-gate #endif
10257c478bd9Sstevel@tonic-gate 			error = EIO;
10267c478bd9Sstevel@tonic-gate 			goto bad;
10277c478bd9Sstevel@tonic-gate 		}
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 		/*
10307c478bd9Sstevel@tonic-gate 		 * These signal the ability of the server to create
10317c478bd9Sstevel@tonic-gate 		 * hard links and symbolic links, so they really
10327c478bd9Sstevel@tonic-gate 		 * aren't relevant if there is more than one server.
10337c478bd9Sstevel@tonic-gate 		 * We'll set them here, though it probably looks odd.
10347c478bd9Sstevel@tonic-gate 		 */
10357c478bd9Sstevel@tonic-gate 		if (res.resok.properties & FSF3_LINK)
10367c478bd9Sstevel@tonic-gate 			mi->mi_flags |= MI_LINK;
10377c478bd9Sstevel@tonic-gate 		if (res.resok.properties & FSF3_SYMLINK)
10387c478bd9Sstevel@tonic-gate 			mi->mi_flags |= MI_SYMLINK;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 		/* Pick up smallest non-zero maxfilesize value */
10417c478bd9Sstevel@tonic-gate 		if (res.resok.maxfilesize) {
10427c478bd9Sstevel@tonic-gate 			if (mi->mi_maxfilesize) {
10437c478bd9Sstevel@tonic-gate 				mi->mi_maxfilesize = MIN(mi->mi_maxfilesize,
10447c478bd9Sstevel@tonic-gate 							res.resok.maxfilesize);
10457c478bd9Sstevel@tonic-gate 			} else
10467c478bd9Sstevel@tonic-gate 				mi->mi_maxfilesize = res.resok.maxfilesize;
10477c478bd9Sstevel@tonic-gate 		}
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 		/*
10507c478bd9Sstevel@tonic-gate 		 * AUTH_F_TRYNONE is only for the mount operation,
10517c478bd9Sstevel@tonic-gate 		 * so turn it back off.
10527c478bd9Sstevel@tonic-gate 		 */
10537c478bd9Sstevel@tonic-gate 		svp->sv_secdata->flags &= ~AUTH_F_TRYNONE;
10547c478bd9Sstevel@tonic-gate 	}
10557c478bd9Sstevel@tonic-gate 	mi->mi_curr_serv = mi->mi_servers;
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	/*
10587c478bd9Sstevel@tonic-gate 	 * Start the thread responsible for handling async worker threads.
10597c478bd9Sstevel@tonic-gate 	 */
10607c478bd9Sstevel@tonic-gate 	VFS_HOLD(vfsp);	/* add reference for thread */
10617c478bd9Sstevel@tonic-gate 	mi->mi_manager_thread = zthread_create(NULL, 0, nfs_async_manager,
10627c478bd9Sstevel@tonic-gate 					vfsp, 0, minclsyspri);
10637c478bd9Sstevel@tonic-gate 	ASSERT(mi->mi_manager_thread != NULL);
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	/*
10667c478bd9Sstevel@tonic-gate 	 * Initialize kstats
10677c478bd9Sstevel@tonic-gate 	 */
10687c478bd9Sstevel@tonic-gate 	nfs_mnt_kstat_init(vfsp);
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	/* If we didn't get a type, get one now */
10717c478bd9Sstevel@tonic-gate 	if (rtvp->v_type == VNON) {
10727c478bd9Sstevel@tonic-gate 		va.va_mask = AT_ALL;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 		error = nfs3getattr(rtvp, &va, tcr);
10757c478bd9Sstevel@tonic-gate 		if (error)
10767c478bd9Sstevel@tonic-gate 			goto bad;
10777c478bd9Sstevel@tonic-gate 		rtvp->v_type = va.va_type;
10787c478bd9Sstevel@tonic-gate 	}
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	mi->mi_type = rtvp->v_type;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	*rtvpp = rtvp;
10837c478bd9Sstevel@tonic-gate 	if (lcr != NULL)
10847c478bd9Sstevel@tonic-gate 		crfree(lcr);
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	return (0);
10877c478bd9Sstevel@tonic-gate bad:
10887c478bd9Sstevel@tonic-gate 	/*
10897c478bd9Sstevel@tonic-gate 	 * An error occurred somewhere, need to clean up...
10907c478bd9Sstevel@tonic-gate 	 * We need to release our reference to the root vnode and
10917c478bd9Sstevel@tonic-gate 	 * destroy the mntinfo struct that we just created.
10927c478bd9Sstevel@tonic-gate 	 */
10937c478bd9Sstevel@tonic-gate 	if (lcr != NULL)
10947c478bd9Sstevel@tonic-gate 		crfree(lcr);
10957c478bd9Sstevel@tonic-gate 	rp = VTOR(rtvp);
10967c478bd9Sstevel@tonic-gate 	if (rp->r_flags & RHASHED)
10977c478bd9Sstevel@tonic-gate 		rp_rmhash(rp);
10987c478bd9Sstevel@tonic-gate 	VN_RELE(rtvp);
10997c478bd9Sstevel@tonic-gate 	nfs_async_stop(vfsp);
11007c478bd9Sstevel@tonic-gate 	nfs_async_manager_stop(vfsp);
11017c478bd9Sstevel@tonic-gate 	if (mi->mi_io_kstats) {
11027c478bd9Sstevel@tonic-gate 		kstat_delete(mi->mi_io_kstats);
11037c478bd9Sstevel@tonic-gate 		mi->mi_io_kstats = NULL;
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 	if (mi->mi_ro_kstats) {
11067c478bd9Sstevel@tonic-gate 		kstat_delete(mi->mi_ro_kstats);
11077c478bd9Sstevel@tonic-gate 		mi->mi_ro_kstats = NULL;
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 	nfs_free_mi(mi);
11107c478bd9Sstevel@tonic-gate 	*rtvpp = NULL;
11117c478bd9Sstevel@tonic-gate 	return (error);
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate /*
11157c478bd9Sstevel@tonic-gate  * vfs operations
11167c478bd9Sstevel@tonic-gate  */
11177c478bd9Sstevel@tonic-gate static int
11187c478bd9Sstevel@tonic-gate nfs3_unmount(vfs_t *vfsp, int flag, cred_t *cr)
11197c478bd9Sstevel@tonic-gate {
11207c478bd9Sstevel@tonic-gate 	mntinfo_t *mi;
11217c478bd9Sstevel@tonic-gate 	ushort_t omax;
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	if (secpolicy_fs_unmount(cr, vfsp) != 0)
11247c478bd9Sstevel@tonic-gate 		return (EPERM);
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	mi = VFTOMI(vfsp);
11277c478bd9Sstevel@tonic-gate 	if (flag & MS_FORCE) {
11287c478bd9Sstevel@tonic-gate 		vfsp->vfs_flag |= VFS_UNMOUNTED;
11297c478bd9Sstevel@tonic-gate 		/*
11307c478bd9Sstevel@tonic-gate 		 * We need to stop the manager thread explicitly; the worker
11317c478bd9Sstevel@tonic-gate 		 * threads can time out and exit on their own.
11327c478bd9Sstevel@tonic-gate 		 */
11337c478bd9Sstevel@tonic-gate 		nfs_async_manager_stop(vfsp);
11347c478bd9Sstevel@tonic-gate 		destroy_rtable(vfsp, cr);
11357c478bd9Sstevel@tonic-gate 		if (mi->mi_io_kstats) {
11367c478bd9Sstevel@tonic-gate 			kstat_delete(mi->mi_io_kstats);
11377c478bd9Sstevel@tonic-gate 			mi->mi_io_kstats = NULL;
11387c478bd9Sstevel@tonic-gate 		}
11397c478bd9Sstevel@tonic-gate 		if (mi->mi_ro_kstats) {
11407c478bd9Sstevel@tonic-gate 			kstat_delete(mi->mi_ro_kstats);
11417c478bd9Sstevel@tonic-gate 			mi->mi_ro_kstats = NULL;
11427c478bd9Sstevel@tonic-gate 		}
11437c478bd9Sstevel@tonic-gate 		return (0);
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 	/*
11467c478bd9Sstevel@tonic-gate 	 * Wait until all asynchronous putpage operations on
11477c478bd9Sstevel@tonic-gate 	 * this file system are complete before flushing rnodes
11487c478bd9Sstevel@tonic-gate 	 * from the cache.
11497c478bd9Sstevel@tonic-gate 	 */
11507c478bd9Sstevel@tonic-gate 	omax = mi->mi_max_threads;
11517c478bd9Sstevel@tonic-gate 	if (nfs_async_stop_sig(vfsp)) {
11527c478bd9Sstevel@tonic-gate 		return (EINTR);
11537c478bd9Sstevel@tonic-gate 	}
11547c478bd9Sstevel@tonic-gate 	rflush(vfsp, cr);
11557c478bd9Sstevel@tonic-gate 	/*
11567c478bd9Sstevel@tonic-gate 	 * If there are any active vnodes on this file system,
11577c478bd9Sstevel@tonic-gate 	 * then the file system is busy and can't be umounted.
11587c478bd9Sstevel@tonic-gate 	 */
11597c478bd9Sstevel@tonic-gate 	if (check_rtable(vfsp)) {
11607c478bd9Sstevel@tonic-gate 		mutex_enter(&mi->mi_async_lock);
11617c478bd9Sstevel@tonic-gate 		mi->mi_max_threads = omax;
11627c478bd9Sstevel@tonic-gate 		mutex_exit(&mi->mi_async_lock);
11637c478bd9Sstevel@tonic-gate 		return (EBUSY);
11647c478bd9Sstevel@tonic-gate 	}
11657c478bd9Sstevel@tonic-gate 	/*
11667c478bd9Sstevel@tonic-gate 	 * The unmount can't fail from now on; stop the worker thread manager.
11677c478bd9Sstevel@tonic-gate 	 */
11687c478bd9Sstevel@tonic-gate 	nfs_async_manager_stop(vfsp);
11697c478bd9Sstevel@tonic-gate 	/*
11707c478bd9Sstevel@tonic-gate 	 * Destroy all rnodes belonging to this file system from the
11717c478bd9Sstevel@tonic-gate 	 * rnode hash queues and purge any resources allocated to
11727c478bd9Sstevel@tonic-gate 	 * them.
11737c478bd9Sstevel@tonic-gate 	 */
11747c478bd9Sstevel@tonic-gate 	destroy_rtable(vfsp, cr);
11757c478bd9Sstevel@tonic-gate 	if (mi->mi_io_kstats) {
11767c478bd9Sstevel@tonic-gate 		kstat_delete(mi->mi_io_kstats);
11777c478bd9Sstevel@tonic-gate 		mi->mi_io_kstats = NULL;
11787c478bd9Sstevel@tonic-gate 	}
11797c478bd9Sstevel@tonic-gate 	if (mi->mi_ro_kstats) {
11807c478bd9Sstevel@tonic-gate 		kstat_delete(mi->mi_ro_kstats);
11817c478bd9Sstevel@tonic-gate 		mi->mi_ro_kstats = NULL;
11827c478bd9Sstevel@tonic-gate 	}
11837c478bd9Sstevel@tonic-gate 	return (0);
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate /*
11877c478bd9Sstevel@tonic-gate  * find root of nfs
11887c478bd9Sstevel@tonic-gate  */
11897c478bd9Sstevel@tonic-gate static int
11907c478bd9Sstevel@tonic-gate nfs3_root(vfs_t *vfsp, vnode_t **vpp)
11917c478bd9Sstevel@tonic-gate {
11927c478bd9Sstevel@tonic-gate 	mntinfo_t *mi;
11937c478bd9Sstevel@tonic-gate 	vnode_t *vp;
11947c478bd9Sstevel@tonic-gate 	servinfo_t *svp;
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	mi = VFTOMI(vfsp);
11977c478bd9Sstevel@tonic-gate 
1198108322fbScarlsonj 	if (nfs_zone() != mi->mi_zone)
11997c478bd9Sstevel@tonic-gate 		return (EPERM);
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	svp = mi->mi_curr_serv;
12027c478bd9Sstevel@tonic-gate 	if (svp && (svp->sv_flags & SV_ROOT_STALE)) {
12037c478bd9Sstevel@tonic-gate 		mutex_enter(&svp->sv_lock);
12047c478bd9Sstevel@tonic-gate 		svp->sv_flags &= ~SV_ROOT_STALE;
12057c478bd9Sstevel@tonic-gate 		mutex_exit(&svp->sv_lock);
12067c478bd9Sstevel@tonic-gate 		return (ENOENT);
12077c478bd9Sstevel@tonic-gate 	}
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	vp = makenfs3node((nfs_fh3 *)&mi->mi_curr_serv->sv_fhandle,
12107c478bd9Sstevel@tonic-gate 	    NULL, vfsp, gethrtime(), CRED(), NULL, NULL);
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	if (VTOR(vp)->r_flags & RSTALE) {
12137c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
12147c478bd9Sstevel@tonic-gate 		return (ENOENT);
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_type == VNON || vp->v_type == mi->mi_type);
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	vp->v_type = mi->mi_type;
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	*vpp = vp;
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	return (0);
12247c478bd9Sstevel@tonic-gate }
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate /*
12277c478bd9Sstevel@tonic-gate  * Get file system statistics.
12287c478bd9Sstevel@tonic-gate  */
12297c478bd9Sstevel@tonic-gate static int
12307c478bd9Sstevel@tonic-gate nfs3_statvfs(vfs_t *vfsp, struct statvfs64 *sbp)
12317c478bd9Sstevel@tonic-gate {
12327c478bd9Sstevel@tonic-gate 	int error;
12337c478bd9Sstevel@tonic-gate 	struct mntinfo *mi;
12347c478bd9Sstevel@tonic-gate 	struct FSSTAT3args args;
12357c478bd9Sstevel@tonic-gate 	struct FSSTAT3res res;
12367c478bd9Sstevel@tonic-gate 	int douprintf;
12377c478bd9Sstevel@tonic-gate 	failinfo_t fi;
12387c478bd9Sstevel@tonic-gate 	vnode_t *vp;
12397c478bd9Sstevel@tonic-gate 	cred_t *cr;
12407c478bd9Sstevel@tonic-gate 	hrtime_t t;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	mi = VFTOMI(vfsp);
1243108322fbScarlsonj 	if (nfs_zone() != mi->mi_zone)
12447c478bd9Sstevel@tonic-gate 		return (EPERM);
12457c478bd9Sstevel@tonic-gate 	error = nfs3_root(vfsp, &vp);
12467c478bd9Sstevel@tonic-gate 	if (error)
12477c478bd9Sstevel@tonic-gate 		return (error);
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	cr = CRED();
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	args.fsroot = *VTOFH3(vp);
12527c478bd9Sstevel@tonic-gate 	fi.vp = vp;
12537c478bd9Sstevel@tonic-gate 	fi.fhp = (caddr_t)&args.fsroot;
12547c478bd9Sstevel@tonic-gate 	fi.copyproc = nfs3copyfh;
12557c478bd9Sstevel@tonic-gate 	fi.lookupproc = nfs3lookup;
12567c478bd9Sstevel@tonic-gate 	fi.xattrdirproc = acl_getxattrdir3;
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	douprintf = 1;
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	t = gethrtime();
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	error = rfs3call(mi, NFSPROC3_FSSTAT,
12637c478bd9Sstevel@tonic-gate 	    xdr_nfs_fh3, (caddr_t)&args,
12647c478bd9Sstevel@tonic-gate 	    xdr_FSSTAT3res, (caddr_t)&res, cr,
12657c478bd9Sstevel@tonic-gate 	    &douprintf, &res.status, 0, &fi);
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	if (error) {
12687c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
12697c478bd9Sstevel@tonic-gate 		return (error);
12707c478bd9Sstevel@tonic-gate 	}
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	error = geterrno3(res.status);
12737c478bd9Sstevel@tonic-gate 	if (!error) {
12747c478bd9Sstevel@tonic-gate 		nfs3_cache_post_op_attr(vp, &res.resok.obj_attributes, t, cr);
12757c478bd9Sstevel@tonic-gate 		sbp->f_bsize = MAXBSIZE;
12767c478bd9Sstevel@tonic-gate 		sbp->f_frsize = DEV_BSIZE;
12777c478bd9Sstevel@tonic-gate 		/*
12787c478bd9Sstevel@tonic-gate 		 * Allow -1 fields to pass through unconverted.  These
12797c478bd9Sstevel@tonic-gate 		 * indicate "don't know" fields.
12807c478bd9Sstevel@tonic-gate 		 */
12817c478bd9Sstevel@tonic-gate 		if (res.resok.tbytes == (size3)-1)
12827c478bd9Sstevel@tonic-gate 			sbp->f_blocks = (fsblkcnt64_t)res.resok.tbytes;
12837c478bd9Sstevel@tonic-gate 		else {
12847c478bd9Sstevel@tonic-gate 			sbp->f_blocks = (fsblkcnt64_t)
12857c478bd9Sstevel@tonic-gate 			    (res.resok.tbytes / DEV_BSIZE);
12867c478bd9Sstevel@tonic-gate 		}
12877c478bd9Sstevel@tonic-gate 		if (res.resok.fbytes == (size3)-1)
12887c478bd9Sstevel@tonic-gate 			sbp->f_bfree = (fsblkcnt64_t)res.resok.fbytes;
12897c478bd9Sstevel@tonic-gate 		else {
12907c478bd9Sstevel@tonic-gate 			sbp->f_bfree = (fsblkcnt64_t)
12917c478bd9Sstevel@tonic-gate 			    (res.resok.fbytes / DEV_BSIZE);
12927c478bd9Sstevel@tonic-gate 		}
12937c478bd9Sstevel@tonic-gate 		if (res.resok.abytes == (size3)-1)
12947c478bd9Sstevel@tonic-gate 			sbp->f_bavail = (fsblkcnt64_t)res.resok.abytes;
12957c478bd9Sstevel@tonic-gate 		else {
12967c478bd9Sstevel@tonic-gate 			sbp->f_bavail = (fsblkcnt64_t)
12977c478bd9Sstevel@tonic-gate 			    (res.resok.abytes / DEV_BSIZE);
12987c478bd9Sstevel@tonic-gate 		}
12997c478bd9Sstevel@tonic-gate 		sbp->f_files = (fsfilcnt64_t)res.resok.tfiles;
13007c478bd9Sstevel@tonic-gate 		sbp->f_ffree = (fsfilcnt64_t)res.resok.ffiles;
13017c478bd9Sstevel@tonic-gate 		sbp->f_favail = (fsfilcnt64_t)res.resok.afiles;
13027c478bd9Sstevel@tonic-gate 		sbp->f_fsid = (unsigned long)vfsp->vfs_fsid.val[0];
13037c478bd9Sstevel@tonic-gate 		(void) strncpy(sbp->f_basetype,
13047c478bd9Sstevel@tonic-gate 		    vfssw[vfsp->vfs_fstype].vsw_name, FSTYPSZ);
13057c478bd9Sstevel@tonic-gate 		sbp->f_flag = vf_to_stf(vfsp->vfs_flag);
13067c478bd9Sstevel@tonic-gate 		sbp->f_namemax = (ulong_t)-1;
13077c478bd9Sstevel@tonic-gate 	} else {
13087c478bd9Sstevel@tonic-gate 		nfs3_cache_post_op_attr(vp, &res.resfail.obj_attributes, t, cr);
13097c478bd9Sstevel@tonic-gate 		PURGE_STALE_FH(error, vp, cr);
13107c478bd9Sstevel@tonic-gate 	}
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	return (error);
13157c478bd9Sstevel@tonic-gate }
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate static kmutex_t nfs3_syncbusy;
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate /*
13207c478bd9Sstevel@tonic-gate  * Flush dirty nfs files for file system vfsp.
13217c478bd9Sstevel@tonic-gate  * If vfsp == NULL, all nfs files are flushed.
13227c478bd9Sstevel@tonic-gate  */
13237c478bd9Sstevel@tonic-gate /* ARGSUSED */
13247c478bd9Sstevel@tonic-gate static int
13257c478bd9Sstevel@tonic-gate nfs3_sync(vfs_t *vfsp, short flag, cred_t *cr)
13267c478bd9Sstevel@tonic-gate {
13277c478bd9Sstevel@tonic-gate 	/*
13287c478bd9Sstevel@tonic-gate 	 * Cross-zone calls are OK here, since this translates to a
13297c478bd9Sstevel@tonic-gate 	 * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone.
13307c478bd9Sstevel@tonic-gate 	 */
13317c478bd9Sstevel@tonic-gate 	if (!(flag & SYNC_ATTR) && mutex_tryenter(&nfs3_syncbusy) != 0) {
13327c478bd9Sstevel@tonic-gate 		rflush(vfsp, cr);
13337c478bd9Sstevel@tonic-gate 		mutex_exit(&nfs3_syncbusy);
13347c478bd9Sstevel@tonic-gate 	}
13357c478bd9Sstevel@tonic-gate 	return (0);
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate /* ARGSUSED */
13397c478bd9Sstevel@tonic-gate static int
13407c478bd9Sstevel@tonic-gate nfs3_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
13417c478bd9Sstevel@tonic-gate {
13427c478bd9Sstevel@tonic-gate 	int error;
13437c478bd9Sstevel@tonic-gate 	nfs_fh3 fh;
13447c478bd9Sstevel@tonic-gate 	vnode_t *vp;
13457c478bd9Sstevel@tonic-gate 	struct vattr va;
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	if (fidp->fid_len > NFS3_FHSIZE) {
13487c478bd9Sstevel@tonic-gate 		*vpp = NULL;
13497c478bd9Sstevel@tonic-gate 		return (ESTALE);
13507c478bd9Sstevel@tonic-gate 	}
13517c478bd9Sstevel@tonic-gate 
1352108322fbScarlsonj 	if (nfs_zone() != VFTOMI(vfsp)->mi_zone)
13537c478bd9Sstevel@tonic-gate 		return (EPERM);
13547c478bd9Sstevel@tonic-gate 	fh.fh3_length = fidp->fid_len;
13557c478bd9Sstevel@tonic-gate 	bcopy(fidp->fid_data, fh.fh3_u.data, fh.fh3_length);
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 	vp = makenfs3node(&fh, NULL, vfsp, gethrtime(), CRED(), NULL, NULL);
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 	if (VTOR(vp)->r_flags & RSTALE) {
13607c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
13617c478bd9Sstevel@tonic-gate 		*vpp = NULL;
13627c478bd9Sstevel@tonic-gate 		return (ENOENT);
13637c478bd9Sstevel@tonic-gate 	}
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	if (vp->v_type == VNON) {
13667c478bd9Sstevel@tonic-gate 		va.va_mask = AT_ALL;
13677c478bd9Sstevel@tonic-gate 		error = nfs3getattr(vp, &va, CRED());
13687c478bd9Sstevel@tonic-gate 		if (error) {
13697c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
13707c478bd9Sstevel@tonic-gate 			*vpp = NULL;
13717c478bd9Sstevel@tonic-gate 			return (error);
13727c478bd9Sstevel@tonic-gate 		}
13737c478bd9Sstevel@tonic-gate 		vp->v_type = va.va_type;
13747c478bd9Sstevel@tonic-gate 	}
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	*vpp = vp;
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	return (0);
13797c478bd9Sstevel@tonic-gate }
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate /* ARGSUSED */
13827c478bd9Sstevel@tonic-gate static int
13837c478bd9Sstevel@tonic-gate nfs3_mountroot(vfs_t *vfsp, whymountroot_t why)
13847c478bd9Sstevel@tonic-gate {
13857c478bd9Sstevel@tonic-gate 	vnode_t *rtvp;
13867c478bd9Sstevel@tonic-gate 	char root_hostname[SYS_NMLN+1];
13877c478bd9Sstevel@tonic-gate 	struct servinfo *svp;
13887c478bd9Sstevel@tonic-gate 	int error;
13897c478bd9Sstevel@tonic-gate 	int vfsflags;
13907c478bd9Sstevel@tonic-gate 	size_t size;
13917c478bd9Sstevel@tonic-gate 	char *root_path;
13927c478bd9Sstevel@tonic-gate 	struct pathname pn;
13937c478bd9Sstevel@tonic-gate 	char *name;
13947c478bd9Sstevel@tonic-gate 	cred_t *cr;
13957c478bd9Sstevel@tonic-gate 	struct nfs_args args;		/* nfs mount arguments */
13967c478bd9Sstevel@tonic-gate 	static char token[10];
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	bzero(&args, sizeof (args));
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	/* do this BEFORE getfile which causes xid stamps to be initialized */
14017c478bd9Sstevel@tonic-gate 	clkset(-1L);		/* hack for now - until we get time svc? */
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	if (why == ROOT_REMOUNT) {
14047c478bd9Sstevel@tonic-gate 		/*
14057c478bd9Sstevel@tonic-gate 		 * Shouldn't happen.
14067c478bd9Sstevel@tonic-gate 		 */
14077c478bd9Sstevel@tonic-gate 		panic("nfs3_mountroot: why == ROOT_REMOUNT");
14087c478bd9Sstevel@tonic-gate 	}
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	if (why == ROOT_UNMOUNT) {
14117c478bd9Sstevel@tonic-gate 		/*
14127c478bd9Sstevel@tonic-gate 		 * Nothing to do for NFS.
14137c478bd9Sstevel@tonic-gate 		 */
14147c478bd9Sstevel@tonic-gate 		return (0);
14157c478bd9Sstevel@tonic-gate 	}
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	/*
14187c478bd9Sstevel@tonic-gate 	 * why == ROOT_INIT
14197c478bd9Sstevel@tonic-gate 	 */
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 	name = token;
14227c478bd9Sstevel@tonic-gate 	*name = 0;
14237c478bd9Sstevel@tonic-gate 	getfsname("root", name, sizeof (token));
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	pn_alloc(&pn);
14267c478bd9Sstevel@tonic-gate 	root_path = pn.pn_path;
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	svp = kmem_zalloc(sizeof (*svp), KM_SLEEP);
14297c478bd9Sstevel@tonic-gate 	svp->sv_knconf = kmem_zalloc(sizeof (*svp->sv_knconf), KM_SLEEP);
14307c478bd9Sstevel@tonic-gate 	svp->sv_knconf->knc_protofmly = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
14317c478bd9Sstevel@tonic-gate 	svp->sv_knconf->knc_proto = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	/*
14347c478bd9Sstevel@tonic-gate 	 * Get server address
14357c478bd9Sstevel@tonic-gate 	 * Get the root fhandle
14367c478bd9Sstevel@tonic-gate 	 * Get server's transport
14377c478bd9Sstevel@tonic-gate 	 * Get server's hostname
14387c478bd9Sstevel@tonic-gate 	 * Get options
14397c478bd9Sstevel@tonic-gate 	 */
14407c478bd9Sstevel@tonic-gate 	args.addr = &svp->sv_addr;
14417c478bd9Sstevel@tonic-gate 	args.fh = (char *)&svp->sv_fhandle;
14427c478bd9Sstevel@tonic-gate 	args.knconf = svp->sv_knconf;
14437c478bd9Sstevel@tonic-gate 	args.hostname = root_hostname;
14447c478bd9Sstevel@tonic-gate 	vfsflags = 0;
14457c478bd9Sstevel@tonic-gate 	if (error = mount_root(*name ? name : "root", root_path, NFS_V3,
14467c478bd9Sstevel@tonic-gate 	    &args, &vfsflags)) {
14477c478bd9Sstevel@tonic-gate 		if (error == EPROTONOSUPPORT)
14487c478bd9Sstevel@tonic-gate 			nfs_cmn_err(error, CE_WARN, "nfs3_mountroot: "
14497c478bd9Sstevel@tonic-gate 			    "mount_root failed: server doesn't support NFS V3");
14507c478bd9Sstevel@tonic-gate 		else
14517c478bd9Sstevel@tonic-gate 			nfs_cmn_err(error, CE_WARN,
14527c478bd9Sstevel@tonic-gate 			    "nfs3_mountroot: mount_root failed: %m");
14537c478bd9Sstevel@tonic-gate 		sv_free(svp);
14547c478bd9Sstevel@tonic-gate 		pn_free(&pn);
14557c478bd9Sstevel@tonic-gate 		return (error);
14567c478bd9Sstevel@tonic-gate 	}
14577c478bd9Sstevel@tonic-gate 	svp->sv_hostnamelen = (int)(strlen(root_hostname) + 1);
14587c478bd9Sstevel@tonic-gate 	svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP);
14597c478bd9Sstevel@tonic-gate 	(void) strcpy(svp->sv_hostname, root_hostname);
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	/*
14627c478bd9Sstevel@tonic-gate 	 * Force root partition to always be mounted with AUTH_UNIX for now
14637c478bd9Sstevel@tonic-gate 	 */
14647c478bd9Sstevel@tonic-gate 	svp->sv_secdata = kmem_alloc(sizeof (*svp->sv_secdata), KM_SLEEP);
14657c478bd9Sstevel@tonic-gate 	svp->sv_secdata->secmod = AUTH_UNIX;
14667c478bd9Sstevel@tonic-gate 	svp->sv_secdata->rpcflavor = AUTH_UNIX;
14677c478bd9Sstevel@tonic-gate 	svp->sv_secdata->data = NULL;
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	cr = crgetcred();
14707c478bd9Sstevel@tonic-gate 	rtvp = NULL;
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	error = nfs3rootvp(&rtvp, vfsp, svp, args.flags, cr, global_zone);
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	crfree(cr);
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	if (error) {
14777c478bd9Sstevel@tonic-gate 		pn_free(&pn);
14787c478bd9Sstevel@tonic-gate 		goto errout;
14797c478bd9Sstevel@tonic-gate 	}
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	error = nfs_setopts(rtvp, DATAMODEL_NATIVE, &args);
14827c478bd9Sstevel@tonic-gate 	if (error) {
14837c478bd9Sstevel@tonic-gate 		nfs_cmn_err(error, CE_WARN,
14847c478bd9Sstevel@tonic-gate 		    "nfs3_mountroot: invalid root mount options");
14857c478bd9Sstevel@tonic-gate 		pn_free(&pn);
14867c478bd9Sstevel@tonic-gate 		goto errout;
14877c478bd9Sstevel@tonic-gate 	}
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 	(void) vfs_lock_wait(vfsp);
14907c478bd9Sstevel@tonic-gate 	vfs_add(NULL, vfsp, vfsflags);
14917c478bd9Sstevel@tonic-gate 	vfs_unlock(vfsp);
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 	size = strlen(svp->sv_hostname);
14947c478bd9Sstevel@tonic-gate 	(void) strcpy(rootfs.bo_name, svp->sv_hostname);
14957c478bd9Sstevel@tonic-gate 	rootfs.bo_name[size] = ':';
14967c478bd9Sstevel@tonic-gate 	(void) strcpy(&rootfs.bo_name[size + 1], root_path);
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	pn_free(&pn);
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate errout:
15017c478bd9Sstevel@tonic-gate 	if (error) {
15027c478bd9Sstevel@tonic-gate 		sv_free(svp);
15037c478bd9Sstevel@tonic-gate 		nfs_async_stop(vfsp);
15047c478bd9Sstevel@tonic-gate 		nfs_async_manager_stop(vfsp);
15057c478bd9Sstevel@tonic-gate 	}
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	if (rtvp != NULL)
15087c478bd9Sstevel@tonic-gate 		VN_RELE(rtvp);
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	return (error);
15117c478bd9Sstevel@tonic-gate }
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate /*
15147c478bd9Sstevel@tonic-gate  * Initialization routine for VFS routines.  Should only be called once
15157c478bd9Sstevel@tonic-gate  */
15167c478bd9Sstevel@tonic-gate int
15177c478bd9Sstevel@tonic-gate nfs3_vfsinit(void)
15187c478bd9Sstevel@tonic-gate {
15197c478bd9Sstevel@tonic-gate 	mutex_init(&nfs3_syncbusy, NULL, MUTEX_DEFAULT, NULL);
15207c478bd9Sstevel@tonic-gate 	return (0);
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate void
15247c478bd9Sstevel@tonic-gate nfs3_vfsfini(void)
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate 	mutex_destroy(&nfs3_syncbusy);
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate void
15307c478bd9Sstevel@tonic-gate nfs3_freevfs(vfs_t *vfsp)
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate 	mntinfo_t *mi;
15337c478bd9Sstevel@tonic-gate 	servinfo_t *svp;
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 	/* free up the resources */
15367c478bd9Sstevel@tonic-gate 	mi = VFTOMI(vfsp);
15377c478bd9Sstevel@tonic-gate 	svp = mi->mi_servers;
15387c478bd9Sstevel@tonic-gate 	mi->mi_servers = mi->mi_curr_serv = NULL;
15397c478bd9Sstevel@tonic-gate 	sv_free(svp);
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 	/*
15427c478bd9Sstevel@tonic-gate 	 * By this time we should have already deleted the
15437c478bd9Sstevel@tonic-gate 	 * mi kstats in the unmount code. If they are still around
15447c478bd9Sstevel@tonic-gate 	 * somethings wrong
15457c478bd9Sstevel@tonic-gate 	 */
15467c478bd9Sstevel@tonic-gate 	ASSERT(mi->mi_io_kstats == NULL);
15477c478bd9Sstevel@tonic-gate 	nfs_free_mi(mi);
15487c478bd9Sstevel@tonic-gate }
1549