xref: /titanic_53/usr/src/uts/common/fs/vfs.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
32*7c478bd9Sstevel@tonic-gate  * The Regents of the University of California
33*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
36*7c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
37*7c478bd9Sstevel@tonic-gate  * contributors.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/fstyp.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/mount.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/fem.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/statfs.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/rwstlock.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/dnlc.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
67*7c478bd9Sstevel@tonic-gate #include <sys/buf.h>
68*7c478bd9Sstevel@tonic-gate #include <sys/swap.h>
69*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
70*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
71*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
72*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
73*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
74*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
75*7c478bd9Sstevel@tonic-gate #include <sys/dumphdr.h>
76*7c478bd9Sstevel@tonic-gate #include <sys/dc_ki.h>
77*7c478bd9Sstevel@tonic-gate #include <sys/poll.h>
78*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
79*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
80*7c478bd9Sstevel@tonic-gate #include <sys/zone.h>
81*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
82*7c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
83*7c478bd9Sstevel@tonic-gate #include <sys/objfs.h>
84*7c478bd9Sstevel@tonic-gate #include <sys/console.h>
85*7c478bd9Sstevel@tonic-gate #include <sys/reboot.h>
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate #include <vm/page.h>
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
92*7c478bd9Sstevel@tonic-gate static void vfs_setmntopt_nolock(mntopts_t *, const char *,
93*7c478bd9Sstevel@tonic-gate     const char *, int, int);
94*7c478bd9Sstevel@tonic-gate static int  vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
95*7c478bd9Sstevel@tonic-gate static void vfs_freemnttab(struct vfs *);
96*7c478bd9Sstevel@tonic-gate static void vfs_freeopt(mntopt_t *);
97*7c478bd9Sstevel@tonic-gate static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
98*7c478bd9Sstevel@tonic-gate static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
99*7c478bd9Sstevel@tonic-gate static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
100*7c478bd9Sstevel@tonic-gate static void vfs_createopttbl_extend(mntopts_t *, const char *,
101*7c478bd9Sstevel@tonic-gate     const mntopts_t *);
102*7c478bd9Sstevel@tonic-gate static char **vfs_copycancelopt_extend(char **const, int);
103*7c478bd9Sstevel@tonic-gate static void vfs_freecancelopt(char **);
104*7c478bd9Sstevel@tonic-gate static char *getrootfs(void);
105*7c478bd9Sstevel@tonic-gate static int getmacpath(dev_info_t *, void *);
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate struct ipmnt {
108*7c478bd9Sstevel@tonic-gate 	struct ipmnt	*mip_next;
109*7c478bd9Sstevel@tonic-gate 	dev_t		mip_dev;
110*7c478bd9Sstevel@tonic-gate 	struct vfs	*mip_vfsp;
111*7c478bd9Sstevel@tonic-gate };
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate static kmutex_t		vfs_miplist_mutex;
114*7c478bd9Sstevel@tonic-gate static struct ipmnt	*vfs_miplist = NULL;
115*7c478bd9Sstevel@tonic-gate static struct ipmnt	*vfs_miplist_end = NULL;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate /*
118*7c478bd9Sstevel@tonic-gate  * VFS global data.
119*7c478bd9Sstevel@tonic-gate  */
120*7c478bd9Sstevel@tonic-gate vnode_t *rootdir;		/* pointer to root inode vnode. */
121*7c478bd9Sstevel@tonic-gate vnode_t *devicesdir;		/* pointer to inode of devices root */
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate char *server_rootpath;		/* root path for diskless clients */
124*7c478bd9Sstevel@tonic-gate char *server_hostname;		/* hostname of diskless server */
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate static struct vfs root;
127*7c478bd9Sstevel@tonic-gate static struct vfs devices;
128*7c478bd9Sstevel@tonic-gate struct vfs *rootvfs = &root;	/* pointer to root vfs; head of VFS list. */
129*7c478bd9Sstevel@tonic-gate rvfs_t *rvfs_list;		/* array of vfs ptrs for vfs hash list */
130*7c478bd9Sstevel@tonic-gate int vfshsz = 512;		/* # of heads/locks in vfs hash arrays */
131*7c478bd9Sstevel@tonic-gate 				/* must be power of 2!	*/
132*7c478bd9Sstevel@tonic-gate timespec_t vfs_mnttab_ctime;	/* mnttab created time */
133*7c478bd9Sstevel@tonic-gate timespec_t vfs_mnttab_mtime;	/* mnttab last modified time */
134*7c478bd9Sstevel@tonic-gate char *vfs_dummyfstype = "\0";
135*7c478bd9Sstevel@tonic-gate struct pollhead vfs_pollhd;	/* for mnttab pollers */
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate /*
138*7c478bd9Sstevel@tonic-gate  * Table for generic options recognized in the VFS layer and acted
139*7c478bd9Sstevel@tonic-gate  * on at this level before parsing file system specific options.
140*7c478bd9Sstevel@tonic-gate  * The nosuid option is stronger than any of the devices and setuid
141*7c478bd9Sstevel@tonic-gate  * options, so those are canceled when nosuid is seen.
142*7c478bd9Sstevel@tonic-gate  *
143*7c478bd9Sstevel@tonic-gate  * All options which are added here need to be added to the
144*7c478bd9Sstevel@tonic-gate  * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
145*7c478bd9Sstevel@tonic-gate  */
146*7c478bd9Sstevel@tonic-gate /*
147*7c478bd9Sstevel@tonic-gate  * VFS Mount options table
148*7c478bd9Sstevel@tonic-gate  */
149*7c478bd9Sstevel@tonic-gate static char *ro_cancel[] = { MNTOPT_RW, NULL };
150*7c478bd9Sstevel@tonic-gate static char *rw_cancel[] = { MNTOPT_RO, NULL };
151*7c478bd9Sstevel@tonic-gate static char *suid_cancel[] = { MNTOPT_NOSUID, NULL };
152*7c478bd9Sstevel@tonic-gate static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES,
153*7c478bd9Sstevel@tonic-gate     MNTOPT_NOSETUID, MNTOPT_SETUID, NULL };
154*7c478bd9Sstevel@tonic-gate static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL };
155*7c478bd9Sstevel@tonic-gate static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL };
156*7c478bd9Sstevel@tonic-gate static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL };
157*7c478bd9Sstevel@tonic-gate static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL };
158*7c478bd9Sstevel@tonic-gate static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL };
159*7c478bd9Sstevel@tonic-gate static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL };
160*7c478bd9Sstevel@tonic-gate static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL };
161*7c478bd9Sstevel@tonic-gate static char *noexec_cancel[] = { MNTOPT_EXEC, NULL };
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate static const mntopt_t mntopts[] = {
164*7c478bd9Sstevel@tonic-gate /*
165*7c478bd9Sstevel@tonic-gate  *	option name		cancel options		default arg	flags
166*7c478bd9Sstevel@tonic-gate  */
167*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_REMOUNT,	NULL,			NULL,
168*7c478bd9Sstevel@tonic-gate 		MO_NODISPLAY, (void *)0 },
169*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_RO,		ro_cancel,		NULL,		0,
170*7c478bd9Sstevel@tonic-gate 		(void *)0 },
171*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_RW,		rw_cancel,		NULL,		0,
172*7c478bd9Sstevel@tonic-gate 		(void *)0 },
173*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_SUID,		suid_cancel,		NULL,		0,
174*7c478bd9Sstevel@tonic-gate 		(void *)0 },
175*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_NOSUID,	nosuid_cancel,		NULL,		0,
176*7c478bd9Sstevel@tonic-gate 		(void *)0 },
177*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_DEVICES,	devices_cancel,		NULL,		0,
178*7c478bd9Sstevel@tonic-gate 		(void *)0 },
179*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_NODEVICES,	nodevices_cancel,	NULL,		0,
180*7c478bd9Sstevel@tonic-gate 		(void *)0 },
181*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_SETUID,	setuid_cancel,		NULL,		0,
182*7c478bd9Sstevel@tonic-gate 		(void *)0 },
183*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_NOSETUID,	nosetuid_cancel,	NULL,		0,
184*7c478bd9Sstevel@tonic-gate 		(void *)0 },
185*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_NBMAND,	nbmand_cancel,		NULL,		0,
186*7c478bd9Sstevel@tonic-gate 		(void *)0 },
187*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_NONBMAND,	nonbmand_cancel,	NULL,		0,
188*7c478bd9Sstevel@tonic-gate 		(void *)0 },
189*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_EXEC,		exec_cancel,		NULL,		0,
190*7c478bd9Sstevel@tonic-gate 		(void *)0 },
191*7c478bd9Sstevel@tonic-gate 	{ MNTOPT_NOEXEC,	noexec_cancel,		NULL,		0,
192*7c478bd9Sstevel@tonic-gate 		(void *)0 },
193*7c478bd9Sstevel@tonic-gate };
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate const mntopts_t vfs_mntopts = {
196*7c478bd9Sstevel@tonic-gate 	sizeof (mntopts) / sizeof (mntopt_t),
197*7c478bd9Sstevel@tonic-gate 	(mntopt_t *)&mntopts[0]
198*7c478bd9Sstevel@tonic-gate };
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate /*
201*7c478bd9Sstevel@tonic-gate  * File system operation dispatch functions.
202*7c478bd9Sstevel@tonic-gate  */
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate int
205*7c478bd9Sstevel@tonic-gate fsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
206*7c478bd9Sstevel@tonic-gate {
207*7c478bd9Sstevel@tonic-gate 	return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr);
208*7c478bd9Sstevel@tonic-gate }
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate int
211*7c478bd9Sstevel@tonic-gate fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr)
212*7c478bd9Sstevel@tonic-gate {
213*7c478bd9Sstevel@tonic-gate 	return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr);
214*7c478bd9Sstevel@tonic-gate }
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate int
217*7c478bd9Sstevel@tonic-gate fsop_root(vfs_t *vfsp, vnode_t **vpp)
218*7c478bd9Sstevel@tonic-gate {
219*7c478bd9Sstevel@tonic-gate 	refstr_t *mntpt;
220*7c478bd9Sstevel@tonic-gate 	int ret = (*(vfsp)->vfs_op->vfs_root)(vfsp, vpp);
221*7c478bd9Sstevel@tonic-gate 	/*
222*7c478bd9Sstevel@tonic-gate 	 * Make sure this root has a path.  With lofs, it is possible to have
223*7c478bd9Sstevel@tonic-gate 	 * a NULL mountpoint.
224*7c478bd9Sstevel@tonic-gate 	 */
225*7c478bd9Sstevel@tonic-gate 	if (vfs_vnode_path && ret == 0 && vfsp->vfs_mntpt != NULL &&
226*7c478bd9Sstevel@tonic-gate 	    vn_path(*vpp) == NULL) {
227*7c478bd9Sstevel@tonic-gate 		mntpt = vfs_getmntpoint(vfsp);
228*7c478bd9Sstevel@tonic-gate 		vn_setpath_str(*vpp, refstr_value(mntpt),
229*7c478bd9Sstevel@tonic-gate 		    strlen(refstr_value(mntpt)));
230*7c478bd9Sstevel@tonic-gate 		refstr_rele(mntpt);
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	return (ret);
234*7c478bd9Sstevel@tonic-gate }
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate int
237*7c478bd9Sstevel@tonic-gate fsop_statfs(vfs_t *vfsp, statvfs64_t *sp)
238*7c478bd9Sstevel@tonic-gate {
239*7c478bd9Sstevel@tonic-gate 	return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp);
240*7c478bd9Sstevel@tonic-gate }
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate int
243*7c478bd9Sstevel@tonic-gate fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
244*7c478bd9Sstevel@tonic-gate {
245*7c478bd9Sstevel@tonic-gate 	return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr);
246*7c478bd9Sstevel@tonic-gate }
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate int
249*7c478bd9Sstevel@tonic-gate fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
250*7c478bd9Sstevel@tonic-gate {
251*7c478bd9Sstevel@tonic-gate 	return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
252*7c478bd9Sstevel@tonic-gate }
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate int
255*7c478bd9Sstevel@tonic-gate fsop_mountroot(vfs_t *vfsp, enum whymountroot reason)
256*7c478bd9Sstevel@tonic-gate {
257*7c478bd9Sstevel@tonic-gate 	return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason);
258*7c478bd9Sstevel@tonic-gate }
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate void
261*7c478bd9Sstevel@tonic-gate fsop_freefs(vfs_t *vfsp)
262*7c478bd9Sstevel@tonic-gate {
263*7c478bd9Sstevel@tonic-gate 	(*(vfsp)->vfs_op->vfs_freevfs)(vfsp);
264*7c478bd9Sstevel@tonic-gate }
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate int
267*7c478bd9Sstevel@tonic-gate fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
268*7c478bd9Sstevel@tonic-gate {
269*7c478bd9Sstevel@tonic-gate 	return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate));
270*7c478bd9Sstevel@tonic-gate }
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate int
273*7c478bd9Sstevel@tonic-gate fsop_sync_by_kind(int fstype, short flag, cred_t *cr)
274*7c478bd9Sstevel@tonic-gate {
275*7c478bd9Sstevel@tonic-gate 	ASSERT((fstype >= 0) && (fstype < nfstype));
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype]))
278*7c478bd9Sstevel@tonic-gate 		return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr);
279*7c478bd9Sstevel@tonic-gate 	else
280*7c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
281*7c478bd9Sstevel@tonic-gate }
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate /*
284*7c478bd9Sstevel@tonic-gate  * File system initialization.  vfs_setfsops() must be called from a file
285*7c478bd9Sstevel@tonic-gate  * system's init routine.
286*7c478bd9Sstevel@tonic-gate  */
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate static int
289*7c478bd9Sstevel@tonic-gate fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual,
290*7c478bd9Sstevel@tonic-gate     int *unused_ops)
291*7c478bd9Sstevel@tonic-gate {
292*7c478bd9Sstevel@tonic-gate 	static const fs_operation_trans_def_t vfs_ops_table[] = {
293*7c478bd9Sstevel@tonic-gate 		VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount),
294*7c478bd9Sstevel@tonic-gate 			fs_nosys, fs_nosys,
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 		VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount),
297*7c478bd9Sstevel@tonic-gate 			fs_nosys, fs_nosys,
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 		VFSNAME_ROOT, offsetof(vfsops_t, vfs_root),
300*7c478bd9Sstevel@tonic-gate 			fs_nosys, fs_nosys,
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 		VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs),
303*7c478bd9Sstevel@tonic-gate 			fs_nosys, fs_nosys,
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 		VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync),
306*7c478bd9Sstevel@tonic-gate 			(fs_generic_func_p) fs_sync,
307*7c478bd9Sstevel@tonic-gate 			(fs_generic_func_p) fs_sync,	/* No errors allowed */
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 		VFSNAME_VGET, offsetof(vfsops_t, vfs_vget),
310*7c478bd9Sstevel@tonic-gate 			fs_nosys, fs_nosys,
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 		VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot),
313*7c478bd9Sstevel@tonic-gate 			fs_nosys, fs_nosys,
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 		VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs),
316*7c478bd9Sstevel@tonic-gate 			(fs_generic_func_p)fs_freevfs,
317*7c478bd9Sstevel@tonic-gate 			(fs_generic_func_p)fs_freevfs,	/* Shouldn't fail */
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 		VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate),
320*7c478bd9Sstevel@tonic-gate 			(fs_generic_func_p)fs_nosys,
321*7c478bd9Sstevel@tonic-gate 			(fs_generic_func_p)fs_nosys,
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 		NULL, 0, NULL, NULL
324*7c478bd9Sstevel@tonic-gate 	};
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	return (fs_build_vector(actual, unused_ops, vfs_ops_table, template));
327*7c478bd9Sstevel@tonic-gate }
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate int
330*7c478bd9Sstevel@tonic-gate vfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual)
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate 	int error;
333*7c478bd9Sstevel@tonic-gate 	int unused_ops;
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	/* Verify that fstype refers to a loaded fs (and not fsid 0). */
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 	if ((fstype <= 0) || (fstype >= nfstype))
338*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	if (!ALLOCATED_VFSSW(&vfssw[fstype]))
341*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	/* Set up the operations vector. */
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops);
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 	if (error != 0)
348*7c478bd9Sstevel@tonic-gate 		return (error);
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	vfssw[fstype].vsw_flag |= VSW_INSTALLED;
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	if (actual != NULL)
353*7c478bd9Sstevel@tonic-gate 		*actual = &vfssw[fstype].vsw_vfsops;
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate #if DEBUG
356*7c478bd9Sstevel@tonic-gate 	if (unused_ops != 0)
357*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied "
358*7c478bd9Sstevel@tonic-gate 		    "but not used", vfssw[fstype].vsw_name, unused_ops);
359*7c478bd9Sstevel@tonic-gate #endif
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	return (0);
362*7c478bd9Sstevel@tonic-gate }
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate int
365*7c478bd9Sstevel@tonic-gate vfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual)
366*7c478bd9Sstevel@tonic-gate {
367*7c478bd9Sstevel@tonic-gate 	int error;
368*7c478bd9Sstevel@tonic-gate 	int unused_ops;
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	*actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP);
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	error = fs_copyfsops(template, *actual, &unused_ops);
373*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
374*7c478bd9Sstevel@tonic-gate 		kmem_free(*actual, sizeof (vfsops_t));
375*7c478bd9Sstevel@tonic-gate 		*actual = NULL;
376*7c478bd9Sstevel@tonic-gate 		return (error);
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	return (0);
380*7c478bd9Sstevel@tonic-gate }
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate /*
383*7c478bd9Sstevel@tonic-gate  * Free a vfsops structure created as a result of vfs_makefsops().
384*7c478bd9Sstevel@tonic-gate  * NOTE: For a vfsops structure initialized by vfs_setfsops(), use
385*7c478bd9Sstevel@tonic-gate  * vfs_freevfsops_by_type().
386*7c478bd9Sstevel@tonic-gate  */
387*7c478bd9Sstevel@tonic-gate void
388*7c478bd9Sstevel@tonic-gate vfs_freevfsops(vfsops_t *vfsops)
389*7c478bd9Sstevel@tonic-gate {
390*7c478bd9Sstevel@tonic-gate 	kmem_free(vfsops, sizeof (vfsops_t));
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate /*
394*7c478bd9Sstevel@tonic-gate  * Since the vfsops structure is part of the vfssw table and wasn't
395*7c478bd9Sstevel@tonic-gate  * really allocated, we're not really freeing anything.  We keep
396*7c478bd9Sstevel@tonic-gate  * the name for consistency with vfs_freevfsops().  We do, however,
397*7c478bd9Sstevel@tonic-gate  * need to take care of a little bookkeeping.
398*7c478bd9Sstevel@tonic-gate  * NOTE: For a vfsops structure created by vfs_setfsops(), use
399*7c478bd9Sstevel@tonic-gate  * vfs_freevfsops_by_type().
400*7c478bd9Sstevel@tonic-gate  */
401*7c478bd9Sstevel@tonic-gate int
402*7c478bd9Sstevel@tonic-gate vfs_freevfsops_by_type(int fstype)
403*7c478bd9Sstevel@tonic-gate {
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	/* Verify that fstype refers to a loaded fs (and not fsid 0). */
406*7c478bd9Sstevel@tonic-gate 	if ((fstype <= 0) || (fstype >= nfstype))
407*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	WLOCK_VFSSW();
410*7c478bd9Sstevel@tonic-gate 	if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) {
411*7c478bd9Sstevel@tonic-gate 		WUNLOCK_VFSSW();
412*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
413*7c478bd9Sstevel@tonic-gate 	}
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	vfssw[fstype].vsw_flag &= ~VSW_INSTALLED;
416*7c478bd9Sstevel@tonic-gate 	WUNLOCK_VFSSW();
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	return (0);
419*7c478bd9Sstevel@tonic-gate }
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate /* Support routines used to reference vfs_op */
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate /* Set the operations vector for a vfs */
424*7c478bd9Sstevel@tonic-gate void
425*7c478bd9Sstevel@tonic-gate vfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
426*7c478bd9Sstevel@tonic-gate {
427*7c478bd9Sstevel@tonic-gate 	vfsops_t	*op;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	ASSERT(vfsp != NULL);
430*7c478bd9Sstevel@tonic-gate 	ASSERT(vfsops != NULL);
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	op = vfsp->vfs_op;
433*7c478bd9Sstevel@tonic-gate 	membar_consumer();
434*7c478bd9Sstevel@tonic-gate 	if (vfsp->vfs_femhead == NULL &&
435*7c478bd9Sstevel@tonic-gate 	    casptr(&vfsp->vfs_op, op, vfsops) == op) {
436*7c478bd9Sstevel@tonic-gate 		return;
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate 	fsem_setvfsops(vfsp, vfsops);
439*7c478bd9Sstevel@tonic-gate }
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate /* Retrieve the operations vector for a vfs */
442*7c478bd9Sstevel@tonic-gate vfsops_t *
443*7c478bd9Sstevel@tonic-gate vfs_getops(vfs_t *vfsp)
444*7c478bd9Sstevel@tonic-gate {
445*7c478bd9Sstevel@tonic-gate 	vfsops_t	*op;
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	ASSERT(vfsp != NULL);
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	op = vfsp->vfs_op;
450*7c478bd9Sstevel@tonic-gate 	membar_consumer();
451*7c478bd9Sstevel@tonic-gate 	if (vfsp->vfs_femhead == NULL && op == vfsp->vfs_op) {
452*7c478bd9Sstevel@tonic-gate 		return (op);
453*7c478bd9Sstevel@tonic-gate 	} else {
454*7c478bd9Sstevel@tonic-gate 		return (fsem_getvfsops(vfsp));
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate }
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate /*
459*7c478bd9Sstevel@tonic-gate  * Returns non-zero (1) if the vfsops matches that of the vfs.
460*7c478bd9Sstevel@tonic-gate  * Returns zero (0) if not.
461*7c478bd9Sstevel@tonic-gate  */
462*7c478bd9Sstevel@tonic-gate int
463*7c478bd9Sstevel@tonic-gate vfs_matchops(vfs_t *vfsp, vfsops_t *vfsops)
464*7c478bd9Sstevel@tonic-gate {
465*7c478bd9Sstevel@tonic-gate 	return (vfs_getops(vfsp) == vfsops);
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate /*
469*7c478bd9Sstevel@tonic-gate  * Returns non-zero (1) if the file system has installed a non-default,
470*7c478bd9Sstevel@tonic-gate  * non-error vfs_sync routine.  Returns zero (0) otherwise.
471*7c478bd9Sstevel@tonic-gate  */
472*7c478bd9Sstevel@tonic-gate int
473*7c478bd9Sstevel@tonic-gate vfs_can_sync(vfs_t *vfsp)
474*7c478bd9Sstevel@tonic-gate {
475*7c478bd9Sstevel@tonic-gate 	/* vfs_sync() routine is not the default/error function */
476*7c478bd9Sstevel@tonic-gate 	return (vfs_getops(vfsp)->vfs_sync != fs_sync);
477*7c478bd9Sstevel@tonic-gate }
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate /*
480*7c478bd9Sstevel@tonic-gate  * Initialize a vfs structure.
481*7c478bd9Sstevel@tonic-gate  */
482*7c478bd9Sstevel@tonic-gate void
483*7c478bd9Sstevel@tonic-gate vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
484*7c478bd9Sstevel@tonic-gate {
485*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_count = 0;
486*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_next = vfsp;
487*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_prev = vfsp;
488*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_zone_next = vfsp;
489*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_zone_prev = vfsp;
490*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_flag = 0;
491*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_data = (data);
492*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_resource = NULL;
493*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_mntpt = NULL;
494*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_mntopts.mo_count = 0;
495*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_mntopts.mo_list = NULL;
496*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_femhead = NULL;
497*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_zone = NULL;
498*7c478bd9Sstevel@tonic-gate 	vfs_setops((vfsp), (op));
499*7c478bd9Sstevel@tonic-gate 	sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
500*7c478bd9Sstevel@tonic-gate }
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate /*
504*7c478bd9Sstevel@tonic-gate  * VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs,
505*7c478bd9Sstevel@tonic-gate  * fstatvfs, and sysfs moved to common/syscall.
506*7c478bd9Sstevel@tonic-gate  */
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate /*
509*7c478bd9Sstevel@tonic-gate  * Update every mounted file system.  We call the vfs_sync operation of
510*7c478bd9Sstevel@tonic-gate  * each file system type, passing it a NULL vfsp to indicate that all
511*7c478bd9Sstevel@tonic-gate  * mounted file systems of that type should be updated.
512*7c478bd9Sstevel@tonic-gate  */
513*7c478bd9Sstevel@tonic-gate void
514*7c478bd9Sstevel@tonic-gate vfs_sync(int flag)
515*7c478bd9Sstevel@tonic-gate {
516*7c478bd9Sstevel@tonic-gate 	struct vfssw *vswp;
517*7c478bd9Sstevel@tonic-gate 	RLOCK_VFSSW();
518*7c478bd9Sstevel@tonic-gate 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
519*7c478bd9Sstevel@tonic-gate 		if (ALLOCATED_VFSSW(vswp) && VFS_INSTALLED(vswp)) {
520*7c478bd9Sstevel@tonic-gate 			vfs_refvfssw(vswp);
521*7c478bd9Sstevel@tonic-gate 			RUNLOCK_VFSSW();
522*7c478bd9Sstevel@tonic-gate 			(void) (*vswp->vsw_vfsops.vfs_sync)(NULL, flag,
523*7c478bd9Sstevel@tonic-gate 			    CRED());
524*7c478bd9Sstevel@tonic-gate 			vfs_unrefvfssw(vswp);
525*7c478bd9Sstevel@tonic-gate 			RLOCK_VFSSW();
526*7c478bd9Sstevel@tonic-gate 		}
527*7c478bd9Sstevel@tonic-gate 	}
528*7c478bd9Sstevel@tonic-gate 	RUNLOCK_VFSSW();
529*7c478bd9Sstevel@tonic-gate }
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate void
532*7c478bd9Sstevel@tonic-gate sync(void)
533*7c478bd9Sstevel@tonic-gate {
534*7c478bd9Sstevel@tonic-gate 	vfs_sync(0);
535*7c478bd9Sstevel@tonic-gate }
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate /*
538*7c478bd9Sstevel@tonic-gate  * External routines.
539*7c478bd9Sstevel@tonic-gate  */
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate krwlock_t vfssw_lock;	/* lock accesses to vfssw */
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate /*
544*7c478bd9Sstevel@tonic-gate  * Lock for accessing the vfs linked list.  Initialized in vfs_mountroot(),
545*7c478bd9Sstevel@tonic-gate  * but otherwise should be accessed only via vfs_list_lock() and
546*7c478bd9Sstevel@tonic-gate  * vfs_list_unlock().  Also used to protect the timestamp for mods to the list.
547*7c478bd9Sstevel@tonic-gate  */
548*7c478bd9Sstevel@tonic-gate static krwlock_t vfslist;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate /*
551*7c478bd9Sstevel@tonic-gate  * Mount devfs on /devices. This is done right after root is mounted
552*7c478bd9Sstevel@tonic-gate  * to provide device access support for the system
553*7c478bd9Sstevel@tonic-gate  */
554*7c478bd9Sstevel@tonic-gate static void
555*7c478bd9Sstevel@tonic-gate vfs_mountdevices(void)
556*7c478bd9Sstevel@tonic-gate {
557*7c478bd9Sstevel@tonic-gate 	struct vfssw *vsw;
558*7c478bd9Sstevel@tonic-gate 	struct vnode *mvp;
559*7c478bd9Sstevel@tonic-gate 	struct mounta mounta = {	/* fake mounta for devfs_mount() */
560*7c478bd9Sstevel@tonic-gate 		NULL,
561*7c478bd9Sstevel@tonic-gate 		NULL,
562*7c478bd9Sstevel@tonic-gate 		MS_SYSSPACE,
563*7c478bd9Sstevel@tonic-gate 		NULL,
564*7c478bd9Sstevel@tonic-gate 		NULL,
565*7c478bd9Sstevel@tonic-gate 		0,
566*7c478bd9Sstevel@tonic-gate 		NULL,
567*7c478bd9Sstevel@tonic-gate 		0
568*7c478bd9Sstevel@tonic-gate 	};
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	/*
571*7c478bd9Sstevel@tonic-gate 	 * _init devfs module to fill in the vfssw
572*7c478bd9Sstevel@tonic-gate 	 */
573*7c478bd9Sstevel@tonic-gate 	if (modload("fs", "devfs") == -1)
574*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "Cannot _init devfs module\n");
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	/*
577*7c478bd9Sstevel@tonic-gate 	 * Hold vfs
578*7c478bd9Sstevel@tonic-gate 	 */
579*7c478bd9Sstevel@tonic-gate 	RLOCK_VFSSW();
580*7c478bd9Sstevel@tonic-gate 	vsw = vfs_getvfsswbyname("devfs");
581*7c478bd9Sstevel@tonic-gate 	VFS_INIT(&devices, &vsw->vsw_vfsops, NULL);
582*7c478bd9Sstevel@tonic-gate 	VFS_HOLD(&devices);
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	/*
585*7c478bd9Sstevel@tonic-gate 	 * Locate mount point
586*7c478bd9Sstevel@tonic-gate 	 */
587*7c478bd9Sstevel@tonic-gate 	if (lookupname("/devices", UIO_SYSSPACE, FOLLOW, NULLVPP, &mvp))
588*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "Cannot find /devices\n");
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	/*
591*7c478bd9Sstevel@tonic-gate 	 * Perform the mount of /devices
592*7c478bd9Sstevel@tonic-gate 	 */
593*7c478bd9Sstevel@tonic-gate 	if (VFS_MOUNT(&devices, mvp, &mounta, CRED()))
594*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "Cannot mount /devices\n");
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	RUNLOCK_VFSSW();
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	/*
599*7c478bd9Sstevel@tonic-gate 	 * Set appropriate members and add to vfs list for mnttab display
600*7c478bd9Sstevel@tonic-gate 	 */
601*7c478bd9Sstevel@tonic-gate 	vfs_setresource(&devices, "/devices");
602*7c478bd9Sstevel@tonic-gate 	vfs_setmntpoint(&devices, "/devices");
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	/*
605*7c478bd9Sstevel@tonic-gate 	 * Hold the root of /devices so it won't go away
606*7c478bd9Sstevel@tonic-gate 	 */
607*7c478bd9Sstevel@tonic-gate 	if (VFS_ROOT(&devices, &devicesdir))
608*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "vfs_mountdevices: not devices root");
609*7c478bd9Sstevel@tonic-gate 	VN_HOLD(devicesdir);
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	if (vfs_lock(&devices) != 0) {
612*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "Cannot acquire vfs_lock of /devices");
613*7c478bd9Sstevel@tonic-gate 		return;
614*7c478bd9Sstevel@tonic-gate 	}
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 	if (vn_vfswlock(mvp) != 0) {
617*7c478bd9Sstevel@tonic-gate 		vfs_unlock(&devices);
618*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "Cannot acquire vfswlock of /devices");
619*7c478bd9Sstevel@tonic-gate 		return;
620*7c478bd9Sstevel@tonic-gate 	}
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	vfs_add(mvp, &devices, 0);
623*7c478bd9Sstevel@tonic-gate 	vn_vfsunlock(mvp);
624*7c478bd9Sstevel@tonic-gate 	vfs_unlock(&devices);
625*7c478bd9Sstevel@tonic-gate }
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate /*
628*7c478bd9Sstevel@tonic-gate  * Mount required filesystem. This is done right after root is mounted.
629*7c478bd9Sstevel@tonic-gate  */
630*7c478bd9Sstevel@tonic-gate static void
631*7c478bd9Sstevel@tonic-gate vfs_mountfs(char *module, char *spec, char *path)
632*7c478bd9Sstevel@tonic-gate {
633*7c478bd9Sstevel@tonic-gate 	struct vnode *mvp;
634*7c478bd9Sstevel@tonic-gate 	struct mounta mounta;
635*7c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	mounta.flags = MS_SYSSPACE | MS_DATA;
638*7c478bd9Sstevel@tonic-gate 	mounta.fstype = module;
639*7c478bd9Sstevel@tonic-gate 	mounta.spec = spec;
640*7c478bd9Sstevel@tonic-gate 	mounta.dir = path;
641*7c478bd9Sstevel@tonic-gate 	if (lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, &mvp)) {
642*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "Cannot find %s\n", path);
643*7c478bd9Sstevel@tonic-gate 		return;
644*7c478bd9Sstevel@tonic-gate 	}
645*7c478bd9Sstevel@tonic-gate 	if (domount(NULL, &mounta, mvp, CRED(), &vfsp))
646*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "Cannot mount %s\n", path);
647*7c478bd9Sstevel@tonic-gate 	else
648*7c478bd9Sstevel@tonic-gate 		VFS_RELE(vfsp);
649*7c478bd9Sstevel@tonic-gate 	VN_RELE(mvp);
650*7c478bd9Sstevel@tonic-gate }
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate /*
653*7c478bd9Sstevel@tonic-gate  * vfs_mountroot is called by main() to mount the root filesystem.
654*7c478bd9Sstevel@tonic-gate  */
655*7c478bd9Sstevel@tonic-gate void
656*7c478bd9Sstevel@tonic-gate vfs_mountroot(void)
657*7c478bd9Sstevel@tonic-gate {
658*7c478bd9Sstevel@tonic-gate 	struct vnode	*rvp = NULL;
659*7c478bd9Sstevel@tonic-gate 	char		*path;
660*7c478bd9Sstevel@tonic-gate 	size_t		plen;
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	rw_init(&vfssw_lock, NULL, RW_DEFAULT, NULL);
663*7c478bd9Sstevel@tonic-gate 	rw_init(&vfslist, NULL, RW_DEFAULT, NULL);
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	/*
666*7c478bd9Sstevel@tonic-gate 	 * Alloc the vfs hash bucket array and locks
667*7c478bd9Sstevel@tonic-gate 	 */
668*7c478bd9Sstevel@tonic-gate 	rvfs_list = kmem_zalloc(vfshsz * sizeof (rvfs_t), KM_SLEEP);
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	/*
671*7c478bd9Sstevel@tonic-gate 	 * Call machine-dependent routine "rootconf" to choose a root
672*7c478bd9Sstevel@tonic-gate 	 * file system type.
673*7c478bd9Sstevel@tonic-gate 	 */
674*7c478bd9Sstevel@tonic-gate 	if (rootconf())
675*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "vfs_mountroot: cannot mount root");
676*7c478bd9Sstevel@tonic-gate 	/*
677*7c478bd9Sstevel@tonic-gate 	 * Get vnode for '/'.  Set up rootdir, u.u_rdir and u.u_cdir
678*7c478bd9Sstevel@tonic-gate 	 * to point to it.  These are used by lookuppn() so that it
679*7c478bd9Sstevel@tonic-gate 	 * knows where to start from ('/' or '.').
680*7c478bd9Sstevel@tonic-gate 	 */
681*7c478bd9Sstevel@tonic-gate 	vfs_setmntpoint(rootvfs, "/");
682*7c478bd9Sstevel@tonic-gate 	if (VFS_ROOT(rootvfs, &rootdir))
683*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "vfs_mountroot: no root vnode");
684*7c478bd9Sstevel@tonic-gate 	u.u_cdir = rootdir;
685*7c478bd9Sstevel@tonic-gate 	VN_HOLD(u.u_cdir);
686*7c478bd9Sstevel@tonic-gate 	u.u_rdir = NULL;
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	/*
689*7c478bd9Sstevel@tonic-gate 	 * Setup the global zone's rootvp, now that it exists.
690*7c478bd9Sstevel@tonic-gate 	 */
691*7c478bd9Sstevel@tonic-gate 	global_zone->zone_rootvp = rootdir;
692*7c478bd9Sstevel@tonic-gate 	VN_HOLD(global_zone->zone_rootvp);
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	/*
695*7c478bd9Sstevel@tonic-gate 	 * Notify the module code that it can begin using the
696*7c478bd9Sstevel@tonic-gate 	 * root filesystem instead of the boot program's services.
697*7c478bd9Sstevel@tonic-gate 	 */
698*7c478bd9Sstevel@tonic-gate 	modrootloaded = 1;
699*7c478bd9Sstevel@tonic-gate 	/*
700*7c478bd9Sstevel@tonic-gate 	 * Set up mnttab information for root
701*7c478bd9Sstevel@tonic-gate 	 */
702*7c478bd9Sstevel@tonic-gate 	vfs_setresource(rootvfs, rootfs.bo_name);
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 	/*
705*7c478bd9Sstevel@tonic-gate 	 * Notify cluster software that the root filesystem is available.
706*7c478bd9Sstevel@tonic-gate 	 */
707*7c478bd9Sstevel@tonic-gate 	clboot_mountroot();
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	/*
710*7c478bd9Sstevel@tonic-gate 	 * Mount /devices, /system/contract, /etc/mnttab, /etc/svc/volatile,
711*7c478bd9Sstevel@tonic-gate 	 * /system/object, and /proc.
712*7c478bd9Sstevel@tonic-gate 	 */
713*7c478bd9Sstevel@tonic-gate 	vfs_mountdevices();
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	vfs_mountfs("ctfs", "ctfs", CTFS_ROOT);
716*7c478bd9Sstevel@tonic-gate 	vfs_mountfs("proc", "/proc", "/proc");
717*7c478bd9Sstevel@tonic-gate 	vfs_mountfs("mntfs", "/etc/mnttab", "/etc/mnttab");
718*7c478bd9Sstevel@tonic-gate 	vfs_mountfs("tmpfs", "/etc/svc/volatile", "/etc/svc/volatile");
719*7c478bd9Sstevel@tonic-gate 	vfs_mountfs("objfs", "objfs", OBJFS_ROOT);
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate #ifdef __sparc
722*7c478bd9Sstevel@tonic-gate 	/*
723*7c478bd9Sstevel@tonic-gate 	 * This bit of magic can go away when we convert sparc to
724*7c478bd9Sstevel@tonic-gate 	 * the new boot architecture based on ramdisk.
725*7c478bd9Sstevel@tonic-gate 	 *
726*7c478bd9Sstevel@tonic-gate 	 * Booting off a mirrored root volume:
727*7c478bd9Sstevel@tonic-gate 	 * At this point, we have booted and mounted root on a
728*7c478bd9Sstevel@tonic-gate 	 * single component of the mirror.  Complete the boot
729*7c478bd9Sstevel@tonic-gate 	 * by configuring SVM and converting the root to the
730*7c478bd9Sstevel@tonic-gate 	 * dev_t of the mirrored root device.  This dev_t conversion
731*7c478bd9Sstevel@tonic-gate 	 * only works because the underlying device doesn't change.
732*7c478bd9Sstevel@tonic-gate 	 */
733*7c478bd9Sstevel@tonic-gate 	if (root_is_svm) {
734*7c478bd9Sstevel@tonic-gate 		if (svm_rootconf()) {
735*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC, "vfs_mountroot: cannot remount root");
736*7c478bd9Sstevel@tonic-gate 		}
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 		/*
739*7c478bd9Sstevel@tonic-gate 		 * mnttab should reflect the new root device
740*7c478bd9Sstevel@tonic-gate 		 */
741*7c478bd9Sstevel@tonic-gate 		vfs_lock_wait(rootvfs);
742*7c478bd9Sstevel@tonic-gate 		vfs_setresource(rootvfs, rootfs.bo_name);
743*7c478bd9Sstevel@tonic-gate 		vfs_unlock(rootvfs);
744*7c478bd9Sstevel@tonic-gate 	}
745*7c478bd9Sstevel@tonic-gate #endif /* __sparc */
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 	/*
748*7c478bd9Sstevel@tonic-gate 	 * Look up the root device via devfs so that a dv_node is
749*7c478bd9Sstevel@tonic-gate 	 * created for it. The vnode is never VN_RELE()ed.
750*7c478bd9Sstevel@tonic-gate 	 * We allocate more than MAXPATHLEN so that the
751*7c478bd9Sstevel@tonic-gate 	 * buffer passed to i_ddi_prompath_to_devfspath() is
752*7c478bd9Sstevel@tonic-gate 	 * exactly MAXPATHLEN (the function expects a buffer
753*7c478bd9Sstevel@tonic-gate 	 * of that length).
754*7c478bd9Sstevel@tonic-gate 	 */
755*7c478bd9Sstevel@tonic-gate 	plen = strlen("/devices");
756*7c478bd9Sstevel@tonic-gate 	path = kmem_alloc(plen + MAXPATHLEN, KM_SLEEP);
757*7c478bd9Sstevel@tonic-gate 	(void) strcpy(path, "/devices");
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	if (i_ddi_prompath_to_devfspath(rootfs.bo_name, path + plen)
760*7c478bd9Sstevel@tonic-gate 	    != DDI_SUCCESS ||
761*7c478bd9Sstevel@tonic-gate 	    lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, &rvp)) {
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 		/* NUL terminate in case "path" has garbage */
764*7c478bd9Sstevel@tonic-gate 		path[plen + MAXPATHLEN - 1] = '\0';
765*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
766*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!Cannot lookup root device: %s", path);
767*7c478bd9Sstevel@tonic-gate #endif
768*7c478bd9Sstevel@tonic-gate 	}
769*7c478bd9Sstevel@tonic-gate 	kmem_free(path, plen + MAXPATHLEN);
770*7c478bd9Sstevel@tonic-gate }
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate /*
773*7c478bd9Sstevel@tonic-gate  * Common mount code.  Called from the system call entry point, from autofs,
774*7c478bd9Sstevel@tonic-gate  * and from pxfs.
775*7c478bd9Sstevel@tonic-gate  *
776*7c478bd9Sstevel@tonic-gate  * Takes the effective file system type, mount arguments, the mount point
777*7c478bd9Sstevel@tonic-gate  * vnode, flags specifying whether the mount is a remount and whether it
778*7c478bd9Sstevel@tonic-gate  * should be entered into the vfs list, and credentials.  Fills in its vfspp
779*7c478bd9Sstevel@tonic-gate  * parameter with the mounted file system instance's vfs.
780*7c478bd9Sstevel@tonic-gate  *
781*7c478bd9Sstevel@tonic-gate  * Note that the effective file system type is specified as a string.  It may
782*7c478bd9Sstevel@tonic-gate  * be null, in which case it's determined from the mount arguments, and may
783*7c478bd9Sstevel@tonic-gate  * differ from the type specified in the mount arguments; this is a hook to
784*7c478bd9Sstevel@tonic-gate  * allow interposition when instantiating file system instances.
785*7c478bd9Sstevel@tonic-gate  *
786*7c478bd9Sstevel@tonic-gate  * The caller is responsible for releasing its own hold on the mount point
787*7c478bd9Sstevel@tonic-gate  * vp (this routine does its own hold when necessary).
788*7c478bd9Sstevel@tonic-gate  * Also note that for remounts, the mount point vp should be the vnode for
789*7c478bd9Sstevel@tonic-gate  * the root of the file system rather than the vnode that the file system
790*7c478bd9Sstevel@tonic-gate  * is mounted on top of.
791*7c478bd9Sstevel@tonic-gate  */
792*7c478bd9Sstevel@tonic-gate int
793*7c478bd9Sstevel@tonic-gate domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
794*7c478bd9Sstevel@tonic-gate 	struct vfs **vfspp)
795*7c478bd9Sstevel@tonic-gate {
796*7c478bd9Sstevel@tonic-gate 	struct vfssw	*vswp;
797*7c478bd9Sstevel@tonic-gate 	vfsops_t	*vfsops;
798*7c478bd9Sstevel@tonic-gate 	struct vfs	*vfsp;
799*7c478bd9Sstevel@tonic-gate 	struct vnode	*bvp;
800*7c478bd9Sstevel@tonic-gate 	dev_t		bdev = 0;
801*7c478bd9Sstevel@tonic-gate 	mntopts_t	mnt_mntopts;
802*7c478bd9Sstevel@tonic-gate 	int		error = 0;
803*7c478bd9Sstevel@tonic-gate 	int		copyout_error = 0;
804*7c478bd9Sstevel@tonic-gate 	int		ovflags;
805*7c478bd9Sstevel@tonic-gate 	char		*opts = uap->optptr;
806*7c478bd9Sstevel@tonic-gate 	char		*inargs = opts;
807*7c478bd9Sstevel@tonic-gate 	int		optlen = uap->optlen;
808*7c478bd9Sstevel@tonic-gate 	int		remount;
809*7c478bd9Sstevel@tonic-gate 	int		rdonly;
810*7c478bd9Sstevel@tonic-gate 	int		nbmand = 0;
811*7c478bd9Sstevel@tonic-gate 	int		delmip = 0;
812*7c478bd9Sstevel@tonic-gate 	int		addmip = 0;
813*7c478bd9Sstevel@tonic-gate 	int		splice = ((uap->flags & MS_NOSPLICE) == 0);
814*7c478bd9Sstevel@tonic-gate 	int		fromspace = (uap->flags & MS_SYSSPACE) ?
815*7c478bd9Sstevel@tonic-gate 				UIO_SYSSPACE : UIO_USERSPACE;
816*7c478bd9Sstevel@tonic-gate 	char		*resource = NULL, *mountpt = NULL;
817*7c478bd9Sstevel@tonic-gate 	refstr_t	*oldresource, *oldmntpt;
818*7c478bd9Sstevel@tonic-gate 	struct pathname	pn, rpn;
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	/*
821*7c478bd9Sstevel@tonic-gate 	 * The v_flag value for the mount point vp is permanently set
822*7c478bd9Sstevel@tonic-gate 	 * to VVFSLOCK so that no one bypasses the vn_vfs*locks routine
823*7c478bd9Sstevel@tonic-gate 	 * for mount point locking.
824*7c478bd9Sstevel@tonic-gate 	 */
825*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
826*7c478bd9Sstevel@tonic-gate 	vp->v_flag |= VVFSLOCK;
827*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	mnt_mntopts.mo_count = 0;
830*7c478bd9Sstevel@tonic-gate 	/*
831*7c478bd9Sstevel@tonic-gate 	 * Find the ops vector to use to invoke the file system-specific mount
832*7c478bd9Sstevel@tonic-gate 	 * method.  If the fsname argument is non-NULL, use it directly.
833*7c478bd9Sstevel@tonic-gate 	 * Otherwise, dig the file system type information out of the mount
834*7c478bd9Sstevel@tonic-gate 	 * arguments.
835*7c478bd9Sstevel@tonic-gate 	 *
836*7c478bd9Sstevel@tonic-gate 	 * A side effect is to hold the vfssw entry.
837*7c478bd9Sstevel@tonic-gate 	 *
838*7c478bd9Sstevel@tonic-gate 	 * Mount arguments can be specified in several ways, which are
839*7c478bd9Sstevel@tonic-gate 	 * distinguished by flag bit settings.  The preferred way is to set
840*7c478bd9Sstevel@tonic-gate 	 * MS_OPTIONSTR, indicating an 8 argument mount with the file system
841*7c478bd9Sstevel@tonic-gate 	 * type supplied as a character string and the last two arguments
842*7c478bd9Sstevel@tonic-gate 	 * being a pointer to a character buffer and the size of the buffer.
843*7c478bd9Sstevel@tonic-gate 	 * On entry, the buffer holds a null terminated list of options; on
844*7c478bd9Sstevel@tonic-gate 	 * return, the string is the list of options the file system
845*7c478bd9Sstevel@tonic-gate 	 * recognized. If MS_DATA is set arguments five and six point to a
846*7c478bd9Sstevel@tonic-gate 	 * block of binary data which the file system interprets.
847*7c478bd9Sstevel@tonic-gate 	 * A further wrinkle is that some callers don't set MS_FSS and MS_DATA
848*7c478bd9Sstevel@tonic-gate 	 * consistently with these conventions.  To handle them, we check to
849*7c478bd9Sstevel@tonic-gate 	 * see whether the pointer to the file system name has a numeric value
850*7c478bd9Sstevel@tonic-gate 	 * less than 256.  If so, we treat it as an index.
851*7c478bd9Sstevel@tonic-gate 	 */
852*7c478bd9Sstevel@tonic-gate 	if (fsname != NULL) {
853*7c478bd9Sstevel@tonic-gate 		if ((vswp = vfs_getvfssw(fsname)) == NULL) {
854*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
855*7c478bd9Sstevel@tonic-gate 		}
856*7c478bd9Sstevel@tonic-gate 	} else if (uap->flags & (MS_OPTIONSTR | MS_DATA | MS_FSS)) {
857*7c478bd9Sstevel@tonic-gate 		size_t n;
858*7c478bd9Sstevel@tonic-gate 		uint_t fstype;
859*7c478bd9Sstevel@tonic-gate 		char name[FSTYPSZ];
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 		if ((fstype = (uintptr_t)uap->fstype) < 256) {
862*7c478bd9Sstevel@tonic-gate 			RLOCK_VFSSW();
863*7c478bd9Sstevel@tonic-gate 			if (fstype == 0 || fstype >= nfstype ||
864*7c478bd9Sstevel@tonic-gate 			    !ALLOCATED_VFSSW(&vfssw[fstype])) {
865*7c478bd9Sstevel@tonic-gate 				RUNLOCK_VFSSW();
866*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
867*7c478bd9Sstevel@tonic-gate 			}
868*7c478bd9Sstevel@tonic-gate 			(void) strcpy(name, vfssw[fstype].vsw_name);
869*7c478bd9Sstevel@tonic-gate 			RUNLOCK_VFSSW();
870*7c478bd9Sstevel@tonic-gate 			if ((vswp = vfs_getvfssw(name)) == NULL)
871*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
872*7c478bd9Sstevel@tonic-gate 		} else {
873*7c478bd9Sstevel@tonic-gate 			/*
874*7c478bd9Sstevel@tonic-gate 			 * Handle either kernel or user address space.
875*7c478bd9Sstevel@tonic-gate 			 */
876*7c478bd9Sstevel@tonic-gate 			if (uap->flags & MS_SYSSPACE) {
877*7c478bd9Sstevel@tonic-gate 				error = copystr(uap->fstype, name,
878*7c478bd9Sstevel@tonic-gate 				    FSTYPSZ, &n);
879*7c478bd9Sstevel@tonic-gate 			} else {
880*7c478bd9Sstevel@tonic-gate 				error = copyinstr(uap->fstype, name,
881*7c478bd9Sstevel@tonic-gate 				    FSTYPSZ, &n);
882*7c478bd9Sstevel@tonic-gate 			}
883*7c478bd9Sstevel@tonic-gate 			if (error) {
884*7c478bd9Sstevel@tonic-gate 				if (error == ENAMETOOLONG)
885*7c478bd9Sstevel@tonic-gate 					return (EINVAL);
886*7c478bd9Sstevel@tonic-gate 				return (error);
887*7c478bd9Sstevel@tonic-gate 			}
888*7c478bd9Sstevel@tonic-gate 			if ((vswp = vfs_getvfssw(name)) == NULL)
889*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
890*7c478bd9Sstevel@tonic-gate 		}
891*7c478bd9Sstevel@tonic-gate 	} else {
892*7c478bd9Sstevel@tonic-gate 		if ((vswp = vfs_getvfsswbyvfsops(vfs_getops(rootvfs))) == NULL)
893*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
894*7c478bd9Sstevel@tonic-gate 	}
895*7c478bd9Sstevel@tonic-gate 	if (!VFS_INSTALLED(vswp))
896*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
897*7c478bd9Sstevel@tonic-gate 	vfsops = &vswp->vsw_vfsops;
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts);
900*7c478bd9Sstevel@tonic-gate 	/*
901*7c478bd9Sstevel@tonic-gate 	 * Fetch mount options and parse them for generic vfs options
902*7c478bd9Sstevel@tonic-gate 	 */
903*7c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_OPTIONSTR) {
904*7c478bd9Sstevel@tonic-gate 		/*
905*7c478bd9Sstevel@tonic-gate 		 * Limit the buffer size
906*7c478bd9Sstevel@tonic-gate 		 */
907*7c478bd9Sstevel@tonic-gate 		if (optlen < 0 || optlen > MAX_MNTOPT_STR) {
908*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
909*7c478bd9Sstevel@tonic-gate 			goto errout;
910*7c478bd9Sstevel@tonic-gate 		}
911*7c478bd9Sstevel@tonic-gate 		if ((uap->flags & MS_SYSSPACE) == 0) {
912*7c478bd9Sstevel@tonic-gate 			inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
913*7c478bd9Sstevel@tonic-gate 			inargs[0] = '\0';
914*7c478bd9Sstevel@tonic-gate 			if (optlen) {
915*7c478bd9Sstevel@tonic-gate 				error = copyinstr(opts, inargs, (size_t)optlen,
916*7c478bd9Sstevel@tonic-gate 					NULL);
917*7c478bd9Sstevel@tonic-gate 				if (error) {
918*7c478bd9Sstevel@tonic-gate 					goto errout;
919*7c478bd9Sstevel@tonic-gate 				}
920*7c478bd9Sstevel@tonic-gate 			}
921*7c478bd9Sstevel@tonic-gate 		}
922*7c478bd9Sstevel@tonic-gate 		vfs_parsemntopts(&mnt_mntopts, inargs, 0);
923*7c478bd9Sstevel@tonic-gate 	}
924*7c478bd9Sstevel@tonic-gate 	/*
925*7c478bd9Sstevel@tonic-gate 	 * Flag bits override the options string.
926*7c478bd9Sstevel@tonic-gate 	 */
927*7c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_REMOUNT)
928*7c478bd9Sstevel@tonic-gate 		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0);
929*7c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_RDONLY)
930*7c478bd9Sstevel@tonic-gate 		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0);
931*7c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_NOSUID)
932*7c478bd9Sstevel@tonic-gate 		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	/*
935*7c478bd9Sstevel@tonic-gate 	 * Check if this is a remount; must be set in the option string and
936*7c478bd9Sstevel@tonic-gate 	 * the file system must support a remount option.
937*7c478bd9Sstevel@tonic-gate 	 */
938*7c478bd9Sstevel@tonic-gate 	if (remount = vfs_optionisset_nolock(&mnt_mntopts,
939*7c478bd9Sstevel@tonic-gate 	    MNTOPT_REMOUNT, NULL)) {
940*7c478bd9Sstevel@tonic-gate 		if (!(vswp->vsw_flag & VSW_CANREMOUNT)) {
941*7c478bd9Sstevel@tonic-gate 			error = ENOTSUP;
942*7c478bd9Sstevel@tonic-gate 			goto errout;
943*7c478bd9Sstevel@tonic-gate 		}
944*7c478bd9Sstevel@tonic-gate 		uap->flags |= MS_REMOUNT;
945*7c478bd9Sstevel@tonic-gate 	}
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	/*
948*7c478bd9Sstevel@tonic-gate 	 * uap->flags and vfs_optionisset() should agree.
949*7c478bd9Sstevel@tonic-gate 	 */
950*7c478bd9Sstevel@tonic-gate 	if (rdonly = vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) {
951*7c478bd9Sstevel@tonic-gate 		uap->flags |= MS_RDONLY;
952*7c478bd9Sstevel@tonic-gate 	}
953*7c478bd9Sstevel@tonic-gate 	if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) {
954*7c478bd9Sstevel@tonic-gate 		uap->flags |= MS_NOSUID;
955*7c478bd9Sstevel@tonic-gate 	}
956*7c478bd9Sstevel@tonic-gate 	nbmand = vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NBMAND, NULL);
957*7c478bd9Sstevel@tonic-gate 	ASSERT(splice || !remount);
958*7c478bd9Sstevel@tonic-gate 	/*
959*7c478bd9Sstevel@tonic-gate 	 * If we are splicing the fs into the namespace,
960*7c478bd9Sstevel@tonic-gate 	 * perform mount point checks.
961*7c478bd9Sstevel@tonic-gate 	 *
962*7c478bd9Sstevel@tonic-gate 	 * We want to resolve the path for the mount point to eliminate
963*7c478bd9Sstevel@tonic-gate 	 * '.' and ".." and symlinks in mount points; we can't do the
964*7c478bd9Sstevel@tonic-gate 	 * same for the resource string, since it would turn
965*7c478bd9Sstevel@tonic-gate 	 * "/dev/dsk/c0t0d0s0" into "/devices/pci@...".  We need to do
966*7c478bd9Sstevel@tonic-gate 	 * this before grabbing vn_vfswlock(), because otherwise we
967*7c478bd9Sstevel@tonic-gate 	 * would deadlock with lookuppn().
968*7c478bd9Sstevel@tonic-gate 	 */
969*7c478bd9Sstevel@tonic-gate 	if (splice) {
970*7c478bd9Sstevel@tonic-gate 		ASSERT(vp->v_count > 0);
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 		/*
973*7c478bd9Sstevel@tonic-gate 		 * Pick up mount point and device from appropriate space.
974*7c478bd9Sstevel@tonic-gate 		 */
975*7c478bd9Sstevel@tonic-gate 		if (pn_get(uap->spec, fromspace, &pn) == 0) {
976*7c478bd9Sstevel@tonic-gate 			resource = kmem_alloc(pn.pn_pathlen + 1,
977*7c478bd9Sstevel@tonic-gate 			    KM_SLEEP);
978*7c478bd9Sstevel@tonic-gate 			(void) strcpy(resource, pn.pn_path);
979*7c478bd9Sstevel@tonic-gate 			pn_free(&pn);
980*7c478bd9Sstevel@tonic-gate 		}
981*7c478bd9Sstevel@tonic-gate 		/*
982*7c478bd9Sstevel@tonic-gate 		 * Do a lookupname prior to taking the
983*7c478bd9Sstevel@tonic-gate 		 * writelock. Mark this as completed if
984*7c478bd9Sstevel@tonic-gate 		 * successful for later cleanup and addition to
985*7c478bd9Sstevel@tonic-gate 		 * the mount in progress table.
986*7c478bd9Sstevel@tonic-gate 		 */
987*7c478bd9Sstevel@tonic-gate 		if ((uap->flags & MS_GLOBAL) == 0 &&
988*7c478bd9Sstevel@tonic-gate 		    lookupname(uap->spec, fromspace,
989*7c478bd9Sstevel@tonic-gate 			    FOLLOW, NULL, &bvp) == 0) {
990*7c478bd9Sstevel@tonic-gate 			addmip = 1;
991*7c478bd9Sstevel@tonic-gate 		}
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 		if ((error = pn_get(uap->dir, fromspace, &pn)) == 0) {
994*7c478bd9Sstevel@tonic-gate 			pathname_t *pnp;
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 			if (*pn.pn_path != '/') {
997*7c478bd9Sstevel@tonic-gate 				error = EINVAL;
998*7c478bd9Sstevel@tonic-gate 				pn_free(&pn);
999*7c478bd9Sstevel@tonic-gate 				goto errout;
1000*7c478bd9Sstevel@tonic-gate 			}
1001*7c478bd9Sstevel@tonic-gate 			pn_alloc(&rpn);
1002*7c478bd9Sstevel@tonic-gate 			/*
1003*7c478bd9Sstevel@tonic-gate 			 * Kludge to prevent autofs from deadlocking with
1004*7c478bd9Sstevel@tonic-gate 			 * itself when it calls domount().
1005*7c478bd9Sstevel@tonic-gate 			 *
1006*7c478bd9Sstevel@tonic-gate 			 * If autofs is calling, it is because it is doing
1007*7c478bd9Sstevel@tonic-gate 			 * (autofs) mounts in the process of an NFS mount.  A
1008*7c478bd9Sstevel@tonic-gate 			 * lookuppn() here would cause us to block waiting for
1009*7c478bd9Sstevel@tonic-gate 			 * said NFS mount to complete, which can't since this
1010*7c478bd9Sstevel@tonic-gate 			 * is the thread that was supposed to doing it.
1011*7c478bd9Sstevel@tonic-gate 			 */
1012*7c478bd9Sstevel@tonic-gate 			if (fromspace == UIO_USERSPACE) {
1013*7c478bd9Sstevel@tonic-gate 				if ((error = lookuppn(&pn, &rpn, FOLLOW, NULL,
1014*7c478bd9Sstevel@tonic-gate 				    NULL)) == 0) {
1015*7c478bd9Sstevel@tonic-gate 					pnp = &rpn;
1016*7c478bd9Sstevel@tonic-gate 				} else {
1017*7c478bd9Sstevel@tonic-gate 					/*
1018*7c478bd9Sstevel@tonic-gate 					 * The file disappeared or otherwise
1019*7c478bd9Sstevel@tonic-gate 					 * became inaccessible since we opened
1020*7c478bd9Sstevel@tonic-gate 					 * it; might as well fail the mount
1021*7c478bd9Sstevel@tonic-gate 					 * since the mount point is no longer
1022*7c478bd9Sstevel@tonic-gate 					 * accessible.
1023*7c478bd9Sstevel@tonic-gate 					 */
1024*7c478bd9Sstevel@tonic-gate 					pn_free(&rpn);
1025*7c478bd9Sstevel@tonic-gate 					pn_free(&pn);
1026*7c478bd9Sstevel@tonic-gate 					goto errout;
1027*7c478bd9Sstevel@tonic-gate 				}
1028*7c478bd9Sstevel@tonic-gate 			} else {
1029*7c478bd9Sstevel@tonic-gate 				pnp = &pn;
1030*7c478bd9Sstevel@tonic-gate 			}
1031*7c478bd9Sstevel@tonic-gate 			mountpt = kmem_alloc(pnp->pn_pathlen + 1, KM_SLEEP);
1032*7c478bd9Sstevel@tonic-gate 			(void) strcpy(mountpt, pnp->pn_path);
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 			/*
1035*7c478bd9Sstevel@tonic-gate 			 * If the addition of the zone's rootpath
1036*7c478bd9Sstevel@tonic-gate 			 * would push us over a total path length
1037*7c478bd9Sstevel@tonic-gate 			 * of MAXPATHLEN, we fail the mount with
1038*7c478bd9Sstevel@tonic-gate 			 * ENAMETOOLONG, which is what we would have
1039*7c478bd9Sstevel@tonic-gate 			 * gotten if we were trying to perform the same
1040*7c478bd9Sstevel@tonic-gate 			 * mount in the global zone.
1041*7c478bd9Sstevel@tonic-gate 			 *
1042*7c478bd9Sstevel@tonic-gate 			 * strlen() doesn't count the trailing
1043*7c478bd9Sstevel@tonic-gate 			 * '\0', but zone_rootpathlen counts both a
1044*7c478bd9Sstevel@tonic-gate 			 * trailing '/' and the terminating '\0'.
1045*7c478bd9Sstevel@tonic-gate 			 */
1046*7c478bd9Sstevel@tonic-gate 			if ((curproc->p_zone->zone_rootpathlen - 1 +
1047*7c478bd9Sstevel@tonic-gate 			    strlen(mountpt)) > MAXPATHLEN ||
1048*7c478bd9Sstevel@tonic-gate 			    (resource != NULL &&
1049*7c478bd9Sstevel@tonic-gate 			    (curproc->p_zone->zone_rootpathlen - 1 +
1050*7c478bd9Sstevel@tonic-gate 			    strlen(resource)) > MAXPATHLEN)) {
1051*7c478bd9Sstevel@tonic-gate 				error = ENAMETOOLONG;
1052*7c478bd9Sstevel@tonic-gate 			}
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 			pn_free(&rpn);
1055*7c478bd9Sstevel@tonic-gate 			pn_free(&pn);
1056*7c478bd9Sstevel@tonic-gate 		}
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 		if (error)
1059*7c478bd9Sstevel@tonic-gate 			goto errout;
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 		/*
1062*7c478bd9Sstevel@tonic-gate 		 * Prevent path name resolution from proceeding past
1063*7c478bd9Sstevel@tonic-gate 		 * the mount point.
1064*7c478bd9Sstevel@tonic-gate 		 */
1065*7c478bd9Sstevel@tonic-gate 		if (vn_vfswlock(vp) != 0) {
1066*7c478bd9Sstevel@tonic-gate 			error = EBUSY;
1067*7c478bd9Sstevel@tonic-gate 			goto errout;
1068*7c478bd9Sstevel@tonic-gate 		}
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate 		/*
1071*7c478bd9Sstevel@tonic-gate 		 * Verify that it's legitimate to establish a mount on
1072*7c478bd9Sstevel@tonic-gate 		 * the prospective mount point.
1073*7c478bd9Sstevel@tonic-gate 		 */
1074*7c478bd9Sstevel@tonic-gate 		if (vn_mountedvfs(vp) != NULL) {
1075*7c478bd9Sstevel@tonic-gate 			/*
1076*7c478bd9Sstevel@tonic-gate 			 * The mount point lock was obtained after some
1077*7c478bd9Sstevel@tonic-gate 			 * other thread raced through and established a mount.
1078*7c478bd9Sstevel@tonic-gate 			 */
1079*7c478bd9Sstevel@tonic-gate 			vn_vfsunlock(vp);
1080*7c478bd9Sstevel@tonic-gate 			error = EBUSY;
1081*7c478bd9Sstevel@tonic-gate 			goto errout;
1082*7c478bd9Sstevel@tonic-gate 		}
1083*7c478bd9Sstevel@tonic-gate 		if (vp->v_flag & VNOMOUNT) {
1084*7c478bd9Sstevel@tonic-gate 			vn_vfsunlock(vp);
1085*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
1086*7c478bd9Sstevel@tonic-gate 			goto errout;
1087*7c478bd9Sstevel@tonic-gate 		}
1088*7c478bd9Sstevel@tonic-gate 	}
1089*7c478bd9Sstevel@tonic-gate 	if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) {
1090*7c478bd9Sstevel@tonic-gate 		uap->dataptr = NULL;
1091*7c478bd9Sstevel@tonic-gate 		uap->datalen = 0;
1092*7c478bd9Sstevel@tonic-gate 	}
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	/*
1095*7c478bd9Sstevel@tonic-gate 	 * If this is a remount, we don't want to create a new VFS.
1096*7c478bd9Sstevel@tonic-gate 	 * Instead, we pass the existing one with a remount flag.
1097*7c478bd9Sstevel@tonic-gate 	 */
1098*7c478bd9Sstevel@tonic-gate 	if (remount) {
1099*7c478bd9Sstevel@tonic-gate 		/*
1100*7c478bd9Sstevel@tonic-gate 		 * Confirm that the mount point is the root vnode of the
1101*7c478bd9Sstevel@tonic-gate 		 * file system that is being remounted.
1102*7c478bd9Sstevel@tonic-gate 		 * This can happen if the user specifies a different
1103*7c478bd9Sstevel@tonic-gate 		 * mount point directory pathname in the (re)mount command.
1104*7c478bd9Sstevel@tonic-gate 		 *
1105*7c478bd9Sstevel@tonic-gate 		 * Code below can only be reached if splice is true, so it's
1106*7c478bd9Sstevel@tonic-gate 		 * safe to do vn_vfsunlock() here.
1107*7c478bd9Sstevel@tonic-gate 		 */
1108*7c478bd9Sstevel@tonic-gate 		if ((vp->v_flag & VROOT) == 0) {
1109*7c478bd9Sstevel@tonic-gate 			vn_vfsunlock(vp);
1110*7c478bd9Sstevel@tonic-gate 			error = ENOENT;
1111*7c478bd9Sstevel@tonic-gate 			goto errout;
1112*7c478bd9Sstevel@tonic-gate 		}
1113*7c478bd9Sstevel@tonic-gate 		/*
1114*7c478bd9Sstevel@tonic-gate 		 * Disallow making file systems read-only unless file system
1115*7c478bd9Sstevel@tonic-gate 		 * explicitly allows it in its vfssw.  Ignore other flags.
1116*7c478bd9Sstevel@tonic-gate 		 */
1117*7c478bd9Sstevel@tonic-gate 		if (rdonly && vn_is_readonly(vp) == 0 &&
1118*7c478bd9Sstevel@tonic-gate 		    (vswp->vsw_flag & VSW_CANRWRO) == 0) {
1119*7c478bd9Sstevel@tonic-gate 			vn_vfsunlock(vp);
1120*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
1121*7c478bd9Sstevel@tonic-gate 			goto errout;
1122*7c478bd9Sstevel@tonic-gate 		}
1123*7c478bd9Sstevel@tonic-gate 		/*
1124*7c478bd9Sstevel@tonic-gate 		 * Changing the NBMAND setting on remounts is permitted
1125*7c478bd9Sstevel@tonic-gate 		 * but logged since it can lead to unexpected behavior.
1126*7c478bd9Sstevel@tonic-gate 		 * We also counsel against using it for / and /usr.
1127*7c478bd9Sstevel@tonic-gate 		 */
1128*7c478bd9Sstevel@tonic-gate 		if ((nbmand && ((vp->v_vfsp->vfs_flag & VFS_NBMAND) == 0)) ||
1129*7c478bd9Sstevel@tonic-gate 		    (!nbmand && (vp->v_vfsp->vfs_flag & VFS_NBMAND))) {
1130*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "domount: nbmand turned %s via "
1131*7c478bd9Sstevel@tonic-gate 			    "remounting %s", nbmand ? "on" : "off",
1132*7c478bd9Sstevel@tonic-gate 			    refstr_value(vp->v_vfsp->vfs_mntpt));
1133*7c478bd9Sstevel@tonic-gate 		}
1134*7c478bd9Sstevel@tonic-gate 		vfsp = vp->v_vfsp;
1135*7c478bd9Sstevel@tonic-gate 		ovflags = vfsp->vfs_flag;
1136*7c478bd9Sstevel@tonic-gate 		vfsp->vfs_flag |= VFS_REMOUNT;
1137*7c478bd9Sstevel@tonic-gate 		vfsp->vfs_flag &= ~VFS_RDONLY;
1138*7c478bd9Sstevel@tonic-gate 	} else {
1139*7c478bd9Sstevel@tonic-gate 		vfsp = kmem_alloc(sizeof (vfs_t), KM_SLEEP);
1140*7c478bd9Sstevel@tonic-gate 		VFS_INIT(vfsp, vfsops, NULL);
1141*7c478bd9Sstevel@tonic-gate 	}
1142*7c478bd9Sstevel@tonic-gate 
1143*7c478bd9Sstevel@tonic-gate 	VFS_HOLD(vfsp);
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate 	/*
1146*7c478bd9Sstevel@tonic-gate 	 * The vfs_reflock is not used anymore the code below explicitly
1147*7c478bd9Sstevel@tonic-gate 	 * holds it preventing others accesing it directly.
1148*7c478bd9Sstevel@tonic-gate 	 */
1149*7c478bd9Sstevel@tonic-gate 	if ((sema_tryp(&vfsp->vfs_reflock) == 0) &&
1150*7c478bd9Sstevel@tonic-gate 	    !(vfsp->vfs_flag & VFS_REMOUNT))
1151*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1152*7c478bd9Sstevel@tonic-gate 		    "mount type %s couldn't get vfs_reflock\n", vswp->vsw_name);
1153*7c478bd9Sstevel@tonic-gate 
1154*7c478bd9Sstevel@tonic-gate 	/*
1155*7c478bd9Sstevel@tonic-gate 	 * Lock the vfs. If this is a remount we want to avoid spurious umount
1156*7c478bd9Sstevel@tonic-gate 	 * failures that happen as a side-effect of fsflush() and other mount
1157*7c478bd9Sstevel@tonic-gate 	 * and unmount operations that might be going on simultaneously and
1158*7c478bd9Sstevel@tonic-gate 	 * may have locked the vfs currently. To not return EBUSY immediately
1159*7c478bd9Sstevel@tonic-gate 	 * here we use vfs_lock_wait() instead vfs_lock() for the remount case.
1160*7c478bd9Sstevel@tonic-gate 	 */
1161*7c478bd9Sstevel@tonic-gate 	if (!remount) {
1162*7c478bd9Sstevel@tonic-gate 		if (error = vfs_lock(vfsp)) {
1163*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag = ovflags;
1164*7c478bd9Sstevel@tonic-gate 			if (splice)
1165*7c478bd9Sstevel@tonic-gate 				vn_vfsunlock(vp);
1166*7c478bd9Sstevel@tonic-gate 			kmem_free(vfsp, sizeof (struct vfs));
1167*7c478bd9Sstevel@tonic-gate 			goto errout;
1168*7c478bd9Sstevel@tonic-gate 		}
1169*7c478bd9Sstevel@tonic-gate 	} else {
1170*7c478bd9Sstevel@tonic-gate 		vfs_lock_wait(vfsp);
1171*7c478bd9Sstevel@tonic-gate 	}
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 	/*
1174*7c478bd9Sstevel@tonic-gate 	 * Add device to mount in progress table, global mounts require special
1175*7c478bd9Sstevel@tonic-gate 	 * handling. It is possible that we have already done the lookupname
1176*7c478bd9Sstevel@tonic-gate 	 * on a spliced, non-global fs. If so, we don't want to do it again
1177*7c478bd9Sstevel@tonic-gate 	 * since we cannot do a lookupname after taking the
1178*7c478bd9Sstevel@tonic-gate 	 * wlock above. This case is for a non-spliced, non-global filesystem.
1179*7c478bd9Sstevel@tonic-gate 	 */
1180*7c478bd9Sstevel@tonic-gate 	if (!addmip) {
1181*7c478bd9Sstevel@tonic-gate 	    if ((uap->flags & MS_GLOBAL) == 0 &&
1182*7c478bd9Sstevel@tonic-gate 		lookupname(uap->spec, fromspace, FOLLOW, NULL, &bvp) == 0) {
1183*7c478bd9Sstevel@tonic-gate 			addmip = 1;
1184*7c478bd9Sstevel@tonic-gate 		}
1185*7c478bd9Sstevel@tonic-gate 	}
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate 	if (addmip) {
1188*7c478bd9Sstevel@tonic-gate 		bdev = bvp->v_rdev;
1189*7c478bd9Sstevel@tonic-gate 		VN_RELE(bvp);
1190*7c478bd9Sstevel@tonic-gate 		vfs_addmip(bdev, vfsp);
1191*7c478bd9Sstevel@tonic-gate 		addmip = 0;
1192*7c478bd9Sstevel@tonic-gate 		delmip = 1;
1193*7c478bd9Sstevel@tonic-gate 	}
1194*7c478bd9Sstevel@tonic-gate 	/*
1195*7c478bd9Sstevel@tonic-gate 	 * Invalidate cached entry for the mount point.
1196*7c478bd9Sstevel@tonic-gate 	 */
1197*7c478bd9Sstevel@tonic-gate 	if (splice)
1198*7c478bd9Sstevel@tonic-gate 		dnlc_purge_vp(vp);
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate 	/*
1201*7c478bd9Sstevel@tonic-gate 	 * If have an option string but the filesystem doesn't supply a
1202*7c478bd9Sstevel@tonic-gate 	 * prototype options table, create a table with the global
1203*7c478bd9Sstevel@tonic-gate 	 * options and sufficient room to accept all the options in the
1204*7c478bd9Sstevel@tonic-gate 	 * string.  Then parse the passed in option string
1205*7c478bd9Sstevel@tonic-gate 	 * accepting all the options in the string.  This gives us an
1206*7c478bd9Sstevel@tonic-gate 	 * option table with all the proper cancel properties for the
1207*7c478bd9Sstevel@tonic-gate 	 * global options.
1208*7c478bd9Sstevel@tonic-gate 	 *
1209*7c478bd9Sstevel@tonic-gate 	 * Filesystems that supply a prototype options table are handled
1210*7c478bd9Sstevel@tonic-gate 	 * earlier in this function.
1211*7c478bd9Sstevel@tonic-gate 	 */
1212*7c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_OPTIONSTR) {
1213*7c478bd9Sstevel@tonic-gate 		if (!(vswp->vsw_flag & VSW_HASPROTO)) {
1214*7c478bd9Sstevel@tonic-gate 			mntopts_t tmp_mntopts;
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 			tmp_mntopts.mo_count = 0;
1217*7c478bd9Sstevel@tonic-gate 			vfs_createopttbl_extend(&tmp_mntopts, inargs,
1218*7c478bd9Sstevel@tonic-gate 			    &mnt_mntopts);
1219*7c478bd9Sstevel@tonic-gate 			vfs_parsemntopts(&tmp_mntopts, inargs, 1);
1220*7c478bd9Sstevel@tonic-gate 			vfs_swapopttbl_nolock(&mnt_mntopts, &tmp_mntopts);
1221*7c478bd9Sstevel@tonic-gate 			vfs_freeopttbl(&tmp_mntopts);
1222*7c478bd9Sstevel@tonic-gate 		}
1223*7c478bd9Sstevel@tonic-gate 	}
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 	/*
1226*7c478bd9Sstevel@tonic-gate 	 * Serialize with zone creations.
1227*7c478bd9Sstevel@tonic-gate 	 */
1228*7c478bd9Sstevel@tonic-gate 	mount_in_progress();
1229*7c478bd9Sstevel@tonic-gate 	/*
1230*7c478bd9Sstevel@tonic-gate 	 * Instantiate (or reinstantiate) the file system.  If appropriate,
1231*7c478bd9Sstevel@tonic-gate 	 * splice it into the file system name space.
1232*7c478bd9Sstevel@tonic-gate 	 *
1233*7c478bd9Sstevel@tonic-gate 	 * We want VFS_MOUNT() to be able to override the vfs_resource
1234*7c478bd9Sstevel@tonic-gate 	 * string if necessary (ie, mntfs), and also for a remount to
1235*7c478bd9Sstevel@tonic-gate 	 * change the same (necessary when remounting '/' during boot).
1236*7c478bd9Sstevel@tonic-gate 	 * So we set up vfs_mntpt and vfs_resource to what we think they
1237*7c478bd9Sstevel@tonic-gate 	 * should be, then hand off control to VFS_MOUNT() which can
1238*7c478bd9Sstevel@tonic-gate 	 * override this.
1239*7c478bd9Sstevel@tonic-gate 	 *
1240*7c478bd9Sstevel@tonic-gate 	 * For safety's sake, when changing vfs_resource or vfs_mntpt of
1241*7c478bd9Sstevel@tonic-gate 	 * a vfs which is on the vfs list (i.e. during a remount), we must
1242*7c478bd9Sstevel@tonic-gate 	 * never set those fields to NULL. Several bits of code make
1243*7c478bd9Sstevel@tonic-gate 	 * assumptions that the fields are always valid.
1244*7c478bd9Sstevel@tonic-gate 	 */
1245*7c478bd9Sstevel@tonic-gate 	vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
1246*7c478bd9Sstevel@tonic-gate 	if (remount) {
1247*7c478bd9Sstevel@tonic-gate 		if ((oldresource = vfsp->vfs_resource) != NULL)
1248*7c478bd9Sstevel@tonic-gate 			refstr_hold(oldresource);
1249*7c478bd9Sstevel@tonic-gate 		if ((oldmntpt = vfsp->vfs_mntpt) != NULL)
1250*7c478bd9Sstevel@tonic-gate 			refstr_hold(oldmntpt);
1251*7c478bd9Sstevel@tonic-gate 	}
1252*7c478bd9Sstevel@tonic-gate 	vfs_setresource(vfsp, resource);
1253*7c478bd9Sstevel@tonic-gate 	vfs_setmntpoint(vfsp, mountpt);
1254*7c478bd9Sstevel@tonic-gate 
1255*7c478bd9Sstevel@tonic-gate 	error = VFS_MOUNT(vfsp, vp, uap, credp);
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_RDONLY)
1258*7c478bd9Sstevel@tonic-gate 		vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
1259*7c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_NOSUID)
1260*7c478bd9Sstevel@tonic-gate 		vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
1261*7c478bd9Sstevel@tonic-gate 	if (uap->flags & MS_GLOBAL)
1262*7c478bd9Sstevel@tonic-gate 		vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 	if (error) {
1265*7c478bd9Sstevel@tonic-gate 		if (remount) {
1266*7c478bd9Sstevel@tonic-gate 			/* put back pre-remount options */
1267*7c478bd9Sstevel@tonic-gate 			vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
1268*7c478bd9Sstevel@tonic-gate 			vfs_setmntpoint(vfsp, refstr_value(oldmntpt));
1269*7c478bd9Sstevel@tonic-gate 			if (oldmntpt)
1270*7c478bd9Sstevel@tonic-gate 				refstr_rele(oldmntpt);
1271*7c478bd9Sstevel@tonic-gate 			vfs_setresource(vfsp, refstr_value(oldresource));
1272*7c478bd9Sstevel@tonic-gate 			if (oldresource)
1273*7c478bd9Sstevel@tonic-gate 				refstr_rele(oldresource);
1274*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag = ovflags;
1275*7c478bd9Sstevel@tonic-gate 			vfs_unlock(vfsp);
1276*7c478bd9Sstevel@tonic-gate 			VFS_RELE(vfsp);
1277*7c478bd9Sstevel@tonic-gate 		} else {
1278*7c478bd9Sstevel@tonic-gate 			vfs_unlock(vfsp);
1279*7c478bd9Sstevel@tonic-gate 			vfs_freemnttab(vfsp);
1280*7c478bd9Sstevel@tonic-gate 			kmem_free(vfsp, sizeof (struct vfs));
1281*7c478bd9Sstevel@tonic-gate 		}
1282*7c478bd9Sstevel@tonic-gate 	} else {
1283*7c478bd9Sstevel@tonic-gate 		/*
1284*7c478bd9Sstevel@tonic-gate 		 * Set the mount time to now
1285*7c478bd9Sstevel@tonic-gate 		 */
1286*7c478bd9Sstevel@tonic-gate 		vfsp->vfs_mtime = ddi_get_time();
1287*7c478bd9Sstevel@tonic-gate 		if (remount) {
1288*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag &= ~VFS_REMOUNT;
1289*7c478bd9Sstevel@tonic-gate 			if (oldresource)
1290*7c478bd9Sstevel@tonic-gate 				refstr_rele(oldresource);
1291*7c478bd9Sstevel@tonic-gate 			if (oldmntpt)
1292*7c478bd9Sstevel@tonic-gate 				refstr_rele(oldmntpt);
1293*7c478bd9Sstevel@tonic-gate 		} else if (splice) {
1294*7c478bd9Sstevel@tonic-gate 			/*
1295*7c478bd9Sstevel@tonic-gate 			 * Link vfsp into the name space at the mount
1296*7c478bd9Sstevel@tonic-gate 			 * point. Vfs_add() is responsible for
1297*7c478bd9Sstevel@tonic-gate 			 * holding the mount point which will be
1298*7c478bd9Sstevel@tonic-gate 			 * released when vfs_remove() is called.
1299*7c478bd9Sstevel@tonic-gate 			 */
1300*7c478bd9Sstevel@tonic-gate 			vfs_add(vp, vfsp, uap->flags);
1301*7c478bd9Sstevel@tonic-gate 		} else {
1302*7c478bd9Sstevel@tonic-gate 			/*
1303*7c478bd9Sstevel@tonic-gate 			 * Hold the reference to file system which is
1304*7c478bd9Sstevel@tonic-gate 			 * not linked into the name space.
1305*7c478bd9Sstevel@tonic-gate 			 */
1306*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_zone = NULL;
1307*7c478bd9Sstevel@tonic-gate 			VFS_HOLD(vfsp);
1308*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_vnodecovered = NULL;
1309*7c478bd9Sstevel@tonic-gate 		}
1310*7c478bd9Sstevel@tonic-gate 		/*
1311*7c478bd9Sstevel@tonic-gate 		 * Set flags for global options encountered
1312*7c478bd9Sstevel@tonic-gate 		 */
1313*7c478bd9Sstevel@tonic-gate 		if (vfs_optionisset(vfsp, MNTOPT_RO, NULL))
1314*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag |= VFS_RDONLY;
1315*7c478bd9Sstevel@tonic-gate 		else
1316*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag &= ~VFS_RDONLY;
1317*7c478bd9Sstevel@tonic-gate 		if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) {
1318*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
1319*7c478bd9Sstevel@tonic-gate 		} else {
1320*7c478bd9Sstevel@tonic-gate 			if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL))
1321*7c478bd9Sstevel@tonic-gate 				vfsp->vfs_flag |= VFS_NODEVICES;
1322*7c478bd9Sstevel@tonic-gate 			else
1323*7c478bd9Sstevel@tonic-gate 				vfsp->vfs_flag &= ~VFS_NODEVICES;
1324*7c478bd9Sstevel@tonic-gate 			if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))
1325*7c478bd9Sstevel@tonic-gate 				vfsp->vfs_flag |= VFS_NOSETUID;
1326*7c478bd9Sstevel@tonic-gate 			else
1327*7c478bd9Sstevel@tonic-gate 				vfsp->vfs_flag &= ~VFS_NOSETUID;
1328*7c478bd9Sstevel@tonic-gate 		}
1329*7c478bd9Sstevel@tonic-gate 		if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL))
1330*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag |= VFS_NBMAND;
1331*7c478bd9Sstevel@tonic-gate 		else
1332*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag &= ~VFS_NBMAND;
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 		if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL))
1335*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag |= VFS_XATTR;
1336*7c478bd9Sstevel@tonic-gate 		else
1337*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag &= ~VFS_XATTR;
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 		if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL))
1340*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag |= VFS_NOEXEC;
1341*7c478bd9Sstevel@tonic-gate 		else
1342*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_flag &= ~VFS_NOEXEC;
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 		/*
1345*7c478bd9Sstevel@tonic-gate 		 * Now construct the output option string of options
1346*7c478bd9Sstevel@tonic-gate 		 * we recognized.
1347*7c478bd9Sstevel@tonic-gate 		 */
1348*7c478bd9Sstevel@tonic-gate 		if (uap->flags & MS_OPTIONSTR) {
1349*7c478bd9Sstevel@tonic-gate 			vfs_list_read_lock();
1350*7c478bd9Sstevel@tonic-gate 			copyout_error = vfs_buildoptionstr(
1351*7c478bd9Sstevel@tonic-gate 				&vfsp->vfs_mntopts, inargs, optlen);
1352*7c478bd9Sstevel@tonic-gate 			vfs_list_unlock();
1353*7c478bd9Sstevel@tonic-gate 			if (copyout_error == 0 &&
1354*7c478bd9Sstevel@tonic-gate 			    (uap->flags & MS_SYSSPACE) == 0) {
1355*7c478bd9Sstevel@tonic-gate 				copyout_error = copyoutstr(inargs, opts,
1356*7c478bd9Sstevel@tonic-gate 				    optlen, NULL);
1357*7c478bd9Sstevel@tonic-gate 			}
1358*7c478bd9Sstevel@tonic-gate 		}
1359*7c478bd9Sstevel@tonic-gate 		vfs_unlock(vfsp);
1360*7c478bd9Sstevel@tonic-gate 	}
1361*7c478bd9Sstevel@tonic-gate 	mount_completed();
1362*7c478bd9Sstevel@tonic-gate 	if (splice)
1363*7c478bd9Sstevel@tonic-gate 		vn_vfsunlock(vp);
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate 	/*
1366*7c478bd9Sstevel@tonic-gate 	 * Return vfsp to caller.
1367*7c478bd9Sstevel@tonic-gate 	 */
1368*7c478bd9Sstevel@tonic-gate 	if ((error == 0) && (copyout_error == 0)) {
1369*7c478bd9Sstevel@tonic-gate 		*vfspp = vfsp;
1370*7c478bd9Sstevel@tonic-gate 	}
1371*7c478bd9Sstevel@tonic-gate errout:
1372*7c478bd9Sstevel@tonic-gate 	vfs_freeopttbl(&mnt_mntopts);
1373*7c478bd9Sstevel@tonic-gate 	if (resource != NULL)
1374*7c478bd9Sstevel@tonic-gate 		kmem_free(resource, strlen(resource) + 1);
1375*7c478bd9Sstevel@tonic-gate 	if (mountpt != NULL)
1376*7c478bd9Sstevel@tonic-gate 		kmem_free(mountpt, strlen(mountpt) + 1);
1377*7c478bd9Sstevel@tonic-gate 	/*
1378*7c478bd9Sstevel@tonic-gate 	 * It is possible we errored prior to adding to mount in progress
1379*7c478bd9Sstevel@tonic-gate 	 * table. Must free vnode we acquired with successful lookupname.
1380*7c478bd9Sstevel@tonic-gate 	 */
1381*7c478bd9Sstevel@tonic-gate 	if (addmip)
1382*7c478bd9Sstevel@tonic-gate 		VN_RELE(bvp);
1383*7c478bd9Sstevel@tonic-gate 	if (delmip)
1384*7c478bd9Sstevel@tonic-gate 		vfs_delmip(vfsp);
1385*7c478bd9Sstevel@tonic-gate 	ASSERT(vswp != NULL);
1386*7c478bd9Sstevel@tonic-gate 	vfs_unrefvfssw(vswp);
1387*7c478bd9Sstevel@tonic-gate 	if (inargs != opts)
1388*7c478bd9Sstevel@tonic-gate 		kmem_free(inargs, MAX_MNTOPT_STR);
1389*7c478bd9Sstevel@tonic-gate 	if (copyout_error) {
1390*7c478bd9Sstevel@tonic-gate 		VFS_RELE(vfsp);
1391*7c478bd9Sstevel@tonic-gate 		error = copyout_error;
1392*7c478bd9Sstevel@tonic-gate 	}
1393*7c478bd9Sstevel@tonic-gate 	return (error);
1394*7c478bd9Sstevel@tonic-gate }
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate static void
1397*7c478bd9Sstevel@tonic-gate vfs_setpath(struct vfs *vfsp, refstr_t **refp, const char *newpath)
1398*7c478bd9Sstevel@tonic-gate {
1399*7c478bd9Sstevel@tonic-gate 	size_t len;
1400*7c478bd9Sstevel@tonic-gate 	refstr_t *ref;
1401*7c478bd9Sstevel@tonic-gate 	zone_t *zone = curproc->p_zone;
1402*7c478bd9Sstevel@tonic-gate 	char *sp;
1403*7c478bd9Sstevel@tonic-gate 	int have_list_lock = 0;
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate 	ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp));
1406*7c478bd9Sstevel@tonic-gate 
1407*7c478bd9Sstevel@tonic-gate 	/*
1408*7c478bd9Sstevel@tonic-gate 	 * New path must be less than MAXPATHLEN because mntfs
1409*7c478bd9Sstevel@tonic-gate 	 * will only display up to MAXPATHLEN bytes. This is currently
1410*7c478bd9Sstevel@tonic-gate 	 * safe, because domount() uses pn_get(), and other callers
1411*7c478bd9Sstevel@tonic-gate 	 * similarly cap the size to fewer than MAXPATHLEN bytes.
1412*7c478bd9Sstevel@tonic-gate 	 */
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate 	ASSERT(strlen(newpath) < MAXPATHLEN);
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 	/* mntfs requires consistency while vfs list lock is held */
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate 	if (VFS_ON_LIST(vfsp)) {
1419*7c478bd9Sstevel@tonic-gate 		have_list_lock = 1;
1420*7c478bd9Sstevel@tonic-gate 		vfs_list_lock();
1421*7c478bd9Sstevel@tonic-gate 	}
1422*7c478bd9Sstevel@tonic-gate 
1423*7c478bd9Sstevel@tonic-gate 	if (*refp != NULL)
1424*7c478bd9Sstevel@tonic-gate 		refstr_rele(*refp);
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 	/* Do we need to modify the path? */
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate 	if (zone == global_zone || *newpath != '/') {
1429*7c478bd9Sstevel@tonic-gate 		ref = refstr_alloc(newpath);
1430*7c478bd9Sstevel@tonic-gate 		goto out;
1431*7c478bd9Sstevel@tonic-gate 	}
1432*7c478bd9Sstevel@tonic-gate 
1433*7c478bd9Sstevel@tonic-gate 	/*
1434*7c478bd9Sstevel@tonic-gate 	 * Truncate the trailing '/' in the zoneroot, and merge
1435*7c478bd9Sstevel@tonic-gate 	 * in the zone's rootpath with the "newpath" (resource
1436*7c478bd9Sstevel@tonic-gate 	 * or mountpoint) passed in.
1437*7c478bd9Sstevel@tonic-gate 	 *
1438*7c478bd9Sstevel@tonic-gate 	 * The size of the required buffer is thus the size of
1439*7c478bd9Sstevel@tonic-gate 	 * the buffer required for the passed-in newpath
1440*7c478bd9Sstevel@tonic-gate 	 * (strlen(newpath) + 1), plus the size of the buffer
1441*7c478bd9Sstevel@tonic-gate 	 * required to hold zone_rootpath (zone_rootpathlen)
1442*7c478bd9Sstevel@tonic-gate 	 * minus one for one of the now-superfluous NUL
1443*7c478bd9Sstevel@tonic-gate 	 * terminations, minus one for the trailing '/'.
1444*7c478bd9Sstevel@tonic-gate 	 *
1445*7c478bd9Sstevel@tonic-gate 	 * That gives us:
1446*7c478bd9Sstevel@tonic-gate 	 *
1447*7c478bd9Sstevel@tonic-gate 	 * (strlen(newpath) + 1) + zone_rootpathlen - 1 - 1
1448*7c478bd9Sstevel@tonic-gate 	 *
1449*7c478bd9Sstevel@tonic-gate 	 * Which is what we have below.
1450*7c478bd9Sstevel@tonic-gate 	 */
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 	len = strlen(newpath) + zone->zone_rootpathlen - 1;
1453*7c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(len, KM_SLEEP);
1454*7c478bd9Sstevel@tonic-gate 
1455*7c478bd9Sstevel@tonic-gate 	/*
1456*7c478bd9Sstevel@tonic-gate 	 * Copy everything including the trailing slash, which
1457*7c478bd9Sstevel@tonic-gate 	 * we then overwrite with the NUL character.
1458*7c478bd9Sstevel@tonic-gate 	 */
1459*7c478bd9Sstevel@tonic-gate 
1460*7c478bd9Sstevel@tonic-gate 	(void) strcpy(sp, zone->zone_rootpath);
1461*7c478bd9Sstevel@tonic-gate 	sp[zone->zone_rootpathlen - 2] = '\0';
1462*7c478bd9Sstevel@tonic-gate 	(void) strcat(sp, newpath);
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate 	ref = refstr_alloc(sp);
1465*7c478bd9Sstevel@tonic-gate 	kmem_free(sp, len);
1466*7c478bd9Sstevel@tonic-gate out:
1467*7c478bd9Sstevel@tonic-gate 	*refp = ref;
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate 	if (have_list_lock) {
1470*7c478bd9Sstevel@tonic-gate 		vfs_mnttab_modtimeupd();
1471*7c478bd9Sstevel@tonic-gate 		vfs_list_unlock();
1472*7c478bd9Sstevel@tonic-gate 	}
1473*7c478bd9Sstevel@tonic-gate }
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate /*
1476*7c478bd9Sstevel@tonic-gate  * Record a mounted resource name in a vfs structure.
1477*7c478bd9Sstevel@tonic-gate  * If vfsp is already mounted, caller must hold the vfs lock.
1478*7c478bd9Sstevel@tonic-gate  */
1479*7c478bd9Sstevel@tonic-gate void
1480*7c478bd9Sstevel@tonic-gate vfs_setresource(struct vfs *vfsp, const char *resource)
1481*7c478bd9Sstevel@tonic-gate {
1482*7c478bd9Sstevel@tonic-gate 	if (resource == NULL || resource[0] == '\0')
1483*7c478bd9Sstevel@tonic-gate 		resource = VFS_NORESOURCE;
1484*7c478bd9Sstevel@tonic-gate 	vfs_setpath(vfsp, &vfsp->vfs_resource, resource);
1485*7c478bd9Sstevel@tonic-gate }
1486*7c478bd9Sstevel@tonic-gate 
1487*7c478bd9Sstevel@tonic-gate /*
1488*7c478bd9Sstevel@tonic-gate  * Record a mount point name in a vfs structure.
1489*7c478bd9Sstevel@tonic-gate  * If vfsp is already mounted, caller must hold the vfs lock.
1490*7c478bd9Sstevel@tonic-gate  */
1491*7c478bd9Sstevel@tonic-gate void
1492*7c478bd9Sstevel@tonic-gate vfs_setmntpoint(struct vfs *vfsp, const char *mntpt)
1493*7c478bd9Sstevel@tonic-gate {
1494*7c478bd9Sstevel@tonic-gate 	if (mntpt == NULL || mntpt[0] == '\0')
1495*7c478bd9Sstevel@tonic-gate 		mntpt = VFS_NOMNTPT;
1496*7c478bd9Sstevel@tonic-gate 	vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt);
1497*7c478bd9Sstevel@tonic-gate }
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate /* Returns the vfs_resource. Caller must call refstr_rele() when finished. */
1500*7c478bd9Sstevel@tonic-gate 
1501*7c478bd9Sstevel@tonic-gate refstr_t *
1502*7c478bd9Sstevel@tonic-gate vfs_getresource(const struct vfs *vfsp)
1503*7c478bd9Sstevel@tonic-gate {
1504*7c478bd9Sstevel@tonic-gate 	refstr_t *resource;
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 	vfs_list_read_lock();
1507*7c478bd9Sstevel@tonic-gate 	resource = vfsp->vfs_resource;
1508*7c478bd9Sstevel@tonic-gate 	refstr_hold(resource);
1509*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 	return (resource);
1512*7c478bd9Sstevel@tonic-gate }
1513*7c478bd9Sstevel@tonic-gate 
1514*7c478bd9Sstevel@tonic-gate /* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate refstr_t *
1517*7c478bd9Sstevel@tonic-gate vfs_getmntpoint(const struct vfs *vfsp)
1518*7c478bd9Sstevel@tonic-gate {
1519*7c478bd9Sstevel@tonic-gate 	refstr_t *mntpt;
1520*7c478bd9Sstevel@tonic-gate 
1521*7c478bd9Sstevel@tonic-gate 	vfs_list_read_lock();
1522*7c478bd9Sstevel@tonic-gate 	mntpt = vfsp->vfs_mntpt;
1523*7c478bd9Sstevel@tonic-gate 	refstr_hold(mntpt);
1524*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 	return (mntpt);
1527*7c478bd9Sstevel@tonic-gate }
1528*7c478bd9Sstevel@tonic-gate 
1529*7c478bd9Sstevel@tonic-gate /*
1530*7c478bd9Sstevel@tonic-gate  * Create an empty options table with enough empty slots to hold all
1531*7c478bd9Sstevel@tonic-gate  * The options in the options string passed as an argument.
1532*7c478bd9Sstevel@tonic-gate  * Potentially prepend another options table.
1533*7c478bd9Sstevel@tonic-gate  *
1534*7c478bd9Sstevel@tonic-gate  * Note: caller is responsible for locking the vfs list, if needed,
1535*7c478bd9Sstevel@tonic-gate  *       to protect mops.
1536*7c478bd9Sstevel@tonic-gate  */
1537*7c478bd9Sstevel@tonic-gate static void
1538*7c478bd9Sstevel@tonic-gate vfs_createopttbl_extend(mntopts_t *mops, const char *opts,
1539*7c478bd9Sstevel@tonic-gate     const mntopts_t *mtmpl)
1540*7c478bd9Sstevel@tonic-gate {
1541*7c478bd9Sstevel@tonic-gate 	const char *s = opts;
1542*7c478bd9Sstevel@tonic-gate 	uint_t count;
1543*7c478bd9Sstevel@tonic-gate 
1544*7c478bd9Sstevel@tonic-gate 	if (opts == NULL || *opts == '\0') {
1545*7c478bd9Sstevel@tonic-gate 		count = 0;
1546*7c478bd9Sstevel@tonic-gate 	} else {
1547*7c478bd9Sstevel@tonic-gate 		count = 1;
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 		/*
1550*7c478bd9Sstevel@tonic-gate 		 * Count number of options in the string
1551*7c478bd9Sstevel@tonic-gate 		 */
1552*7c478bd9Sstevel@tonic-gate 		for (s = strchr(s, ','); s != NULL; s = strchr(s, ',')) {
1553*7c478bd9Sstevel@tonic-gate 			count++;
1554*7c478bd9Sstevel@tonic-gate 			s++;
1555*7c478bd9Sstevel@tonic-gate 		}
1556*7c478bd9Sstevel@tonic-gate 	}
1557*7c478bd9Sstevel@tonic-gate 	vfs_copyopttbl_extend(mtmpl, mops, count);
1558*7c478bd9Sstevel@tonic-gate }
1559*7c478bd9Sstevel@tonic-gate 
1560*7c478bd9Sstevel@tonic-gate /*
1561*7c478bd9Sstevel@tonic-gate  * Create an empty options table with enough empty slots to hold all
1562*7c478bd9Sstevel@tonic-gate  * The options in the options string passed as an argument.
1563*7c478bd9Sstevel@tonic-gate  *
1564*7c478bd9Sstevel@tonic-gate  * This function is *not* for general use by filesystems.
1565*7c478bd9Sstevel@tonic-gate  *
1566*7c478bd9Sstevel@tonic-gate  * Note: caller is responsible for locking the vfs list, if needed,
1567*7c478bd9Sstevel@tonic-gate  *       to protect mops.
1568*7c478bd9Sstevel@tonic-gate  */
1569*7c478bd9Sstevel@tonic-gate void
1570*7c478bd9Sstevel@tonic-gate vfs_createopttbl(mntopts_t *mops, const char *opts)
1571*7c478bd9Sstevel@tonic-gate {
1572*7c478bd9Sstevel@tonic-gate 	vfs_createopttbl_extend(mops, opts, NULL);
1573*7c478bd9Sstevel@tonic-gate }
1574*7c478bd9Sstevel@tonic-gate 
1575*7c478bd9Sstevel@tonic-gate 
1576*7c478bd9Sstevel@tonic-gate /*
1577*7c478bd9Sstevel@tonic-gate  * Swap two mount options tables
1578*7c478bd9Sstevel@tonic-gate  */
1579*7c478bd9Sstevel@tonic-gate static void
1580*7c478bd9Sstevel@tonic-gate vfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2)
1581*7c478bd9Sstevel@tonic-gate {
1582*7c478bd9Sstevel@tonic-gate 	uint_t tmpcnt;
1583*7c478bd9Sstevel@tonic-gate 	mntopt_t *tmplist;
1584*7c478bd9Sstevel@tonic-gate 
1585*7c478bd9Sstevel@tonic-gate 	tmpcnt = optbl2->mo_count;
1586*7c478bd9Sstevel@tonic-gate 	tmplist = optbl2->mo_list;
1587*7c478bd9Sstevel@tonic-gate 	optbl2->mo_count = optbl1->mo_count;
1588*7c478bd9Sstevel@tonic-gate 	optbl2->mo_list = optbl1->mo_list;
1589*7c478bd9Sstevel@tonic-gate 	optbl1->mo_count = tmpcnt;
1590*7c478bd9Sstevel@tonic-gate 	optbl1->mo_list = tmplist;
1591*7c478bd9Sstevel@tonic-gate }
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate static void
1594*7c478bd9Sstevel@tonic-gate vfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2)
1595*7c478bd9Sstevel@tonic-gate {
1596*7c478bd9Sstevel@tonic-gate 	vfs_list_lock();
1597*7c478bd9Sstevel@tonic-gate 	vfs_swapopttbl_nolock(optbl1, optbl2);
1598*7c478bd9Sstevel@tonic-gate 	vfs_mnttab_modtimeupd();
1599*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
1600*7c478bd9Sstevel@tonic-gate }
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate static char **
1603*7c478bd9Sstevel@tonic-gate vfs_copycancelopt_extend(char **const moc, int extend)
1604*7c478bd9Sstevel@tonic-gate {
1605*7c478bd9Sstevel@tonic-gate 	int i = 0;
1606*7c478bd9Sstevel@tonic-gate 	int j;
1607*7c478bd9Sstevel@tonic-gate 	char **result;
1608*7c478bd9Sstevel@tonic-gate 
1609*7c478bd9Sstevel@tonic-gate 	if (moc != NULL) {
1610*7c478bd9Sstevel@tonic-gate 		for (; moc[i] != NULL; i++)
1611*7c478bd9Sstevel@tonic-gate 			/* count number of options to cancel */;
1612*7c478bd9Sstevel@tonic-gate 	}
1613*7c478bd9Sstevel@tonic-gate 
1614*7c478bd9Sstevel@tonic-gate 	if (i + extend == 0)
1615*7c478bd9Sstevel@tonic-gate 		return (NULL);
1616*7c478bd9Sstevel@tonic-gate 
1617*7c478bd9Sstevel@tonic-gate 	result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP);
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate 	for (j = 0; j < i; j++) {
1620*7c478bd9Sstevel@tonic-gate 		result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP);
1621*7c478bd9Sstevel@tonic-gate 		(void) strcpy(result[j], moc[j]);
1622*7c478bd9Sstevel@tonic-gate 	}
1623*7c478bd9Sstevel@tonic-gate 	for (; j <= i + extend; j++)
1624*7c478bd9Sstevel@tonic-gate 		result[j] = NULL;
1625*7c478bd9Sstevel@tonic-gate 
1626*7c478bd9Sstevel@tonic-gate 	return (result);
1627*7c478bd9Sstevel@tonic-gate }
1628*7c478bd9Sstevel@tonic-gate 
1629*7c478bd9Sstevel@tonic-gate static void
1630*7c478bd9Sstevel@tonic-gate vfs_copyopt(const mntopt_t *s, mntopt_t *d)
1631*7c478bd9Sstevel@tonic-gate {
1632*7c478bd9Sstevel@tonic-gate 	char *sp, *dp;
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate 	d->mo_flags = s->mo_flags;
1635*7c478bd9Sstevel@tonic-gate 	d->mo_data = s->mo_data;
1636*7c478bd9Sstevel@tonic-gate 	sp = s->mo_name;
1637*7c478bd9Sstevel@tonic-gate 	if (sp != NULL) {
1638*7c478bd9Sstevel@tonic-gate 		dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
1639*7c478bd9Sstevel@tonic-gate 		(void) strcpy(dp, sp);
1640*7c478bd9Sstevel@tonic-gate 		d->mo_name = dp;
1641*7c478bd9Sstevel@tonic-gate 	} else {
1642*7c478bd9Sstevel@tonic-gate 		d->mo_name = NULL; /* should never happen */
1643*7c478bd9Sstevel@tonic-gate 	}
1644*7c478bd9Sstevel@tonic-gate 
1645*7c478bd9Sstevel@tonic-gate 	d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0);
1646*7c478bd9Sstevel@tonic-gate 
1647*7c478bd9Sstevel@tonic-gate 	sp = s->mo_arg;
1648*7c478bd9Sstevel@tonic-gate 	if (sp != NULL) {
1649*7c478bd9Sstevel@tonic-gate 		dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
1650*7c478bd9Sstevel@tonic-gate 		(void) strcpy(dp, sp);
1651*7c478bd9Sstevel@tonic-gate 		d->mo_arg = dp;
1652*7c478bd9Sstevel@tonic-gate 	} else {
1653*7c478bd9Sstevel@tonic-gate 		d->mo_arg = NULL;
1654*7c478bd9Sstevel@tonic-gate 	}
1655*7c478bd9Sstevel@tonic-gate }
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate /*
1658*7c478bd9Sstevel@tonic-gate  * Copy a mount options table, possibly allocating some spare
1659*7c478bd9Sstevel@tonic-gate  * slots at the end.  It is permissible to copy_extend the NULL table.
1660*7c478bd9Sstevel@tonic-gate  */
1661*7c478bd9Sstevel@tonic-gate static void
1662*7c478bd9Sstevel@tonic-gate vfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra)
1663*7c478bd9Sstevel@tonic-gate {
1664*7c478bd9Sstevel@tonic-gate 	uint_t i, count;
1665*7c478bd9Sstevel@tonic-gate 	mntopt_t *motbl;
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate 	/*
1668*7c478bd9Sstevel@tonic-gate 	 * Clear out any existing stuff in the options table being initialized
1669*7c478bd9Sstevel@tonic-gate 	 */
1670*7c478bd9Sstevel@tonic-gate 	vfs_freeopttbl(dmo);
1671*7c478bd9Sstevel@tonic-gate 	count = (smo == NULL) ? 0 : smo->mo_count;
1672*7c478bd9Sstevel@tonic-gate 	if ((count + extra) == 0)	/* nothing to do */
1673*7c478bd9Sstevel@tonic-gate 		return;
1674*7c478bd9Sstevel@tonic-gate 	dmo->mo_count = count + extra;
1675*7c478bd9Sstevel@tonic-gate 	motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP);
1676*7c478bd9Sstevel@tonic-gate 	dmo->mo_list = motbl;
1677*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
1678*7c478bd9Sstevel@tonic-gate 		vfs_copyopt(&smo->mo_list[i], &motbl[i]);
1679*7c478bd9Sstevel@tonic-gate 	}
1680*7c478bd9Sstevel@tonic-gate 	for (i = count; i < count + extra; i++) {
1681*7c478bd9Sstevel@tonic-gate 		motbl[i].mo_flags = MO_EMPTY;
1682*7c478bd9Sstevel@tonic-gate 	}
1683*7c478bd9Sstevel@tonic-gate }
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate /*
1686*7c478bd9Sstevel@tonic-gate  * Copy a mount options table.
1687*7c478bd9Sstevel@tonic-gate  *
1688*7c478bd9Sstevel@tonic-gate  * This function is *not* for general use by filesystems.
1689*7c478bd9Sstevel@tonic-gate  *
1690*7c478bd9Sstevel@tonic-gate  * Note: caller is responsible for locking the vfs list, if needed,
1691*7c478bd9Sstevel@tonic-gate  *       to protect smo and dmo.
1692*7c478bd9Sstevel@tonic-gate  */
1693*7c478bd9Sstevel@tonic-gate void
1694*7c478bd9Sstevel@tonic-gate vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo)
1695*7c478bd9Sstevel@tonic-gate {
1696*7c478bd9Sstevel@tonic-gate 	vfs_copyopttbl_extend(smo, dmo, 0);
1697*7c478bd9Sstevel@tonic-gate }
1698*7c478bd9Sstevel@tonic-gate 
1699*7c478bd9Sstevel@tonic-gate static char **
1700*7c478bd9Sstevel@tonic-gate vfs_mergecancelopts(const mntopt_t *mop1, const mntopt_t *mop2)
1701*7c478bd9Sstevel@tonic-gate {
1702*7c478bd9Sstevel@tonic-gate 	int c1 = 0;
1703*7c478bd9Sstevel@tonic-gate 	int c2 = 0;
1704*7c478bd9Sstevel@tonic-gate 	char **result;
1705*7c478bd9Sstevel@tonic-gate 	char **sp1, **sp2, **dp;
1706*7c478bd9Sstevel@tonic-gate 
1707*7c478bd9Sstevel@tonic-gate 	/*
1708*7c478bd9Sstevel@tonic-gate 	 * First we count both lists of cancel options.
1709*7c478bd9Sstevel@tonic-gate 	 * If either is NULL or has no elements, we return a copy of
1710*7c478bd9Sstevel@tonic-gate 	 * the other.
1711*7c478bd9Sstevel@tonic-gate 	 */
1712*7c478bd9Sstevel@tonic-gate 	if (mop1->mo_cancel != NULL) {
1713*7c478bd9Sstevel@tonic-gate 		for (; mop1->mo_cancel[c1] != NULL; c1++)
1714*7c478bd9Sstevel@tonic-gate 			/* count cancel options in mop1 */;
1715*7c478bd9Sstevel@tonic-gate 	}
1716*7c478bd9Sstevel@tonic-gate 
1717*7c478bd9Sstevel@tonic-gate 	if (c1 == 0)
1718*7c478bd9Sstevel@tonic-gate 		return (vfs_copycancelopt_extend(mop2->mo_cancel, 0));
1719*7c478bd9Sstevel@tonic-gate 
1720*7c478bd9Sstevel@tonic-gate 	if (mop2->mo_cancel != NULL) {
1721*7c478bd9Sstevel@tonic-gate 		for (; mop2->mo_cancel[c2] != NULL; c2++)
1722*7c478bd9Sstevel@tonic-gate 			/* count cancel options in mop2 */;
1723*7c478bd9Sstevel@tonic-gate 	}
1724*7c478bd9Sstevel@tonic-gate 
1725*7c478bd9Sstevel@tonic-gate 	result = vfs_copycancelopt_extend(mop1->mo_cancel, c2);
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate 	if (c2 == 0)
1728*7c478bd9Sstevel@tonic-gate 		return (result);
1729*7c478bd9Sstevel@tonic-gate 
1730*7c478bd9Sstevel@tonic-gate 	/*
1731*7c478bd9Sstevel@tonic-gate 	 * When we get here, we've got two sets of cancel options;
1732*7c478bd9Sstevel@tonic-gate 	 * we need to merge the two sets.  We know that the result
1733*7c478bd9Sstevel@tonic-gate 	 * array has "c1+c2+1" entries and in the end we might shrink
1734*7c478bd9Sstevel@tonic-gate 	 * it.
1735*7c478bd9Sstevel@tonic-gate 	 * Result now has a copy of the c1 entries from mop1; we'll
1736*7c478bd9Sstevel@tonic-gate 	 * now lookup all the entries of mop2 in mop1 and copy it if
1737*7c478bd9Sstevel@tonic-gate 	 * it is unique.
1738*7c478bd9Sstevel@tonic-gate 	 * This operation is O(n^2) but it's only called once per
1739*7c478bd9Sstevel@tonic-gate 	 * filesystem per duplicate option.  This is a situation
1740*7c478bd9Sstevel@tonic-gate 	 * which doesn't arise with the filesystems in ON and
1741*7c478bd9Sstevel@tonic-gate 	 * n is generally 1.
1742*7c478bd9Sstevel@tonic-gate 	 */
1743*7c478bd9Sstevel@tonic-gate 
1744*7c478bd9Sstevel@tonic-gate 	dp = &result[c1];
1745*7c478bd9Sstevel@tonic-gate 	for (sp2 = mop2->mo_cancel; *sp2 != NULL; sp2++) {
1746*7c478bd9Sstevel@tonic-gate 		for (sp1 = mop1->mo_cancel; *sp1 != NULL; sp1++) {
1747*7c478bd9Sstevel@tonic-gate 			if (strcmp(*sp1, *sp2) == 0)
1748*7c478bd9Sstevel@tonic-gate 				break;
1749*7c478bd9Sstevel@tonic-gate 		}
1750*7c478bd9Sstevel@tonic-gate 		if (*sp1 == NULL) {
1751*7c478bd9Sstevel@tonic-gate 			/*
1752*7c478bd9Sstevel@tonic-gate 			 * Option *sp2 not found in mop1, so copy it.
1753*7c478bd9Sstevel@tonic-gate 			 * The calls to vfs_copycancelopt_extend()
1754*7c478bd9Sstevel@tonic-gate 			 * guarantee that there's enough room.
1755*7c478bd9Sstevel@tonic-gate 			 */
1756*7c478bd9Sstevel@tonic-gate 			*dp = kmem_alloc(strlen(*sp2) + 1, KM_SLEEP);
1757*7c478bd9Sstevel@tonic-gate 			(void) strcpy(*dp++, *sp2);
1758*7c478bd9Sstevel@tonic-gate 		}
1759*7c478bd9Sstevel@tonic-gate 	}
1760*7c478bd9Sstevel@tonic-gate 	if (dp != &result[c1+c2]) {
1761*7c478bd9Sstevel@tonic-gate 		size_t bytes = (dp - result + 1) * sizeof (char *);
1762*7c478bd9Sstevel@tonic-gate 		char **nres = kmem_alloc(bytes, KM_SLEEP);
1763*7c478bd9Sstevel@tonic-gate 
1764*7c478bd9Sstevel@tonic-gate 		bcopy(result, nres, bytes);
1765*7c478bd9Sstevel@tonic-gate 		kmem_free(result, (c1 + c2 + 1) * sizeof (char *));
1766*7c478bd9Sstevel@tonic-gate 		result = nres;
1767*7c478bd9Sstevel@tonic-gate 	}
1768*7c478bd9Sstevel@tonic-gate 	return (result);
1769*7c478bd9Sstevel@tonic-gate }
1770*7c478bd9Sstevel@tonic-gate 
1771*7c478bd9Sstevel@tonic-gate /*
1772*7c478bd9Sstevel@tonic-gate  * Merge two mount option tables (outer and inner) into one.  This is very
1773*7c478bd9Sstevel@tonic-gate  * similar to "merging" global variables and automatic variables in C.
1774*7c478bd9Sstevel@tonic-gate  *
1775*7c478bd9Sstevel@tonic-gate  * This isn't (and doesn't have to be) fast.
1776*7c478bd9Sstevel@tonic-gate  *
1777*7c478bd9Sstevel@tonic-gate  * This function is *not* for general use by filesystems.
1778*7c478bd9Sstevel@tonic-gate  *
1779*7c478bd9Sstevel@tonic-gate  * Note: caller is responsible for locking the vfs list, if needed,
1780*7c478bd9Sstevel@tonic-gate  *       to protect omo, imo & dmo.
1781*7c478bd9Sstevel@tonic-gate  */
1782*7c478bd9Sstevel@tonic-gate void
1783*7c478bd9Sstevel@tonic-gate vfs_mergeopttbl(const mntopts_t *omo, const mntopts_t *imo, mntopts_t *dmo)
1784*7c478bd9Sstevel@tonic-gate {
1785*7c478bd9Sstevel@tonic-gate 	uint_t i, count;
1786*7c478bd9Sstevel@tonic-gate 	mntopt_t *mop, *motbl;
1787*7c478bd9Sstevel@tonic-gate 	uint_t freeidx;
1788*7c478bd9Sstevel@tonic-gate 
1789*7c478bd9Sstevel@tonic-gate 	/*
1790*7c478bd9Sstevel@tonic-gate 	 * First determine how much space we need to allocate.
1791*7c478bd9Sstevel@tonic-gate 	 */
1792*7c478bd9Sstevel@tonic-gate 	count = omo->mo_count;
1793*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < imo->mo_count; i++) {
1794*7c478bd9Sstevel@tonic-gate 		if (imo->mo_list[i].mo_flags & MO_EMPTY)
1795*7c478bd9Sstevel@tonic-gate 			continue;
1796*7c478bd9Sstevel@tonic-gate 		if (vfs_hasopt(omo, imo->mo_list[i].mo_name) == NULL)
1797*7c478bd9Sstevel@tonic-gate 			count++;
1798*7c478bd9Sstevel@tonic-gate 	}
1799*7c478bd9Sstevel@tonic-gate 	ASSERT(count >= omo->mo_count &&
1800*7c478bd9Sstevel@tonic-gate 	    count <= omo->mo_count + imo->mo_count);
1801*7c478bd9Sstevel@tonic-gate 	motbl = kmem_alloc(count * sizeof (mntopt_t), KM_SLEEP);
1802*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < omo->mo_count; i++)
1803*7c478bd9Sstevel@tonic-gate 		vfs_copyopt(&omo->mo_list[i], &motbl[i]);
1804*7c478bd9Sstevel@tonic-gate 	freeidx = omo->mo_count;
1805*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < imo->mo_count; i++) {
1806*7c478bd9Sstevel@tonic-gate 		if (imo->mo_list[i].mo_flags & MO_EMPTY)
1807*7c478bd9Sstevel@tonic-gate 			continue;
1808*7c478bd9Sstevel@tonic-gate 		if ((mop = vfs_hasopt(omo, imo->mo_list[i].mo_name)) != NULL) {
1809*7c478bd9Sstevel@tonic-gate 			char **newcanp;
1810*7c478bd9Sstevel@tonic-gate 			uint_t index = mop - omo->mo_list;
1811*7c478bd9Sstevel@tonic-gate 
1812*7c478bd9Sstevel@tonic-gate 			newcanp = vfs_mergecancelopts(mop, &motbl[index]);
1813*7c478bd9Sstevel@tonic-gate 
1814*7c478bd9Sstevel@tonic-gate 			vfs_freeopt(&motbl[index]);
1815*7c478bd9Sstevel@tonic-gate 			vfs_copyopt(&imo->mo_list[i], &motbl[index]);
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate 			vfs_freecancelopt(motbl[index].mo_cancel);
1818*7c478bd9Sstevel@tonic-gate 			motbl[index].mo_cancel = newcanp;
1819*7c478bd9Sstevel@tonic-gate 		} else {
1820*7c478bd9Sstevel@tonic-gate 			/*
1821*7c478bd9Sstevel@tonic-gate 			 * If it's a new option, just copy it over to the first
1822*7c478bd9Sstevel@tonic-gate 			 * free location.
1823*7c478bd9Sstevel@tonic-gate 			 */
1824*7c478bd9Sstevel@tonic-gate 			vfs_copyopt(&imo->mo_list[i], &motbl[freeidx++]);
1825*7c478bd9Sstevel@tonic-gate 		}
1826*7c478bd9Sstevel@tonic-gate 	}
1827*7c478bd9Sstevel@tonic-gate 	dmo->mo_count = count;
1828*7c478bd9Sstevel@tonic-gate 	dmo->mo_list = motbl;
1829*7c478bd9Sstevel@tonic-gate }
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate /*
1832*7c478bd9Sstevel@tonic-gate  * Functions to set and clear mount options in a mount options table.
1833*7c478bd9Sstevel@tonic-gate  */
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate /*
1836*7c478bd9Sstevel@tonic-gate  * Clear a mount option, if it exists.
1837*7c478bd9Sstevel@tonic-gate  *
1838*7c478bd9Sstevel@tonic-gate  * The update_mnttab arg indicates whether mops is part of a vfs that is on
1839*7c478bd9Sstevel@tonic-gate  * the vfs list.
1840*7c478bd9Sstevel@tonic-gate  */
1841*7c478bd9Sstevel@tonic-gate static void
1842*7c478bd9Sstevel@tonic-gate vfs_clearmntopt_nolock(mntopts_t *mops, const char *opt, int update_mnttab)
1843*7c478bd9Sstevel@tonic-gate {
1844*7c478bd9Sstevel@tonic-gate 	struct mntopt *mop;
1845*7c478bd9Sstevel@tonic-gate 	uint_t i, count;
1846*7c478bd9Sstevel@tonic-gate 
1847*7c478bd9Sstevel@tonic-gate 	ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
1848*7c478bd9Sstevel@tonic-gate 
1849*7c478bd9Sstevel@tonic-gate 	count = mops->mo_count;
1850*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
1851*7c478bd9Sstevel@tonic-gate 		mop = &mops->mo_list[i];
1852*7c478bd9Sstevel@tonic-gate 
1853*7c478bd9Sstevel@tonic-gate 		if (mop->mo_flags & MO_EMPTY)
1854*7c478bd9Sstevel@tonic-gate 			continue;
1855*7c478bd9Sstevel@tonic-gate 		if (strcmp(opt, mop->mo_name))
1856*7c478bd9Sstevel@tonic-gate 			continue;
1857*7c478bd9Sstevel@tonic-gate 		mop->mo_flags &= ~MO_SET;
1858*7c478bd9Sstevel@tonic-gate 		if (mop->mo_arg != NULL) {
1859*7c478bd9Sstevel@tonic-gate 			kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
1860*7c478bd9Sstevel@tonic-gate 		}
1861*7c478bd9Sstevel@tonic-gate 		mop->mo_arg = NULL;
1862*7c478bd9Sstevel@tonic-gate 		if (update_mnttab)
1863*7c478bd9Sstevel@tonic-gate 			vfs_mnttab_modtimeupd();
1864*7c478bd9Sstevel@tonic-gate 		break;
1865*7c478bd9Sstevel@tonic-gate 	}
1866*7c478bd9Sstevel@tonic-gate }
1867*7c478bd9Sstevel@tonic-gate 
1868*7c478bd9Sstevel@tonic-gate void
1869*7c478bd9Sstevel@tonic-gate vfs_clearmntopt(struct vfs *vfsp, const char *opt)
1870*7c478bd9Sstevel@tonic-gate {
1871*7c478bd9Sstevel@tonic-gate 	int gotlock = 0;
1872*7c478bd9Sstevel@tonic-gate 
1873*7c478bd9Sstevel@tonic-gate 	if (VFS_ON_LIST(vfsp)) {
1874*7c478bd9Sstevel@tonic-gate 		gotlock = 1;
1875*7c478bd9Sstevel@tonic-gate 		vfs_list_lock();
1876*7c478bd9Sstevel@tonic-gate 	}
1877*7c478bd9Sstevel@tonic-gate 	vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, opt, gotlock);
1878*7c478bd9Sstevel@tonic-gate 	if (gotlock)
1879*7c478bd9Sstevel@tonic-gate 		vfs_list_unlock();
1880*7c478bd9Sstevel@tonic-gate }
1881*7c478bd9Sstevel@tonic-gate 
1882*7c478bd9Sstevel@tonic-gate 
1883*7c478bd9Sstevel@tonic-gate /*
1884*7c478bd9Sstevel@tonic-gate  * Set a mount option on.  If it's not found in the table, it's silently
1885*7c478bd9Sstevel@tonic-gate  * ignored.  If the option has MO_IGNORE set, it is still set unless the
1886*7c478bd9Sstevel@tonic-gate  * VFS_NOFORCEOPT bit is set in the flags.  Also, VFS_DISPLAY/VFS_NODISPLAY flag
1887*7c478bd9Sstevel@tonic-gate  * bits can be used to toggle the MO_NODISPLAY bit for the option.
1888*7c478bd9Sstevel@tonic-gate  * If the VFS_CREATEOPT flag bit is set then the first option slot with
1889*7c478bd9Sstevel@tonic-gate  * MO_EMPTY set is created as the option passed in.
1890*7c478bd9Sstevel@tonic-gate  *
1891*7c478bd9Sstevel@tonic-gate  * The update_mnttab arg indicates whether mops is part of a vfs that is on
1892*7c478bd9Sstevel@tonic-gate  * the vfs list.
1893*7c478bd9Sstevel@tonic-gate  */
1894*7c478bd9Sstevel@tonic-gate static void
1895*7c478bd9Sstevel@tonic-gate vfs_setmntopt_nolock(mntopts_t *mops, const char *opt,
1896*7c478bd9Sstevel@tonic-gate     const char *arg, int flags, int update_mnttab)
1897*7c478bd9Sstevel@tonic-gate {
1898*7c478bd9Sstevel@tonic-gate 	mntopt_t *mop;
1899*7c478bd9Sstevel@tonic-gate 	uint_t i, count;
1900*7c478bd9Sstevel@tonic-gate 	char *sp;
1901*7c478bd9Sstevel@tonic-gate 
1902*7c478bd9Sstevel@tonic-gate 	ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
1903*7c478bd9Sstevel@tonic-gate 
1904*7c478bd9Sstevel@tonic-gate 	if (flags & VFS_CREATEOPT) {
1905*7c478bd9Sstevel@tonic-gate 		if (vfs_hasopt(mops, opt) != NULL) {
1906*7c478bd9Sstevel@tonic-gate 			flags &= ~VFS_CREATEOPT;
1907*7c478bd9Sstevel@tonic-gate 		}
1908*7c478bd9Sstevel@tonic-gate 	}
1909*7c478bd9Sstevel@tonic-gate 	count = mops->mo_count;
1910*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
1911*7c478bd9Sstevel@tonic-gate 		mop = &mops->mo_list[i];
1912*7c478bd9Sstevel@tonic-gate 
1913*7c478bd9Sstevel@tonic-gate 		if (mop->mo_flags & MO_EMPTY) {
1914*7c478bd9Sstevel@tonic-gate 			if ((flags & VFS_CREATEOPT) == 0)
1915*7c478bd9Sstevel@tonic-gate 				continue;
1916*7c478bd9Sstevel@tonic-gate 			sp = kmem_alloc(strlen(opt) + 1, KM_SLEEP);
1917*7c478bd9Sstevel@tonic-gate 			(void) strcpy(sp, opt);
1918*7c478bd9Sstevel@tonic-gate 			mop->mo_name = sp;
1919*7c478bd9Sstevel@tonic-gate 			if (arg != NULL)
1920*7c478bd9Sstevel@tonic-gate 				mop->mo_flags = MO_HASVALUE;
1921*7c478bd9Sstevel@tonic-gate 			else
1922*7c478bd9Sstevel@tonic-gate 				mop->mo_flags = 0;
1923*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(opt, mop->mo_name)) {
1924*7c478bd9Sstevel@tonic-gate 			continue;
1925*7c478bd9Sstevel@tonic-gate 		}
1926*7c478bd9Sstevel@tonic-gate 		if ((mop->mo_flags & MO_IGNORE) && (flags & VFS_NOFORCEOPT))
1927*7c478bd9Sstevel@tonic-gate 			break;
1928*7c478bd9Sstevel@tonic-gate 		if (arg != NULL && (mop->mo_flags & MO_HASVALUE) != 0) {
1929*7c478bd9Sstevel@tonic-gate 			sp = kmem_alloc(strlen(arg) + 1, KM_SLEEP);
1930*7c478bd9Sstevel@tonic-gate 			(void) strcpy(sp, arg);
1931*7c478bd9Sstevel@tonic-gate 		} else {
1932*7c478bd9Sstevel@tonic-gate 			sp = NULL;
1933*7c478bd9Sstevel@tonic-gate 		}
1934*7c478bd9Sstevel@tonic-gate 		if (mop->mo_arg != NULL)
1935*7c478bd9Sstevel@tonic-gate 			kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
1936*7c478bd9Sstevel@tonic-gate 		mop->mo_arg = sp;
1937*7c478bd9Sstevel@tonic-gate 		if (flags & VFS_DISPLAY)
1938*7c478bd9Sstevel@tonic-gate 			mop->mo_flags &= ~MO_NODISPLAY;
1939*7c478bd9Sstevel@tonic-gate 		if (flags & VFS_NODISPLAY)
1940*7c478bd9Sstevel@tonic-gate 			mop->mo_flags |= MO_NODISPLAY;
1941*7c478bd9Sstevel@tonic-gate 		mop->mo_flags |= MO_SET;
1942*7c478bd9Sstevel@tonic-gate 		if (mop->mo_cancel != NULL) {
1943*7c478bd9Sstevel@tonic-gate 			char **cp;
1944*7c478bd9Sstevel@tonic-gate 
1945*7c478bd9Sstevel@tonic-gate 			for (cp = mop->mo_cancel; *cp != NULL; cp++)
1946*7c478bd9Sstevel@tonic-gate 				vfs_clearmntopt_nolock(mops, *cp, 0);
1947*7c478bd9Sstevel@tonic-gate 		}
1948*7c478bd9Sstevel@tonic-gate 		if (update_mnttab)
1949*7c478bd9Sstevel@tonic-gate 			vfs_mnttab_modtimeupd();
1950*7c478bd9Sstevel@tonic-gate 		break;
1951*7c478bd9Sstevel@tonic-gate 	}
1952*7c478bd9Sstevel@tonic-gate }
1953*7c478bd9Sstevel@tonic-gate 
1954*7c478bd9Sstevel@tonic-gate void
1955*7c478bd9Sstevel@tonic-gate vfs_setmntopt(struct vfs *vfsp, const char *opt, const char *arg, int flags)
1956*7c478bd9Sstevel@tonic-gate {
1957*7c478bd9Sstevel@tonic-gate 	int gotlock = 0;
1958*7c478bd9Sstevel@tonic-gate 
1959*7c478bd9Sstevel@tonic-gate 	if (VFS_ON_LIST(vfsp)) {
1960*7c478bd9Sstevel@tonic-gate 		gotlock = 1;
1961*7c478bd9Sstevel@tonic-gate 		vfs_list_lock();
1962*7c478bd9Sstevel@tonic-gate 	}
1963*7c478bd9Sstevel@tonic-gate 	vfs_setmntopt_nolock(&vfsp->vfs_mntopts, opt, arg, flags, gotlock);
1964*7c478bd9Sstevel@tonic-gate 	if (gotlock)
1965*7c478bd9Sstevel@tonic-gate 		vfs_list_unlock();
1966*7c478bd9Sstevel@tonic-gate }
1967*7c478bd9Sstevel@tonic-gate 
1968*7c478bd9Sstevel@tonic-gate 
1969*7c478bd9Sstevel@tonic-gate /*
1970*7c478bd9Sstevel@tonic-gate  * Add a "tag" option to a mounted file system's options list.
1971*7c478bd9Sstevel@tonic-gate  *
1972*7c478bd9Sstevel@tonic-gate  * Note: caller is responsible for locking the vfs list, if needed,
1973*7c478bd9Sstevel@tonic-gate  *       to protect mops.
1974*7c478bd9Sstevel@tonic-gate  */
1975*7c478bd9Sstevel@tonic-gate static mntopt_t *
1976*7c478bd9Sstevel@tonic-gate vfs_addtag(mntopts_t *mops, const char *tag)
1977*7c478bd9Sstevel@tonic-gate {
1978*7c478bd9Sstevel@tonic-gate 	uint_t count;
1979*7c478bd9Sstevel@tonic-gate 	mntopt_t *mop, *motbl;
1980*7c478bd9Sstevel@tonic-gate 
1981*7c478bd9Sstevel@tonic-gate 	count = mops->mo_count + 1;
1982*7c478bd9Sstevel@tonic-gate 	motbl = kmem_zalloc(count * sizeof (mntopt_t), KM_SLEEP);
1983*7c478bd9Sstevel@tonic-gate 	if (mops->mo_count) {
1984*7c478bd9Sstevel@tonic-gate 		size_t len = (count - 1) * sizeof (mntopt_t);
1985*7c478bd9Sstevel@tonic-gate 
1986*7c478bd9Sstevel@tonic-gate 		bcopy(mops->mo_list, motbl, len);
1987*7c478bd9Sstevel@tonic-gate 		kmem_free(mops->mo_list, len);
1988*7c478bd9Sstevel@tonic-gate 	}
1989*7c478bd9Sstevel@tonic-gate 	mops->mo_count = count;
1990*7c478bd9Sstevel@tonic-gate 	mops->mo_list = motbl;
1991*7c478bd9Sstevel@tonic-gate 	mop = &motbl[count - 1];
1992*7c478bd9Sstevel@tonic-gate 	mop->mo_flags = MO_TAG;
1993*7c478bd9Sstevel@tonic-gate 	mop->mo_name = kmem_alloc(strlen(tag) + 1, KM_SLEEP);
1994*7c478bd9Sstevel@tonic-gate 	(void) strcpy(mop->mo_name, tag);
1995*7c478bd9Sstevel@tonic-gate 	return (mop);
1996*7c478bd9Sstevel@tonic-gate }
1997*7c478bd9Sstevel@tonic-gate 
1998*7c478bd9Sstevel@tonic-gate /*
1999*7c478bd9Sstevel@tonic-gate  * Allow users to set arbitrary "tags" in a vfs's mount options.
2000*7c478bd9Sstevel@tonic-gate  * Broader use within the kernel is discouraged.
2001*7c478bd9Sstevel@tonic-gate  */
2002*7c478bd9Sstevel@tonic-gate int
2003*7c478bd9Sstevel@tonic-gate vfs_settag(uint_t major, uint_t minor, const char *mntpt, const char *tag,
2004*7c478bd9Sstevel@tonic-gate     cred_t *cr)
2005*7c478bd9Sstevel@tonic-gate {
2006*7c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
2007*7c478bd9Sstevel@tonic-gate 	mntopts_t *mops;
2008*7c478bd9Sstevel@tonic-gate 	mntopt_t *mop;
2009*7c478bd9Sstevel@tonic-gate 	int found = 0;
2010*7c478bd9Sstevel@tonic-gate 	dev_t dev = makedevice(major, minor);
2011*7c478bd9Sstevel@tonic-gate 	int err = 0;
2012*7c478bd9Sstevel@tonic-gate 	char *buf = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
2013*7c478bd9Sstevel@tonic-gate 
2014*7c478bd9Sstevel@tonic-gate 	/*
2015*7c478bd9Sstevel@tonic-gate 	 * Find the desired mounted file system
2016*7c478bd9Sstevel@tonic-gate 	 */
2017*7c478bd9Sstevel@tonic-gate 	vfs_list_lock();
2018*7c478bd9Sstevel@tonic-gate 	vfsp = rootvfs;
2019*7c478bd9Sstevel@tonic-gate 	do {
2020*7c478bd9Sstevel@tonic-gate 		if (vfsp->vfs_dev == dev &&
2021*7c478bd9Sstevel@tonic-gate 		    strcmp(mntpt, refstr_value(vfsp->vfs_mntpt)) == 0) {
2022*7c478bd9Sstevel@tonic-gate 			found = 1;
2023*7c478bd9Sstevel@tonic-gate 			break;
2024*7c478bd9Sstevel@tonic-gate 		}
2025*7c478bd9Sstevel@tonic-gate 		vfsp = vfsp->vfs_next;
2026*7c478bd9Sstevel@tonic-gate 	} while (vfsp != rootvfs);
2027*7c478bd9Sstevel@tonic-gate 
2028*7c478bd9Sstevel@tonic-gate 	if (!found) {
2029*7c478bd9Sstevel@tonic-gate 		err = EINVAL;
2030*7c478bd9Sstevel@tonic-gate 		goto out;
2031*7c478bd9Sstevel@tonic-gate 	}
2032*7c478bd9Sstevel@tonic-gate 	err = secpolicy_fs_config(cr, vfsp);
2033*7c478bd9Sstevel@tonic-gate 	if (err != 0)
2034*7c478bd9Sstevel@tonic-gate 		goto out;
2035*7c478bd9Sstevel@tonic-gate 
2036*7c478bd9Sstevel@tonic-gate 	mops = &vfsp->vfs_mntopts;
2037*7c478bd9Sstevel@tonic-gate 	/*
2038*7c478bd9Sstevel@tonic-gate 	 * Add tag if it doesn't already exist
2039*7c478bd9Sstevel@tonic-gate 	 */
2040*7c478bd9Sstevel@tonic-gate 	if ((mop = vfs_hasopt(mops, tag)) == NULL) {
2041*7c478bd9Sstevel@tonic-gate 		int len;
2042*7c478bd9Sstevel@tonic-gate 
2043*7c478bd9Sstevel@tonic-gate 		(void) vfs_buildoptionstr(mops, buf, MAX_MNTOPT_STR);
2044*7c478bd9Sstevel@tonic-gate 		len = strlen(buf);
2045*7c478bd9Sstevel@tonic-gate 		if (len + strlen(tag) + 2 > MAX_MNTOPT_STR) {
2046*7c478bd9Sstevel@tonic-gate 			err = ENAMETOOLONG;
2047*7c478bd9Sstevel@tonic-gate 			goto out;
2048*7c478bd9Sstevel@tonic-gate 		}
2049*7c478bd9Sstevel@tonic-gate 		mop = vfs_addtag(mops, tag);
2050*7c478bd9Sstevel@tonic-gate 	}
2051*7c478bd9Sstevel@tonic-gate 	if ((mop->mo_flags & MO_TAG) == 0) {
2052*7c478bd9Sstevel@tonic-gate 		err = EINVAL;
2053*7c478bd9Sstevel@tonic-gate 		goto out;
2054*7c478bd9Sstevel@tonic-gate 	}
2055*7c478bd9Sstevel@tonic-gate 	vfs_setmntopt_nolock(mops, tag, NULL, 0, 1);
2056*7c478bd9Sstevel@tonic-gate out:
2057*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
2058*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, MAX_MNTOPT_STR);
2059*7c478bd9Sstevel@tonic-gate 	return (err);
2060*7c478bd9Sstevel@tonic-gate }
2061*7c478bd9Sstevel@tonic-gate 
2062*7c478bd9Sstevel@tonic-gate /*
2063*7c478bd9Sstevel@tonic-gate  * Allow users to remove arbitrary "tags" in a vfs's mount options.
2064*7c478bd9Sstevel@tonic-gate  * Broader use within the kernel is discouraged.
2065*7c478bd9Sstevel@tonic-gate  */
2066*7c478bd9Sstevel@tonic-gate int
2067*7c478bd9Sstevel@tonic-gate vfs_clrtag(uint_t major, uint_t minor, const char *mntpt, const char *tag,
2068*7c478bd9Sstevel@tonic-gate     cred_t *cr)
2069*7c478bd9Sstevel@tonic-gate {
2070*7c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
2071*7c478bd9Sstevel@tonic-gate 	mntopt_t *mop;
2072*7c478bd9Sstevel@tonic-gate 	int found = 0;
2073*7c478bd9Sstevel@tonic-gate 	dev_t dev = makedevice(major, minor);
2074*7c478bd9Sstevel@tonic-gate 	int err = 0;
2075*7c478bd9Sstevel@tonic-gate 
2076*7c478bd9Sstevel@tonic-gate 	/*
2077*7c478bd9Sstevel@tonic-gate 	 * Find the desired mounted file system
2078*7c478bd9Sstevel@tonic-gate 	 */
2079*7c478bd9Sstevel@tonic-gate 	vfs_list_lock();
2080*7c478bd9Sstevel@tonic-gate 	vfsp = rootvfs;
2081*7c478bd9Sstevel@tonic-gate 	do {
2082*7c478bd9Sstevel@tonic-gate 		if (vfsp->vfs_dev == dev &&
2083*7c478bd9Sstevel@tonic-gate 		    strcmp(mntpt, refstr_value(vfsp->vfs_mntpt)) == 0) {
2084*7c478bd9Sstevel@tonic-gate 			found = 1;
2085*7c478bd9Sstevel@tonic-gate 			break;
2086*7c478bd9Sstevel@tonic-gate 		}
2087*7c478bd9Sstevel@tonic-gate 		vfsp = vfsp->vfs_next;
2088*7c478bd9Sstevel@tonic-gate 	} while (vfsp != rootvfs);
2089*7c478bd9Sstevel@tonic-gate 
2090*7c478bd9Sstevel@tonic-gate 	if (!found) {
2091*7c478bd9Sstevel@tonic-gate 		err = EINVAL;
2092*7c478bd9Sstevel@tonic-gate 		goto out;
2093*7c478bd9Sstevel@tonic-gate 	}
2094*7c478bd9Sstevel@tonic-gate 	err = secpolicy_fs_config(cr, vfsp);
2095*7c478bd9Sstevel@tonic-gate 	if (err != 0)
2096*7c478bd9Sstevel@tonic-gate 		goto out;
2097*7c478bd9Sstevel@tonic-gate 
2098*7c478bd9Sstevel@tonic-gate 	if ((mop = vfs_hasopt(&vfsp->vfs_mntopts, tag)) == NULL) {
2099*7c478bd9Sstevel@tonic-gate 		err = EINVAL;
2100*7c478bd9Sstevel@tonic-gate 		goto out;
2101*7c478bd9Sstevel@tonic-gate 	}
2102*7c478bd9Sstevel@tonic-gate 	if ((mop->mo_flags & MO_TAG) == 0) {
2103*7c478bd9Sstevel@tonic-gate 		err = EINVAL;
2104*7c478bd9Sstevel@tonic-gate 		goto out;
2105*7c478bd9Sstevel@tonic-gate 	}
2106*7c478bd9Sstevel@tonic-gate 	vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, tag, 1);
2107*7c478bd9Sstevel@tonic-gate out:
2108*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
2109*7c478bd9Sstevel@tonic-gate 	return (err);
2110*7c478bd9Sstevel@tonic-gate }
2111*7c478bd9Sstevel@tonic-gate 
2112*7c478bd9Sstevel@tonic-gate /*
2113*7c478bd9Sstevel@tonic-gate  * Function to parse an option string and fill in a mount options table.
2114*7c478bd9Sstevel@tonic-gate  * Unknown options are silently ignored.  The input option string is modified
2115*7c478bd9Sstevel@tonic-gate  * by replacing separators with nulls.  If the create flag is set, options
2116*7c478bd9Sstevel@tonic-gate  * not found in the table are just added on the fly.  The table must have
2117*7c478bd9Sstevel@tonic-gate  * an option slot marked MO_EMPTY to add an option on the fly.
2118*7c478bd9Sstevel@tonic-gate  *
2119*7c478bd9Sstevel@tonic-gate  * This function is *not* for general use by filesystems.
2120*7c478bd9Sstevel@tonic-gate  *
2121*7c478bd9Sstevel@tonic-gate  * Note: caller is responsible for locking the vfs list, if needed,
2122*7c478bd9Sstevel@tonic-gate  *       to protect mops..
2123*7c478bd9Sstevel@tonic-gate  */
2124*7c478bd9Sstevel@tonic-gate void
2125*7c478bd9Sstevel@tonic-gate vfs_parsemntopts(mntopts_t *mops, char *osp, int create)
2126*7c478bd9Sstevel@tonic-gate {
2127*7c478bd9Sstevel@tonic-gate 	char *s = osp, *p, *nextop, *valp, *cp, *ep;
2128*7c478bd9Sstevel@tonic-gate 	int setflg = VFS_NOFORCEOPT;
2129*7c478bd9Sstevel@tonic-gate 
2130*7c478bd9Sstevel@tonic-gate 	if (osp == NULL)
2131*7c478bd9Sstevel@tonic-gate 		return;
2132*7c478bd9Sstevel@tonic-gate 	while (*s != '\0') {
2133*7c478bd9Sstevel@tonic-gate 		p = strchr(s, ',');	/* find next option */
2134*7c478bd9Sstevel@tonic-gate 		if (p == NULL) {
2135*7c478bd9Sstevel@tonic-gate 			cp = NULL;
2136*7c478bd9Sstevel@tonic-gate 			p = s + strlen(s);
2137*7c478bd9Sstevel@tonic-gate 		} else {
2138*7c478bd9Sstevel@tonic-gate 			cp = p;		/* save location of comma */
2139*7c478bd9Sstevel@tonic-gate 			*p++ = '\0';	/* mark end and point to next option */
2140*7c478bd9Sstevel@tonic-gate 		}
2141*7c478bd9Sstevel@tonic-gate 		nextop = p;
2142*7c478bd9Sstevel@tonic-gate 		p = strchr(s, '=');	/* look for value */
2143*7c478bd9Sstevel@tonic-gate 		if (p == NULL) {
2144*7c478bd9Sstevel@tonic-gate 			valp = NULL;	/* no value supplied */
2145*7c478bd9Sstevel@tonic-gate 		} else {
2146*7c478bd9Sstevel@tonic-gate 			ep = p;		/* save location of equals */
2147*7c478bd9Sstevel@tonic-gate 			*p++ = '\0';	/* end option and point to value */
2148*7c478bd9Sstevel@tonic-gate 			valp = p;
2149*7c478bd9Sstevel@tonic-gate 		}
2150*7c478bd9Sstevel@tonic-gate 		/*
2151*7c478bd9Sstevel@tonic-gate 		 * set option into options table
2152*7c478bd9Sstevel@tonic-gate 		 */
2153*7c478bd9Sstevel@tonic-gate 		if (create)
2154*7c478bd9Sstevel@tonic-gate 			setflg |= VFS_CREATEOPT;
2155*7c478bd9Sstevel@tonic-gate 		vfs_setmntopt_nolock(mops, s, valp, setflg, 0);
2156*7c478bd9Sstevel@tonic-gate 		if (cp != NULL)
2157*7c478bd9Sstevel@tonic-gate 			*cp = ',';	/* restore the comma */
2158*7c478bd9Sstevel@tonic-gate 		if (valp != NULL)
2159*7c478bd9Sstevel@tonic-gate 			*ep = '=';	/* restore the equals */
2160*7c478bd9Sstevel@tonic-gate 		s = nextop;
2161*7c478bd9Sstevel@tonic-gate 	}
2162*7c478bd9Sstevel@tonic-gate }
2163*7c478bd9Sstevel@tonic-gate 
2164*7c478bd9Sstevel@tonic-gate /*
2165*7c478bd9Sstevel@tonic-gate  * Function to inquire if an option exists in a mount options table.
2166*7c478bd9Sstevel@tonic-gate  * Returns a pointer to the option if it exists, else NULL.
2167*7c478bd9Sstevel@tonic-gate  *
2168*7c478bd9Sstevel@tonic-gate  * This function is *not* for general use by filesystems.
2169*7c478bd9Sstevel@tonic-gate  *
2170*7c478bd9Sstevel@tonic-gate  * Note: caller is responsible for locking the vfs list, if needed,
2171*7c478bd9Sstevel@tonic-gate  *       to protect mops.
2172*7c478bd9Sstevel@tonic-gate  */
2173*7c478bd9Sstevel@tonic-gate struct mntopt *
2174*7c478bd9Sstevel@tonic-gate vfs_hasopt(const mntopts_t *mops, const char *opt)
2175*7c478bd9Sstevel@tonic-gate {
2176*7c478bd9Sstevel@tonic-gate 	struct mntopt *mop;
2177*7c478bd9Sstevel@tonic-gate 	uint_t i, count;
2178*7c478bd9Sstevel@tonic-gate 
2179*7c478bd9Sstevel@tonic-gate 	count = mops->mo_count;
2180*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
2181*7c478bd9Sstevel@tonic-gate 		mop = &mops->mo_list[i];
2182*7c478bd9Sstevel@tonic-gate 
2183*7c478bd9Sstevel@tonic-gate 		if (mop->mo_flags & MO_EMPTY)
2184*7c478bd9Sstevel@tonic-gate 			continue;
2185*7c478bd9Sstevel@tonic-gate 		if (strcmp(opt, mop->mo_name) == 0)
2186*7c478bd9Sstevel@tonic-gate 			return (mop);
2187*7c478bd9Sstevel@tonic-gate 	}
2188*7c478bd9Sstevel@tonic-gate 	return (NULL);
2189*7c478bd9Sstevel@tonic-gate }
2190*7c478bd9Sstevel@tonic-gate 
2191*7c478bd9Sstevel@tonic-gate /*
2192*7c478bd9Sstevel@tonic-gate  * Function to inquire if an option is set in a mount options table.
2193*7c478bd9Sstevel@tonic-gate  * Returns non-zero if set and fills in the arg pointer with a pointer to
2194*7c478bd9Sstevel@tonic-gate  * the argument string or NULL if there is no argument string.
2195*7c478bd9Sstevel@tonic-gate  */
2196*7c478bd9Sstevel@tonic-gate static int
2197*7c478bd9Sstevel@tonic-gate vfs_optionisset_nolock(const mntopts_t *mops, const char *opt, char **argp)
2198*7c478bd9Sstevel@tonic-gate {
2199*7c478bd9Sstevel@tonic-gate 	struct mntopt *mop;
2200*7c478bd9Sstevel@tonic-gate 	uint_t i, count;
2201*7c478bd9Sstevel@tonic-gate 
2202*7c478bd9Sstevel@tonic-gate 	count = mops->mo_count;
2203*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
2204*7c478bd9Sstevel@tonic-gate 		mop = &mops->mo_list[i];
2205*7c478bd9Sstevel@tonic-gate 
2206*7c478bd9Sstevel@tonic-gate 		if (mop->mo_flags & MO_EMPTY)
2207*7c478bd9Sstevel@tonic-gate 			continue;
2208*7c478bd9Sstevel@tonic-gate 		if (strcmp(opt, mop->mo_name))
2209*7c478bd9Sstevel@tonic-gate 			continue;
2210*7c478bd9Sstevel@tonic-gate 		if ((mop->mo_flags & MO_SET) == 0)
2211*7c478bd9Sstevel@tonic-gate 			return (0);
2212*7c478bd9Sstevel@tonic-gate 		if (argp != NULL && (mop->mo_flags & MO_HASVALUE) != 0)
2213*7c478bd9Sstevel@tonic-gate 			*argp = mop->mo_arg;
2214*7c478bd9Sstevel@tonic-gate 		return (1);
2215*7c478bd9Sstevel@tonic-gate 	}
2216*7c478bd9Sstevel@tonic-gate 	return (0);
2217*7c478bd9Sstevel@tonic-gate }
2218*7c478bd9Sstevel@tonic-gate 
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate int
2221*7c478bd9Sstevel@tonic-gate vfs_optionisset(const struct vfs *vfsp, const char *opt, char **argp)
2222*7c478bd9Sstevel@tonic-gate {
2223*7c478bd9Sstevel@tonic-gate 	int ret;
2224*7c478bd9Sstevel@tonic-gate 
2225*7c478bd9Sstevel@tonic-gate 	vfs_list_read_lock();
2226*7c478bd9Sstevel@tonic-gate 	ret = vfs_optionisset_nolock(&vfsp->vfs_mntopts, opt, argp);
2227*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
2228*7c478bd9Sstevel@tonic-gate 	return (ret);
2229*7c478bd9Sstevel@tonic-gate }
2230*7c478bd9Sstevel@tonic-gate 
2231*7c478bd9Sstevel@tonic-gate 
2232*7c478bd9Sstevel@tonic-gate /*
2233*7c478bd9Sstevel@tonic-gate  * Construct a comma separated string of the options set in the given
2234*7c478bd9Sstevel@tonic-gate  * mount table, return the string in the given buffer.  Return non-zero if
2235*7c478bd9Sstevel@tonic-gate  * the buffer would overflow.
2236*7c478bd9Sstevel@tonic-gate  *
2237*7c478bd9Sstevel@tonic-gate  * This function is *not* for general use by filesystems.
2238*7c478bd9Sstevel@tonic-gate  *
2239*7c478bd9Sstevel@tonic-gate  * Note: caller is responsible for locking the vfs list, if needed,
2240*7c478bd9Sstevel@tonic-gate  *       to protect mp.
2241*7c478bd9Sstevel@tonic-gate  */
2242*7c478bd9Sstevel@tonic-gate int
2243*7c478bd9Sstevel@tonic-gate vfs_buildoptionstr(const mntopts_t *mp, char *buf, int len)
2244*7c478bd9Sstevel@tonic-gate {
2245*7c478bd9Sstevel@tonic-gate 	char *cp;
2246*7c478bd9Sstevel@tonic-gate 	uint_t i;
2247*7c478bd9Sstevel@tonic-gate 
2248*7c478bd9Sstevel@tonic-gate 	buf[0] = '\0';
2249*7c478bd9Sstevel@tonic-gate 	cp = buf;
2250*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < mp->mo_count; i++) {
2251*7c478bd9Sstevel@tonic-gate 		struct mntopt *mop;
2252*7c478bd9Sstevel@tonic-gate 
2253*7c478bd9Sstevel@tonic-gate 		mop = &mp->mo_list[i];
2254*7c478bd9Sstevel@tonic-gate 		if (mop->mo_flags & MO_SET) {
2255*7c478bd9Sstevel@tonic-gate 			int optlen, comma = 0;
2256*7c478bd9Sstevel@tonic-gate 
2257*7c478bd9Sstevel@tonic-gate 			if (buf[0] != '\0')
2258*7c478bd9Sstevel@tonic-gate 				comma = 1;
2259*7c478bd9Sstevel@tonic-gate 			optlen = strlen(mop->mo_name);
2260*7c478bd9Sstevel@tonic-gate 			if (strlen(buf) + comma + optlen + 1 > len)
2261*7c478bd9Sstevel@tonic-gate 				goto err;
2262*7c478bd9Sstevel@tonic-gate 			if (comma)
2263*7c478bd9Sstevel@tonic-gate 				*cp++ = ',';
2264*7c478bd9Sstevel@tonic-gate 			(void) strcpy(cp, mop->mo_name);
2265*7c478bd9Sstevel@tonic-gate 			cp += optlen;
2266*7c478bd9Sstevel@tonic-gate 			/*
2267*7c478bd9Sstevel@tonic-gate 			 * Append option value if there is one
2268*7c478bd9Sstevel@tonic-gate 			 */
2269*7c478bd9Sstevel@tonic-gate 			if (mop->mo_arg != NULL) {
2270*7c478bd9Sstevel@tonic-gate 				int arglen;
2271*7c478bd9Sstevel@tonic-gate 
2272*7c478bd9Sstevel@tonic-gate 				arglen = strlen(mop->mo_arg);
2273*7c478bd9Sstevel@tonic-gate 				if (strlen(buf) + arglen + 2 > len)
2274*7c478bd9Sstevel@tonic-gate 					goto err;
2275*7c478bd9Sstevel@tonic-gate 				*cp++ = '=';
2276*7c478bd9Sstevel@tonic-gate 				(void) strcpy(cp, mop->mo_arg);
2277*7c478bd9Sstevel@tonic-gate 				cp += arglen;
2278*7c478bd9Sstevel@tonic-gate 			}
2279*7c478bd9Sstevel@tonic-gate 		}
2280*7c478bd9Sstevel@tonic-gate 	}
2281*7c478bd9Sstevel@tonic-gate 	return (0);
2282*7c478bd9Sstevel@tonic-gate err:
2283*7c478bd9Sstevel@tonic-gate 	return (EOVERFLOW);
2284*7c478bd9Sstevel@tonic-gate }
2285*7c478bd9Sstevel@tonic-gate 
2286*7c478bd9Sstevel@tonic-gate static void
2287*7c478bd9Sstevel@tonic-gate vfs_freecancelopt(char **moc)
2288*7c478bd9Sstevel@tonic-gate {
2289*7c478bd9Sstevel@tonic-gate 	if (moc != NULL) {
2290*7c478bd9Sstevel@tonic-gate 		int ccnt = 0;
2291*7c478bd9Sstevel@tonic-gate 		char **cp;
2292*7c478bd9Sstevel@tonic-gate 
2293*7c478bd9Sstevel@tonic-gate 		for (cp = moc; *cp != NULL; cp++) {
2294*7c478bd9Sstevel@tonic-gate 			kmem_free(*cp, strlen(*cp) + 1);
2295*7c478bd9Sstevel@tonic-gate 			ccnt++;
2296*7c478bd9Sstevel@tonic-gate 		}
2297*7c478bd9Sstevel@tonic-gate 		kmem_free(moc, (ccnt + 1) * sizeof (char *));
2298*7c478bd9Sstevel@tonic-gate 	}
2299*7c478bd9Sstevel@tonic-gate }
2300*7c478bd9Sstevel@tonic-gate 
2301*7c478bd9Sstevel@tonic-gate static void
2302*7c478bd9Sstevel@tonic-gate vfs_freeopt(mntopt_t *mop)
2303*7c478bd9Sstevel@tonic-gate {
2304*7c478bd9Sstevel@tonic-gate 	if (mop->mo_name != NULL)
2305*7c478bd9Sstevel@tonic-gate 		kmem_free(mop->mo_name, strlen(mop->mo_name) + 1);
2306*7c478bd9Sstevel@tonic-gate 
2307*7c478bd9Sstevel@tonic-gate 	vfs_freecancelopt(mop->mo_cancel);
2308*7c478bd9Sstevel@tonic-gate 
2309*7c478bd9Sstevel@tonic-gate 	if (mop->mo_arg != NULL)
2310*7c478bd9Sstevel@tonic-gate 		kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
2311*7c478bd9Sstevel@tonic-gate }
2312*7c478bd9Sstevel@tonic-gate 
2313*7c478bd9Sstevel@tonic-gate /*
2314*7c478bd9Sstevel@tonic-gate  * Free a mount options table
2315*7c478bd9Sstevel@tonic-gate  *
2316*7c478bd9Sstevel@tonic-gate  * This function is *not* for general use by filesystems.
2317*7c478bd9Sstevel@tonic-gate  *
2318*7c478bd9Sstevel@tonic-gate  * Note: caller is responsible for locking the vfs list, if needed,
2319*7c478bd9Sstevel@tonic-gate  *       to protect mp.
2320*7c478bd9Sstevel@tonic-gate  */
2321*7c478bd9Sstevel@tonic-gate void
2322*7c478bd9Sstevel@tonic-gate vfs_freeopttbl(mntopts_t *mp)
2323*7c478bd9Sstevel@tonic-gate {
2324*7c478bd9Sstevel@tonic-gate 	uint_t i, count;
2325*7c478bd9Sstevel@tonic-gate 
2326*7c478bd9Sstevel@tonic-gate 	count = mp->mo_count;
2327*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
2328*7c478bd9Sstevel@tonic-gate 		vfs_freeopt(&mp->mo_list[i]);
2329*7c478bd9Sstevel@tonic-gate 	}
2330*7c478bd9Sstevel@tonic-gate 	if (count) {
2331*7c478bd9Sstevel@tonic-gate 		kmem_free(mp->mo_list, sizeof (mntopt_t) * count);
2332*7c478bd9Sstevel@tonic-gate 		mp->mo_count = 0;
2333*7c478bd9Sstevel@tonic-gate 		mp->mo_list = NULL;
2334*7c478bd9Sstevel@tonic-gate 	}
2335*7c478bd9Sstevel@tonic-gate }
2336*7c478bd9Sstevel@tonic-gate 
2337*7c478bd9Sstevel@tonic-gate /*
2338*7c478bd9Sstevel@tonic-gate  * Free any mnttab information recorded in the vfs struct.
2339*7c478bd9Sstevel@tonic-gate  * The vfs must not be on the vfs list.
2340*7c478bd9Sstevel@tonic-gate  */
2341*7c478bd9Sstevel@tonic-gate static void
2342*7c478bd9Sstevel@tonic-gate vfs_freemnttab(struct vfs *vfsp)
2343*7c478bd9Sstevel@tonic-gate {
2344*7c478bd9Sstevel@tonic-gate 	ASSERT(!VFS_ON_LIST(vfsp));
2345*7c478bd9Sstevel@tonic-gate 
2346*7c478bd9Sstevel@tonic-gate 	/*
2347*7c478bd9Sstevel@tonic-gate 	 * Free device and mount point information
2348*7c478bd9Sstevel@tonic-gate 	 */
2349*7c478bd9Sstevel@tonic-gate 	if (vfsp->vfs_mntpt != NULL) {
2350*7c478bd9Sstevel@tonic-gate 		refstr_rele(vfsp->vfs_mntpt);
2351*7c478bd9Sstevel@tonic-gate 		vfsp->vfs_mntpt = NULL;
2352*7c478bd9Sstevel@tonic-gate 	}
2353*7c478bd9Sstevel@tonic-gate 	if (vfsp->vfs_resource != NULL) {
2354*7c478bd9Sstevel@tonic-gate 		refstr_rele(vfsp->vfs_resource);
2355*7c478bd9Sstevel@tonic-gate 		vfsp->vfs_resource = NULL;
2356*7c478bd9Sstevel@tonic-gate 	}
2357*7c478bd9Sstevel@tonic-gate 	/*
2358*7c478bd9Sstevel@tonic-gate 	 * Now free mount options information
2359*7c478bd9Sstevel@tonic-gate 	 */
2360*7c478bd9Sstevel@tonic-gate 	vfs_freeopttbl(&vfsp->vfs_mntopts);
2361*7c478bd9Sstevel@tonic-gate }
2362*7c478bd9Sstevel@tonic-gate 
2363*7c478bd9Sstevel@tonic-gate /*
2364*7c478bd9Sstevel@tonic-gate  * Return the last mnttab modification time
2365*7c478bd9Sstevel@tonic-gate  */
2366*7c478bd9Sstevel@tonic-gate void
2367*7c478bd9Sstevel@tonic-gate vfs_mnttab_modtime(timespec_t *ts)
2368*7c478bd9Sstevel@tonic-gate {
2369*7c478bd9Sstevel@tonic-gate 	ASSERT(RW_LOCK_HELD(&vfslist));
2370*7c478bd9Sstevel@tonic-gate 	*ts = vfs_mnttab_mtime;
2371*7c478bd9Sstevel@tonic-gate }
2372*7c478bd9Sstevel@tonic-gate 
2373*7c478bd9Sstevel@tonic-gate /*
2374*7c478bd9Sstevel@tonic-gate  * See if mnttab is changed
2375*7c478bd9Sstevel@tonic-gate  */
2376*7c478bd9Sstevel@tonic-gate void
2377*7c478bd9Sstevel@tonic-gate vfs_mnttab_poll(timespec_t *old, struct pollhead **phpp)
2378*7c478bd9Sstevel@tonic-gate {
2379*7c478bd9Sstevel@tonic-gate 	int changed;
2380*7c478bd9Sstevel@tonic-gate 
2381*7c478bd9Sstevel@tonic-gate 	*phpp = (struct pollhead *)NULL;
2382*7c478bd9Sstevel@tonic-gate 
2383*7c478bd9Sstevel@tonic-gate 	/*
2384*7c478bd9Sstevel@tonic-gate 	 * Note: don't grab vfs list lock before accessing vfs_mnttab_mtime.
2385*7c478bd9Sstevel@tonic-gate 	 * Can lead to deadlock against vfs_mnttab_modtimeupd(). It is safe
2386*7c478bd9Sstevel@tonic-gate 	 * to not grab the vfs list lock because tv_sec is monotonically
2387*7c478bd9Sstevel@tonic-gate 	 * increasing.
2388*7c478bd9Sstevel@tonic-gate 	 */
2389*7c478bd9Sstevel@tonic-gate 
2390*7c478bd9Sstevel@tonic-gate 	changed = (old->tv_nsec != vfs_mnttab_mtime.tv_nsec) ||
2391*7c478bd9Sstevel@tonic-gate 	    (old->tv_sec != vfs_mnttab_mtime.tv_sec);
2392*7c478bd9Sstevel@tonic-gate 	if (!changed) {
2393*7c478bd9Sstevel@tonic-gate 		*phpp = &vfs_pollhd;
2394*7c478bd9Sstevel@tonic-gate 	}
2395*7c478bd9Sstevel@tonic-gate }
2396*7c478bd9Sstevel@tonic-gate 
2397*7c478bd9Sstevel@tonic-gate /*
2398*7c478bd9Sstevel@tonic-gate  * Update the mnttab modification time and wake up any waiters for
2399*7c478bd9Sstevel@tonic-gate  * mnttab changes
2400*7c478bd9Sstevel@tonic-gate  */
2401*7c478bd9Sstevel@tonic-gate void
2402*7c478bd9Sstevel@tonic-gate vfs_mnttab_modtimeupd()
2403*7c478bd9Sstevel@tonic-gate {
2404*7c478bd9Sstevel@tonic-gate 	hrtime_t oldhrt, newhrt;
2405*7c478bd9Sstevel@tonic-gate 
2406*7c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&vfslist));
2407*7c478bd9Sstevel@tonic-gate 	oldhrt = ts2hrt(&vfs_mnttab_mtime);
2408*7c478bd9Sstevel@tonic-gate 	gethrestime(&vfs_mnttab_mtime);
2409*7c478bd9Sstevel@tonic-gate 	newhrt = ts2hrt(&vfs_mnttab_mtime);
2410*7c478bd9Sstevel@tonic-gate 	if (oldhrt == (hrtime_t)0)
2411*7c478bd9Sstevel@tonic-gate 		vfs_mnttab_ctime = vfs_mnttab_mtime;
2412*7c478bd9Sstevel@tonic-gate 	/*
2413*7c478bd9Sstevel@tonic-gate 	 * Attempt to provide unique mtime (like uniqtime but not).
2414*7c478bd9Sstevel@tonic-gate 	 */
2415*7c478bd9Sstevel@tonic-gate 	if (newhrt == oldhrt) {
2416*7c478bd9Sstevel@tonic-gate 		newhrt++;
2417*7c478bd9Sstevel@tonic-gate 		hrt2ts(newhrt, &vfs_mnttab_mtime);
2418*7c478bd9Sstevel@tonic-gate 	}
2419*7c478bd9Sstevel@tonic-gate 	pollwakeup(&vfs_pollhd, (short)POLLRDBAND);
2420*7c478bd9Sstevel@tonic-gate }
2421*7c478bd9Sstevel@tonic-gate 
2422*7c478bd9Sstevel@tonic-gate int
2423*7c478bd9Sstevel@tonic-gate dounmount(struct vfs *vfsp, int flag, cred_t *cr)
2424*7c478bd9Sstevel@tonic-gate {
2425*7c478bd9Sstevel@tonic-gate 	vnode_t *coveredvp;
2426*7c478bd9Sstevel@tonic-gate 	int error;
2427*7c478bd9Sstevel@tonic-gate 
2428*7c478bd9Sstevel@tonic-gate 	/*
2429*7c478bd9Sstevel@tonic-gate 	 * Get covered vnode. This will be NULL if the vfs is not linked
2430*7c478bd9Sstevel@tonic-gate 	 * into the file system name space (i.e., domount() with MNT_NOSPICE).
2431*7c478bd9Sstevel@tonic-gate 	 */
2432*7c478bd9Sstevel@tonic-gate 	coveredvp = vfsp->vfs_vnodecovered;
2433*7c478bd9Sstevel@tonic-gate 	ASSERT(coveredvp == NULL || vn_vfswlock_held(coveredvp));
2434*7c478bd9Sstevel@tonic-gate 
2435*7c478bd9Sstevel@tonic-gate 	/*
2436*7c478bd9Sstevel@tonic-gate 	 * Purge all dnlc entries for this vfs.
2437*7c478bd9Sstevel@tonic-gate 	 */
2438*7c478bd9Sstevel@tonic-gate 	(void) dnlc_purge_vfsp(vfsp, 0);
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate 	/* For forcible umount, skip VFS_SYNC() since it may hang */
2441*7c478bd9Sstevel@tonic-gate 	if ((flag & MS_FORCE) == 0)
2442*7c478bd9Sstevel@tonic-gate 		(void) VFS_SYNC(vfsp, 0, cr);
2443*7c478bd9Sstevel@tonic-gate 
2444*7c478bd9Sstevel@tonic-gate 	/*
2445*7c478bd9Sstevel@tonic-gate 	 * Lock the vfs to maintain fs status quo during unmount.  This
2446*7c478bd9Sstevel@tonic-gate 	 * has to be done after the sync because ufs_update tries to acquire
2447*7c478bd9Sstevel@tonic-gate 	 * the vfs_reflock.
2448*7c478bd9Sstevel@tonic-gate 	 */
2449*7c478bd9Sstevel@tonic-gate 	vfs_lock_wait(vfsp);
2450*7c478bd9Sstevel@tonic-gate 
2451*7c478bd9Sstevel@tonic-gate 	if (error = VFS_UNMOUNT(vfsp, flag, cr)) {
2452*7c478bd9Sstevel@tonic-gate 		vfs_unlock(vfsp);
2453*7c478bd9Sstevel@tonic-gate 		if (coveredvp != NULL)
2454*7c478bd9Sstevel@tonic-gate 			vn_vfsunlock(coveredvp);
2455*7c478bd9Sstevel@tonic-gate 	} else if (coveredvp != NULL) {
2456*7c478bd9Sstevel@tonic-gate 		/*
2457*7c478bd9Sstevel@tonic-gate 		 * vfs_remove() will do a VN_RELE(vfsp->vfs_vnodecovered)
2458*7c478bd9Sstevel@tonic-gate 		 * when it frees vfsp so we do a VN_HOLD() so we can
2459*7c478bd9Sstevel@tonic-gate 		 * continue to use coveredvp afterwards.
2460*7c478bd9Sstevel@tonic-gate 		 */
2461*7c478bd9Sstevel@tonic-gate 		VN_HOLD(coveredvp);
2462*7c478bd9Sstevel@tonic-gate 		vfs_remove(vfsp);
2463*7c478bd9Sstevel@tonic-gate 		vn_vfsunlock(coveredvp);
2464*7c478bd9Sstevel@tonic-gate 		VN_RELE(coveredvp);
2465*7c478bd9Sstevel@tonic-gate 	} else {
2466*7c478bd9Sstevel@tonic-gate 		/*
2467*7c478bd9Sstevel@tonic-gate 		 * Release the reference to vfs that is not linked
2468*7c478bd9Sstevel@tonic-gate 		 * into the name space.
2469*7c478bd9Sstevel@tonic-gate 		 */
2470*7c478bd9Sstevel@tonic-gate 		vfs_unlock(vfsp);
2471*7c478bd9Sstevel@tonic-gate 		VFS_RELE(vfsp);
2472*7c478bd9Sstevel@tonic-gate 	}
2473*7c478bd9Sstevel@tonic-gate 	return (error);
2474*7c478bd9Sstevel@tonic-gate }
2475*7c478bd9Sstevel@tonic-gate 
2476*7c478bd9Sstevel@tonic-gate 
2477*7c478bd9Sstevel@tonic-gate /*
2478*7c478bd9Sstevel@tonic-gate  * Vfs_unmountall() is called by uadmin() to unmount all
2479*7c478bd9Sstevel@tonic-gate  * mounted file systems (except the root file system) during shutdown.
2480*7c478bd9Sstevel@tonic-gate  * It follows the existing locking protocol when traversing the vfs list
2481*7c478bd9Sstevel@tonic-gate  * to sync and unmount vfses. Even though there should be no
2482*7c478bd9Sstevel@tonic-gate  * other thread running while the system is shutting down, it is prudent
2483*7c478bd9Sstevel@tonic-gate  * to still follow the locking protocol.
2484*7c478bd9Sstevel@tonic-gate  */
2485*7c478bd9Sstevel@tonic-gate void
2486*7c478bd9Sstevel@tonic-gate vfs_unmountall(void)
2487*7c478bd9Sstevel@tonic-gate {
2488*7c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
2489*7c478bd9Sstevel@tonic-gate 	struct vfs *prev_vfsp = NULL;
2490*7c478bd9Sstevel@tonic-gate 	int error;
2491*7c478bd9Sstevel@tonic-gate 
2492*7c478bd9Sstevel@tonic-gate 	/*
2493*7c478bd9Sstevel@tonic-gate 	 * Toss all dnlc entries now so that the per-vfs sync
2494*7c478bd9Sstevel@tonic-gate 	 * and unmount operations don't have to slog through
2495*7c478bd9Sstevel@tonic-gate 	 * a bunch of uninteresting vnodes over and over again.
2496*7c478bd9Sstevel@tonic-gate 	 */
2497*7c478bd9Sstevel@tonic-gate 	dnlc_purge();
2498*7c478bd9Sstevel@tonic-gate 
2499*7c478bd9Sstevel@tonic-gate 	vfs_list_lock();
2500*7c478bd9Sstevel@tonic-gate 	for (vfsp = rootvfs->vfs_prev; vfsp != rootvfs; vfsp = prev_vfsp) {
2501*7c478bd9Sstevel@tonic-gate 		prev_vfsp = vfsp->vfs_prev;
2502*7c478bd9Sstevel@tonic-gate 
2503*7c478bd9Sstevel@tonic-gate 		if (vfs_lock(vfsp) != 0)
2504*7c478bd9Sstevel@tonic-gate 			continue;
2505*7c478bd9Sstevel@tonic-gate 		error = vn_vfswlock(vfsp->vfs_vnodecovered);
2506*7c478bd9Sstevel@tonic-gate 		vfs_unlock(vfsp);
2507*7c478bd9Sstevel@tonic-gate 		if (error)
2508*7c478bd9Sstevel@tonic-gate 			continue;
2509*7c478bd9Sstevel@tonic-gate 
2510*7c478bd9Sstevel@tonic-gate 		vfs_list_unlock();
2511*7c478bd9Sstevel@tonic-gate 
2512*7c478bd9Sstevel@tonic-gate 		(void) VFS_SYNC(vfsp, SYNC_CLOSE, CRED());
2513*7c478bd9Sstevel@tonic-gate 		(void) dounmount(vfsp, 0, CRED());
2514*7c478bd9Sstevel@tonic-gate 
2515*7c478bd9Sstevel@tonic-gate 		/*
2516*7c478bd9Sstevel@tonic-gate 		 * Since we dropped the vfslist lock above we must
2517*7c478bd9Sstevel@tonic-gate 		 * verify that next_vfsp still exists, else start over.
2518*7c478bd9Sstevel@tonic-gate 		 */
2519*7c478bd9Sstevel@tonic-gate 		vfs_list_lock();
2520*7c478bd9Sstevel@tonic-gate 		for (vfsp = rootvfs->vfs_prev;
2521*7c478bd9Sstevel@tonic-gate 			vfsp != rootvfs; vfsp = vfsp->vfs_prev)
2522*7c478bd9Sstevel@tonic-gate 			if (vfsp == prev_vfsp)
2523*7c478bd9Sstevel@tonic-gate 				break;
2524*7c478bd9Sstevel@tonic-gate 		if (vfsp == rootvfs && prev_vfsp != rootvfs)
2525*7c478bd9Sstevel@tonic-gate 			prev_vfsp = rootvfs->vfs_prev;
2526*7c478bd9Sstevel@tonic-gate 	}
2527*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
2528*7c478bd9Sstevel@tonic-gate }
2529*7c478bd9Sstevel@tonic-gate 
2530*7c478bd9Sstevel@tonic-gate /*
2531*7c478bd9Sstevel@tonic-gate  * Called to add an entry to the end of the vfs mount in progress list
2532*7c478bd9Sstevel@tonic-gate  */
2533*7c478bd9Sstevel@tonic-gate void
2534*7c478bd9Sstevel@tonic-gate vfs_addmip(dev_t dev, struct vfs *vfsp)
2535*7c478bd9Sstevel@tonic-gate {
2536*7c478bd9Sstevel@tonic-gate 	struct ipmnt *mipp;
2537*7c478bd9Sstevel@tonic-gate 
2538*7c478bd9Sstevel@tonic-gate 	mipp = (struct ipmnt *)kmem_alloc(sizeof (struct ipmnt), KM_SLEEP);
2539*7c478bd9Sstevel@tonic-gate 	mipp->mip_next = NULL;
2540*7c478bd9Sstevel@tonic-gate 	mipp->mip_dev = dev;
2541*7c478bd9Sstevel@tonic-gate 	mipp->mip_vfsp = vfsp;
2542*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vfs_miplist_mutex);
2543*7c478bd9Sstevel@tonic-gate 	if (vfs_miplist_end != NULL)
2544*7c478bd9Sstevel@tonic-gate 		vfs_miplist_end->mip_next = mipp;
2545*7c478bd9Sstevel@tonic-gate 	else
2546*7c478bd9Sstevel@tonic-gate 		vfs_miplist = mipp;
2547*7c478bd9Sstevel@tonic-gate 	vfs_miplist_end = mipp;
2548*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vfs_miplist_mutex);
2549*7c478bd9Sstevel@tonic-gate }
2550*7c478bd9Sstevel@tonic-gate 
2551*7c478bd9Sstevel@tonic-gate /*
2552*7c478bd9Sstevel@tonic-gate  * Called to remove an entry from the mount in progress list
2553*7c478bd9Sstevel@tonic-gate  * Either because the mount completed or it failed.
2554*7c478bd9Sstevel@tonic-gate  */
2555*7c478bd9Sstevel@tonic-gate void
2556*7c478bd9Sstevel@tonic-gate vfs_delmip(struct vfs *vfsp)
2557*7c478bd9Sstevel@tonic-gate {
2558*7c478bd9Sstevel@tonic-gate 	struct ipmnt *mipp, *mipprev;
2559*7c478bd9Sstevel@tonic-gate 
2560*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vfs_miplist_mutex);
2561*7c478bd9Sstevel@tonic-gate 	mipprev = NULL;
2562*7c478bd9Sstevel@tonic-gate 	for (mipp = vfs_miplist;
2563*7c478bd9Sstevel@tonic-gate 		mipp && mipp->mip_vfsp != vfsp; mipp = mipp->mip_next) {
2564*7c478bd9Sstevel@tonic-gate 		mipprev = mipp;
2565*7c478bd9Sstevel@tonic-gate 	}
2566*7c478bd9Sstevel@tonic-gate 	if (mipp == NULL)
2567*7c478bd9Sstevel@tonic-gate 		return; /* shouldn't happen */
2568*7c478bd9Sstevel@tonic-gate 	if (mipp == vfs_miplist_end)
2569*7c478bd9Sstevel@tonic-gate 		vfs_miplist_end = mipprev;
2570*7c478bd9Sstevel@tonic-gate 	if (mipprev == NULL)
2571*7c478bd9Sstevel@tonic-gate 		vfs_miplist = mipp->mip_next;
2572*7c478bd9Sstevel@tonic-gate 	else
2573*7c478bd9Sstevel@tonic-gate 		mipprev->mip_next = mipp->mip_next;
2574*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vfs_miplist_mutex);
2575*7c478bd9Sstevel@tonic-gate 	kmem_free(mipp, sizeof (struct ipmnt));
2576*7c478bd9Sstevel@tonic-gate }
2577*7c478bd9Sstevel@tonic-gate 
2578*7c478bd9Sstevel@tonic-gate /*
2579*7c478bd9Sstevel@tonic-gate  * vfs_add is called by a specific filesystem's mount routine to add
2580*7c478bd9Sstevel@tonic-gate  * the new vfs into the vfs list/hash and to cover the mounted-on vnode.
2581*7c478bd9Sstevel@tonic-gate  * The vfs should already have been locked by the caller.
2582*7c478bd9Sstevel@tonic-gate  *
2583*7c478bd9Sstevel@tonic-gate  * coveredvp is NULL if this is the root.
2584*7c478bd9Sstevel@tonic-gate  */
2585*7c478bd9Sstevel@tonic-gate void
2586*7c478bd9Sstevel@tonic-gate vfs_add(vnode_t *coveredvp, struct vfs *vfsp, int mflag)
2587*7c478bd9Sstevel@tonic-gate {
2588*7c478bd9Sstevel@tonic-gate 	int newflag;
2589*7c478bd9Sstevel@tonic-gate 
2590*7c478bd9Sstevel@tonic-gate 	ASSERT(vfs_lock_held(vfsp));
2591*7c478bd9Sstevel@tonic-gate 	VFS_HOLD(vfsp);
2592*7c478bd9Sstevel@tonic-gate 	newflag = vfsp->vfs_flag;
2593*7c478bd9Sstevel@tonic-gate 	if (mflag & MS_RDONLY)
2594*7c478bd9Sstevel@tonic-gate 		newflag |= VFS_RDONLY;
2595*7c478bd9Sstevel@tonic-gate 	else
2596*7c478bd9Sstevel@tonic-gate 		newflag &= ~VFS_RDONLY;
2597*7c478bd9Sstevel@tonic-gate 	if (mflag & MS_NOSUID)
2598*7c478bd9Sstevel@tonic-gate 		newflag |= (VFS_NOSETUID|VFS_NODEVICES);
2599*7c478bd9Sstevel@tonic-gate 	else
2600*7c478bd9Sstevel@tonic-gate 		newflag &= ~(VFS_NOSETUID|VFS_NODEVICES);
2601*7c478bd9Sstevel@tonic-gate 	if (mflag & MS_NOMNTTAB)
2602*7c478bd9Sstevel@tonic-gate 		newflag |= VFS_NOMNTTAB;
2603*7c478bd9Sstevel@tonic-gate 	else
2604*7c478bd9Sstevel@tonic-gate 		newflag &= ~VFS_NOMNTTAB;
2605*7c478bd9Sstevel@tonic-gate 
2606*7c478bd9Sstevel@tonic-gate 	if (coveredvp != NULL) {
2607*7c478bd9Sstevel@tonic-gate 		ASSERT(vn_vfswlock_held(coveredvp));
2608*7c478bd9Sstevel@tonic-gate 		coveredvp->v_vfsmountedhere = vfsp;
2609*7c478bd9Sstevel@tonic-gate 		VN_HOLD(coveredvp);
2610*7c478bd9Sstevel@tonic-gate 	}
2611*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_vnodecovered = coveredvp;
2612*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_flag = newflag;
2613*7c478bd9Sstevel@tonic-gate 
2614*7c478bd9Sstevel@tonic-gate 	vfs_list_add(vfsp);
2615*7c478bd9Sstevel@tonic-gate }
2616*7c478bd9Sstevel@tonic-gate 
2617*7c478bd9Sstevel@tonic-gate /*
2618*7c478bd9Sstevel@tonic-gate  * Remove a vfs from the vfs list, null out the pointer from the
2619*7c478bd9Sstevel@tonic-gate  * covered vnode to the vfs (v_vfsmountedhere), and null out the pointer
2620*7c478bd9Sstevel@tonic-gate  * from the vfs to the covered vnode (vfs_vnodecovered). Release the
2621*7c478bd9Sstevel@tonic-gate  * reference to the vfs and to the covered vnode.
2622*7c478bd9Sstevel@tonic-gate  *
2623*7c478bd9Sstevel@tonic-gate  * Called from dounmount after it's confirmed with the file system
2624*7c478bd9Sstevel@tonic-gate  * that the unmount is legal.
2625*7c478bd9Sstevel@tonic-gate  */
2626*7c478bd9Sstevel@tonic-gate void
2627*7c478bd9Sstevel@tonic-gate vfs_remove(struct vfs *vfsp)
2628*7c478bd9Sstevel@tonic-gate {
2629*7c478bd9Sstevel@tonic-gate 	vnode_t *vp;
2630*7c478bd9Sstevel@tonic-gate 
2631*7c478bd9Sstevel@tonic-gate 	ASSERT(vfs_lock_held(vfsp));
2632*7c478bd9Sstevel@tonic-gate 
2633*7c478bd9Sstevel@tonic-gate 	/*
2634*7c478bd9Sstevel@tonic-gate 	 * Can't unmount root.  Should never happen because fs will
2635*7c478bd9Sstevel@tonic-gate 	 * be busy.
2636*7c478bd9Sstevel@tonic-gate 	 */
2637*7c478bd9Sstevel@tonic-gate 	if (vfsp == rootvfs)
2638*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "vfs_remove: unmounting root");
2639*7c478bd9Sstevel@tonic-gate 
2640*7c478bd9Sstevel@tonic-gate 	vfs_list_remove(vfsp);
2641*7c478bd9Sstevel@tonic-gate 
2642*7c478bd9Sstevel@tonic-gate 	/*
2643*7c478bd9Sstevel@tonic-gate 	 * Unhook from the file system name space.
2644*7c478bd9Sstevel@tonic-gate 	 */
2645*7c478bd9Sstevel@tonic-gate 	vp = vfsp->vfs_vnodecovered;
2646*7c478bd9Sstevel@tonic-gate 	ASSERT(vn_vfswlock_held(vp));
2647*7c478bd9Sstevel@tonic-gate 	vp->v_vfsmountedhere = NULL;
2648*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_vnodecovered = NULL;
2649*7c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
2650*7c478bd9Sstevel@tonic-gate 
2651*7c478bd9Sstevel@tonic-gate 	/*
2652*7c478bd9Sstevel@tonic-gate 	 * Release lock and wakeup anybody waiting.
2653*7c478bd9Sstevel@tonic-gate 	 */
2654*7c478bd9Sstevel@tonic-gate 	vfs_unlock(vfsp);
2655*7c478bd9Sstevel@tonic-gate 	VFS_RELE(vfsp);
2656*7c478bd9Sstevel@tonic-gate }
2657*7c478bd9Sstevel@tonic-gate 
2658*7c478bd9Sstevel@tonic-gate /*
2659*7c478bd9Sstevel@tonic-gate  * Lock a filesystem to prevent access to it while mounting,
2660*7c478bd9Sstevel@tonic-gate  * unmounting and syncing.  Return EBUSY immediately if lock
2661*7c478bd9Sstevel@tonic-gate  * can't be acquired.
2662*7c478bd9Sstevel@tonic-gate  */
2663*7c478bd9Sstevel@tonic-gate int
2664*7c478bd9Sstevel@tonic-gate vfs_lock(vfs_t *vfsp)
2665*7c478bd9Sstevel@tonic-gate {
2666*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
2667*7c478bd9Sstevel@tonic-gate 
2668*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vfsp);
2669*7c478bd9Sstevel@tonic-gate 	if (rwst_tryenter(&vpvfsentry->ve_lock, RW_WRITER))
2670*7c478bd9Sstevel@tonic-gate 		return (0);
2671*7c478bd9Sstevel@tonic-gate 
2672*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
2673*7c478bd9Sstevel@tonic-gate 	return (EBUSY);
2674*7c478bd9Sstevel@tonic-gate }
2675*7c478bd9Sstevel@tonic-gate 
2676*7c478bd9Sstevel@tonic-gate int
2677*7c478bd9Sstevel@tonic-gate vfs_rlock(vfs_t *vfsp)
2678*7c478bd9Sstevel@tonic-gate {
2679*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
2680*7c478bd9Sstevel@tonic-gate 
2681*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vfsp);
2682*7c478bd9Sstevel@tonic-gate 
2683*7c478bd9Sstevel@tonic-gate 	if (rwst_tryenter(&vpvfsentry->ve_lock, RW_READER))
2684*7c478bd9Sstevel@tonic-gate 		return (0);
2685*7c478bd9Sstevel@tonic-gate 
2686*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
2687*7c478bd9Sstevel@tonic-gate 	return (EBUSY);
2688*7c478bd9Sstevel@tonic-gate }
2689*7c478bd9Sstevel@tonic-gate 
2690*7c478bd9Sstevel@tonic-gate void
2691*7c478bd9Sstevel@tonic-gate vfs_lock_wait(vfs_t *vfsp)
2692*7c478bd9Sstevel@tonic-gate {
2693*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
2694*7c478bd9Sstevel@tonic-gate 
2695*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vfsp);
2696*7c478bd9Sstevel@tonic-gate 	rwst_enter(&vpvfsentry->ve_lock, RW_WRITER);
2697*7c478bd9Sstevel@tonic-gate }
2698*7c478bd9Sstevel@tonic-gate 
2699*7c478bd9Sstevel@tonic-gate void
2700*7c478bd9Sstevel@tonic-gate vfs_rlock_wait(vfs_t *vfsp)
2701*7c478bd9Sstevel@tonic-gate {
2702*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
2703*7c478bd9Sstevel@tonic-gate 
2704*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vfsp);
2705*7c478bd9Sstevel@tonic-gate 	rwst_enter(&vpvfsentry->ve_lock, RW_READER);
2706*7c478bd9Sstevel@tonic-gate }
2707*7c478bd9Sstevel@tonic-gate 
2708*7c478bd9Sstevel@tonic-gate /*
2709*7c478bd9Sstevel@tonic-gate  * Unlock a locked filesystem.
2710*7c478bd9Sstevel@tonic-gate  */
2711*7c478bd9Sstevel@tonic-gate void
2712*7c478bd9Sstevel@tonic-gate vfs_unlock(vfs_t *vfsp)
2713*7c478bd9Sstevel@tonic-gate {
2714*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
2715*7c478bd9Sstevel@tonic-gate 
2716*7c478bd9Sstevel@tonic-gate 	/*
2717*7c478bd9Sstevel@tonic-gate 	 * vfs_unlock will mimic sema_v behaviour to fix 4748018.
2718*7c478bd9Sstevel@tonic-gate 	 * And these changes should remain for the patch changes as it is.
2719*7c478bd9Sstevel@tonic-gate 	 */
2720*7c478bd9Sstevel@tonic-gate 	if (panicstr)
2721*7c478bd9Sstevel@tonic-gate 		return;
2722*7c478bd9Sstevel@tonic-gate 
2723*7c478bd9Sstevel@tonic-gate 	/*
2724*7c478bd9Sstevel@tonic-gate 	 * ve_refcount needs to be dropped twice here.
2725*7c478bd9Sstevel@tonic-gate 	 * 1. To release refernce after a call to vfs_locks_getlock()
2726*7c478bd9Sstevel@tonic-gate 	 * 2. To release the reference from the locking routines like
2727*7c478bd9Sstevel@tonic-gate 	 *    vfs_rlock_wait/vfs_wlock_wait/vfs_wlock etc,.
2728*7c478bd9Sstevel@tonic-gate 	 */
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vfsp);
2731*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
2732*7c478bd9Sstevel@tonic-gate 
2733*7c478bd9Sstevel@tonic-gate 	rwst_exit(&vpvfsentry->ve_lock);
2734*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
2735*7c478bd9Sstevel@tonic-gate }
2736*7c478bd9Sstevel@tonic-gate 
2737*7c478bd9Sstevel@tonic-gate /*
2738*7c478bd9Sstevel@tonic-gate  * Utility routine that allows a filesystem to construct its
2739*7c478bd9Sstevel@tonic-gate  * fsid in "the usual way" - by munging some underlying dev_t and
2740*7c478bd9Sstevel@tonic-gate  * the filesystem type number into the 64-bit fsid.  Note that
2741*7c478bd9Sstevel@tonic-gate  * this implicitly relies on dev_t persistence to make filesystem
2742*7c478bd9Sstevel@tonic-gate  * id's persistent.
2743*7c478bd9Sstevel@tonic-gate  *
2744*7c478bd9Sstevel@tonic-gate  * There's nothing to prevent an individual fs from constructing its
2745*7c478bd9Sstevel@tonic-gate  * fsid in a different way, and indeed they should.
2746*7c478bd9Sstevel@tonic-gate  *
2747*7c478bd9Sstevel@tonic-gate  * Since we want fsids to be 32-bit quantities (so that they can be
2748*7c478bd9Sstevel@tonic-gate  * exported identically by either 32-bit or 64-bit APIs, as well as
2749*7c478bd9Sstevel@tonic-gate  * the fact that fsid's are "known" to NFS), we compress the device
2750*7c478bd9Sstevel@tonic-gate  * number given down to 32-bits, and panic if that isn't possible.
2751*7c478bd9Sstevel@tonic-gate  */
2752*7c478bd9Sstevel@tonic-gate void
2753*7c478bd9Sstevel@tonic-gate vfs_make_fsid(fsid_t *fsi, dev_t dev, int val)
2754*7c478bd9Sstevel@tonic-gate {
2755*7c478bd9Sstevel@tonic-gate 	if (!cmpldev((dev32_t *)&fsi->val[0], dev))
2756*7c478bd9Sstevel@tonic-gate 		panic("device number too big for fsid!");
2757*7c478bd9Sstevel@tonic-gate 	fsi->val[1] = val;
2758*7c478bd9Sstevel@tonic-gate }
2759*7c478bd9Sstevel@tonic-gate 
2760*7c478bd9Sstevel@tonic-gate int
2761*7c478bd9Sstevel@tonic-gate vfs_lock_held(vfs_t *vfsp)
2762*7c478bd9Sstevel@tonic-gate {
2763*7c478bd9Sstevel@tonic-gate 	int held;
2764*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
2765*7c478bd9Sstevel@tonic-gate 
2766*7c478bd9Sstevel@tonic-gate 	/*
2767*7c478bd9Sstevel@tonic-gate 	 * vfs_lock_held will mimic sema_held behaviour
2768*7c478bd9Sstevel@tonic-gate 	 * if panicstr is set. And these changes should remain
2769*7c478bd9Sstevel@tonic-gate 	 * for the patch changes as it is.
2770*7c478bd9Sstevel@tonic-gate 	 */
2771*7c478bd9Sstevel@tonic-gate 	if (panicstr)
2772*7c478bd9Sstevel@tonic-gate 		return (1);
2773*7c478bd9Sstevel@tonic-gate 
2774*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vfsp);
2775*7c478bd9Sstevel@tonic-gate 	held = rwst_lock_held(&vpvfsentry->ve_lock, RW_WRITER);
2776*7c478bd9Sstevel@tonic-gate 
2777*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
2778*7c478bd9Sstevel@tonic-gate 	return (held);
2779*7c478bd9Sstevel@tonic-gate }
2780*7c478bd9Sstevel@tonic-gate 
2781*7c478bd9Sstevel@tonic-gate struct _kthread *
2782*7c478bd9Sstevel@tonic-gate vfs_lock_owner(vfs_t *vfsp)
2783*7c478bd9Sstevel@tonic-gate {
2784*7c478bd9Sstevel@tonic-gate 	struct _kthread *owner;
2785*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_entry_t *vpvfsentry;
2786*7c478bd9Sstevel@tonic-gate 
2787*7c478bd9Sstevel@tonic-gate 	/*
2788*7c478bd9Sstevel@tonic-gate 	 * vfs_wlock_held will mimic sema_held behaviour
2789*7c478bd9Sstevel@tonic-gate 	 * if panicstr is set. And these changes should remain
2790*7c478bd9Sstevel@tonic-gate 	 * for the patch changes as it is.
2791*7c478bd9Sstevel@tonic-gate 	 */
2792*7c478bd9Sstevel@tonic-gate 	if (panicstr)
2793*7c478bd9Sstevel@tonic-gate 		return (NULL);
2794*7c478bd9Sstevel@tonic-gate 
2795*7c478bd9Sstevel@tonic-gate 	vpvfsentry = vn_vfslocks_getlock(vfsp);
2796*7c478bd9Sstevel@tonic-gate 	owner = rwst_owner(&vpvfsentry->ve_lock);
2797*7c478bd9Sstevel@tonic-gate 
2798*7c478bd9Sstevel@tonic-gate 	vn_vfslocks_rele(vpvfsentry);
2799*7c478bd9Sstevel@tonic-gate 	return (owner);
2800*7c478bd9Sstevel@tonic-gate }
2801*7c478bd9Sstevel@tonic-gate 
2802*7c478bd9Sstevel@tonic-gate /*
2803*7c478bd9Sstevel@tonic-gate  * vfs list locking.
2804*7c478bd9Sstevel@tonic-gate  *
2805*7c478bd9Sstevel@tonic-gate  * Rather than manipulate the vfslist lock directly, we abstract into lock
2806*7c478bd9Sstevel@tonic-gate  * and unlock routines to allow the locking implementation to be changed for
2807*7c478bd9Sstevel@tonic-gate  * clustering.
2808*7c478bd9Sstevel@tonic-gate  *
2809*7c478bd9Sstevel@tonic-gate  * Whenever the vfs list is modified through its hash links, the overall list
2810*7c478bd9Sstevel@tonic-gate  * lock must be obtained before locking the relevant hash bucket.  But to see
2811*7c478bd9Sstevel@tonic-gate  * whether a given vfs is on the list, it suffices to obtain the lock for the
2812*7c478bd9Sstevel@tonic-gate  * hash bucket without getting the overall list lock.  (See getvfs() below.)
2813*7c478bd9Sstevel@tonic-gate  */
2814*7c478bd9Sstevel@tonic-gate 
2815*7c478bd9Sstevel@tonic-gate void
2816*7c478bd9Sstevel@tonic-gate vfs_list_lock()
2817*7c478bd9Sstevel@tonic-gate {
2818*7c478bd9Sstevel@tonic-gate 	rw_enter(&vfslist, RW_WRITER);
2819*7c478bd9Sstevel@tonic-gate }
2820*7c478bd9Sstevel@tonic-gate 
2821*7c478bd9Sstevel@tonic-gate void
2822*7c478bd9Sstevel@tonic-gate vfs_list_read_lock()
2823*7c478bd9Sstevel@tonic-gate {
2824*7c478bd9Sstevel@tonic-gate 	rw_enter(&vfslist, RW_READER);
2825*7c478bd9Sstevel@tonic-gate }
2826*7c478bd9Sstevel@tonic-gate 
2827*7c478bd9Sstevel@tonic-gate void
2828*7c478bd9Sstevel@tonic-gate vfs_list_unlock()
2829*7c478bd9Sstevel@tonic-gate {
2830*7c478bd9Sstevel@tonic-gate 	rw_exit(&vfslist);
2831*7c478bd9Sstevel@tonic-gate }
2832*7c478bd9Sstevel@tonic-gate 
2833*7c478bd9Sstevel@tonic-gate /*
2834*7c478bd9Sstevel@tonic-gate  * Low level worker routines for adding entries to and removing entries from
2835*7c478bd9Sstevel@tonic-gate  * the vfs list.
2836*7c478bd9Sstevel@tonic-gate  */
2837*7c478bd9Sstevel@tonic-gate 
2838*7c478bd9Sstevel@tonic-gate static void
2839*7c478bd9Sstevel@tonic-gate vfs_hash_add(struct vfs *vfsp, int insert_at_head)
2840*7c478bd9Sstevel@tonic-gate {
2841*7c478bd9Sstevel@tonic-gate 	int vhno;
2842*7c478bd9Sstevel@tonic-gate 	struct vfs **hp;
2843*7c478bd9Sstevel@tonic-gate 	dev_t dev;
2844*7c478bd9Sstevel@tonic-gate 
2845*7c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&vfslist));
2846*7c478bd9Sstevel@tonic-gate 
2847*7c478bd9Sstevel@tonic-gate 	dev = expldev(vfsp->vfs_fsid.val[0]);
2848*7c478bd9Sstevel@tonic-gate 	vhno = VFSHASH(getmajor(dev), getminor(dev));
2849*7c478bd9Sstevel@tonic-gate 
2850*7c478bd9Sstevel@tonic-gate 	mutex_enter(&rvfs_list[vhno].rvfs_lock);
2851*7c478bd9Sstevel@tonic-gate 
2852*7c478bd9Sstevel@tonic-gate 	/*
2853*7c478bd9Sstevel@tonic-gate 	 * Link into the hash table, inserting it at the end, so that LOFS
2854*7c478bd9Sstevel@tonic-gate 	 * with the same fsid as UFS (or other) file systems will not hide the
2855*7c478bd9Sstevel@tonic-gate 	 * UFS.
2856*7c478bd9Sstevel@tonic-gate 	 */
2857*7c478bd9Sstevel@tonic-gate 	if (insert_at_head) {
2858*7c478bd9Sstevel@tonic-gate 		vfsp->vfs_hash = rvfs_list[vhno].rvfs_head;
2859*7c478bd9Sstevel@tonic-gate 		rvfs_list[vhno].rvfs_head = vfsp;
2860*7c478bd9Sstevel@tonic-gate 	} else {
2861*7c478bd9Sstevel@tonic-gate 		for (hp = &rvfs_list[vhno].rvfs_head; *hp != NULL;
2862*7c478bd9Sstevel@tonic-gate 		    hp = &(*hp)->vfs_hash)
2863*7c478bd9Sstevel@tonic-gate 			continue;
2864*7c478bd9Sstevel@tonic-gate 		/*
2865*7c478bd9Sstevel@tonic-gate 		 * hp now contains the address of the pointer to update
2866*7c478bd9Sstevel@tonic-gate 		 * to effect the insertion.
2867*7c478bd9Sstevel@tonic-gate 		 */
2868*7c478bd9Sstevel@tonic-gate 		vfsp->vfs_hash = NULL;
2869*7c478bd9Sstevel@tonic-gate 		*hp = vfsp;
2870*7c478bd9Sstevel@tonic-gate 	}
2871*7c478bd9Sstevel@tonic-gate 
2872*7c478bd9Sstevel@tonic-gate 	rvfs_list[vhno].rvfs_len++;
2873*7c478bd9Sstevel@tonic-gate 	mutex_exit(&rvfs_list[vhno].rvfs_lock);
2874*7c478bd9Sstevel@tonic-gate }
2875*7c478bd9Sstevel@tonic-gate 
2876*7c478bd9Sstevel@tonic-gate 
2877*7c478bd9Sstevel@tonic-gate static void
2878*7c478bd9Sstevel@tonic-gate vfs_hash_remove(struct vfs *vfsp)
2879*7c478bd9Sstevel@tonic-gate {
2880*7c478bd9Sstevel@tonic-gate 	int vhno;
2881*7c478bd9Sstevel@tonic-gate 	struct vfs *tvfsp;
2882*7c478bd9Sstevel@tonic-gate 	dev_t dev;
2883*7c478bd9Sstevel@tonic-gate 
2884*7c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&vfslist));
2885*7c478bd9Sstevel@tonic-gate 
2886*7c478bd9Sstevel@tonic-gate 	dev = expldev(vfsp->vfs_fsid.val[0]);
2887*7c478bd9Sstevel@tonic-gate 	vhno = VFSHASH(getmajor(dev), getminor(dev));
2888*7c478bd9Sstevel@tonic-gate 
2889*7c478bd9Sstevel@tonic-gate 	mutex_enter(&rvfs_list[vhno].rvfs_lock);
2890*7c478bd9Sstevel@tonic-gate 
2891*7c478bd9Sstevel@tonic-gate 	/*
2892*7c478bd9Sstevel@tonic-gate 	 * Remove from hash.
2893*7c478bd9Sstevel@tonic-gate 	 */
2894*7c478bd9Sstevel@tonic-gate 	if (rvfs_list[vhno].rvfs_head == vfsp) {
2895*7c478bd9Sstevel@tonic-gate 		rvfs_list[vhno].rvfs_head = vfsp->vfs_hash;
2896*7c478bd9Sstevel@tonic-gate 		rvfs_list[vhno].rvfs_len--;
2897*7c478bd9Sstevel@tonic-gate 		goto foundit;
2898*7c478bd9Sstevel@tonic-gate 	}
2899*7c478bd9Sstevel@tonic-gate 	for (tvfsp = rvfs_list[vhno].rvfs_head; tvfsp != NULL;
2900*7c478bd9Sstevel@tonic-gate 	    tvfsp = tvfsp->vfs_hash) {
2901*7c478bd9Sstevel@tonic-gate 		if (tvfsp->vfs_hash == vfsp) {
2902*7c478bd9Sstevel@tonic-gate 			tvfsp->vfs_hash = vfsp->vfs_hash;
2903*7c478bd9Sstevel@tonic-gate 			rvfs_list[vhno].rvfs_len--;
2904*7c478bd9Sstevel@tonic-gate 			goto foundit;
2905*7c478bd9Sstevel@tonic-gate 		}
2906*7c478bd9Sstevel@tonic-gate 	}
2907*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "vfs_list_remove: vfs not found in hash");
2908*7c478bd9Sstevel@tonic-gate 
2909*7c478bd9Sstevel@tonic-gate foundit:
2910*7c478bd9Sstevel@tonic-gate 
2911*7c478bd9Sstevel@tonic-gate 	mutex_exit(&rvfs_list[vhno].rvfs_lock);
2912*7c478bd9Sstevel@tonic-gate }
2913*7c478bd9Sstevel@tonic-gate 
2914*7c478bd9Sstevel@tonic-gate 
2915*7c478bd9Sstevel@tonic-gate void
2916*7c478bd9Sstevel@tonic-gate vfs_list_add(struct vfs *vfsp)
2917*7c478bd9Sstevel@tonic-gate {
2918*7c478bd9Sstevel@tonic-gate 	zone_t *zone;
2919*7c478bd9Sstevel@tonic-gate 
2920*7c478bd9Sstevel@tonic-gate 	/*
2921*7c478bd9Sstevel@tonic-gate 	 * The zone that owns the mount is the one that performed the mount.
2922*7c478bd9Sstevel@tonic-gate 	 * Note that this isn't necessarily the same as the zone mounted into.
2923*7c478bd9Sstevel@tonic-gate 	 * The corresponding zone_rele() will be done when the vfs_t is
2924*7c478bd9Sstevel@tonic-gate 	 * being free'd.
2925*7c478bd9Sstevel@tonic-gate 	 */
2926*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_zone = curproc->p_zone;
2927*7c478bd9Sstevel@tonic-gate 	zone_hold(vfsp->vfs_zone);
2928*7c478bd9Sstevel@tonic-gate 
2929*7c478bd9Sstevel@tonic-gate 	/*
2930*7c478bd9Sstevel@tonic-gate 	 * Find the zone mounted into, and put this mount on its vfs list.
2931*7c478bd9Sstevel@tonic-gate 	 */
2932*7c478bd9Sstevel@tonic-gate 	zone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
2933*7c478bd9Sstevel@tonic-gate 	ASSERT(zone != NULL);
2934*7c478bd9Sstevel@tonic-gate 	/*
2935*7c478bd9Sstevel@tonic-gate 	 * Special casing for the root vfs.  This structure is allocated
2936*7c478bd9Sstevel@tonic-gate 	 * statically and hooked onto rootvfs at link time.  During the
2937*7c478bd9Sstevel@tonic-gate 	 * vfs_mountroot call at system startup time, the root file system's
2938*7c478bd9Sstevel@tonic-gate 	 * VFS_MOUNTROOT routine will call vfs_add with this root vfs struct
2939*7c478bd9Sstevel@tonic-gate 	 * as argument.  The code below must detect and handle this special
2940*7c478bd9Sstevel@tonic-gate 	 * case.  The only apparent justification for this special casing is
2941*7c478bd9Sstevel@tonic-gate 	 * to ensure that the root file system appears at the head of the
2942*7c478bd9Sstevel@tonic-gate 	 * list.
2943*7c478bd9Sstevel@tonic-gate 	 *
2944*7c478bd9Sstevel@tonic-gate 	 * XXX:	I'm assuming that it's ok to do normal list locking when
2945*7c478bd9Sstevel@tonic-gate 	 *	adding the entry for the root file system (this used to be
2946*7c478bd9Sstevel@tonic-gate 	 *	done with no locks held).
2947*7c478bd9Sstevel@tonic-gate 	 */
2948*7c478bd9Sstevel@tonic-gate 	vfs_list_lock();
2949*7c478bd9Sstevel@tonic-gate 	/*
2950*7c478bd9Sstevel@tonic-gate 	 * Link into the vfs list proper.
2951*7c478bd9Sstevel@tonic-gate 	 */
2952*7c478bd9Sstevel@tonic-gate 	if (vfsp == &root) {
2953*7c478bd9Sstevel@tonic-gate 		/*
2954*7c478bd9Sstevel@tonic-gate 		 * Assert: This vfs is already on the list as its first entry.
2955*7c478bd9Sstevel@tonic-gate 		 * Thus, there's nothing to do.
2956*7c478bd9Sstevel@tonic-gate 		 */
2957*7c478bd9Sstevel@tonic-gate 		ASSERT(rootvfs == vfsp);
2958*7c478bd9Sstevel@tonic-gate 		/*
2959*7c478bd9Sstevel@tonic-gate 		 * Add it to the head of the global zone's vfslist.
2960*7c478bd9Sstevel@tonic-gate 		 */
2961*7c478bd9Sstevel@tonic-gate 		ASSERT(zone == global_zone);
2962*7c478bd9Sstevel@tonic-gate 		ASSERT(zone->zone_vfslist == NULL);
2963*7c478bd9Sstevel@tonic-gate 		zone->zone_vfslist = vfsp;
2964*7c478bd9Sstevel@tonic-gate 	} else {
2965*7c478bd9Sstevel@tonic-gate 		/*
2966*7c478bd9Sstevel@tonic-gate 		 * Link to end of list using vfs_prev (as rootvfs is now a
2967*7c478bd9Sstevel@tonic-gate 		 * doubly linked circular list) so list is in mount order for
2968*7c478bd9Sstevel@tonic-gate 		 * mnttab use.
2969*7c478bd9Sstevel@tonic-gate 		 */
2970*7c478bd9Sstevel@tonic-gate 		rootvfs->vfs_prev->vfs_next = vfsp;
2971*7c478bd9Sstevel@tonic-gate 		vfsp->vfs_prev = rootvfs->vfs_prev;
2972*7c478bd9Sstevel@tonic-gate 		rootvfs->vfs_prev = vfsp;
2973*7c478bd9Sstevel@tonic-gate 		vfsp->vfs_next = rootvfs;
2974*7c478bd9Sstevel@tonic-gate 
2975*7c478bd9Sstevel@tonic-gate 		/*
2976*7c478bd9Sstevel@tonic-gate 		 * Do it again for the zone-private list (which may be NULL).
2977*7c478bd9Sstevel@tonic-gate 		 */
2978*7c478bd9Sstevel@tonic-gate 		if (zone->zone_vfslist == NULL) {
2979*7c478bd9Sstevel@tonic-gate 			ASSERT(zone != global_zone);
2980*7c478bd9Sstevel@tonic-gate 			zone->zone_vfslist = vfsp;
2981*7c478bd9Sstevel@tonic-gate 		} else {
2982*7c478bd9Sstevel@tonic-gate 			zone->zone_vfslist->vfs_zone_prev->vfs_zone_next = vfsp;
2983*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_zone_prev = zone->zone_vfslist->vfs_zone_prev;
2984*7c478bd9Sstevel@tonic-gate 			zone->zone_vfslist->vfs_zone_prev = vfsp;
2985*7c478bd9Sstevel@tonic-gate 			vfsp->vfs_zone_next = zone->zone_vfslist;
2986*7c478bd9Sstevel@tonic-gate 		}
2987*7c478bd9Sstevel@tonic-gate 	}
2988*7c478bd9Sstevel@tonic-gate 
2989*7c478bd9Sstevel@tonic-gate 	/*
2990*7c478bd9Sstevel@tonic-gate 	 * Link into the hash table, inserting it at the end, so that LOFS
2991*7c478bd9Sstevel@tonic-gate 	 * with the same fsid as UFS (or other) file systems will not hide
2992*7c478bd9Sstevel@tonic-gate 	 * the UFS.
2993*7c478bd9Sstevel@tonic-gate 	 */
2994*7c478bd9Sstevel@tonic-gate 	vfs_hash_add(vfsp, 0);
2995*7c478bd9Sstevel@tonic-gate 
2996*7c478bd9Sstevel@tonic-gate 	/*
2997*7c478bd9Sstevel@tonic-gate 	 * update the mnttab modification time
2998*7c478bd9Sstevel@tonic-gate 	 */
2999*7c478bd9Sstevel@tonic-gate 	vfs_mnttab_modtimeupd();
3000*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
3001*7c478bd9Sstevel@tonic-gate 	zone_rele(zone);
3002*7c478bd9Sstevel@tonic-gate }
3003*7c478bd9Sstevel@tonic-gate 
3004*7c478bd9Sstevel@tonic-gate void
3005*7c478bd9Sstevel@tonic-gate vfs_list_remove(struct vfs *vfsp)
3006*7c478bd9Sstevel@tonic-gate {
3007*7c478bd9Sstevel@tonic-gate 	zone_t *zone;
3008*7c478bd9Sstevel@tonic-gate 
3009*7c478bd9Sstevel@tonic-gate 	zone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
3010*7c478bd9Sstevel@tonic-gate 	ASSERT(zone != NULL);
3011*7c478bd9Sstevel@tonic-gate 	/*
3012*7c478bd9Sstevel@tonic-gate 	 * Callers are responsible for preventing attempts to unmount the
3013*7c478bd9Sstevel@tonic-gate 	 * root.
3014*7c478bd9Sstevel@tonic-gate 	 */
3015*7c478bd9Sstevel@tonic-gate 	ASSERT(vfsp != rootvfs);
3016*7c478bd9Sstevel@tonic-gate 
3017*7c478bd9Sstevel@tonic-gate 	vfs_list_lock();
3018*7c478bd9Sstevel@tonic-gate 
3019*7c478bd9Sstevel@tonic-gate 	/*
3020*7c478bd9Sstevel@tonic-gate 	 * Remove from hash.
3021*7c478bd9Sstevel@tonic-gate 	 */
3022*7c478bd9Sstevel@tonic-gate 	vfs_hash_remove(vfsp);
3023*7c478bd9Sstevel@tonic-gate 
3024*7c478bd9Sstevel@tonic-gate 	/*
3025*7c478bd9Sstevel@tonic-gate 	 * Remove from vfs list.
3026*7c478bd9Sstevel@tonic-gate 	 */
3027*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_prev->vfs_next = vfsp->vfs_next;
3028*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_next->vfs_prev = vfsp->vfs_prev;
3029*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_next = vfsp->vfs_prev = NULL;
3030*7c478bd9Sstevel@tonic-gate 
3031*7c478bd9Sstevel@tonic-gate 	/*
3032*7c478bd9Sstevel@tonic-gate 	 * Remove from zone-specific vfs list.
3033*7c478bd9Sstevel@tonic-gate 	 */
3034*7c478bd9Sstevel@tonic-gate 	if (zone->zone_vfslist == vfsp)
3035*7c478bd9Sstevel@tonic-gate 		zone->zone_vfslist = vfsp->vfs_zone_next;
3036*7c478bd9Sstevel@tonic-gate 
3037*7c478bd9Sstevel@tonic-gate 	if (vfsp->vfs_zone_next == vfsp) {
3038*7c478bd9Sstevel@tonic-gate 		ASSERT(vfsp->vfs_zone_prev == vfsp);
3039*7c478bd9Sstevel@tonic-gate 		ASSERT(zone->zone_vfslist == vfsp);
3040*7c478bd9Sstevel@tonic-gate 		zone->zone_vfslist = NULL;
3041*7c478bd9Sstevel@tonic-gate 	}
3042*7c478bd9Sstevel@tonic-gate 
3043*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_zone_prev->vfs_zone_next = vfsp->vfs_zone_next;
3044*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_zone_next->vfs_zone_prev = vfsp->vfs_zone_prev;
3045*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_zone_next = vfsp->vfs_zone_prev = NULL;
3046*7c478bd9Sstevel@tonic-gate 
3047*7c478bd9Sstevel@tonic-gate 	/*
3048*7c478bd9Sstevel@tonic-gate 	 * update the mnttab modification time
3049*7c478bd9Sstevel@tonic-gate 	 */
3050*7c478bd9Sstevel@tonic-gate 	vfs_mnttab_modtimeupd();
3051*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
3052*7c478bd9Sstevel@tonic-gate 	zone_rele(zone);
3053*7c478bd9Sstevel@tonic-gate }
3054*7c478bd9Sstevel@tonic-gate 
3055*7c478bd9Sstevel@tonic-gate struct vfs *
3056*7c478bd9Sstevel@tonic-gate getvfs(fsid_t *fsid)
3057*7c478bd9Sstevel@tonic-gate {
3058*7c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
3059*7c478bd9Sstevel@tonic-gate 	int val0 = fsid->val[0];
3060*7c478bd9Sstevel@tonic-gate 	int val1 = fsid->val[1];
3061*7c478bd9Sstevel@tonic-gate 	dev_t dev = expldev(val0);
3062*7c478bd9Sstevel@tonic-gate 	int vhno = VFSHASH(getmajor(dev), getminor(dev));
3063*7c478bd9Sstevel@tonic-gate 	kmutex_t *hmp = &rvfs_list[vhno].rvfs_lock;
3064*7c478bd9Sstevel@tonic-gate 
3065*7c478bd9Sstevel@tonic-gate 	mutex_enter(hmp);
3066*7c478bd9Sstevel@tonic-gate 	for (vfsp = rvfs_list[vhno].rvfs_head; vfsp; vfsp = vfsp->vfs_hash) {
3067*7c478bd9Sstevel@tonic-gate 		if (vfsp->vfs_fsid.val[0] == val0 &&
3068*7c478bd9Sstevel@tonic-gate 		    vfsp->vfs_fsid.val[1] == val1) {
3069*7c478bd9Sstevel@tonic-gate 			VFS_HOLD(vfsp);
3070*7c478bd9Sstevel@tonic-gate 			mutex_exit(hmp);
3071*7c478bd9Sstevel@tonic-gate 			return (vfsp);
3072*7c478bd9Sstevel@tonic-gate 		}
3073*7c478bd9Sstevel@tonic-gate 	}
3074*7c478bd9Sstevel@tonic-gate 	mutex_exit(hmp);
3075*7c478bd9Sstevel@tonic-gate 	return (NULL);
3076*7c478bd9Sstevel@tonic-gate }
3077*7c478bd9Sstevel@tonic-gate 
3078*7c478bd9Sstevel@tonic-gate /*
3079*7c478bd9Sstevel@tonic-gate  * Search the vfs mount in progress list for a specified device/vfs entry.
3080*7c478bd9Sstevel@tonic-gate  * Returns 0 if the first entry in the list that the device matches has the
3081*7c478bd9Sstevel@tonic-gate  * given vfs pointer as well.  If the device matches but a different vfs
3082*7c478bd9Sstevel@tonic-gate  * pointer is encountered in the list before the given vfs pointer then
3083*7c478bd9Sstevel@tonic-gate  * a 1 is returned.
3084*7c478bd9Sstevel@tonic-gate  */
3085*7c478bd9Sstevel@tonic-gate 
3086*7c478bd9Sstevel@tonic-gate int
3087*7c478bd9Sstevel@tonic-gate vfs_devmounting(dev_t dev, struct vfs *vfsp)
3088*7c478bd9Sstevel@tonic-gate {
3089*7c478bd9Sstevel@tonic-gate 	int retval = 0;
3090*7c478bd9Sstevel@tonic-gate 	struct ipmnt *mipp;
3091*7c478bd9Sstevel@tonic-gate 
3092*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vfs_miplist_mutex);
3093*7c478bd9Sstevel@tonic-gate 	for (mipp = vfs_miplist; mipp != NULL; mipp = mipp->mip_next) {
3094*7c478bd9Sstevel@tonic-gate 		if (mipp->mip_dev == dev) {
3095*7c478bd9Sstevel@tonic-gate 			if (mipp->mip_vfsp != vfsp)
3096*7c478bd9Sstevel@tonic-gate 				retval = 1;
3097*7c478bd9Sstevel@tonic-gate 			break;
3098*7c478bd9Sstevel@tonic-gate 		}
3099*7c478bd9Sstevel@tonic-gate 	}
3100*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vfs_miplist_mutex);
3101*7c478bd9Sstevel@tonic-gate 	return (retval);
3102*7c478bd9Sstevel@tonic-gate }
3103*7c478bd9Sstevel@tonic-gate 
3104*7c478bd9Sstevel@tonic-gate /*
3105*7c478bd9Sstevel@tonic-gate  * Search the vfs list for a specified device.  Returns 1, if entry is found
3106*7c478bd9Sstevel@tonic-gate  * or 0 if no suitable entry is found.
3107*7c478bd9Sstevel@tonic-gate  */
3108*7c478bd9Sstevel@tonic-gate 
3109*7c478bd9Sstevel@tonic-gate int
3110*7c478bd9Sstevel@tonic-gate vfs_devismounted(dev_t dev)
3111*7c478bd9Sstevel@tonic-gate {
3112*7c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
3113*7c478bd9Sstevel@tonic-gate 	int found;
3114*7c478bd9Sstevel@tonic-gate 
3115*7c478bd9Sstevel@tonic-gate 	vfs_list_read_lock();
3116*7c478bd9Sstevel@tonic-gate 	vfsp = rootvfs;
3117*7c478bd9Sstevel@tonic-gate 	found = 0;
3118*7c478bd9Sstevel@tonic-gate 	do {
3119*7c478bd9Sstevel@tonic-gate 		if (vfsp->vfs_dev == dev) {
3120*7c478bd9Sstevel@tonic-gate 			found = 1;
3121*7c478bd9Sstevel@tonic-gate 			break;
3122*7c478bd9Sstevel@tonic-gate 		}
3123*7c478bd9Sstevel@tonic-gate 		vfsp = vfsp->vfs_next;
3124*7c478bd9Sstevel@tonic-gate 	} while (vfsp != rootvfs);
3125*7c478bd9Sstevel@tonic-gate 
3126*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
3127*7c478bd9Sstevel@tonic-gate 	return (found);
3128*7c478bd9Sstevel@tonic-gate }
3129*7c478bd9Sstevel@tonic-gate 
3130*7c478bd9Sstevel@tonic-gate /*
3131*7c478bd9Sstevel@tonic-gate  * Search the vfs list for a specified device.  Returns a pointer to it
3132*7c478bd9Sstevel@tonic-gate  * or NULL if no suitable entry is found. The caller of this routine
3133*7c478bd9Sstevel@tonic-gate  * is responsible for releasing the returned vfs pointer.
3134*7c478bd9Sstevel@tonic-gate  */
3135*7c478bd9Sstevel@tonic-gate struct vfs *
3136*7c478bd9Sstevel@tonic-gate vfs_dev2vfsp(dev_t dev)
3137*7c478bd9Sstevel@tonic-gate {
3138*7c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
3139*7c478bd9Sstevel@tonic-gate 	int found;
3140*7c478bd9Sstevel@tonic-gate 
3141*7c478bd9Sstevel@tonic-gate 	vfs_list_read_lock();
3142*7c478bd9Sstevel@tonic-gate 	vfsp = rootvfs;
3143*7c478bd9Sstevel@tonic-gate 	found = 0;
3144*7c478bd9Sstevel@tonic-gate 	do {
3145*7c478bd9Sstevel@tonic-gate 		/*
3146*7c478bd9Sstevel@tonic-gate 		 * The following could be made more efficient by making
3147*7c478bd9Sstevel@tonic-gate 		 * the entire loop use vfs_zone_next if the call is from
3148*7c478bd9Sstevel@tonic-gate 		 * a zone.  The only callers, however, ustat(2) and
3149*7c478bd9Sstevel@tonic-gate 		 * umount2(2), don't seem to justify the added
3150*7c478bd9Sstevel@tonic-gate 		 * complexity at present.
3151*7c478bd9Sstevel@tonic-gate 		 */
3152*7c478bd9Sstevel@tonic-gate 		if (vfsp->vfs_dev == dev &&
3153*7c478bd9Sstevel@tonic-gate 		    ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt),
3154*7c478bd9Sstevel@tonic-gate 		    curproc->p_zone)) {
3155*7c478bd9Sstevel@tonic-gate 			VFS_HOLD(vfsp);
3156*7c478bd9Sstevel@tonic-gate 			found = 1;
3157*7c478bd9Sstevel@tonic-gate 			break;
3158*7c478bd9Sstevel@tonic-gate 		}
3159*7c478bd9Sstevel@tonic-gate 		vfsp = vfsp->vfs_next;
3160*7c478bd9Sstevel@tonic-gate 	} while (vfsp != rootvfs);
3161*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
3162*7c478bd9Sstevel@tonic-gate 	return (found ? vfsp: NULL);
3163*7c478bd9Sstevel@tonic-gate }
3164*7c478bd9Sstevel@tonic-gate 
3165*7c478bd9Sstevel@tonic-gate /*
3166*7c478bd9Sstevel@tonic-gate  * Search the vfs list for a specified mntpoint.  Returns a pointer to it
3167*7c478bd9Sstevel@tonic-gate  * or NULL if no suitable entry is found. The caller of this routine
3168*7c478bd9Sstevel@tonic-gate  * is responsible for releasing the returned vfs pointer.
3169*7c478bd9Sstevel@tonic-gate  *
3170*7c478bd9Sstevel@tonic-gate  * Note that if multiple mntpoints match, the last one matching is
3171*7c478bd9Sstevel@tonic-gate  * returned in an attempt to return the "top" mount when overlay
3172*7c478bd9Sstevel@tonic-gate  * mounts are covering the same mount point.  This is accomplished by starting
3173*7c478bd9Sstevel@tonic-gate  * at the end of the list and working our way backwards, stopping at the first
3174*7c478bd9Sstevel@tonic-gate  * matching mount.
3175*7c478bd9Sstevel@tonic-gate  */
3176*7c478bd9Sstevel@tonic-gate struct vfs *
3177*7c478bd9Sstevel@tonic-gate vfs_mntpoint2vfsp(const char *mp)
3178*7c478bd9Sstevel@tonic-gate {
3179*7c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
3180*7c478bd9Sstevel@tonic-gate 	struct vfs *retvfsp = NULL;
3181*7c478bd9Sstevel@tonic-gate 	zone_t *zone = curproc->p_zone;
3182*7c478bd9Sstevel@tonic-gate 	struct vfs *list;
3183*7c478bd9Sstevel@tonic-gate 
3184*7c478bd9Sstevel@tonic-gate 	vfs_list_read_lock();
3185*7c478bd9Sstevel@tonic-gate 	if (getzoneid() == GLOBAL_ZONEID) {
3186*7c478bd9Sstevel@tonic-gate 		/*
3187*7c478bd9Sstevel@tonic-gate 		 * The global zone may see filesystems in any zone.
3188*7c478bd9Sstevel@tonic-gate 		 */
3189*7c478bd9Sstevel@tonic-gate 		vfsp = rootvfs->vfs_prev;
3190*7c478bd9Sstevel@tonic-gate 		do {
3191*7c478bd9Sstevel@tonic-gate 			if (strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0) {
3192*7c478bd9Sstevel@tonic-gate 				retvfsp = vfsp;
3193*7c478bd9Sstevel@tonic-gate 				break;
3194*7c478bd9Sstevel@tonic-gate 			}
3195*7c478bd9Sstevel@tonic-gate 			vfsp = vfsp->vfs_prev;
3196*7c478bd9Sstevel@tonic-gate 		} while (vfsp != rootvfs->vfs_prev);
3197*7c478bd9Sstevel@tonic-gate 	} else if ((list = zone->zone_vfslist) != NULL) {
3198*7c478bd9Sstevel@tonic-gate 		const char *mntpt;
3199*7c478bd9Sstevel@tonic-gate 
3200*7c478bd9Sstevel@tonic-gate 		vfsp = list->vfs_zone_prev;
3201*7c478bd9Sstevel@tonic-gate 		do {
3202*7c478bd9Sstevel@tonic-gate 			mntpt = refstr_value(vfsp->vfs_mntpt);
3203*7c478bd9Sstevel@tonic-gate 			mntpt = ZONE_PATH_TRANSLATE(mntpt, zone);
3204*7c478bd9Sstevel@tonic-gate 			if (strcmp(mntpt, mp) == 0) {
3205*7c478bd9Sstevel@tonic-gate 				retvfsp = vfsp;
3206*7c478bd9Sstevel@tonic-gate 				break;
3207*7c478bd9Sstevel@tonic-gate 			}
3208*7c478bd9Sstevel@tonic-gate 			vfsp = vfsp->vfs_zone_prev;
3209*7c478bd9Sstevel@tonic-gate 		} while (vfsp != list->vfs_zone_prev);
3210*7c478bd9Sstevel@tonic-gate 	}
3211*7c478bd9Sstevel@tonic-gate 	if (retvfsp)
3212*7c478bd9Sstevel@tonic-gate 		VFS_HOLD(retvfsp);
3213*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
3214*7c478bd9Sstevel@tonic-gate 	return (retvfsp);
3215*7c478bd9Sstevel@tonic-gate }
3216*7c478bd9Sstevel@tonic-gate 
3217*7c478bd9Sstevel@tonic-gate /*
3218*7c478bd9Sstevel@tonic-gate  * Search the vfs list for a specified vfsops.
3219*7c478bd9Sstevel@tonic-gate  * if vfs entry is found then return 1, else 0.
3220*7c478bd9Sstevel@tonic-gate  */
3221*7c478bd9Sstevel@tonic-gate int
3222*7c478bd9Sstevel@tonic-gate vfs_opsinuse(vfsops_t *ops)
3223*7c478bd9Sstevel@tonic-gate {
3224*7c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
3225*7c478bd9Sstevel@tonic-gate 	int found;
3226*7c478bd9Sstevel@tonic-gate 
3227*7c478bd9Sstevel@tonic-gate 	vfs_list_read_lock();
3228*7c478bd9Sstevel@tonic-gate 	vfsp = rootvfs;
3229*7c478bd9Sstevel@tonic-gate 	found = 0;
3230*7c478bd9Sstevel@tonic-gate 	do {
3231*7c478bd9Sstevel@tonic-gate 		if (vfs_getops(vfsp) == ops) {
3232*7c478bd9Sstevel@tonic-gate 			found = 1;
3233*7c478bd9Sstevel@tonic-gate 			break;
3234*7c478bd9Sstevel@tonic-gate 		}
3235*7c478bd9Sstevel@tonic-gate 		vfsp = vfsp->vfs_next;
3236*7c478bd9Sstevel@tonic-gate 	} while (vfsp != rootvfs);
3237*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
3238*7c478bd9Sstevel@tonic-gate 	return (found);
3239*7c478bd9Sstevel@tonic-gate }
3240*7c478bd9Sstevel@tonic-gate 
3241*7c478bd9Sstevel@tonic-gate /*
3242*7c478bd9Sstevel@tonic-gate  * Allocate an entry in vfssw for a file system type
3243*7c478bd9Sstevel@tonic-gate  */
3244*7c478bd9Sstevel@tonic-gate struct vfssw *
3245*7c478bd9Sstevel@tonic-gate allocate_vfssw(char *type)
3246*7c478bd9Sstevel@tonic-gate {
3247*7c478bd9Sstevel@tonic-gate 	struct vfssw *vswp;
3248*7c478bd9Sstevel@tonic-gate 
3249*7c478bd9Sstevel@tonic-gate 	if (type[0] == '\0' || strlen(type) + 1 > _ST_FSTYPSZ) {
3250*7c478bd9Sstevel@tonic-gate 		/*
3251*7c478bd9Sstevel@tonic-gate 		 * The vfssw table uses the empty string to identify an
3252*7c478bd9Sstevel@tonic-gate 		 * available entry; we cannot add any type which has
3253*7c478bd9Sstevel@tonic-gate 		 * a leading NUL. The string length is limited to
3254*7c478bd9Sstevel@tonic-gate 		 * the size of the st_fstype array in struct stat.
3255*7c478bd9Sstevel@tonic-gate 		 */
3256*7c478bd9Sstevel@tonic-gate 		return (NULL);
3257*7c478bd9Sstevel@tonic-gate 	}
3258*7c478bd9Sstevel@tonic-gate 
3259*7c478bd9Sstevel@tonic-gate 	ASSERT(VFSSW_WRITE_LOCKED());
3260*7c478bd9Sstevel@tonic-gate 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++)
3261*7c478bd9Sstevel@tonic-gate 		if (!ALLOCATED_VFSSW(vswp)) {
3262*7c478bd9Sstevel@tonic-gate 			vswp->vsw_name = kmem_alloc(strlen(type) + 1, KM_SLEEP);
3263*7c478bd9Sstevel@tonic-gate 			(void) strcpy(vswp->vsw_name, type);
3264*7c478bd9Sstevel@tonic-gate 			ASSERT(vswp->vsw_count == 0);
3265*7c478bd9Sstevel@tonic-gate 			vswp->vsw_count = 1;
3266*7c478bd9Sstevel@tonic-gate 			mutex_init(&vswp->vsw_lock, NULL, MUTEX_DEFAULT, NULL);
3267*7c478bd9Sstevel@tonic-gate 			return (vswp);
3268*7c478bd9Sstevel@tonic-gate 		}
3269*7c478bd9Sstevel@tonic-gate 	return (NULL);
3270*7c478bd9Sstevel@tonic-gate }
3271*7c478bd9Sstevel@tonic-gate 
3272*7c478bd9Sstevel@tonic-gate /*
3273*7c478bd9Sstevel@tonic-gate  * Impose additional layer of translation between vfstype names
3274*7c478bd9Sstevel@tonic-gate  * and module names in the filesystem.
3275*7c478bd9Sstevel@tonic-gate  */
3276*7c478bd9Sstevel@tonic-gate static char *
3277*7c478bd9Sstevel@tonic-gate vfs_to_modname(char *vfstype)
3278*7c478bd9Sstevel@tonic-gate {
3279*7c478bd9Sstevel@tonic-gate 	if (strcmp(vfstype, "proc") == 0) {
3280*7c478bd9Sstevel@tonic-gate 		vfstype = "procfs";
3281*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(vfstype, "fd") == 0) {
3282*7c478bd9Sstevel@tonic-gate 		vfstype = "fdfs";
3283*7c478bd9Sstevel@tonic-gate 	} else if (strncmp(vfstype, "nfs", 3) == 0) {
3284*7c478bd9Sstevel@tonic-gate 		vfstype = "nfs";
3285*7c478bd9Sstevel@tonic-gate 	}
3286*7c478bd9Sstevel@tonic-gate 
3287*7c478bd9Sstevel@tonic-gate 	return (vfstype);
3288*7c478bd9Sstevel@tonic-gate }
3289*7c478bd9Sstevel@tonic-gate 
3290*7c478bd9Sstevel@tonic-gate /*
3291*7c478bd9Sstevel@tonic-gate  * Find a vfssw entry given a file system type name.
3292*7c478bd9Sstevel@tonic-gate  * Try to autoload the filesystem if it's not found.
3293*7c478bd9Sstevel@tonic-gate  * If it's installed, return the vfssw locked to prevent unloading.
3294*7c478bd9Sstevel@tonic-gate  */
3295*7c478bd9Sstevel@tonic-gate struct vfssw *
3296*7c478bd9Sstevel@tonic-gate vfs_getvfssw(char *type)
3297*7c478bd9Sstevel@tonic-gate {
3298*7c478bd9Sstevel@tonic-gate 	struct vfssw *vswp;
3299*7c478bd9Sstevel@tonic-gate 	char	*modname;
3300*7c478bd9Sstevel@tonic-gate 
3301*7c478bd9Sstevel@tonic-gate 	RLOCK_VFSSW();
3302*7c478bd9Sstevel@tonic-gate 	vswp = vfs_getvfsswbyname(type);
3303*7c478bd9Sstevel@tonic-gate 	modname = vfs_to_modname(type);
3304*7c478bd9Sstevel@tonic-gate 
3305*7c478bd9Sstevel@tonic-gate 	if (rootdir == NULL) {
3306*7c478bd9Sstevel@tonic-gate 		/*
3307*7c478bd9Sstevel@tonic-gate 		 * If we haven't yet loaded the root file system, then our
3308*7c478bd9Sstevel@tonic-gate 		 * _init won't be called until later. Allocate vfssw entry,
3309*7c478bd9Sstevel@tonic-gate 		 * because mod_installfs won't be called.
3310*7c478bd9Sstevel@tonic-gate 		 */
3311*7c478bd9Sstevel@tonic-gate 		if (vswp == NULL) {
3312*7c478bd9Sstevel@tonic-gate 			RUNLOCK_VFSSW();
3313*7c478bd9Sstevel@tonic-gate 			WLOCK_VFSSW();
3314*7c478bd9Sstevel@tonic-gate 			if ((vswp = vfs_getvfsswbyname(type)) == NULL) {
3315*7c478bd9Sstevel@tonic-gate 				if ((vswp = allocate_vfssw(type)) == NULL) {
3316*7c478bd9Sstevel@tonic-gate 					WUNLOCK_VFSSW();
3317*7c478bd9Sstevel@tonic-gate 					return (NULL);
3318*7c478bd9Sstevel@tonic-gate 				}
3319*7c478bd9Sstevel@tonic-gate 			}
3320*7c478bd9Sstevel@tonic-gate 			WUNLOCK_VFSSW();
3321*7c478bd9Sstevel@tonic-gate 			RLOCK_VFSSW();
3322*7c478bd9Sstevel@tonic-gate 		}
3323*7c478bd9Sstevel@tonic-gate 		if (!VFS_INSTALLED(vswp)) {
3324*7c478bd9Sstevel@tonic-gate 			RUNLOCK_VFSSW();
3325*7c478bd9Sstevel@tonic-gate 			(void) modloadonly("fs", modname);
3326*7c478bd9Sstevel@tonic-gate 		} else
3327*7c478bd9Sstevel@tonic-gate 			RUNLOCK_VFSSW();
3328*7c478bd9Sstevel@tonic-gate 		return (vswp);
3329*7c478bd9Sstevel@tonic-gate 	}
3330*7c478bd9Sstevel@tonic-gate 
3331*7c478bd9Sstevel@tonic-gate 	/*
3332*7c478bd9Sstevel@tonic-gate 	 * Try to load the filesystem.  Before calling modload(), we drop
3333*7c478bd9Sstevel@tonic-gate 	 * our lock on the VFS switch table, and pick it up after the
3334*7c478bd9Sstevel@tonic-gate 	 * module is loaded.  However, there is a potential race:  the
3335*7c478bd9Sstevel@tonic-gate 	 * module could be unloaded after the call to modload() completes
3336*7c478bd9Sstevel@tonic-gate 	 * but before we pick up the lock and drive on.  Therefore,
3337*7c478bd9Sstevel@tonic-gate 	 * we keep reloading the module until we've loaded the module
3338*7c478bd9Sstevel@tonic-gate 	 * _and_ we have the lock on the VFS switch table.
3339*7c478bd9Sstevel@tonic-gate 	 */
3340*7c478bd9Sstevel@tonic-gate 	while (vswp == NULL || !VFS_INSTALLED(vswp)) {
3341*7c478bd9Sstevel@tonic-gate 		RUNLOCK_VFSSW();
3342*7c478bd9Sstevel@tonic-gate 		if (modload("fs", modname) == -1)
3343*7c478bd9Sstevel@tonic-gate 			return (NULL);
3344*7c478bd9Sstevel@tonic-gate 		RLOCK_VFSSW();
3345*7c478bd9Sstevel@tonic-gate 		if (vswp == NULL)
3346*7c478bd9Sstevel@tonic-gate 			if ((vswp = vfs_getvfsswbyname(type)) == NULL)
3347*7c478bd9Sstevel@tonic-gate 				break;
3348*7c478bd9Sstevel@tonic-gate 	}
3349*7c478bd9Sstevel@tonic-gate 	RUNLOCK_VFSSW();
3350*7c478bd9Sstevel@tonic-gate 
3351*7c478bd9Sstevel@tonic-gate 	return (vswp);
3352*7c478bd9Sstevel@tonic-gate }
3353*7c478bd9Sstevel@tonic-gate 
3354*7c478bd9Sstevel@tonic-gate /*
3355*7c478bd9Sstevel@tonic-gate  * Find a vfssw entry given a file system type name.
3356*7c478bd9Sstevel@tonic-gate  */
3357*7c478bd9Sstevel@tonic-gate struct vfssw *
3358*7c478bd9Sstevel@tonic-gate vfs_getvfsswbyname(char *type)
3359*7c478bd9Sstevel@tonic-gate {
3360*7c478bd9Sstevel@tonic-gate 	struct vfssw *vswp;
3361*7c478bd9Sstevel@tonic-gate 
3362*7c478bd9Sstevel@tonic-gate 	ASSERT(VFSSW_LOCKED());
3363*7c478bd9Sstevel@tonic-gate 	if (type == NULL || *type == '\0')
3364*7c478bd9Sstevel@tonic-gate 		return (NULL);
3365*7c478bd9Sstevel@tonic-gate 
3366*7c478bd9Sstevel@tonic-gate 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
3367*7c478bd9Sstevel@tonic-gate 		if (strcmp(type, vswp->vsw_name) == 0) {
3368*7c478bd9Sstevel@tonic-gate 			vfs_refvfssw(vswp);
3369*7c478bd9Sstevel@tonic-gate 			return (vswp);
3370*7c478bd9Sstevel@tonic-gate 		}
3371*7c478bd9Sstevel@tonic-gate 	}
3372*7c478bd9Sstevel@tonic-gate 
3373*7c478bd9Sstevel@tonic-gate 	return (NULL);
3374*7c478bd9Sstevel@tonic-gate }
3375*7c478bd9Sstevel@tonic-gate 
3376*7c478bd9Sstevel@tonic-gate /*
3377*7c478bd9Sstevel@tonic-gate  * Find a vfssw entry given a set of vfsops.
3378*7c478bd9Sstevel@tonic-gate  */
3379*7c478bd9Sstevel@tonic-gate struct vfssw *
3380*7c478bd9Sstevel@tonic-gate vfs_getvfsswbyvfsops(vfsops_t *vfsops)
3381*7c478bd9Sstevel@tonic-gate {
3382*7c478bd9Sstevel@tonic-gate 	struct vfssw *vswp;
3383*7c478bd9Sstevel@tonic-gate 
3384*7c478bd9Sstevel@tonic-gate 	RLOCK_VFSSW();
3385*7c478bd9Sstevel@tonic-gate 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
3386*7c478bd9Sstevel@tonic-gate 		if (ALLOCATED_VFSSW(vswp) && &vswp->vsw_vfsops == vfsops) {
3387*7c478bd9Sstevel@tonic-gate 			vfs_refvfssw(vswp);
3388*7c478bd9Sstevel@tonic-gate 			RUNLOCK_VFSSW();
3389*7c478bd9Sstevel@tonic-gate 			return (vswp);
3390*7c478bd9Sstevel@tonic-gate 		}
3391*7c478bd9Sstevel@tonic-gate 	}
3392*7c478bd9Sstevel@tonic-gate 	RUNLOCK_VFSSW();
3393*7c478bd9Sstevel@tonic-gate 
3394*7c478bd9Sstevel@tonic-gate 	return (NULL);
3395*7c478bd9Sstevel@tonic-gate }
3396*7c478bd9Sstevel@tonic-gate 
3397*7c478bd9Sstevel@tonic-gate /*
3398*7c478bd9Sstevel@tonic-gate  * Reference a vfssw entry.
3399*7c478bd9Sstevel@tonic-gate  */
3400*7c478bd9Sstevel@tonic-gate void
3401*7c478bd9Sstevel@tonic-gate vfs_refvfssw(struct vfssw *vswp)
3402*7c478bd9Sstevel@tonic-gate {
3403*7c478bd9Sstevel@tonic-gate 
3404*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vswp->vsw_lock);
3405*7c478bd9Sstevel@tonic-gate 	vswp->vsw_count++;
3406*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vswp->vsw_lock);
3407*7c478bd9Sstevel@tonic-gate }
3408*7c478bd9Sstevel@tonic-gate 
3409*7c478bd9Sstevel@tonic-gate /*
3410*7c478bd9Sstevel@tonic-gate  * Unreference a vfssw entry.
3411*7c478bd9Sstevel@tonic-gate  */
3412*7c478bd9Sstevel@tonic-gate void
3413*7c478bd9Sstevel@tonic-gate vfs_unrefvfssw(struct vfssw *vswp)
3414*7c478bd9Sstevel@tonic-gate {
3415*7c478bd9Sstevel@tonic-gate 
3416*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vswp->vsw_lock);
3417*7c478bd9Sstevel@tonic-gate 	vswp->vsw_count--;
3418*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vswp->vsw_lock);
3419*7c478bd9Sstevel@tonic-gate }
3420*7c478bd9Sstevel@tonic-gate 
3421*7c478bd9Sstevel@tonic-gate int sync_timeout = 30;		/* timeout for syncing a page during panic */
3422*7c478bd9Sstevel@tonic-gate int sync_timeleft;		/* portion of sync_timeout remaining */
3423*7c478bd9Sstevel@tonic-gate 
3424*7c478bd9Sstevel@tonic-gate static int sync_retries = 20;	/* number of retries when not making progress */
3425*7c478bd9Sstevel@tonic-gate static int sync_triesleft;	/* portion of sync_retries remaining */
3426*7c478bd9Sstevel@tonic-gate 
3427*7c478bd9Sstevel@tonic-gate static pgcnt_t old_pgcnt, new_pgcnt;
3428*7c478bd9Sstevel@tonic-gate static int new_bufcnt, old_bufcnt;
3429*7c478bd9Sstevel@tonic-gate 
3430*7c478bd9Sstevel@tonic-gate /*
3431*7c478bd9Sstevel@tonic-gate  * Sync all of the mounted filesystems, and then wait for the actual i/o to
3432*7c478bd9Sstevel@tonic-gate  * complete.  We wait by counting the number of dirty pages and buffers,
3433*7c478bd9Sstevel@tonic-gate  * pushing them out using bio_busy() and page_busy(), and then counting again.
3434*7c478bd9Sstevel@tonic-gate  * This routine is used during both the uadmin A_SHUTDOWN code as well as
3435*7c478bd9Sstevel@tonic-gate  * the SYNC phase of the panic code (see comments in panic.c).  It should only
3436*7c478bd9Sstevel@tonic-gate  * be used after some higher-level mechanism has quiesced the system so that
3437*7c478bd9Sstevel@tonic-gate  * new writes are not being initiated while we are waiting for completion.
3438*7c478bd9Sstevel@tonic-gate  *
3439*7c478bd9Sstevel@tonic-gate  * To ensure finite running time, our algorithm uses two timeout mechanisms:
3440*7c478bd9Sstevel@tonic-gate  * sync_timeleft (a timer implemented by the omnipresent deadman() cyclic), and
3441*7c478bd9Sstevel@tonic-gate  * sync_triesleft (a progress counter used by the vfs_syncall() loop below).
3442*7c478bd9Sstevel@tonic-gate  * Together these ensure that syncing completes if our i/o paths are stuck.
3443*7c478bd9Sstevel@tonic-gate  * The counters are declared above so they can be found easily in the debugger.
3444*7c478bd9Sstevel@tonic-gate  *
3445*7c478bd9Sstevel@tonic-gate  * The sync_timeleft counter is reset by bio_busy() and page_busy() using the
3446*7c478bd9Sstevel@tonic-gate  * vfs_syncprogress() subroutine whenever we make progress through the lists of
3447*7c478bd9Sstevel@tonic-gate  * pages and buffers.  It is decremented and expired by the deadman() cyclic.
3448*7c478bd9Sstevel@tonic-gate  * When vfs_syncall() decides it is done, we disable the deadman() counter by
3449*7c478bd9Sstevel@tonic-gate  * setting sync_timeleft to zero.  This timer guards against vfs_syncall()
3450*7c478bd9Sstevel@tonic-gate  * deadlocking or hanging inside of a broken filesystem or driver routine.
3451*7c478bd9Sstevel@tonic-gate  *
3452*7c478bd9Sstevel@tonic-gate  * The sync_triesleft counter is updated by vfs_syncall() itself.  If we make
3453*7c478bd9Sstevel@tonic-gate  * sync_retries consecutive calls to bio_busy() and page_busy() without
3454*7c478bd9Sstevel@tonic-gate  * decreasing either the number of dirty buffers or dirty pages below the
3455*7c478bd9Sstevel@tonic-gate  * lowest count we have seen so far, we give up and return from vfs_syncall().
3456*7c478bd9Sstevel@tonic-gate  *
3457*7c478bd9Sstevel@tonic-gate  * Each loop iteration ends with a call to delay() one second to allow time for
3458*7c478bd9Sstevel@tonic-gate  * i/o completion and to permit the user time to read our progress messages.
3459*7c478bd9Sstevel@tonic-gate  */
3460*7c478bd9Sstevel@tonic-gate void
3461*7c478bd9Sstevel@tonic-gate vfs_syncall(void)
3462*7c478bd9Sstevel@tonic-gate {
3463*7c478bd9Sstevel@tonic-gate 	if (rootdir == NULL && !modrootloaded)
3464*7c478bd9Sstevel@tonic-gate 		return; /* panic during boot - no filesystems yet */
3465*7c478bd9Sstevel@tonic-gate 
3466*7c478bd9Sstevel@tonic-gate 	printf("syncing file systems...");
3467*7c478bd9Sstevel@tonic-gate 	vfs_syncprogress();
3468*7c478bd9Sstevel@tonic-gate 	sync();
3469*7c478bd9Sstevel@tonic-gate 
3470*7c478bd9Sstevel@tonic-gate 	vfs_syncprogress();
3471*7c478bd9Sstevel@tonic-gate 	sync_triesleft = sync_retries;
3472*7c478bd9Sstevel@tonic-gate 
3473*7c478bd9Sstevel@tonic-gate 	old_bufcnt = new_bufcnt = INT_MAX;
3474*7c478bd9Sstevel@tonic-gate 	old_pgcnt = new_pgcnt = ULONG_MAX;
3475*7c478bd9Sstevel@tonic-gate 
3476*7c478bd9Sstevel@tonic-gate 	while (sync_triesleft > 0) {
3477*7c478bd9Sstevel@tonic-gate 		old_bufcnt = MIN(old_bufcnt, new_bufcnt);
3478*7c478bd9Sstevel@tonic-gate 		old_pgcnt = MIN(old_pgcnt, new_pgcnt);
3479*7c478bd9Sstevel@tonic-gate 
3480*7c478bd9Sstevel@tonic-gate 		new_bufcnt = bio_busy(B_TRUE);
3481*7c478bd9Sstevel@tonic-gate 		new_pgcnt = page_busy(B_TRUE);
3482*7c478bd9Sstevel@tonic-gate 		vfs_syncprogress();
3483*7c478bd9Sstevel@tonic-gate 
3484*7c478bd9Sstevel@tonic-gate 		if (new_bufcnt == 0 && new_pgcnt == 0)
3485*7c478bd9Sstevel@tonic-gate 			break;
3486*7c478bd9Sstevel@tonic-gate 
3487*7c478bd9Sstevel@tonic-gate 		if (new_bufcnt < old_bufcnt || new_pgcnt < old_pgcnt)
3488*7c478bd9Sstevel@tonic-gate 			sync_triesleft = sync_retries;
3489*7c478bd9Sstevel@tonic-gate 		else
3490*7c478bd9Sstevel@tonic-gate 			sync_triesleft--;
3491*7c478bd9Sstevel@tonic-gate 
3492*7c478bd9Sstevel@tonic-gate 		if (new_bufcnt)
3493*7c478bd9Sstevel@tonic-gate 			printf(" [%d]", new_bufcnt);
3494*7c478bd9Sstevel@tonic-gate 		if (new_pgcnt)
3495*7c478bd9Sstevel@tonic-gate 			printf(" %lu", new_pgcnt);
3496*7c478bd9Sstevel@tonic-gate 
3497*7c478bd9Sstevel@tonic-gate 		delay(hz);
3498*7c478bd9Sstevel@tonic-gate 	}
3499*7c478bd9Sstevel@tonic-gate 
3500*7c478bd9Sstevel@tonic-gate 	if (new_bufcnt != 0 || new_pgcnt != 0)
3501*7c478bd9Sstevel@tonic-gate 		printf(" done (not all i/o completed)\n");
3502*7c478bd9Sstevel@tonic-gate 	else
3503*7c478bd9Sstevel@tonic-gate 		printf(" done\n");
3504*7c478bd9Sstevel@tonic-gate 
3505*7c478bd9Sstevel@tonic-gate 	sync_timeleft = 0;
3506*7c478bd9Sstevel@tonic-gate 	delay(hz);
3507*7c478bd9Sstevel@tonic-gate }
3508*7c478bd9Sstevel@tonic-gate 
3509*7c478bd9Sstevel@tonic-gate /*
3510*7c478bd9Sstevel@tonic-gate  * If we are in the middle of the sync phase of panic, reset sync_timeleft to
3511*7c478bd9Sstevel@tonic-gate  * sync_timeout to indicate that we are making progress and the deadman()
3512*7c478bd9Sstevel@tonic-gate  * omnipresent cyclic should not yet time us out.  Note that it is safe to
3513*7c478bd9Sstevel@tonic-gate  * store to sync_timeleft here since the deadman() is firing at high-level
3514*7c478bd9Sstevel@tonic-gate  * on top of us.  If we are racing with the deadman(), either the deadman()
3515*7c478bd9Sstevel@tonic-gate  * will decrement the old value and then we will reset it, or we will
3516*7c478bd9Sstevel@tonic-gate  * reset it and then the deadman() will immediately decrement it.  In either
3517*7c478bd9Sstevel@tonic-gate  * case, correct behavior results.
3518*7c478bd9Sstevel@tonic-gate  */
3519*7c478bd9Sstevel@tonic-gate void
3520*7c478bd9Sstevel@tonic-gate vfs_syncprogress(void)
3521*7c478bd9Sstevel@tonic-gate {
3522*7c478bd9Sstevel@tonic-gate 	if (panicstr)
3523*7c478bd9Sstevel@tonic-gate 		sync_timeleft = sync_timeout;
3524*7c478bd9Sstevel@tonic-gate }
3525*7c478bd9Sstevel@tonic-gate 
3526*7c478bd9Sstevel@tonic-gate /*
3527*7c478bd9Sstevel@tonic-gate  * Map VFS flags to statvfs flags.  These shouldn't really be separate
3528*7c478bd9Sstevel@tonic-gate  * flags at all.
3529*7c478bd9Sstevel@tonic-gate  */
3530*7c478bd9Sstevel@tonic-gate uint_t
3531*7c478bd9Sstevel@tonic-gate vf_to_stf(uint_t vf)
3532*7c478bd9Sstevel@tonic-gate {
3533*7c478bd9Sstevel@tonic-gate 	uint_t stf = 0;
3534*7c478bd9Sstevel@tonic-gate 
3535*7c478bd9Sstevel@tonic-gate 	if (vf & VFS_RDONLY)
3536*7c478bd9Sstevel@tonic-gate 		stf |= ST_RDONLY;
3537*7c478bd9Sstevel@tonic-gate 	if (vf & VFS_NOSETUID)
3538*7c478bd9Sstevel@tonic-gate 		stf |= ST_NOSUID;
3539*7c478bd9Sstevel@tonic-gate 	if (vf & VFS_NOTRUNC)
3540*7c478bd9Sstevel@tonic-gate 		stf |= ST_NOTRUNC;
3541*7c478bd9Sstevel@tonic-gate 
3542*7c478bd9Sstevel@tonic-gate 	return (stf);
3543*7c478bd9Sstevel@tonic-gate }
3544*7c478bd9Sstevel@tonic-gate 
3545*7c478bd9Sstevel@tonic-gate /*
3546*7c478bd9Sstevel@tonic-gate  * Use old-style function prototype for vfsstray() so
3547*7c478bd9Sstevel@tonic-gate  * that we can use it anywhere in the vfsops structure.
3548*7c478bd9Sstevel@tonic-gate  */
3549*7c478bd9Sstevel@tonic-gate int vfsstray();
3550*7c478bd9Sstevel@tonic-gate 
3551*7c478bd9Sstevel@tonic-gate /*
3552*7c478bd9Sstevel@tonic-gate  * Entries for (illegal) fstype 0.
3553*7c478bd9Sstevel@tonic-gate  */
3554*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
3555*7c478bd9Sstevel@tonic-gate int
3556*7c478bd9Sstevel@tonic-gate vfsstray_sync(struct vfs *vfsp, short arg, struct cred *cr)
3557*7c478bd9Sstevel@tonic-gate {
3558*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_PANIC, "stray vfs operation");
3559*7c478bd9Sstevel@tonic-gate 	return (0);
3560*7c478bd9Sstevel@tonic-gate }
3561*7c478bd9Sstevel@tonic-gate 
3562*7c478bd9Sstevel@tonic-gate vfsops_t vfs_strayops = {
3563*7c478bd9Sstevel@tonic-gate 	vfsstray,
3564*7c478bd9Sstevel@tonic-gate 	vfsstray,
3565*7c478bd9Sstevel@tonic-gate 	vfsstray,
3566*7c478bd9Sstevel@tonic-gate 	vfsstray,
3567*7c478bd9Sstevel@tonic-gate 	vfsstray_sync,
3568*7c478bd9Sstevel@tonic-gate 	vfsstray,
3569*7c478bd9Sstevel@tonic-gate 	vfsstray,
3570*7c478bd9Sstevel@tonic-gate 	vfsstray
3571*7c478bd9Sstevel@tonic-gate };
3572*7c478bd9Sstevel@tonic-gate 
3573*7c478bd9Sstevel@tonic-gate /*
3574*7c478bd9Sstevel@tonic-gate  * Entries for (illegal) fstype 0.
3575*7c478bd9Sstevel@tonic-gate  */
3576*7c478bd9Sstevel@tonic-gate int
3577*7c478bd9Sstevel@tonic-gate vfsstray(void)
3578*7c478bd9Sstevel@tonic-gate {
3579*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_PANIC, "stray vfs operation");
3580*7c478bd9Sstevel@tonic-gate 	return (0);
3581*7c478bd9Sstevel@tonic-gate }
3582*7c478bd9Sstevel@tonic-gate 
3583*7c478bd9Sstevel@tonic-gate /*
3584*7c478bd9Sstevel@tonic-gate  * Support for dealing with forced UFS unmount and its interaction with
3585*7c478bd9Sstevel@tonic-gate  * LOFS. Could be used by any filesystem.
3586*7c478bd9Sstevel@tonic-gate  * See bug 1203132.
3587*7c478bd9Sstevel@tonic-gate  */
3588*7c478bd9Sstevel@tonic-gate int
3589*7c478bd9Sstevel@tonic-gate vfs_EIO(void)
3590*7c478bd9Sstevel@tonic-gate {
3591*7c478bd9Sstevel@tonic-gate 	return (EIO);
3592*7c478bd9Sstevel@tonic-gate }
3593*7c478bd9Sstevel@tonic-gate 
3594*7c478bd9Sstevel@tonic-gate /*
3595*7c478bd9Sstevel@tonic-gate  * We've gotta define the op for sync separately, since the compiler gets
3596*7c478bd9Sstevel@tonic-gate  * confused if we mix and match ANSI and normal style prototypes when
3597*7c478bd9Sstevel@tonic-gate  * a "short" argument is present and spits out a warning.
3598*7c478bd9Sstevel@tonic-gate  */
3599*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3600*7c478bd9Sstevel@tonic-gate int
3601*7c478bd9Sstevel@tonic-gate vfs_EIO_sync(struct vfs *vfsp, short arg, struct cred *cr)
3602*7c478bd9Sstevel@tonic-gate {
3603*7c478bd9Sstevel@tonic-gate 	return (EIO);
3604*7c478bd9Sstevel@tonic-gate }
3605*7c478bd9Sstevel@tonic-gate 
3606*7c478bd9Sstevel@tonic-gate vfs_t EIO_vfs;
3607*7c478bd9Sstevel@tonic-gate vfsops_t *EIO_vfsops;
3608*7c478bd9Sstevel@tonic-gate 
3609*7c478bd9Sstevel@tonic-gate /*
3610*7c478bd9Sstevel@tonic-gate  * Called from startup() to initialize all loaded vfs's
3611*7c478bd9Sstevel@tonic-gate  */
3612*7c478bd9Sstevel@tonic-gate void
3613*7c478bd9Sstevel@tonic-gate vfsinit(void)
3614*7c478bd9Sstevel@tonic-gate {
3615*7c478bd9Sstevel@tonic-gate 	struct vfssw *vswp;
3616*7c478bd9Sstevel@tonic-gate 	int error;
3617*7c478bd9Sstevel@tonic-gate 
3618*7c478bd9Sstevel@tonic-gate 	static const fs_operation_def_t EIO_vfsops_template[] = {
3619*7c478bd9Sstevel@tonic-gate 		VFSNAME_MOUNT,		vfs_EIO,
3620*7c478bd9Sstevel@tonic-gate 		VFSNAME_UNMOUNT,	vfs_EIO,
3621*7c478bd9Sstevel@tonic-gate 		VFSNAME_ROOT,		vfs_EIO,
3622*7c478bd9Sstevel@tonic-gate 		VFSNAME_STATVFS,	vfs_EIO,
3623*7c478bd9Sstevel@tonic-gate 		VFSNAME_SYNC, (fs_generic_func_p) vfs_EIO_sync,
3624*7c478bd9Sstevel@tonic-gate 		VFSNAME_VGET,		vfs_EIO,
3625*7c478bd9Sstevel@tonic-gate 		VFSNAME_MOUNTROOT,	vfs_EIO,
3626*7c478bd9Sstevel@tonic-gate 		VFSNAME_FREEVFS,	vfs_EIO,
3627*7c478bd9Sstevel@tonic-gate 		VFSNAME_VNSTATE,	vfs_EIO,
3628*7c478bd9Sstevel@tonic-gate 		NULL, NULL
3629*7c478bd9Sstevel@tonic-gate 	};
3630*7c478bd9Sstevel@tonic-gate 
3631*7c478bd9Sstevel@tonic-gate 
3632*7c478bd9Sstevel@tonic-gate 	/* Initialize the vnode cache (file systems may use it during init). */
3633*7c478bd9Sstevel@tonic-gate 
3634*7c478bd9Sstevel@tonic-gate 	vn_create_cache();
3635*7c478bd9Sstevel@tonic-gate 
3636*7c478bd9Sstevel@tonic-gate 	/* Setup event monitor framework */
3637*7c478bd9Sstevel@tonic-gate 
3638*7c478bd9Sstevel@tonic-gate 	fem_init();
3639*7c478bd9Sstevel@tonic-gate 
3640*7c478bd9Sstevel@tonic-gate 	/* Initialize the dummy stray file system type. */
3641*7c478bd9Sstevel@tonic-gate 
3642*7c478bd9Sstevel@tonic-gate 	vfssw[0].vsw_vfsops = vfs_strayops;
3643*7c478bd9Sstevel@tonic-gate 
3644*7c478bd9Sstevel@tonic-gate 	/* Initialize the dummy EIO file system. */
3645*7c478bd9Sstevel@tonic-gate 	error = vfs_makefsops(EIO_vfsops_template, &EIO_vfsops);
3646*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
3647*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "vfsinit: bad EIO vfs ops template");
3648*7c478bd9Sstevel@tonic-gate 		/* Shouldn't happen, but not bad enough to panic */
3649*7c478bd9Sstevel@tonic-gate 	}
3650*7c478bd9Sstevel@tonic-gate 
3651*7c478bd9Sstevel@tonic-gate 	VFS_INIT(&EIO_vfs, EIO_vfsops, (caddr_t)NULL);
3652*7c478bd9Sstevel@tonic-gate 
3653*7c478bd9Sstevel@tonic-gate 	/*
3654*7c478bd9Sstevel@tonic-gate 	 * Default EIO_vfs.vfs_flag to VFS_UNMOUNTED so a lookup
3655*7c478bd9Sstevel@tonic-gate 	 * on this vfs can immediately notice it's invalid.
3656*7c478bd9Sstevel@tonic-gate 	 */
3657*7c478bd9Sstevel@tonic-gate 	EIO_vfs.vfs_flag |= VFS_UNMOUNTED;
3658*7c478bd9Sstevel@tonic-gate 
3659*7c478bd9Sstevel@tonic-gate 	/*
3660*7c478bd9Sstevel@tonic-gate 	 * Call the init routines of non-loadable filesystems only.
3661*7c478bd9Sstevel@tonic-gate 	 * Filesystems which are loaded as separate modules will be
3662*7c478bd9Sstevel@tonic-gate 	 * initialized by the module loading code instead.
3663*7c478bd9Sstevel@tonic-gate 	 */
3664*7c478bd9Sstevel@tonic-gate 
3665*7c478bd9Sstevel@tonic-gate 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
3666*7c478bd9Sstevel@tonic-gate 		RLOCK_VFSSW();
3667*7c478bd9Sstevel@tonic-gate 		if (vswp->vsw_init != NULL)
3668*7c478bd9Sstevel@tonic-gate 			(*vswp->vsw_init)(vswp - vfssw, vswp->vsw_name);
3669*7c478bd9Sstevel@tonic-gate 		RUNLOCK_VFSSW();
3670*7c478bd9Sstevel@tonic-gate 	}
3671*7c478bd9Sstevel@tonic-gate }
3672*7c478bd9Sstevel@tonic-gate 
3673*7c478bd9Sstevel@tonic-gate /*
3674*7c478bd9Sstevel@tonic-gate  * Increments the vfs reference count by one atomically.
3675*7c478bd9Sstevel@tonic-gate  */
3676*7c478bd9Sstevel@tonic-gate void
3677*7c478bd9Sstevel@tonic-gate vfs_hold(vfs_t *vfsp)
3678*7c478bd9Sstevel@tonic-gate {
3679*7c478bd9Sstevel@tonic-gate 	atomic_add_32(&vfsp->vfs_count, 1);
3680*7c478bd9Sstevel@tonic-gate 	ASSERT(vfsp->vfs_count != 0);
3681*7c478bd9Sstevel@tonic-gate }
3682*7c478bd9Sstevel@tonic-gate 
3683*7c478bd9Sstevel@tonic-gate /*
3684*7c478bd9Sstevel@tonic-gate  * Decrements the vfs reference count by one atomically. When
3685*7c478bd9Sstevel@tonic-gate  * vfs reference count becomes zero, it calls the file system
3686*7c478bd9Sstevel@tonic-gate  * specific vfs_freevfs() to free up the resources.
3687*7c478bd9Sstevel@tonic-gate  */
3688*7c478bd9Sstevel@tonic-gate void
3689*7c478bd9Sstevel@tonic-gate vfs_rele(vfs_t *vfsp)
3690*7c478bd9Sstevel@tonic-gate {
3691*7c478bd9Sstevel@tonic-gate 	ASSERT(vfsp->vfs_count != 0);
3692*7c478bd9Sstevel@tonic-gate 	if (atomic_add_32_nv(&vfsp->vfs_count, -1) == 0) {
3693*7c478bd9Sstevel@tonic-gate 		VFS_FREEVFS(vfsp);
3694*7c478bd9Sstevel@tonic-gate 		if (vfsp->vfs_zone)
3695*7c478bd9Sstevel@tonic-gate 			zone_rele(vfsp->vfs_zone);
3696*7c478bd9Sstevel@tonic-gate 		vfs_freemnttab(vfsp);
3697*7c478bd9Sstevel@tonic-gate 		sema_destroy(&vfsp->vfs_reflock);
3698*7c478bd9Sstevel@tonic-gate 		kmem_free(vfsp, sizeof (*vfsp));
3699*7c478bd9Sstevel@tonic-gate 	}
3700*7c478bd9Sstevel@tonic-gate }
3701*7c478bd9Sstevel@tonic-gate 
3702*7c478bd9Sstevel@tonic-gate /*
3703*7c478bd9Sstevel@tonic-gate  * Generic operations vector support.
3704*7c478bd9Sstevel@tonic-gate  *
3705*7c478bd9Sstevel@tonic-gate  * This is used to build operations vectors for both the vfs and vnode.
3706*7c478bd9Sstevel@tonic-gate  * It's normally called only when a file system is loaded.
3707*7c478bd9Sstevel@tonic-gate  *
3708*7c478bd9Sstevel@tonic-gate  * There are many possible algorithms for this, including the following:
3709*7c478bd9Sstevel@tonic-gate  *
3710*7c478bd9Sstevel@tonic-gate  *   (1) scan the list of known operations; for each, see if the file system
3711*7c478bd9Sstevel@tonic-gate  *       includes an entry for it, and fill it in as appropriate.
3712*7c478bd9Sstevel@tonic-gate  *
3713*7c478bd9Sstevel@tonic-gate  *   (2) set up defaults for all known operations.  scan the list of ops
3714*7c478bd9Sstevel@tonic-gate  *       supplied by the file system; for each which is both supplied and
3715*7c478bd9Sstevel@tonic-gate  *       known, fill it in.
3716*7c478bd9Sstevel@tonic-gate  *
3717*7c478bd9Sstevel@tonic-gate  *   (3) sort the lists of known ops & supplied ops; scan the list, filling
3718*7c478bd9Sstevel@tonic-gate  *       in entries as we go.
3719*7c478bd9Sstevel@tonic-gate  *
3720*7c478bd9Sstevel@tonic-gate  * we choose (1) for simplicity, and because performance isn't critical here.
3721*7c478bd9Sstevel@tonic-gate  * note that (2) could be sped up using a precomputed hash table on known ops.
3722*7c478bd9Sstevel@tonic-gate  * (3) could be faster than either, but only if the lists were very large or
3723*7c478bd9Sstevel@tonic-gate  * supplied in sorted order.
3724*7c478bd9Sstevel@tonic-gate  *
3725*7c478bd9Sstevel@tonic-gate  */
3726*7c478bd9Sstevel@tonic-gate 
3727*7c478bd9Sstevel@tonic-gate int
3728*7c478bd9Sstevel@tonic-gate fs_build_vector(void *vector, int *unused_ops,
3729*7c478bd9Sstevel@tonic-gate     const fs_operation_trans_def_t *translation,
3730*7c478bd9Sstevel@tonic-gate     const fs_operation_def_t *operations)
3731*7c478bd9Sstevel@tonic-gate {
3732*7c478bd9Sstevel@tonic-gate 	int i, num_trans, num_ops, used;
3733*7c478bd9Sstevel@tonic-gate 
3734*7c478bd9Sstevel@tonic-gate 	/* Count the number of translations and the number of supplied */
3735*7c478bd9Sstevel@tonic-gate 	/* operations. */
3736*7c478bd9Sstevel@tonic-gate 
3737*7c478bd9Sstevel@tonic-gate 	{
3738*7c478bd9Sstevel@tonic-gate 		const fs_operation_trans_def_t *p;
3739*7c478bd9Sstevel@tonic-gate 
3740*7c478bd9Sstevel@tonic-gate 		for (num_trans = 0, p = translation;
3741*7c478bd9Sstevel@tonic-gate 		    p->name != NULL;
3742*7c478bd9Sstevel@tonic-gate 		    num_trans++, p++)
3743*7c478bd9Sstevel@tonic-gate 			;
3744*7c478bd9Sstevel@tonic-gate 	}
3745*7c478bd9Sstevel@tonic-gate 
3746*7c478bd9Sstevel@tonic-gate 	{
3747*7c478bd9Sstevel@tonic-gate 		const fs_operation_def_t *p;
3748*7c478bd9Sstevel@tonic-gate 
3749*7c478bd9Sstevel@tonic-gate 		for (num_ops = 0, p = operations;
3750*7c478bd9Sstevel@tonic-gate 		    p->name != NULL;
3751*7c478bd9Sstevel@tonic-gate 		    num_ops++, p++)
3752*7c478bd9Sstevel@tonic-gate 			;
3753*7c478bd9Sstevel@tonic-gate 	}
3754*7c478bd9Sstevel@tonic-gate 
3755*7c478bd9Sstevel@tonic-gate 	/* Walk through each operation known to our caller.  There will be */
3756*7c478bd9Sstevel@tonic-gate 	/* one entry in the supplied "translation table" for each. */
3757*7c478bd9Sstevel@tonic-gate 
3758*7c478bd9Sstevel@tonic-gate 	used = 0;
3759*7c478bd9Sstevel@tonic-gate 
3760*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_trans; i++) {
3761*7c478bd9Sstevel@tonic-gate 		int j, found;
3762*7c478bd9Sstevel@tonic-gate 		char *curname;
3763*7c478bd9Sstevel@tonic-gate 		fs_generic_func_p result;
3764*7c478bd9Sstevel@tonic-gate 		fs_generic_func_p *location;
3765*7c478bd9Sstevel@tonic-gate 
3766*7c478bd9Sstevel@tonic-gate 		curname = translation[i].name;
3767*7c478bd9Sstevel@tonic-gate 
3768*7c478bd9Sstevel@tonic-gate 		/* Look for a matching operation in the list supplied by the */
3769*7c478bd9Sstevel@tonic-gate 		/* file system. */
3770*7c478bd9Sstevel@tonic-gate 
3771*7c478bd9Sstevel@tonic-gate 		found = 0;
3772*7c478bd9Sstevel@tonic-gate 
3773*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < num_ops; j++) {
3774*7c478bd9Sstevel@tonic-gate 			if (strcmp(operations[j].name, curname) == 0) {
3775*7c478bd9Sstevel@tonic-gate 				used++;
3776*7c478bd9Sstevel@tonic-gate 				found = 1;
3777*7c478bd9Sstevel@tonic-gate 				break;
3778*7c478bd9Sstevel@tonic-gate 			}
3779*7c478bd9Sstevel@tonic-gate 		}
3780*7c478bd9Sstevel@tonic-gate 
3781*7c478bd9Sstevel@tonic-gate 		/* If the file system is using a "placeholder" for default */
3782*7c478bd9Sstevel@tonic-gate 		/* or error functions, grab the appropriate function out of */
3783*7c478bd9Sstevel@tonic-gate 		/* the translation table.  If the file system didn't supply */
3784*7c478bd9Sstevel@tonic-gate 		/* this operation at all, use the default function. */
3785*7c478bd9Sstevel@tonic-gate 
3786*7c478bd9Sstevel@tonic-gate 		if (found) {
3787*7c478bd9Sstevel@tonic-gate 			result = operations[j].func;
3788*7c478bd9Sstevel@tonic-gate 			if (result == fs_default) {
3789*7c478bd9Sstevel@tonic-gate 				result = translation[i].defaultFunc;
3790*7c478bd9Sstevel@tonic-gate 			} else if (result == fs_error) {
3791*7c478bd9Sstevel@tonic-gate 				result = translation[i].errorFunc;
3792*7c478bd9Sstevel@tonic-gate 			} else if (result == NULL) {
3793*7c478bd9Sstevel@tonic-gate 				/* Null values are PROHIBITED */
3794*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
3795*7c478bd9Sstevel@tonic-gate 			}
3796*7c478bd9Sstevel@tonic-gate 		} else {
3797*7c478bd9Sstevel@tonic-gate 			result = translation[i].defaultFunc;
3798*7c478bd9Sstevel@tonic-gate 		}
3799*7c478bd9Sstevel@tonic-gate 
3800*7c478bd9Sstevel@tonic-gate 		/* Now store the function into the operations vector. */
3801*7c478bd9Sstevel@tonic-gate 
3802*7c478bd9Sstevel@tonic-gate 		location = (fs_generic_func_p *)
3803*7c478bd9Sstevel@tonic-gate 		    (((char *)vector) + translation[i].offset);
3804*7c478bd9Sstevel@tonic-gate 
3805*7c478bd9Sstevel@tonic-gate 		*location = result;
3806*7c478bd9Sstevel@tonic-gate 	}
3807*7c478bd9Sstevel@tonic-gate 
3808*7c478bd9Sstevel@tonic-gate 	*unused_ops = num_ops - used;
3809*7c478bd9Sstevel@tonic-gate 
3810*7c478bd9Sstevel@tonic-gate 	return (0);
3811*7c478bd9Sstevel@tonic-gate }
3812*7c478bd9Sstevel@tonic-gate 
3813*7c478bd9Sstevel@tonic-gate /* Placeholder functions, should never be called. */
3814*7c478bd9Sstevel@tonic-gate 
3815*7c478bd9Sstevel@tonic-gate int
3816*7c478bd9Sstevel@tonic-gate fs_error(void)
3817*7c478bd9Sstevel@tonic-gate {
3818*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_PANIC, "fs_error called");
3819*7c478bd9Sstevel@tonic-gate 	return (0);
3820*7c478bd9Sstevel@tonic-gate }
3821*7c478bd9Sstevel@tonic-gate 
3822*7c478bd9Sstevel@tonic-gate int
3823*7c478bd9Sstevel@tonic-gate fs_default(void)
3824*7c478bd9Sstevel@tonic-gate {
3825*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_PANIC, "fs_default called");
3826*7c478bd9Sstevel@tonic-gate 	return (0);
3827*7c478bd9Sstevel@tonic-gate }
3828*7c478bd9Sstevel@tonic-gate 
3829*7c478bd9Sstevel@tonic-gate #ifdef __sparc
3830*7c478bd9Sstevel@tonic-gate 
3831*7c478bd9Sstevel@tonic-gate /*
3832*7c478bd9Sstevel@tonic-gate  * Part of the implementation of booting off a mirrored root
3833*7c478bd9Sstevel@tonic-gate  * involves a change of dev_t for the root device.  To
3834*7c478bd9Sstevel@tonic-gate  * accomplish this, first remove the existing hash table
3835*7c478bd9Sstevel@tonic-gate  * entry for the root device, convert to the new dev_t,
3836*7c478bd9Sstevel@tonic-gate  * then re-insert in the hash table at the head of the list.
3837*7c478bd9Sstevel@tonic-gate  */
3838*7c478bd9Sstevel@tonic-gate void
3839*7c478bd9Sstevel@tonic-gate vfs_root_redev(vfs_t *vfsp, dev_t ndev, int fstype)
3840*7c478bd9Sstevel@tonic-gate {
3841*7c478bd9Sstevel@tonic-gate 	vfs_list_lock();
3842*7c478bd9Sstevel@tonic-gate 
3843*7c478bd9Sstevel@tonic-gate 	vfs_hash_remove(vfsp);
3844*7c478bd9Sstevel@tonic-gate 
3845*7c478bd9Sstevel@tonic-gate 	vfsp->vfs_dev = ndev;
3846*7c478bd9Sstevel@tonic-gate 	vfs_make_fsid(&vfsp->vfs_fsid, ndev, fstype);
3847*7c478bd9Sstevel@tonic-gate 
3848*7c478bd9Sstevel@tonic-gate 	vfs_hash_add(vfsp, 1);
3849*7c478bd9Sstevel@tonic-gate 
3850*7c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
3851*7c478bd9Sstevel@tonic-gate }
3852*7c478bd9Sstevel@tonic-gate 
3853*7c478bd9Sstevel@tonic-gate #else /* x86 NEWBOOT */
3854*7c478bd9Sstevel@tonic-gate 
3855*7c478bd9Sstevel@tonic-gate int
3856*7c478bd9Sstevel@tonic-gate rootconf()
3857*7c478bd9Sstevel@tonic-gate {
3858*7c478bd9Sstevel@tonic-gate 	int error;
3859*7c478bd9Sstevel@tonic-gate 	struct vfssw *vsw;
3860*7c478bd9Sstevel@tonic-gate 	extern void pm_init();
3861*7c478bd9Sstevel@tonic-gate 	char *fstyp;
3862*7c478bd9Sstevel@tonic-gate 
3863*7c478bd9Sstevel@tonic-gate 	fstyp = getrootfs();
3864*7c478bd9Sstevel@tonic-gate 
3865*7c478bd9Sstevel@tonic-gate 	if (error = clboot_rootconf())
3866*7c478bd9Sstevel@tonic-gate 		return (error);
3867*7c478bd9Sstevel@tonic-gate 
3868*7c478bd9Sstevel@tonic-gate 	if (modload("fs", fstyp) == -1)
3869*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "Cannot _init %s module\n", fstyp);
3870*7c478bd9Sstevel@tonic-gate 
3871*7c478bd9Sstevel@tonic-gate 	RLOCK_VFSSW();
3872*7c478bd9Sstevel@tonic-gate 	vsw = vfs_getvfsswbyname(fstyp);
3873*7c478bd9Sstevel@tonic-gate 	RUNLOCK_VFSSW();
3874*7c478bd9Sstevel@tonic-gate 	VFS_INIT(rootvfs, &vsw->vsw_vfsops, 0);
3875*7c478bd9Sstevel@tonic-gate 	VFS_HOLD(rootvfs);
3876*7c478bd9Sstevel@tonic-gate 
3877*7c478bd9Sstevel@tonic-gate 	/* always mount readonly first */
3878*7c478bd9Sstevel@tonic-gate 	rootvfs->vfs_flag |= VFS_RDONLY;
3879*7c478bd9Sstevel@tonic-gate 
3880*7c478bd9Sstevel@tonic-gate 	pm_init();
3881*7c478bd9Sstevel@tonic-gate 
3882*7c478bd9Sstevel@tonic-gate 	if (netboot)
3883*7c478bd9Sstevel@tonic-gate 		(void) strplumb();
3884*7c478bd9Sstevel@tonic-gate 
3885*7c478bd9Sstevel@tonic-gate 	error = VFS_MOUNTROOT(rootvfs, ROOT_INIT);
3886*7c478bd9Sstevel@tonic-gate 	vfs_unrefvfssw(vsw);
3887*7c478bd9Sstevel@tonic-gate 	rootdev = rootvfs->vfs_dev;
3888*7c478bd9Sstevel@tonic-gate 
3889*7c478bd9Sstevel@tonic-gate 	if (error)
3890*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_PANIC, "cannot mount root path %s", svm_bootpath);
3891*7c478bd9Sstevel@tonic-gate 	return (error);
3892*7c478bd9Sstevel@tonic-gate }
3893*7c478bd9Sstevel@tonic-gate 
3894*7c478bd9Sstevel@tonic-gate /*
3895*7c478bd9Sstevel@tonic-gate  * XXX this is called by nfs only and should probably be removed
3896*7c478bd9Sstevel@tonic-gate  * If booted with ASKNAME, prompt on the console for a filesystem
3897*7c478bd9Sstevel@tonic-gate  * name and return it.
3898*7c478bd9Sstevel@tonic-gate  */
3899*7c478bd9Sstevel@tonic-gate void
3900*7c478bd9Sstevel@tonic-gate getfsname(char *askfor, char *name, size_t namelen)
3901*7c478bd9Sstevel@tonic-gate {
3902*7c478bd9Sstevel@tonic-gate 	if (boothowto & RB_ASKNAME) {
3903*7c478bd9Sstevel@tonic-gate 		printf("%s name: ", askfor);
3904*7c478bd9Sstevel@tonic-gate 		console_gets(name, namelen);
3905*7c478bd9Sstevel@tonic-gate 	}
3906*7c478bd9Sstevel@tonic-gate }
3907*7c478bd9Sstevel@tonic-gate 
3908*7c478bd9Sstevel@tonic-gate /*
3909*7c478bd9Sstevel@tonic-gate  * If server_path exists, then we are booting a diskless
3910*7c478bd9Sstevel@tonic-gate  * client. Otherwise, we default to ufs. Zfs should perhaps be
3911*7c478bd9Sstevel@tonic-gate  * another property.
3912*7c478bd9Sstevel@tonic-gate  */
3913*7c478bd9Sstevel@tonic-gate static char *
3914*7c478bd9Sstevel@tonic-gate getrootfs(void)
3915*7c478bd9Sstevel@tonic-gate {
3916*7c478bd9Sstevel@tonic-gate 	extern char *strplumb_get_netdev_path(void);
3917*7c478bd9Sstevel@tonic-gate 	char *propstr = NULL;
3918*7c478bd9Sstevel@tonic-gate 
3919*7c478bd9Sstevel@tonic-gate 	/* check fstype property; it should be nfsdyn for diskless */
3920*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
3921*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "fstype", &propstr)
3922*7c478bd9Sstevel@tonic-gate 	    == DDI_SUCCESS) {
3923*7c478bd9Sstevel@tonic-gate 		(void) strncpy(rootfs.bo_fstype, propstr, BO_MAXFSNAME);
3924*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(propstr);
3925*7c478bd9Sstevel@tonic-gate 	}
3926*7c478bd9Sstevel@tonic-gate 
3927*7c478bd9Sstevel@tonic-gate 	if (strncmp(rootfs.bo_fstype, "nfs", 3) != 0)
3928*7c478bd9Sstevel@tonic-gate 		return (rootfs.bo_fstype);
3929*7c478bd9Sstevel@tonic-gate 
3930*7c478bd9Sstevel@tonic-gate 	++netboot;
3931*7c478bd9Sstevel@tonic-gate 	/* check if path to network interface is specified in bootpath */
3932*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
3933*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "bootpath", &propstr)
3934*7c478bd9Sstevel@tonic-gate 	    == DDI_SUCCESS) {
3935*7c478bd9Sstevel@tonic-gate 		(void) strncpy(rootfs.bo_name, propstr, BO_MAXOBJNAME);
3936*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(propstr);
3937*7c478bd9Sstevel@tonic-gate 	} else {
3938*7c478bd9Sstevel@tonic-gate 		/* attempt to determine netdev_path via boot_mac address */
3939*7c478bd9Sstevel@tonic-gate 		netdev_path = strplumb_get_netdev_path();
3940*7c478bd9Sstevel@tonic-gate 		if (netdev_path == NULL)
3941*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC,
3942*7c478bd9Sstevel@tonic-gate 			    "Cannot find boot network interface\n");
3943*7c478bd9Sstevel@tonic-gate 		(void) strncpy(rootfs.bo_name, netdev_path, BO_MAXOBJNAME);
3944*7c478bd9Sstevel@tonic-gate 	}
3945*7c478bd9Sstevel@tonic-gate 	return ("nfs");
3946*7c478bd9Sstevel@tonic-gate }
3947*7c478bd9Sstevel@tonic-gate #endif
3948