xref: /illumos-gate/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c (revision 8329232e00f1048795bae53acb230316243aadb5)
1*8329232eSGordon Ross /*
2*8329232eSGordon Ross  * CDDL HEADER START
3*8329232eSGordon Ross  *
4*8329232eSGordon Ross  * The contents of this file are subject to the terms of the
5*8329232eSGordon Ross  * Common Development and Distribution License (the "License").
6*8329232eSGordon Ross  * You may not use this file except in compliance with the License.
7*8329232eSGordon Ross  *
8*8329232eSGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8329232eSGordon Ross  * or http://www.opensolaris.org/os/licensing.
10*8329232eSGordon Ross  * See the License for the specific language governing permissions
11*8329232eSGordon Ross  * and limitations under the License.
12*8329232eSGordon Ross  *
13*8329232eSGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14*8329232eSGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8329232eSGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16*8329232eSGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17*8329232eSGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18*8329232eSGordon Ross  *
19*8329232eSGordon Ross  * CDDL HEADER END
20*8329232eSGordon Ross  */
21*8329232eSGordon Ross 
22*8329232eSGordon Ross /*
23*8329232eSGordon Ross  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24*8329232eSGordon Ross  * Copyright 2016 Joyent, Inc.
25*8329232eSGordon Ross  * Copyright 2016 Toomas Soome <tsoome@me.com>
26*8329232eSGordon Ross  * Copyright (c) 2016 by Delphix. All rights reserved.
27*8329232eSGordon Ross  * Copyright 2017 RackTop Systems.
28*8329232eSGordon Ross  * Copyright 2018 Nexenta Systems, Inc.
29*8329232eSGordon Ross  */
30*8329232eSGordon Ross 
31*8329232eSGordon Ross /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
32*8329232eSGordon Ross /*	  All Rights Reserved	*/
33*8329232eSGordon Ross 
34*8329232eSGordon Ross /*
35*8329232eSGordon Ross  * University Copyright- Copyright (c) 1982, 1986, 1988
36*8329232eSGordon Ross  * The Regents of the University of California
37*8329232eSGordon Ross  * All Rights Reserved
38*8329232eSGordon Ross  *
39*8329232eSGordon Ross  * University Acknowledgment- Portions of this document are derived from
40*8329232eSGordon Ross  * software developed by the University of California, Berkeley, and its
41*8329232eSGordon Ross  * contributors.
42*8329232eSGordon Ross  */
43*8329232eSGordon Ross 
44*8329232eSGordon Ross /*
45*8329232eSGordon Ross  * This file contains those functions from fs/vfs.c that can be
46*8329232eSGordon Ross  * used with relatively little change.  Functions that differ
47*8329232eSGordon Ross  * significantly from that are in other files.
48*8329232eSGordon Ross  */
49*8329232eSGordon Ross 
50*8329232eSGordon Ross #include <sys/types.h>
51*8329232eSGordon Ross #include <sys/t_lock.h>
52*8329232eSGordon Ross #include <sys/param.h>
53*8329232eSGordon Ross #include <sys/errno.h>
54*8329232eSGordon Ross #include <sys/user.h>
55*8329232eSGordon Ross #include <sys/fstyp.h>
56*8329232eSGordon Ross #include <sys/kmem.h>
57*8329232eSGordon Ross #include <sys/systm.h>
58*8329232eSGordon Ross #include <sys/proc.h>
59*8329232eSGordon Ross #include <sys/mount.h>
60*8329232eSGordon Ross #include <sys/vfs.h>
61*8329232eSGordon Ross #include <sys/vfs_opreg.h>
62*8329232eSGordon Ross #include <sys/fem.h>
63*8329232eSGordon Ross #include <sys/mntent.h>
64*8329232eSGordon Ross #include <sys/stat.h>
65*8329232eSGordon Ross #include <sys/statvfs.h>
66*8329232eSGordon Ross #include <sys/statfs.h>
67*8329232eSGordon Ross #include <sys/cred.h>
68*8329232eSGordon Ross #include <sys/vnode.h>
69*8329232eSGordon Ross #include <sys/rwstlock.h>
70*8329232eSGordon Ross #include <sys/dnlc.h>
71*8329232eSGordon Ross #include <sys/file.h>
72*8329232eSGordon Ross #include <sys/time.h>
73*8329232eSGordon Ross #include <sys/atomic.h>
74*8329232eSGordon Ross #include <sys/cmn_err.h>
75*8329232eSGordon Ross #include <sys/buf.h>
76*8329232eSGordon Ross #include <sys/debug.h>
77*8329232eSGordon Ross #include <sys/vnode.h>
78*8329232eSGordon Ross #include <sys/ddi.h>
79*8329232eSGordon Ross #include <sys/pathname.h>
80*8329232eSGordon Ross #include <sys/poll.h>
81*8329232eSGordon Ross #include <sys/sunddi.h>
82*8329232eSGordon Ross #include <sys/sysmacros.h>
83*8329232eSGordon Ross #include <sys/zone.h>
84*8329232eSGordon Ross #include <sys/policy.h>
85*8329232eSGordon Ross #include <sys/attr.h>
86*8329232eSGordon Ross #include <fs/fs_subr.h>
87*8329232eSGordon Ross 
88*8329232eSGordon Ross #include <libfksmbfs.h>
89*8329232eSGordon Ross 
90*8329232eSGordon Ross static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
91*8329232eSGordon Ross static void vfs_setmntopt_nolock(mntopts_t *, const char *,
92*8329232eSGordon Ross     const char *, int, int);
93*8329232eSGordon Ross static int  vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
94*8329232eSGordon Ross // static void vfs_freemnttab(struct vfs *);
95*8329232eSGordon Ross static void vfs_freeopt(mntopt_t *);
96*8329232eSGordon Ross static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
97*8329232eSGordon Ross static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
98*8329232eSGordon Ross static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
99*8329232eSGordon Ross // static void vfs_createopttbl_extend(mntopts_t *, const char *,
100*8329232eSGordon Ross //    const mntopts_t *);
101*8329232eSGordon Ross // static char **vfs_copycancelopt_extend(char **const, int);
102*8329232eSGordon Ross static void vfs_freecancelopt(char **);
103*8329232eSGordon Ross 
104*8329232eSGordon Ross /*
105*8329232eSGordon Ross  * VFS global data.
106*8329232eSGordon Ross  */
107*8329232eSGordon Ross vnode_t *rootdir;		/* pointer to root inode vnode. */
108*8329232eSGordon Ross struct vfs *rootvfs = NULL;	/* pointer to root vfs; head of VFS list. */
109*8329232eSGordon Ross static krwlock_t vfslist;
110*8329232eSGordon Ross struct vfs	*zone_vfslist;	/* list of FS's mounted in zone */
111*8329232eSGordon Ross 
112*8329232eSGordon Ross /* from os/vfs_conf.c */
113*8329232eSGordon Ross const int nfstype = 5;
114*8329232eSGordon Ross struct vfssw vfssw[10] = {
115*8329232eSGordon Ross 	{ "BADVFS" },				/* 0:invalid */
116*8329232eSGordon Ross 	{ "" },					/* reserved for loadable fs */
117*8329232eSGordon Ross 	{ "" },
118*8329232eSGordon Ross 	{ "" },
119*8329232eSGordon Ross 	{ "" },
120*8329232eSGordon Ross };
121*8329232eSGordon Ross 
122*8329232eSGordon Ross /*
123*8329232eSGordon Ross  * Table for generic options recognized in the VFS layer and acted
124*8329232eSGordon Ross  * on at this level before parsing file system specific options.
125*8329232eSGordon Ross  * The nosuid option is stronger than any of the devices and setuid
126*8329232eSGordon Ross  * options, so those are canceled when nosuid is seen.
127*8329232eSGordon Ross  *
128*8329232eSGordon Ross  * All options which are added here need to be added to the
129*8329232eSGordon Ross  * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
130*8329232eSGordon Ross  */
131*8329232eSGordon Ross /*
132*8329232eSGordon Ross  * VFS Mount options table
133*8329232eSGordon Ross  */
134*8329232eSGordon Ross static char *ro_cancel[] = { MNTOPT_RW, NULL };
135*8329232eSGordon Ross static char *rw_cancel[] = { MNTOPT_RO, NULL };
136*8329232eSGordon Ross static char *suid_cancel[] = { MNTOPT_NOSUID, NULL };
137*8329232eSGordon Ross static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES,
138*8329232eSGordon Ross     MNTOPT_NOSETUID, MNTOPT_SETUID, NULL };
139*8329232eSGordon Ross static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL };
140*8329232eSGordon Ross static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL };
141*8329232eSGordon Ross static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL };
142*8329232eSGordon Ross static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL };
143*8329232eSGordon Ross static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL };
144*8329232eSGordon Ross static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL };
145*8329232eSGordon Ross static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL };
146*8329232eSGordon Ross static char *noexec_cancel[] = { MNTOPT_EXEC, NULL };
147*8329232eSGordon Ross 
148*8329232eSGordon Ross static const mntopt_t mntopts[] = {
149*8329232eSGordon Ross /*
150*8329232eSGordon Ross  *	option name		cancel options		default arg	flags
151*8329232eSGordon Ross  */
152*8329232eSGordon Ross 	{ MNTOPT_REMOUNT,	NULL,			NULL,
153*8329232eSGordon Ross 		MO_NODISPLAY, (void *)0 },
154*8329232eSGordon Ross 	{ MNTOPT_RO,		ro_cancel,		NULL,		0,
155*8329232eSGordon Ross 		(void *)0 },
156*8329232eSGordon Ross 	{ MNTOPT_RW,		rw_cancel,		NULL,		0,
157*8329232eSGordon Ross 		(void *)0 },
158*8329232eSGordon Ross 	{ MNTOPT_SUID,		suid_cancel,		NULL,		0,
159*8329232eSGordon Ross 		(void *)0 },
160*8329232eSGordon Ross 	{ MNTOPT_NOSUID,	nosuid_cancel,		NULL,		0,
161*8329232eSGordon Ross 		(void *)0 },
162*8329232eSGordon Ross 	{ MNTOPT_DEVICES,	devices_cancel,		NULL,		0,
163*8329232eSGordon Ross 		(void *)0 },
164*8329232eSGordon Ross 	{ MNTOPT_NODEVICES,	nodevices_cancel,	NULL,		0,
165*8329232eSGordon Ross 		(void *)0 },
166*8329232eSGordon Ross 	{ MNTOPT_SETUID,	setuid_cancel,		NULL,		0,
167*8329232eSGordon Ross 		(void *)0 },
168*8329232eSGordon Ross 	{ MNTOPT_NOSETUID,	nosetuid_cancel,	NULL,		0,
169*8329232eSGordon Ross 		(void *)0 },
170*8329232eSGordon Ross 	{ MNTOPT_NBMAND,	nbmand_cancel,		NULL,		0,
171*8329232eSGordon Ross 		(void *)0 },
172*8329232eSGordon Ross 	{ MNTOPT_NONBMAND,	nonbmand_cancel,	NULL,		0,
173*8329232eSGordon Ross 		(void *)0 },
174*8329232eSGordon Ross 	{ MNTOPT_EXEC,		exec_cancel,		NULL,		0,
175*8329232eSGordon Ross 		(void *)0 },
176*8329232eSGordon Ross 	{ MNTOPT_NOEXEC,	noexec_cancel,		NULL,		0,
177*8329232eSGordon Ross 		(void *)0 },
178*8329232eSGordon Ross };
179*8329232eSGordon Ross 
180*8329232eSGordon Ross const mntopts_t vfs_mntopts = {
181*8329232eSGordon Ross 	sizeof (mntopts) / sizeof (mntopt_t),
182*8329232eSGordon Ross 	(mntopt_t *)&mntopts[0]
183*8329232eSGordon Ross };
184*8329232eSGordon Ross 
185*8329232eSGordon Ross /*
186*8329232eSGordon Ross  * File system operation dispatch functions.
187*8329232eSGordon Ross  */
188*8329232eSGordon Ross 
189*8329232eSGordon Ross int
190*8329232eSGordon Ross fsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
191*8329232eSGordon Ross {
192*8329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr);
193*8329232eSGordon Ross }
194*8329232eSGordon Ross 
195*8329232eSGordon Ross int
196*8329232eSGordon Ross fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr)
197*8329232eSGordon Ross {
198*8329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr);
199*8329232eSGordon Ross }
200*8329232eSGordon Ross 
201*8329232eSGordon Ross int
202*8329232eSGordon Ross fsop_root(vfs_t *vfsp, vnode_t **vpp)
203*8329232eSGordon Ross {
204*8329232eSGordon Ross 	return ((*(vfsp)->vfs_op->vfs_root)(vfsp, vpp));
205*8329232eSGordon Ross }
206*8329232eSGordon Ross 
207*8329232eSGordon Ross int
208*8329232eSGordon Ross fsop_statfs(vfs_t *vfsp, statvfs64_t *sp)
209*8329232eSGordon Ross {
210*8329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp);
211*8329232eSGordon Ross }
212*8329232eSGordon Ross 
213*8329232eSGordon Ross int
214*8329232eSGordon Ross fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
215*8329232eSGordon Ross {
216*8329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr);
217*8329232eSGordon Ross }
218*8329232eSGordon Ross 
219*8329232eSGordon Ross int
220*8329232eSGordon Ross fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
221*8329232eSGordon Ross {
222*8329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
223*8329232eSGordon Ross }
224*8329232eSGordon Ross 
225*8329232eSGordon Ross int
226*8329232eSGordon Ross fsop_mountroot(vfs_t *vfsp, enum whymountroot reason)
227*8329232eSGordon Ross {
228*8329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason);
229*8329232eSGordon Ross }
230*8329232eSGordon Ross 
231*8329232eSGordon Ross void
232*8329232eSGordon Ross fsop_freefs(vfs_t *vfsp)
233*8329232eSGordon Ross {
234*8329232eSGordon Ross 	(*(vfsp)->vfs_op->vfs_freevfs)(vfsp);
235*8329232eSGordon Ross }
236*8329232eSGordon Ross 
237*8329232eSGordon Ross int
238*8329232eSGordon Ross fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
239*8329232eSGordon Ross {
240*8329232eSGordon Ross 	return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate));
241*8329232eSGordon Ross }
242*8329232eSGordon Ross 
243*8329232eSGordon Ross int
244*8329232eSGordon Ross fsop_sync_by_kind(int fstype, short flag, cred_t *cr)
245*8329232eSGordon Ross {
246*8329232eSGordon Ross 	ASSERT((fstype >= 0) && (fstype < nfstype));
247*8329232eSGordon Ross 
248*8329232eSGordon Ross 	if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype]))
249*8329232eSGordon Ross 		return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr);
250*8329232eSGordon Ross 	else
251*8329232eSGordon Ross 		return (ENOTSUP);
252*8329232eSGordon Ross }
253*8329232eSGordon Ross 
254*8329232eSGordon Ross /*
255*8329232eSGordon Ross  * File system initialization.  vfs_setfsops() must be called from a file
256*8329232eSGordon Ross  * system's init routine.
257*8329232eSGordon Ross  */
258*8329232eSGordon Ross 
259*8329232eSGordon Ross static int
260*8329232eSGordon Ross fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual,
261*8329232eSGordon Ross     int *unused_ops)
262*8329232eSGordon Ross {
263*8329232eSGordon Ross 	static const fs_operation_trans_def_t vfs_ops_table[] = {
264*8329232eSGordon Ross 		VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount),
265*8329232eSGordon Ross 			fs_nosys, fs_nosys,
266*8329232eSGordon Ross 
267*8329232eSGordon Ross 		VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount),
268*8329232eSGordon Ross 			fs_nosys, fs_nosys,
269*8329232eSGordon Ross 
270*8329232eSGordon Ross 		VFSNAME_ROOT, offsetof(vfsops_t, vfs_root),
271*8329232eSGordon Ross 			fs_nosys, fs_nosys,
272*8329232eSGordon Ross 
273*8329232eSGordon Ross 		VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs),
274*8329232eSGordon Ross 			fs_nosys, fs_nosys,
275*8329232eSGordon Ross 
276*8329232eSGordon Ross 		VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync),
277*8329232eSGordon Ross 			(fs_generic_func_p) fs_sync,
278*8329232eSGordon Ross 			(fs_generic_func_p) fs_sync,	/* No errors allowed */
279*8329232eSGordon Ross 
280*8329232eSGordon Ross 		VFSNAME_VGET, offsetof(vfsops_t, vfs_vget),
281*8329232eSGordon Ross 			fs_nosys, fs_nosys,
282*8329232eSGordon Ross 
283*8329232eSGordon Ross 		VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot),
284*8329232eSGordon Ross 			fs_nosys, fs_nosys,
285*8329232eSGordon Ross 
286*8329232eSGordon Ross 		VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs),
287*8329232eSGordon Ross 			(fs_generic_func_p)fs_freevfs,
288*8329232eSGordon Ross 			(fs_generic_func_p)fs_freevfs,	/* Shouldn't fail */
289*8329232eSGordon Ross 
290*8329232eSGordon Ross 		VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate),
291*8329232eSGordon Ross 			(fs_generic_func_p)fs_nosys,
292*8329232eSGordon Ross 			(fs_generic_func_p)fs_nosys,
293*8329232eSGordon Ross 
294*8329232eSGordon Ross 		NULL, 0, NULL, NULL
295*8329232eSGordon Ross 	};
296*8329232eSGordon Ross 
297*8329232eSGordon Ross 	return (fs_build_vector(actual, unused_ops, vfs_ops_table, template));
298*8329232eSGordon Ross }
299*8329232eSGordon Ross 
300*8329232eSGordon Ross /* zfs_boot_init() */
301*8329232eSGordon Ross 
302*8329232eSGordon Ross int
303*8329232eSGordon Ross vfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual)
304*8329232eSGordon Ross {
305*8329232eSGordon Ross 	int error;
306*8329232eSGordon Ross 	int unused_ops;
307*8329232eSGordon Ross 
308*8329232eSGordon Ross 	/*
309*8329232eSGordon Ross 	 * Verify that fstype refers to a valid fs.  Note that
310*8329232eSGordon Ross 	 * 0 is valid since it's used to set "stray" ops.
311*8329232eSGordon Ross 	 */
312*8329232eSGordon Ross 	if ((fstype < 0) || (fstype >= nfstype))
313*8329232eSGordon Ross 		return (EINVAL);
314*8329232eSGordon Ross 
315*8329232eSGordon Ross 	if (!ALLOCATED_VFSSW(&vfssw[fstype]))
316*8329232eSGordon Ross 		return (EINVAL);
317*8329232eSGordon Ross 
318*8329232eSGordon Ross 	/* Set up the operations vector. */
319*8329232eSGordon Ross 
320*8329232eSGordon Ross 	error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops);
321*8329232eSGordon Ross 
322*8329232eSGordon Ross 	if (error != 0)
323*8329232eSGordon Ross 		return (error);
324*8329232eSGordon Ross 
325*8329232eSGordon Ross 	vfssw[fstype].vsw_flag |= VSW_INSTALLED;
326*8329232eSGordon Ross 
327*8329232eSGordon Ross 	if (actual != NULL)
328*8329232eSGordon Ross 		*actual = &vfssw[fstype].vsw_vfsops;
329*8329232eSGordon Ross 
330*8329232eSGordon Ross #if DEBUG
331*8329232eSGordon Ross 	if (unused_ops != 0)
332*8329232eSGordon Ross 		cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied "
333*8329232eSGordon Ross 		    "but not used", vfssw[fstype].vsw_name, unused_ops);
334*8329232eSGordon Ross #endif
335*8329232eSGordon Ross 
336*8329232eSGordon Ross 	return (0);
337*8329232eSGordon Ross }
338*8329232eSGordon Ross 
339*8329232eSGordon Ross int
340*8329232eSGordon Ross vfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual)
341*8329232eSGordon Ross {
342*8329232eSGordon Ross 	int error;
343*8329232eSGordon Ross 	int unused_ops;
344*8329232eSGordon Ross 
345*8329232eSGordon Ross 	*actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP);
346*8329232eSGordon Ross 
347*8329232eSGordon Ross 	error = fs_copyfsops(template, *actual, &unused_ops);
348*8329232eSGordon Ross 	if (error != 0) {
349*8329232eSGordon Ross 		kmem_free(*actual, sizeof (vfsops_t));
350*8329232eSGordon Ross 		*actual = NULL;
351*8329232eSGordon Ross 		return (error);
352*8329232eSGordon Ross 	}
353*8329232eSGordon Ross 
354*8329232eSGordon Ross 	return (0);
355*8329232eSGordon Ross }
356*8329232eSGordon Ross 
357*8329232eSGordon Ross /*
358*8329232eSGordon Ross  * Free a vfsops structure created as a result of vfs_makefsops().
359*8329232eSGordon Ross  * NOTE: For a vfsops structure initialized by vfs_setfsops(), use
360*8329232eSGordon Ross  * vfs_freevfsops_by_type().
361*8329232eSGordon Ross  */
362*8329232eSGordon Ross void
363*8329232eSGordon Ross vfs_freevfsops(vfsops_t *vfsops)
364*8329232eSGordon Ross {
365*8329232eSGordon Ross 	kmem_free(vfsops, sizeof (vfsops_t));
366*8329232eSGordon Ross }
367*8329232eSGordon Ross 
368*8329232eSGordon Ross /*
369*8329232eSGordon Ross  * Since the vfsops structure is part of the vfssw table and wasn't
370*8329232eSGordon Ross  * really allocated, we're not really freeing anything.  We keep
371*8329232eSGordon Ross  * the name for consistency with vfs_freevfsops().  We do, however,
372*8329232eSGordon Ross  * need to take care of a little bookkeeping.
373*8329232eSGordon Ross  * NOTE: For a vfsops structure created by vfs_setfsops(), use
374*8329232eSGordon Ross  * vfs_freevfsops_by_type().
375*8329232eSGordon Ross  */
376*8329232eSGordon Ross int
377*8329232eSGordon Ross vfs_freevfsops_by_type(int fstype)
378*8329232eSGordon Ross {
379*8329232eSGordon Ross 
380*8329232eSGordon Ross 	/* Verify that fstype refers to a loaded fs (and not fsid 0). */
381*8329232eSGordon Ross 	if ((fstype <= 0) || (fstype >= nfstype))
382*8329232eSGordon Ross 		return (EINVAL);
383*8329232eSGordon Ross 
384*8329232eSGordon Ross 	WLOCK_VFSSW();
385*8329232eSGordon Ross 	if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) {
386*8329232eSGordon Ross 		WUNLOCK_VFSSW();
387*8329232eSGordon Ross 		return (EINVAL);
388*8329232eSGordon Ross 	}
389*8329232eSGordon Ross 
390*8329232eSGordon Ross 	vfssw[fstype].vsw_flag &= ~VSW_INSTALLED;
391*8329232eSGordon Ross 	WUNLOCK_VFSSW();
392*8329232eSGordon Ross 
393*8329232eSGordon Ross 	return (0);
394*8329232eSGordon Ross }
395*8329232eSGordon Ross 
396*8329232eSGordon Ross /* Support routines used to reference vfs_op */
397*8329232eSGordon Ross 
398*8329232eSGordon Ross /* Set the operations vector for a vfs */
399*8329232eSGordon Ross void
400*8329232eSGordon Ross vfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
401*8329232eSGordon Ross {
402*8329232eSGordon Ross 
403*8329232eSGordon Ross 	ASSERT(vfsp != NULL);
404*8329232eSGordon Ross 	ASSERT(vfsops != NULL);
405*8329232eSGordon Ross 
406*8329232eSGordon Ross 	vfsp->vfs_op = vfsops;
407*8329232eSGordon Ross }
408*8329232eSGordon Ross 
409*8329232eSGordon Ross /* Retrieve the operations vector for a vfs */
410*8329232eSGordon Ross vfsops_t *
411*8329232eSGordon Ross vfs_getops(vfs_t *vfsp)
412*8329232eSGordon Ross {
413*8329232eSGordon Ross 
414*8329232eSGordon Ross 	ASSERT(vfsp != NULL);
415*8329232eSGordon Ross 
416*8329232eSGordon Ross 	return (vfsp->vfs_op);
417*8329232eSGordon Ross }
418*8329232eSGordon Ross 
419*8329232eSGordon Ross /*
420*8329232eSGordon Ross  * Returns non-zero (1) if the vfsops matches that of the vfs.
421*8329232eSGordon Ross  * Returns zero (0) if not.
422*8329232eSGordon Ross  */
423*8329232eSGordon Ross int
424*8329232eSGordon Ross vfs_matchops(vfs_t *vfsp, vfsops_t *vfsops)
425*8329232eSGordon Ross {
426*8329232eSGordon Ross 	return (vfs_getops(vfsp) == vfsops);
427*8329232eSGordon Ross }
428*8329232eSGordon Ross 
429*8329232eSGordon Ross /*
430*8329232eSGordon Ross  * Returns non-zero (1) if the file system has installed a non-default,
431*8329232eSGordon Ross  * non-error vfs_sync routine.  Returns zero (0) otherwise.
432*8329232eSGordon Ross  */
433*8329232eSGordon Ross int
434*8329232eSGordon Ross vfs_can_sync(vfs_t *vfsp)
435*8329232eSGordon Ross {
436*8329232eSGordon Ross 	/* vfs_sync() routine is not the default/error function */
437*8329232eSGordon Ross 	return (vfs_getops(vfsp)->vfs_sync != fs_sync);
438*8329232eSGordon Ross }
439*8329232eSGordon Ross 
440*8329232eSGordon Ross /*
441*8329232eSGordon Ross  * Initialize a vfs structure.
442*8329232eSGordon Ross  */
443*8329232eSGordon Ross void
444*8329232eSGordon Ross vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
445*8329232eSGordon Ross {
446*8329232eSGordon Ross 	/* Always do full init, like vfs_alloc() */
447*8329232eSGordon Ross 	bzero(vfsp, sizeof (vfs_t));
448*8329232eSGordon Ross 	vfsp->vfs_count = 0;
449*8329232eSGordon Ross 	vfsp->vfs_next = vfsp;
450*8329232eSGordon Ross 	vfsp->vfs_prev = vfsp;
451*8329232eSGordon Ross 	vfsp->vfs_zone_next = vfsp;
452*8329232eSGordon Ross 	vfsp->vfs_zone_prev = vfsp;
453*8329232eSGordon Ross 	vfsp->vfs_lofi_id = 0;
454*8329232eSGordon Ross 	sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
455*8329232eSGordon Ross 	vfsimpl_setup(vfsp);
456*8329232eSGordon Ross 	vfsp->vfs_data = (data);
457*8329232eSGordon Ross 	vfs_setops((vfsp), (op));
458*8329232eSGordon Ross }
459*8329232eSGordon Ross 
460*8329232eSGordon Ross /*
461*8329232eSGordon Ross  * Allocate and initialize the vfs implementation private data
462*8329232eSGordon Ross  * structure, vfs_impl_t.
463*8329232eSGordon Ross  */
464*8329232eSGordon Ross void
465*8329232eSGordon Ross vfsimpl_setup(vfs_t *vfsp)
466*8329232eSGordon Ross {
467*8329232eSGordon Ross 	int i;
468*8329232eSGordon Ross 
469*8329232eSGordon Ross 	if (vfsp->vfs_implp != NULL) {
470*8329232eSGordon Ross 		return;
471*8329232eSGordon Ross 	}
472*8329232eSGordon Ross 
473*8329232eSGordon Ross 	vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP);
474*8329232eSGordon Ross 	/* Note that these are #define'd in vfs.h */
475*8329232eSGordon Ross 	vfsp->vfs_vskap = NULL;
476*8329232eSGordon Ross 	vfsp->vfs_fstypevsp = NULL;
477*8329232eSGordon Ross 
478*8329232eSGordon Ross 	/* Set size of counted array, then zero the array */
479*8329232eSGordon Ross 	vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1;
480*8329232eSGordon Ross 	for (i = 1; i <  VFS_FEATURE_MAXSZ; i++) {
481*8329232eSGordon Ross 		vfsp->vfs_featureset[i] = 0;
482*8329232eSGordon Ross 	}
483*8329232eSGordon Ross }
484*8329232eSGordon Ross 
485*8329232eSGordon Ross /*
486*8329232eSGordon Ross  * Release the vfs_impl_t structure, if it exists. Some unbundled
487*8329232eSGordon Ross  * filesystems may not use the newer version of vfs and thus
488*8329232eSGordon Ross  * would not contain this implementation private data structure.
489*8329232eSGordon Ross  */
490*8329232eSGordon Ross void
491*8329232eSGordon Ross vfsimpl_teardown(vfs_t *vfsp)
492*8329232eSGordon Ross {
493*8329232eSGordon Ross 	vfs_impl_t	*vip = vfsp->vfs_implp;
494*8329232eSGordon Ross 
495*8329232eSGordon Ross 	if (vip == NULL)
496*8329232eSGordon Ross 		return;
497*8329232eSGordon Ross 
498*8329232eSGordon Ross 	kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t));
499*8329232eSGordon Ross 	vfsp->vfs_implp = NULL;
500*8329232eSGordon Ross }
501*8329232eSGordon Ross 
502*8329232eSGordon Ross /*
503*8329232eSGordon Ross  * VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs,
504*8329232eSGordon Ross  * fstatvfs, and sysfs moved to common/syscall.
505*8329232eSGordon Ross  */
506*8329232eSGordon Ross 
507*8329232eSGordon Ross // vfs_sync, sync
508*8329232eSGordon Ross 
509*8329232eSGordon Ross /*
510*8329232eSGordon Ross  * External routines.
511*8329232eSGordon Ross  */
512*8329232eSGordon Ross 
513*8329232eSGordon Ross krwlock_t vfssw_lock;	/* lock accesses to vfssw */
514*8329232eSGordon Ross 
515*8329232eSGordon Ross /*
516*8329232eSGordon Ross  * Lock for accessing the vfs linked list.  Initialized in vfs_mountroot(),
517*8329232eSGordon Ross  * but otherwise should be accessed only via vfs_list_lock() and
518*8329232eSGordon Ross  * vfs_list_unlock().  Also used to protect the timestamp for mods to the list.
519*8329232eSGordon Ross  */
520*8329232eSGordon Ross static krwlock_t vfslist;
521*8329232eSGordon Ross 
522*8329232eSGordon Ross // vfs_mountdevices(void)
523*8329232eSGordon Ross // vfs_mountdev1(void)
524*8329232eSGordon Ross // vfs_mountfs()
525*8329232eSGordon Ross // vfs_mountroot()
526*8329232eSGordon Ross // lofi_add, lofi_remove
527*8329232eSGordon Ross 
528*8329232eSGordon Ross 
529*8329232eSGordon Ross /*
530*8329232eSGordon Ross  * Mount the FS for the test jig.  Based on domount()
531*8329232eSGordon Ross  */
532*8329232eSGordon Ross int
533*8329232eSGordon Ross fake_domount(char *fsname, struct mounta *uap, struct vfs **vfspp)
534*8329232eSGordon Ross {
535*8329232eSGordon Ross 	vnode_t		*vp;
536*8329232eSGordon Ross 	struct cred	*credp;
537*8329232eSGordon Ross 	struct vfssw	*vswp;
538*8329232eSGordon Ross 	vfsops_t	*vfsops;
539*8329232eSGordon Ross 	struct vfs	*vfsp = NULL;
540*8329232eSGordon Ross 	mntopts_t	mnt_mntopts;
541*8329232eSGordon Ross 	int		error = 0;
542*8329232eSGordon Ross 	int		copyout_error = 0;
543*8329232eSGordon Ross 	char		*opts = uap->optptr;
544*8329232eSGordon Ross 	char		*inargs = opts;
545*8329232eSGordon Ross 	int		optlen = uap->optlen;
546*8329232eSGordon Ross 
547*8329232eSGordon Ross 	credp = CRED();
548*8329232eSGordon Ross 
549*8329232eSGordon Ross 	/*
550*8329232eSGordon Ross 	 * Test jig specific: mount on rootdir
551*8329232eSGordon Ross 	 */
552*8329232eSGordon Ross 	if (rootvfs != NULL)
553*8329232eSGordon Ross 		return (EBUSY);
554*8329232eSGordon Ross 	vp = rootdir;
555*8329232eSGordon Ross 
556*8329232eSGordon Ross 	/*
557*8329232eSGordon Ross 	 * The v_flag value for the mount point vp is permanently set
558*8329232eSGordon Ross 	 * to VVFSLOCK so that no one bypasses the vn_vfs*locks routine
559*8329232eSGordon Ross 	 * for mount point locking.
560*8329232eSGordon Ross 	 */
561*8329232eSGordon Ross 	mutex_enter(&vp->v_lock);
562*8329232eSGordon Ross 	vp->v_flag |= VVFSLOCK;
563*8329232eSGordon Ross 	mutex_exit(&vp->v_lock);
564*8329232eSGordon Ross 
565*8329232eSGordon Ross 	mnt_mntopts.mo_count = 0;
566*8329232eSGordon Ross 
567*8329232eSGordon Ross 	/*
568*8329232eSGordon Ross 	 * Find the ops vector to use to invoke the file system-specific mount
569*8329232eSGordon Ross 	 * method.  If the fsname argument is non-NULL, use it directly.
570*8329232eSGordon Ross 	 */
571*8329232eSGordon Ross 	if ((vswp = vfs_getvfssw(fsname)) == NULL) {
572*8329232eSGordon Ross 		return (EINVAL);
573*8329232eSGordon Ross 	}
574*8329232eSGordon Ross 	if (!VFS_INSTALLED(vswp))
575*8329232eSGordon Ross 		return (EINVAL);
576*8329232eSGordon Ross 
577*8329232eSGordon Ross 	// secpolicy_fs_allowed_mount(fsname)
578*8329232eSGordon Ross 
579*8329232eSGordon Ross 	vfsops = &vswp->vsw_vfsops;
580*8329232eSGordon Ross 
581*8329232eSGordon Ross 	vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts);
582*8329232eSGordon Ross 
583*8329232eSGordon Ross 	/*
584*8329232eSGordon Ross 	 * Fetch mount options and parse them for generic vfs options
585*8329232eSGordon Ross 	 */
586*8329232eSGordon Ross 	if (uap->flags & MS_OPTIONSTR) {
587*8329232eSGordon Ross 		/*
588*8329232eSGordon Ross 		 * Limit the buffer size
589*8329232eSGordon Ross 		 */
590*8329232eSGordon Ross 		if (optlen < 0 || optlen > MAX_MNTOPT_STR) {
591*8329232eSGordon Ross 			error = EINVAL;
592*8329232eSGordon Ross 			goto errout;
593*8329232eSGordon Ross 		}
594*8329232eSGordon Ross 		if ((uap->flags & MS_SYSSPACE) == 0) {
595*8329232eSGordon Ross 			inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
596*8329232eSGordon Ross 			inargs[0] = '\0';
597*8329232eSGordon Ross 			if (optlen) {
598*8329232eSGordon Ross 				error = copyinstr(opts, inargs, (size_t)optlen,
599*8329232eSGordon Ross 				    NULL);
600*8329232eSGordon Ross 				if (error) {
601*8329232eSGordon Ross 					goto errout;
602*8329232eSGordon Ross 				}
603*8329232eSGordon Ross 			}
604*8329232eSGordon Ross 		}
605*8329232eSGordon Ross 		vfs_parsemntopts(&mnt_mntopts, inargs, 0);
606*8329232eSGordon Ross 	}
607*8329232eSGordon Ross 	/*
608*8329232eSGordon Ross 	 * Flag bits override the options string.
609*8329232eSGordon Ross 	 */
610*8329232eSGordon Ross 	if (uap->flags & MS_REMOUNT)
611*8329232eSGordon Ross 		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0);
612*8329232eSGordon Ross 	if (uap->flags & MS_RDONLY)
613*8329232eSGordon Ross 		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0);
614*8329232eSGordon Ross 	if (uap->flags & MS_NOSUID)
615*8329232eSGordon Ross 		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
616*8329232eSGordon Ross 
617*8329232eSGordon Ross 	/*
618*8329232eSGordon Ross 	 * Check if this is a remount; must be set in the option string and
619*8329232eSGordon Ross 	 * the file system must support a remount option.
620*8329232eSGordon Ross 	 */
621*8329232eSGordon Ross 	if (vfs_optionisset_nolock(&mnt_mntopts,
622*8329232eSGordon Ross 	    MNTOPT_REMOUNT, NULL)) {
623*8329232eSGordon Ross 		/* disallow here */
624*8329232eSGordon Ross 		error = ENOTSUP;
625*8329232eSGordon Ross 		goto errout;
626*8329232eSGordon Ross 	}
627*8329232eSGordon Ross 
628*8329232eSGordon Ross 	/*
629*8329232eSGordon Ross 	 * uap->flags and vfs_optionisset() should agree.
630*8329232eSGordon Ross 	 */
631*8329232eSGordon Ross 	if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) {
632*8329232eSGordon Ross 		uap->flags |= MS_RDONLY;
633*8329232eSGordon Ross 	}
634*8329232eSGordon Ross 	if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) {
635*8329232eSGordon Ross 		uap->flags |= MS_NOSUID;
636*8329232eSGordon Ross 	}
637*8329232eSGordon Ross 	// nbmand ...
638*8329232eSGordon Ross 
639*8329232eSGordon Ross 	/*
640*8329232eSGordon Ross 	 * If we are splicing the fs into the namespace,
641*8329232eSGordon Ross 	 * perform mount point checks...
642*8329232eSGordon Ross 	 * (always splice=0 here)
643*8329232eSGordon Ross 	 */
644*8329232eSGordon Ross 
645*8329232eSGordon Ross 	if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) {
646*8329232eSGordon Ross 		uap->dataptr = NULL;
647*8329232eSGordon Ross 		uap->datalen = 0;
648*8329232eSGordon Ross 	}
649*8329232eSGordon Ross 
650*8329232eSGordon Ross 	/*
651*8329232eSGordon Ross 	 * If this is a remount, ... (never here)
652*8329232eSGordon Ross 	 */
653*8329232eSGordon Ross 	vfsp = vfs_alloc(KM_SLEEP);
654*8329232eSGordon Ross 	VFS_INIT(vfsp, vfsops, NULL);
655*8329232eSGordon Ross 
656*8329232eSGordon Ross 	VFS_HOLD(vfsp);
657*8329232eSGordon Ross 
658*8329232eSGordon Ross 	// lofi_add(fsname, vfsp, &mnt_mntopts, uap)
659*8329232eSGordon Ross 
660*8329232eSGordon Ross 	/*
661*8329232eSGordon Ross 	 * PRIV_SYS_MOUNT doesn't mean you can become root.
662*8329232eSGordon Ross 	 */
663*8329232eSGordon Ross 	uap->flags |= MS_NOSUID;
664*8329232eSGordon Ross 	vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
665*8329232eSGordon Ross 
666*8329232eSGordon Ross 	/*
667*8329232eSGordon Ross 	 * The vfs_reflock...
668*8329232eSGordon Ross 	 */
669*8329232eSGordon Ross 
670*8329232eSGordon Ross 	/*
671*8329232eSGordon Ross 	 * Lock the vfs...
672*8329232eSGordon Ross 	 */
673*8329232eSGordon Ross 	if ((error = vfs_lock(vfsp)) != 0) {
674*8329232eSGordon Ross 		vfs_free(vfsp);
675*8329232eSGordon Ross 		vfsp = NULL;
676*8329232eSGordon Ross 		goto errout;
677*8329232eSGordon Ross 	}
678*8329232eSGordon Ross 
679*8329232eSGordon Ross 	/*
680*8329232eSGordon Ross 	 * Add device to mount in progress table...
681*8329232eSGordon Ross 	 */
682*8329232eSGordon Ross 	/*
683*8329232eSGordon Ross 	 * Invalidate cached entry for the mount point.
684*8329232eSGordon Ross 	 */
685*8329232eSGordon Ross 
686*8329232eSGordon Ross 	/*
687*8329232eSGordon Ross 	 * If have an option string but the filesystem doesn't supply a
688*8329232eSGordon Ross 	 * prototype options table, create a table...
689*8329232eSGordon Ross 	 */
690*8329232eSGordon Ross 
691*8329232eSGordon Ross 	/*
692*8329232eSGordon Ross 	 * Serialize with zone state transitions...
693*8329232eSGordon Ross 	 */
694*8329232eSGordon Ross 
695*8329232eSGordon Ross 	// mount_in_progress(zone);
696*8329232eSGordon Ross 
697*8329232eSGordon Ross 	/*
698*8329232eSGordon Ross 	 * Instantiate (or reinstantiate) the file system...
699*8329232eSGordon Ross 	 */
700*8329232eSGordon Ross 	vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
701*8329232eSGordon Ross 
702*8329232eSGordon Ross 	vfs_setresource(vfsp, uap->spec, 0);
703*8329232eSGordon Ross 	vfs_setmntpoint(vfsp, uap->dir, 0);
704*8329232eSGordon Ross 
705*8329232eSGordon Ross 	/*
706*8329232eSGordon Ross 	 * going to mount on this vnode, so notify.
707*8329232eSGordon Ross 	 */
708*8329232eSGordon Ross 	// vnevent_mountedover(vp, NULL);
709*8329232eSGordon Ross 	error = VFS_MOUNT(vfsp, vp, uap, credp);
710*8329232eSGordon Ross 
711*8329232eSGordon Ross 	if (uap->flags & MS_RDONLY)
712*8329232eSGordon Ross 		vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
713*8329232eSGordon Ross 	if (uap->flags & MS_NOSUID)
714*8329232eSGordon Ross 		vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
715*8329232eSGordon Ross 	if (uap->flags & MS_GLOBAL)
716*8329232eSGordon Ross 		vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
717*8329232eSGordon Ross 
718*8329232eSGordon Ross 	if (error) {
719*8329232eSGordon Ross 		// lofi_remove(vfsp);
720*8329232eSGordon Ross 
721*8329232eSGordon Ross 		// (remount == 0)
722*8329232eSGordon Ross 		vfs_unlock(vfsp);
723*8329232eSGordon Ross 		// vfs_freemnttab(vfsp);
724*8329232eSGordon Ross 		vfs_free(vfsp);
725*8329232eSGordon Ross 		vfsp = NULL;
726*8329232eSGordon Ross 	} else {
727*8329232eSGordon Ross 		/*
728*8329232eSGordon Ross 		 * Set the mount time to now
729*8329232eSGordon Ross 		 */
730*8329232eSGordon Ross 		// vfsp->vfs_mtime = ddi_get_time();
731*8329232eSGordon Ross 		// if (remount) ...
732*8329232eSGordon Ross 		// else if (splice) vfs_add(vp, vfsp, flags)
733*8329232eSGordon Ross 		// else VFS_HOLD(vfsp);
734*8329232eSGordon Ross 
735*8329232eSGordon Ross 		/*
736*8329232eSGordon Ross 		 * Test jig specific:
737*8329232eSGordon Ross 		 * Do sort of like vfs_add for vp=rootdir
738*8329232eSGordon Ross 		 * Already have hold on vp.
739*8329232eSGordon Ross 		 */
740*8329232eSGordon Ross 		vfsp->vfs_vnodecovered = vp;
741*8329232eSGordon Ross 		vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
742*8329232eSGordon Ross 		VFS_HOLD(vfsp);
743*8329232eSGordon Ross 		rootvfs = vfsp;
744*8329232eSGordon Ross 
745*8329232eSGordon Ross 		/*
746*8329232eSGordon Ross 		 * Set flags for global options encountered
747*8329232eSGordon Ross 		 */
748*8329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_RO, NULL))
749*8329232eSGordon Ross 			vfsp->vfs_flag |= VFS_RDONLY;
750*8329232eSGordon Ross 		else
751*8329232eSGordon Ross 			vfsp->vfs_flag &= ~VFS_RDONLY;
752*8329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) {
753*8329232eSGordon Ross 			vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
754*8329232eSGordon Ross 		} else {
755*8329232eSGordon Ross 			if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL))
756*8329232eSGordon Ross 				vfsp->vfs_flag |= VFS_NODEVICES;
757*8329232eSGordon Ross 			else
758*8329232eSGordon Ross 				vfsp->vfs_flag &= ~VFS_NODEVICES;
759*8329232eSGordon Ross 			if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))
760*8329232eSGordon Ross 				vfsp->vfs_flag |= VFS_NOSETUID;
761*8329232eSGordon Ross 			else
762*8329232eSGordon Ross 				vfsp->vfs_flag &= ~VFS_NOSETUID;
763*8329232eSGordon Ross 		}
764*8329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL))
765*8329232eSGordon Ross 			vfsp->vfs_flag |= VFS_NBMAND;
766*8329232eSGordon Ross 		else
767*8329232eSGordon Ross 			vfsp->vfs_flag &= ~VFS_NBMAND;
768*8329232eSGordon Ross 
769*8329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL))
770*8329232eSGordon Ross 			vfsp->vfs_flag |= VFS_XATTR;
771*8329232eSGordon Ross 		else
772*8329232eSGordon Ross 			vfsp->vfs_flag &= ~VFS_XATTR;
773*8329232eSGordon Ross 
774*8329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL))
775*8329232eSGordon Ross 			vfsp->vfs_flag |= VFS_NOEXEC;
776*8329232eSGordon Ross 		else
777*8329232eSGordon Ross 			vfsp->vfs_flag &= ~VFS_NOEXEC;
778*8329232eSGordon Ross 
779*8329232eSGordon Ross 		/*
780*8329232eSGordon Ross 		 * Now construct the output option string of options
781*8329232eSGordon Ross 		 * we recognized.
782*8329232eSGordon Ross 		 */
783*8329232eSGordon Ross 		if (uap->flags & MS_OPTIONSTR) {
784*8329232eSGordon Ross 			vfs_list_read_lock();
785*8329232eSGordon Ross 			copyout_error = vfs_buildoptionstr(
786*8329232eSGordon Ross 			    &vfsp->vfs_mntopts, inargs, optlen);
787*8329232eSGordon Ross 			vfs_list_unlock();
788*8329232eSGordon Ross 			if (copyout_error == 0 &&
789*8329232eSGordon Ross 			    (uap->flags & MS_SYSSPACE) == 0) {
790*8329232eSGordon Ross 				copyout_error = copyout(inargs, opts, optlen);
791*8329232eSGordon Ross 			}
792*8329232eSGordon Ross 		}
793*8329232eSGordon Ross 
794*8329232eSGordon Ross 		/*
795*8329232eSGordon Ross 		 * If this isn't a remount, set up the vopstats...
796*8329232eSGordon Ross 		 */
797*8329232eSGordon Ross 		if (vswp->vsw_flag & VSW_XID)
798*8329232eSGordon Ross 			vfsp->vfs_flag |= VFS_XID;
799*8329232eSGordon Ross 
800*8329232eSGordon Ross 		vfs_unlock(vfsp);
801*8329232eSGordon Ross 
802*8329232eSGordon Ross 		/*
803*8329232eSGordon Ross 		 * Test jig specicific:
804*8329232eSGordon Ross 		 * Replace rootdir with the mounted root.
805*8329232eSGordon Ross 		 */
806*8329232eSGordon Ross 		error = VFS_ROOT(vfsp, &rootdir);
807*8329232eSGordon Ross 		if (error != 0) {
808*8329232eSGordon Ross 			panic("fake_domount, get root %d\n", error);
809*8329232eSGordon Ross 		}
810*8329232eSGordon Ross 	}
811*8329232eSGordon Ross 	// mount_completed(zone);
812*8329232eSGordon Ross 	// zone_rele(zone);
813*8329232eSGordon Ross 
814*8329232eSGordon Ross 	// if (splice)
815*8329232eSGordon Ross 	//	vn_vfsunlock(vp);
816*8329232eSGordon Ross 
817*8329232eSGordon Ross 	if ((error == 0) && (copyout_error == 0)) {
818*8329232eSGordon Ross 		/* get_vskstat_anchor() */
819*8329232eSGordon Ross 		/* Return vfsp to caller. */
820*8329232eSGordon Ross 		*vfspp = vfsp;
821*8329232eSGordon Ross 	}
822*8329232eSGordon Ross errout:
823*8329232eSGordon Ross 	vfs_freeopttbl(&mnt_mntopts);
824*8329232eSGordon Ross 	/* resource, mountpt not allocated */
825*8329232eSGordon Ross 	/* no addmip, delmip */
826*8329232eSGordon Ross 	ASSERT(vswp != NULL);
827*8329232eSGordon Ross 	vfs_unrefvfssw(vswp);
828*8329232eSGordon Ross 	if (inargs != opts)
829*8329232eSGordon Ross 		kmem_free(inargs, MAX_MNTOPT_STR);
830*8329232eSGordon Ross 	if (copyout_error) {
831*8329232eSGordon Ross 		if (vfsp != NULL) {
832*8329232eSGordon Ross 			// lofi_remove(vfsp);
833*8329232eSGordon Ross 			VFS_RELE(vfsp);
834*8329232eSGordon Ross 		}
835*8329232eSGordon Ross 		error = copyout_error;
836*8329232eSGordon Ross 	}
837*8329232eSGordon Ross 	return (error);
838*8329232eSGordon Ross }
839*8329232eSGordon Ross 
840*8329232eSGordon Ross 
841*8329232eSGordon Ross static void
842*8329232eSGordon Ross vfs_setpath(
843*8329232eSGordon Ross     struct vfs *vfsp,		/* vfs being updated */
844*8329232eSGordon Ross     refstr_t **refp,		/* Ref-count string to contain the new path */
845*8329232eSGordon Ross     const char *newpath,	/* Path to add to refp (above) */
846*8329232eSGordon Ross     uint32_t flag)		/* flag */
847*8329232eSGordon Ross {
848*8329232eSGordon Ross 	// size_t len;
849*8329232eSGordon Ross 	refstr_t *ref;
850*8329232eSGordon Ross 	// char *sp;
851*8329232eSGordon Ross 	int have_list_lock = 0;
852*8329232eSGordon Ross 
853*8329232eSGordon Ross 	ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp));
854*8329232eSGordon Ross 
855*8329232eSGordon Ross 	/*
856*8329232eSGordon Ross 	 * New path must be less than MAXPATHLEN because mntfs
857*8329232eSGordon Ross 	 * will only display up to MAXPATHLEN bytes. This is currently
858*8329232eSGordon Ross 	 * safe, because domount() uses pn_get(), and other callers
859*8329232eSGordon Ross 	 * similarly cap the size to fewer than MAXPATHLEN bytes.
860*8329232eSGordon Ross 	 */
861*8329232eSGordon Ross 
862*8329232eSGordon Ross 	ASSERT(strlen(newpath) < MAXPATHLEN);
863*8329232eSGordon Ross 
864*8329232eSGordon Ross 	/* mntfs requires consistency while vfs list lock is held */
865*8329232eSGordon Ross 
866*8329232eSGordon Ross 	if (VFS_ON_LIST(vfsp)) {
867*8329232eSGordon Ross 		have_list_lock = 1;
868*8329232eSGordon Ross 		vfs_list_lock();
869*8329232eSGordon Ross 	}
870*8329232eSGordon Ross 
871*8329232eSGordon Ross 	if (*refp != NULL)
872*8329232eSGordon Ross 		refstr_rele(*refp);
873*8329232eSGordon Ross 
874*8329232eSGordon Ross 	/*
875*8329232eSGordon Ross 	 * If we are in a non-global zone... (do something else)
876*8329232eSGordon Ross 	 */
877*8329232eSGordon Ross 	ref = refstr_alloc(newpath);
878*8329232eSGordon Ross 	*refp = ref;
879*8329232eSGordon Ross 
880*8329232eSGordon Ross 	if (have_list_lock) {
881*8329232eSGordon Ross 		vfs_mnttab_modtimeupd();
882*8329232eSGordon Ross 		vfs_list_unlock();
883*8329232eSGordon Ross 	}
884*8329232eSGordon Ross }
885*8329232eSGordon Ross 
886*8329232eSGordon Ross /*
887*8329232eSGordon Ross  * Record a mounted resource name in a vfs structure.
888*8329232eSGordon Ross  * If vfsp is already mounted, caller must hold the vfs lock.
889*8329232eSGordon Ross  */
890*8329232eSGordon Ross void
891*8329232eSGordon Ross vfs_setresource(struct vfs *vfsp, const char *resource, uint32_t flag)
892*8329232eSGordon Ross {
893*8329232eSGordon Ross 	if (resource == NULL || resource[0] == '\0')
894*8329232eSGordon Ross 		resource = VFS_NORESOURCE;
895*8329232eSGordon Ross 	vfs_setpath(vfsp, &vfsp->vfs_resource, resource, flag);
896*8329232eSGordon Ross }
897*8329232eSGordon Ross 
898*8329232eSGordon Ross /*
899*8329232eSGordon Ross  * Record a mount point name in a vfs structure.
900*8329232eSGordon Ross  * If vfsp is already mounted, caller must hold the vfs lock.
901*8329232eSGordon Ross  */
902*8329232eSGordon Ross void
903*8329232eSGordon Ross vfs_setmntpoint(struct vfs *vfsp, const char *mntpt, uint32_t flag)
904*8329232eSGordon Ross {
905*8329232eSGordon Ross 	if (mntpt == NULL || mntpt[0] == '\0')
906*8329232eSGordon Ross 		mntpt = VFS_NOMNTPT;
907*8329232eSGordon Ross 	vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt, flag);
908*8329232eSGordon Ross }
909*8329232eSGordon Ross 
910*8329232eSGordon Ross /* Returns the vfs_resource. Caller must call refstr_rele() when finished. */
911*8329232eSGordon Ross 
912*8329232eSGordon Ross refstr_t *
913*8329232eSGordon Ross vfs_getresource(const struct vfs *vfsp)
914*8329232eSGordon Ross {
915*8329232eSGordon Ross 	refstr_t *resource;
916*8329232eSGordon Ross 
917*8329232eSGordon Ross 	vfs_list_read_lock();
918*8329232eSGordon Ross 	resource = vfsp->vfs_resource;
919*8329232eSGordon Ross 	refstr_hold(resource);
920*8329232eSGordon Ross 	vfs_list_unlock();
921*8329232eSGordon Ross 
922*8329232eSGordon Ross 	return (resource);
923*8329232eSGordon Ross }
924*8329232eSGordon Ross 
925*8329232eSGordon Ross /* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */
926*8329232eSGordon Ross 
927*8329232eSGordon Ross refstr_t *
928*8329232eSGordon Ross vfs_getmntpoint(const struct vfs *vfsp)
929*8329232eSGordon Ross {
930*8329232eSGordon Ross 	refstr_t *mntpt;
931*8329232eSGordon Ross 
932*8329232eSGordon Ross 	vfs_list_read_lock();
933*8329232eSGordon Ross 	mntpt = vfsp->vfs_mntpt;
934*8329232eSGordon Ross 	refstr_hold(mntpt);
935*8329232eSGordon Ross 	vfs_list_unlock();
936*8329232eSGordon Ross 
937*8329232eSGordon Ross 	return (mntpt);
938*8329232eSGordon Ross }
939*8329232eSGordon Ross 
940*8329232eSGordon Ross // vfs_createopttbl_extend
941*8329232eSGordon Ross // vfs_createopttbl
942*8329232eSGordon Ross 
943*8329232eSGordon Ross /*
944*8329232eSGordon Ross  * Swap two mount options tables
945*8329232eSGordon Ross  */
946*8329232eSGordon Ross static void
947*8329232eSGordon Ross vfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2)
948*8329232eSGordon Ross {
949*8329232eSGordon Ross 	uint_t tmpcnt;
950*8329232eSGordon Ross 	mntopt_t *tmplist;
951*8329232eSGordon Ross 
952*8329232eSGordon Ross 	tmpcnt = optbl2->mo_count;
953*8329232eSGordon Ross 	tmplist = optbl2->mo_list;
954*8329232eSGordon Ross 	optbl2->mo_count = optbl1->mo_count;
955*8329232eSGordon Ross 	optbl2->mo_list = optbl1->mo_list;
956*8329232eSGordon Ross 	optbl1->mo_count = tmpcnt;
957*8329232eSGordon Ross 	optbl1->mo_list = tmplist;
958*8329232eSGordon Ross }
959*8329232eSGordon Ross 
960*8329232eSGordon Ross static void
961*8329232eSGordon Ross vfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2)
962*8329232eSGordon Ross {
963*8329232eSGordon Ross 	vfs_list_lock();
964*8329232eSGordon Ross 	vfs_swapopttbl_nolock(optbl1, optbl2);
965*8329232eSGordon Ross 	vfs_mnttab_modtimeupd();
966*8329232eSGordon Ross 	vfs_list_unlock();
967*8329232eSGordon Ross }
968*8329232eSGordon Ross 
969*8329232eSGordon Ross static char **
970*8329232eSGordon Ross vfs_copycancelopt_extend(char **const moc, int extend)
971*8329232eSGordon Ross {
972*8329232eSGordon Ross 	int i = 0;
973*8329232eSGordon Ross 	int j;
974*8329232eSGordon Ross 	char **result;
975*8329232eSGordon Ross 
976*8329232eSGordon Ross 	if (moc != NULL) {
977*8329232eSGordon Ross 		for (; moc[i] != NULL; i++)
978*8329232eSGordon Ross 			/* count number of options to cancel */;
979*8329232eSGordon Ross 	}
980*8329232eSGordon Ross 
981*8329232eSGordon Ross 	if (i + extend == 0)
982*8329232eSGordon Ross 		return (NULL);
983*8329232eSGordon Ross 
984*8329232eSGordon Ross 	result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP);
985*8329232eSGordon Ross 
986*8329232eSGordon Ross 	for (j = 0; j < i; j++) {
987*8329232eSGordon Ross 		result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP);
988*8329232eSGordon Ross 		(void) strcpy(result[j], moc[j]);
989*8329232eSGordon Ross 	}
990*8329232eSGordon Ross 	for (; j <= i + extend; j++)
991*8329232eSGordon Ross 		result[j] = NULL;
992*8329232eSGordon Ross 
993*8329232eSGordon Ross 	return (result);
994*8329232eSGordon Ross }
995*8329232eSGordon Ross 
996*8329232eSGordon Ross static void
997*8329232eSGordon Ross vfs_copyopt(const mntopt_t *s, mntopt_t *d)
998*8329232eSGordon Ross {
999*8329232eSGordon Ross 	char *sp, *dp;
1000*8329232eSGordon Ross 
1001*8329232eSGordon Ross 	d->mo_flags = s->mo_flags;
1002*8329232eSGordon Ross 	d->mo_data = s->mo_data;
1003*8329232eSGordon Ross 	sp = s->mo_name;
1004*8329232eSGordon Ross 	if (sp != NULL) {
1005*8329232eSGordon Ross 		dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
1006*8329232eSGordon Ross 		(void) strcpy(dp, sp);
1007*8329232eSGordon Ross 		d->mo_name = dp;
1008*8329232eSGordon Ross 	} else {
1009*8329232eSGordon Ross 		d->mo_name = NULL; /* should never happen */
1010*8329232eSGordon Ross 	}
1011*8329232eSGordon Ross 
1012*8329232eSGordon Ross 	d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0);
1013*8329232eSGordon Ross 
1014*8329232eSGordon Ross 	sp = s->mo_arg;
1015*8329232eSGordon Ross 	if (sp != NULL) {
1016*8329232eSGordon Ross 		dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
1017*8329232eSGordon Ross 		(void) strcpy(dp, sp);
1018*8329232eSGordon Ross 		d->mo_arg = dp;
1019*8329232eSGordon Ross 	} else {
1020*8329232eSGordon Ross 		d->mo_arg = NULL;
1021*8329232eSGordon Ross 	}
1022*8329232eSGordon Ross }
1023*8329232eSGordon Ross 
1024*8329232eSGordon Ross // vfs_copyopttbl_extend
1025*8329232eSGordon Ross // vfs_copyopttbl
1026*8329232eSGordon Ross 
1027*8329232eSGordon Ross /*
1028*8329232eSGordon Ross  * Copy a mount options table, possibly allocating some spare
1029*8329232eSGordon Ross  * slots at the end.  It is permissible to copy_extend the NULL table.
1030*8329232eSGordon Ross  */
1031*8329232eSGordon Ross static void
1032*8329232eSGordon Ross vfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra)
1033*8329232eSGordon Ross {
1034*8329232eSGordon Ross 	uint_t i, count;
1035*8329232eSGordon Ross 	mntopt_t *motbl;
1036*8329232eSGordon Ross 
1037*8329232eSGordon Ross 	/*
1038*8329232eSGordon Ross 	 * Clear out any existing stuff in the options table being initialized
1039*8329232eSGordon Ross 	 */
1040*8329232eSGordon Ross 	vfs_freeopttbl(dmo);
1041*8329232eSGordon Ross 	count = (smo == NULL) ? 0 : smo->mo_count;
1042*8329232eSGordon Ross 	if ((count + extra) == 0)	/* nothing to do */
1043*8329232eSGordon Ross 		return;
1044*8329232eSGordon Ross 	dmo->mo_count = count + extra;
1045*8329232eSGordon Ross 	motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP);
1046*8329232eSGordon Ross 	dmo->mo_list = motbl;
1047*8329232eSGordon Ross 	for (i = 0; i < count; i++) {
1048*8329232eSGordon Ross 		vfs_copyopt(&smo->mo_list[i], &motbl[i]);
1049*8329232eSGordon Ross 	}
1050*8329232eSGordon Ross 	for (i = count; i < count + extra; i++) {
1051*8329232eSGordon Ross 		motbl[i].mo_flags = MO_EMPTY;
1052*8329232eSGordon Ross 	}
1053*8329232eSGordon Ross }
1054*8329232eSGordon Ross 
1055*8329232eSGordon Ross /*
1056*8329232eSGordon Ross  * Copy a mount options table.
1057*8329232eSGordon Ross  *
1058*8329232eSGordon Ross  * This function is *not* for general use by filesystems.
1059*8329232eSGordon Ross  *
1060*8329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
1061*8329232eSGordon Ross  *       to protect smo and dmo.
1062*8329232eSGordon Ross  */
1063*8329232eSGordon Ross void
1064*8329232eSGordon Ross vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo)
1065*8329232eSGordon Ross {
1066*8329232eSGordon Ross 	vfs_copyopttbl_extend(smo, dmo, 0);
1067*8329232eSGordon Ross }
1068*8329232eSGordon Ross 
1069*8329232eSGordon Ross static char **
1070*8329232eSGordon Ross vfs_mergecancelopts(const mntopt_t *mop1, const mntopt_t *mop2)
1071*8329232eSGordon Ross {
1072*8329232eSGordon Ross 	int c1 = 0;
1073*8329232eSGordon Ross 	int c2 = 0;
1074*8329232eSGordon Ross 	char **result;
1075*8329232eSGordon Ross 	char **sp1, **sp2, **dp;
1076*8329232eSGordon Ross 
1077*8329232eSGordon Ross 	/*
1078*8329232eSGordon Ross 	 * First we count both lists of cancel options.
1079*8329232eSGordon Ross 	 * If either is NULL or has no elements, we return a copy of
1080*8329232eSGordon Ross 	 * the other.
1081*8329232eSGordon Ross 	 */
1082*8329232eSGordon Ross 	if (mop1->mo_cancel != NULL) {
1083*8329232eSGordon Ross 		for (; mop1->mo_cancel[c1] != NULL; c1++)
1084*8329232eSGordon Ross 			/* count cancel options in mop1 */;
1085*8329232eSGordon Ross 	}
1086*8329232eSGordon Ross 
1087*8329232eSGordon Ross 	if (c1 == 0)
1088*8329232eSGordon Ross 		return (vfs_copycancelopt_extend(mop2->mo_cancel, 0));
1089*8329232eSGordon Ross 
1090*8329232eSGordon Ross 	if (mop2->mo_cancel != NULL) {
1091*8329232eSGordon Ross 		for (; mop2->mo_cancel[c2] != NULL; c2++)
1092*8329232eSGordon Ross 			/* count cancel options in mop2 */;
1093*8329232eSGordon Ross 	}
1094*8329232eSGordon Ross 
1095*8329232eSGordon Ross 	result = vfs_copycancelopt_extend(mop1->mo_cancel, c2);
1096*8329232eSGordon Ross 
1097*8329232eSGordon Ross 	if (c2 == 0)
1098*8329232eSGordon Ross 		return (result);
1099*8329232eSGordon Ross 
1100*8329232eSGordon Ross 	/*
1101*8329232eSGordon Ross 	 * When we get here, we've got two sets of cancel options;
1102*8329232eSGordon Ross 	 * we need to merge the two sets.  We know that the result
1103*8329232eSGordon Ross 	 * array has "c1+c2+1" entries and in the end we might shrink
1104*8329232eSGordon Ross 	 * it.
1105*8329232eSGordon Ross 	 * Result now has a copy of the c1 entries from mop1; we'll
1106*8329232eSGordon Ross 	 * now lookup all the entries of mop2 in mop1 and copy it if
1107*8329232eSGordon Ross 	 * it is unique.
1108*8329232eSGordon Ross 	 * This operation is O(n^2) but it's only called once per
1109*8329232eSGordon Ross 	 * filesystem per duplicate option.  This is a situation
1110*8329232eSGordon Ross 	 * which doesn't arise with the filesystems in ON and
1111*8329232eSGordon Ross 	 * n is generally 1.
1112*8329232eSGordon Ross 	 */
1113*8329232eSGordon Ross 
1114*8329232eSGordon Ross 	dp = &result[c1];
1115*8329232eSGordon Ross 	for (sp2 = mop2->mo_cancel; *sp2 != NULL; sp2++) {
1116*8329232eSGordon Ross 		for (sp1 = mop1->mo_cancel; *sp1 != NULL; sp1++) {
1117*8329232eSGordon Ross 			if (strcmp(*sp1, *sp2) == 0)
1118*8329232eSGordon Ross 				break;
1119*8329232eSGordon Ross 		}
1120*8329232eSGordon Ross 		if (*sp1 == NULL) {
1121*8329232eSGordon Ross 			/*
1122*8329232eSGordon Ross 			 * Option *sp2 not found in mop1, so copy it.
1123*8329232eSGordon Ross 			 * The calls to vfs_copycancelopt_extend()
1124*8329232eSGordon Ross 			 * guarantee that there's enough room.
1125*8329232eSGordon Ross 			 */
1126*8329232eSGordon Ross 			*dp = kmem_alloc(strlen(*sp2) + 1, KM_SLEEP);
1127*8329232eSGordon Ross 			(void) strcpy(*dp++, *sp2);
1128*8329232eSGordon Ross 		}
1129*8329232eSGordon Ross 	}
1130*8329232eSGordon Ross 	if (dp != &result[c1+c2]) {
1131*8329232eSGordon Ross 		size_t bytes = (dp - result + 1) * sizeof (char *);
1132*8329232eSGordon Ross 		char **nres = kmem_alloc(bytes, KM_SLEEP);
1133*8329232eSGordon Ross 
1134*8329232eSGordon Ross 		bcopy(result, nres, bytes);
1135*8329232eSGordon Ross 		kmem_free(result, (c1 + c2 + 1) * sizeof (char *));
1136*8329232eSGordon Ross 		result = nres;
1137*8329232eSGordon Ross 	}
1138*8329232eSGordon Ross 	return (result);
1139*8329232eSGordon Ross }
1140*8329232eSGordon Ross 
1141*8329232eSGordon Ross /*
1142*8329232eSGordon Ross  * Merge two mount option tables (outer and inner) into one.  This is very
1143*8329232eSGordon Ross  * similar to "merging" global variables and automatic variables in C.
1144*8329232eSGordon Ross  *
1145*8329232eSGordon Ross  * This isn't (and doesn't have to be) fast.
1146*8329232eSGordon Ross  *
1147*8329232eSGordon Ross  * This function is *not* for general use by filesystems.
1148*8329232eSGordon Ross  *
1149*8329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
1150*8329232eSGordon Ross  *       to protect omo, imo & dmo.
1151*8329232eSGordon Ross  */
1152*8329232eSGordon Ross void
1153*8329232eSGordon Ross vfs_mergeopttbl(const mntopts_t *omo, const mntopts_t *imo, mntopts_t *dmo)
1154*8329232eSGordon Ross {
1155*8329232eSGordon Ross 	uint_t i, count;
1156*8329232eSGordon Ross 	mntopt_t *mop, *motbl;
1157*8329232eSGordon Ross 	uint_t freeidx;
1158*8329232eSGordon Ross 
1159*8329232eSGordon Ross 	/*
1160*8329232eSGordon Ross 	 * First determine how much space we need to allocate.
1161*8329232eSGordon Ross 	 */
1162*8329232eSGordon Ross 	count = omo->mo_count;
1163*8329232eSGordon Ross 	for (i = 0; i < imo->mo_count; i++) {
1164*8329232eSGordon Ross 		if (imo->mo_list[i].mo_flags & MO_EMPTY)
1165*8329232eSGordon Ross 			continue;
1166*8329232eSGordon Ross 		if (vfs_hasopt(omo, imo->mo_list[i].mo_name) == NULL)
1167*8329232eSGordon Ross 			count++;
1168*8329232eSGordon Ross 	}
1169*8329232eSGordon Ross 	ASSERT(count >= omo->mo_count &&
1170*8329232eSGordon Ross 	    count <= omo->mo_count + imo->mo_count);
1171*8329232eSGordon Ross 	motbl = kmem_alloc(count * sizeof (mntopt_t), KM_SLEEP);
1172*8329232eSGordon Ross 	for (i = 0; i < omo->mo_count; i++)
1173*8329232eSGordon Ross 		vfs_copyopt(&omo->mo_list[i], &motbl[i]);
1174*8329232eSGordon Ross 	freeidx = omo->mo_count;
1175*8329232eSGordon Ross 	for (i = 0; i < imo->mo_count; i++) {
1176*8329232eSGordon Ross 		if (imo->mo_list[i].mo_flags & MO_EMPTY)
1177*8329232eSGordon Ross 			continue;
1178*8329232eSGordon Ross 		if ((mop = vfs_hasopt(omo, imo->mo_list[i].mo_name)) != NULL) {
1179*8329232eSGordon Ross 			char **newcanp;
1180*8329232eSGordon Ross 			uint_t index = mop - omo->mo_list;
1181*8329232eSGordon Ross 
1182*8329232eSGordon Ross 			newcanp = vfs_mergecancelopts(mop, &motbl[index]);
1183*8329232eSGordon Ross 
1184*8329232eSGordon Ross 			vfs_freeopt(&motbl[index]);
1185*8329232eSGordon Ross 			vfs_copyopt(&imo->mo_list[i], &motbl[index]);
1186*8329232eSGordon Ross 
1187*8329232eSGordon Ross 			vfs_freecancelopt(motbl[index].mo_cancel);
1188*8329232eSGordon Ross 			motbl[index].mo_cancel = newcanp;
1189*8329232eSGordon Ross 		} else {
1190*8329232eSGordon Ross 			/*
1191*8329232eSGordon Ross 			 * If it's a new option, just copy it over to the first
1192*8329232eSGordon Ross 			 * free location.
1193*8329232eSGordon Ross 			 */
1194*8329232eSGordon Ross 			vfs_copyopt(&imo->mo_list[i], &motbl[freeidx++]);
1195*8329232eSGordon Ross 		}
1196*8329232eSGordon Ross 	}
1197*8329232eSGordon Ross 	dmo->mo_count = count;
1198*8329232eSGordon Ross 	dmo->mo_list = motbl;
1199*8329232eSGordon Ross }
1200*8329232eSGordon Ross 
1201*8329232eSGordon Ross /*
1202*8329232eSGordon Ross  * Functions to set and clear mount options in a mount options table.
1203*8329232eSGordon Ross  */
1204*8329232eSGordon Ross 
1205*8329232eSGordon Ross /*
1206*8329232eSGordon Ross  * Clear a mount option, if it exists.
1207*8329232eSGordon Ross  *
1208*8329232eSGordon Ross  * The update_mnttab arg indicates whether mops is part of a vfs that is on
1209*8329232eSGordon Ross  * the vfs list.
1210*8329232eSGordon Ross  */
1211*8329232eSGordon Ross static void
1212*8329232eSGordon Ross vfs_clearmntopt_nolock(mntopts_t *mops, const char *opt, int update_mnttab)
1213*8329232eSGordon Ross {
1214*8329232eSGordon Ross 	struct mntopt *mop;
1215*8329232eSGordon Ross 	uint_t i, count;
1216*8329232eSGordon Ross 
1217*8329232eSGordon Ross 	ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
1218*8329232eSGordon Ross 
1219*8329232eSGordon Ross 	count = mops->mo_count;
1220*8329232eSGordon Ross 	for (i = 0; i < count; i++) {
1221*8329232eSGordon Ross 		mop = &mops->mo_list[i];
1222*8329232eSGordon Ross 
1223*8329232eSGordon Ross 		if (mop->mo_flags & MO_EMPTY)
1224*8329232eSGordon Ross 			continue;
1225*8329232eSGordon Ross 		if (strcmp(opt, mop->mo_name))
1226*8329232eSGordon Ross 			continue;
1227*8329232eSGordon Ross 		mop->mo_flags &= ~MO_SET;
1228*8329232eSGordon Ross 		if (mop->mo_arg != NULL) {
1229*8329232eSGordon Ross 			kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
1230*8329232eSGordon Ross 		}
1231*8329232eSGordon Ross 		mop->mo_arg = NULL;
1232*8329232eSGordon Ross 		if (update_mnttab)
1233*8329232eSGordon Ross 			vfs_mnttab_modtimeupd();
1234*8329232eSGordon Ross 		break;
1235*8329232eSGordon Ross 	}
1236*8329232eSGordon Ross }
1237*8329232eSGordon Ross 
1238*8329232eSGordon Ross void
1239*8329232eSGordon Ross vfs_clearmntopt(struct vfs *vfsp, const char *opt)
1240*8329232eSGordon Ross {
1241*8329232eSGordon Ross 	int gotlock = 0;
1242*8329232eSGordon Ross 
1243*8329232eSGordon Ross 	if (VFS_ON_LIST(vfsp)) {
1244*8329232eSGordon Ross 		gotlock = 1;
1245*8329232eSGordon Ross 		vfs_list_lock();
1246*8329232eSGordon Ross 	}
1247*8329232eSGordon Ross 	vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, opt, gotlock);
1248*8329232eSGordon Ross 	if (gotlock)
1249*8329232eSGordon Ross 		vfs_list_unlock();
1250*8329232eSGordon Ross }
1251*8329232eSGordon Ross 
1252*8329232eSGordon Ross 
1253*8329232eSGordon Ross /*
1254*8329232eSGordon Ross  * Set a mount option on...
1255*8329232eSGordon Ross  */
1256*8329232eSGordon Ross static void
1257*8329232eSGordon Ross vfs_setmntopt_nolock(mntopts_t *mops, const char *opt,
1258*8329232eSGordon Ross     const char *arg, int flags, int update_mnttab)
1259*8329232eSGordon Ross {
1260*8329232eSGordon Ross 	mntopt_t *mop;
1261*8329232eSGordon Ross 	uint_t i, count;
1262*8329232eSGordon Ross 	char *sp;
1263*8329232eSGordon Ross 
1264*8329232eSGordon Ross 	ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
1265*8329232eSGordon Ross 
1266*8329232eSGordon Ross 	if (flags & VFS_CREATEOPT) {
1267*8329232eSGordon Ross 		if (vfs_hasopt(mops, opt) != NULL) {
1268*8329232eSGordon Ross 			flags &= ~VFS_CREATEOPT;
1269*8329232eSGordon Ross 		}
1270*8329232eSGordon Ross 	}
1271*8329232eSGordon Ross 	count = mops->mo_count;
1272*8329232eSGordon Ross 	for (i = 0; i < count; i++) {
1273*8329232eSGordon Ross 		mop = &mops->mo_list[i];
1274*8329232eSGordon Ross 
1275*8329232eSGordon Ross 		if (mop->mo_flags & MO_EMPTY) {
1276*8329232eSGordon Ross 			if ((flags & VFS_CREATEOPT) == 0)
1277*8329232eSGordon Ross 				continue;
1278*8329232eSGordon Ross 			sp = kmem_alloc(strlen(opt) + 1, KM_SLEEP);
1279*8329232eSGordon Ross 			(void) strcpy(sp, opt);
1280*8329232eSGordon Ross 			mop->mo_name = sp;
1281*8329232eSGordon Ross 			if (arg != NULL)
1282*8329232eSGordon Ross 				mop->mo_flags = MO_HASVALUE;
1283*8329232eSGordon Ross 			else
1284*8329232eSGordon Ross 				mop->mo_flags = 0;
1285*8329232eSGordon Ross 		} else if (strcmp(opt, mop->mo_name)) {
1286*8329232eSGordon Ross 			continue;
1287*8329232eSGordon Ross 		}
1288*8329232eSGordon Ross 		if ((mop->mo_flags & MO_IGNORE) && (flags & VFS_NOFORCEOPT))
1289*8329232eSGordon Ross 			break;
1290*8329232eSGordon Ross 		if (arg != NULL && (mop->mo_flags & MO_HASVALUE) != 0) {
1291*8329232eSGordon Ross 			sp = kmem_alloc(strlen(arg) + 1, KM_SLEEP);
1292*8329232eSGordon Ross 			(void) strcpy(sp, arg);
1293*8329232eSGordon Ross 		} else {
1294*8329232eSGordon Ross 			sp = NULL;
1295*8329232eSGordon Ross 		}
1296*8329232eSGordon Ross 		if (mop->mo_arg != NULL)
1297*8329232eSGordon Ross 			kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
1298*8329232eSGordon Ross 		mop->mo_arg = sp;
1299*8329232eSGordon Ross 		if (flags & VFS_DISPLAY)
1300*8329232eSGordon Ross 			mop->mo_flags &= ~MO_NODISPLAY;
1301*8329232eSGordon Ross 		if (flags & VFS_NODISPLAY)
1302*8329232eSGordon Ross 			mop->mo_flags |= MO_NODISPLAY;
1303*8329232eSGordon Ross 		mop->mo_flags |= MO_SET;
1304*8329232eSGordon Ross 		if (mop->mo_cancel != NULL) {
1305*8329232eSGordon Ross 			char **cp;
1306*8329232eSGordon Ross 
1307*8329232eSGordon Ross 			for (cp = mop->mo_cancel; *cp != NULL; cp++)
1308*8329232eSGordon Ross 				vfs_clearmntopt_nolock(mops, *cp, 0);
1309*8329232eSGordon Ross 		}
1310*8329232eSGordon Ross 		if (update_mnttab)
1311*8329232eSGordon Ross 			vfs_mnttab_modtimeupd();
1312*8329232eSGordon Ross 		break;
1313*8329232eSGordon Ross 	}
1314*8329232eSGordon Ross }
1315*8329232eSGordon Ross 
1316*8329232eSGordon Ross void
1317*8329232eSGordon Ross vfs_setmntopt(struct vfs *vfsp, const char *opt, const char *arg, int flags)
1318*8329232eSGordon Ross {
1319*8329232eSGordon Ross 	int gotlock = 0;
1320*8329232eSGordon Ross 
1321*8329232eSGordon Ross 	if (VFS_ON_LIST(vfsp)) {
1322*8329232eSGordon Ross 		gotlock = 1;
1323*8329232eSGordon Ross 		vfs_list_lock();
1324*8329232eSGordon Ross 	}
1325*8329232eSGordon Ross 	vfs_setmntopt_nolock(&vfsp->vfs_mntopts, opt, arg, flags, gotlock);
1326*8329232eSGordon Ross 	if (gotlock)
1327*8329232eSGordon Ross 		vfs_list_unlock();
1328*8329232eSGordon Ross }
1329*8329232eSGordon Ross 
1330*8329232eSGordon Ross // vfs_addtag
1331*8329232eSGordon Ross // vfs_settag
1332*8329232eSGordon Ross // vfs_clrtag
1333*8329232eSGordon Ross 
1334*8329232eSGordon Ross /*
1335*8329232eSGordon Ross  * Function to parse an option string and fill in a mount options table.
1336*8329232eSGordon Ross  * Unknown options are silently ignored.  The input option string is modified
1337*8329232eSGordon Ross  * by replacing separators with nulls.  If the create flag is set, options
1338*8329232eSGordon Ross  * not found in the table are just added on the fly.  The table must have
1339*8329232eSGordon Ross  * an option slot marked MO_EMPTY to add an option on the fly.
1340*8329232eSGordon Ross  *
1341*8329232eSGordon Ross  * This function is *not* for general use by filesystems.
1342*8329232eSGordon Ross  *
1343*8329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
1344*8329232eSGordon Ross  *       to protect mops..
1345*8329232eSGordon Ross  */
1346*8329232eSGordon Ross void
1347*8329232eSGordon Ross vfs_parsemntopts(mntopts_t *mops, char *osp, int create)
1348*8329232eSGordon Ross {
1349*8329232eSGordon Ross 	char *s = osp, *p, *nextop, *valp, *cp, *ep = NULL;
1350*8329232eSGordon Ross 	int setflg = VFS_NOFORCEOPT;
1351*8329232eSGordon Ross 
1352*8329232eSGordon Ross 	if (osp == NULL)
1353*8329232eSGordon Ross 		return;
1354*8329232eSGordon Ross 	while (*s != '\0') {
1355*8329232eSGordon Ross 		p = strchr(s, ',');	/* find next option */
1356*8329232eSGordon Ross 		if (p == NULL) {
1357*8329232eSGordon Ross 			cp = NULL;
1358*8329232eSGordon Ross 			p = s + strlen(s);
1359*8329232eSGordon Ross 		} else {
1360*8329232eSGordon Ross 			cp = p;		/* save location of comma */
1361*8329232eSGordon Ross 			*p++ = '\0';	/* mark end and point to next option */
1362*8329232eSGordon Ross 		}
1363*8329232eSGordon Ross 		nextop = p;
1364*8329232eSGordon Ross 		p = strchr(s, '=');	/* look for value */
1365*8329232eSGordon Ross 		if (p == NULL) {
1366*8329232eSGordon Ross 			valp = NULL;	/* no value supplied */
1367*8329232eSGordon Ross 			ep = NULL;
1368*8329232eSGordon Ross 		} else {
1369*8329232eSGordon Ross 			ep = p;		/* save location of equals */
1370*8329232eSGordon Ross 			*p++ = '\0';	/* end option and point to value */
1371*8329232eSGordon Ross 			valp = p;
1372*8329232eSGordon Ross 		}
1373*8329232eSGordon Ross 		/*
1374*8329232eSGordon Ross 		 * set option into options table
1375*8329232eSGordon Ross 		 */
1376*8329232eSGordon Ross 		if (create)
1377*8329232eSGordon Ross 			setflg |= VFS_CREATEOPT;
1378*8329232eSGordon Ross 		vfs_setmntopt_nolock(mops, s, valp, setflg, 0);
1379*8329232eSGordon Ross 		if (cp != NULL)
1380*8329232eSGordon Ross 			*cp = ',';	/* restore the comma */
1381*8329232eSGordon Ross 		if (valp != NULL)
1382*8329232eSGordon Ross 			*ep = '=';	/* restore the equals */
1383*8329232eSGordon Ross 		s = nextop;
1384*8329232eSGordon Ross 	}
1385*8329232eSGordon Ross }
1386*8329232eSGordon Ross 
1387*8329232eSGordon Ross /*
1388*8329232eSGordon Ross  * Function to inquire if an option exists in a mount options table.
1389*8329232eSGordon Ross  * Returns a pointer to the option if it exists, else NULL.
1390*8329232eSGordon Ross  */
1391*8329232eSGordon Ross struct mntopt *
1392*8329232eSGordon Ross vfs_hasopt(const mntopts_t *mops, const char *opt)
1393*8329232eSGordon Ross {
1394*8329232eSGordon Ross 	struct mntopt *mop;
1395*8329232eSGordon Ross 	uint_t i, count;
1396*8329232eSGordon Ross 
1397*8329232eSGordon Ross 	count = mops->mo_count;
1398*8329232eSGordon Ross 	for (i = 0; i < count; i++) {
1399*8329232eSGordon Ross 		mop = &mops->mo_list[i];
1400*8329232eSGordon Ross 
1401*8329232eSGordon Ross 		if (mop->mo_flags & MO_EMPTY)
1402*8329232eSGordon Ross 			continue;
1403*8329232eSGordon Ross 		if (strcmp(opt, mop->mo_name) == 0)
1404*8329232eSGordon Ross 			return (mop);
1405*8329232eSGordon Ross 	}
1406*8329232eSGordon Ross 	return (NULL);
1407*8329232eSGordon Ross }
1408*8329232eSGordon Ross 
1409*8329232eSGordon Ross /*
1410*8329232eSGordon Ross  * Function to inquire if an option is set in a mount options table.
1411*8329232eSGordon Ross  * Returns non-zero if set and fills in the arg pointer with a pointer to
1412*8329232eSGordon Ross  * the argument string or NULL if there is no argument string.
1413*8329232eSGordon Ross  */
1414*8329232eSGordon Ross static int
1415*8329232eSGordon Ross vfs_optionisset_nolock(const mntopts_t *mops, const char *opt, char **argp)
1416*8329232eSGordon Ross {
1417*8329232eSGordon Ross 	struct mntopt *mop;
1418*8329232eSGordon Ross 	uint_t i, count;
1419*8329232eSGordon Ross 
1420*8329232eSGordon Ross 	count = mops->mo_count;
1421*8329232eSGordon Ross 	for (i = 0; i < count; i++) {
1422*8329232eSGordon Ross 		mop = &mops->mo_list[i];
1423*8329232eSGordon Ross 
1424*8329232eSGordon Ross 		if (mop->mo_flags & MO_EMPTY)
1425*8329232eSGordon Ross 			continue;
1426*8329232eSGordon Ross 		if (strcmp(opt, mop->mo_name))
1427*8329232eSGordon Ross 			continue;
1428*8329232eSGordon Ross 		if ((mop->mo_flags & MO_SET) == 0)
1429*8329232eSGordon Ross 			return (0);
1430*8329232eSGordon Ross 		if (argp != NULL && (mop->mo_flags & MO_HASVALUE) != 0)
1431*8329232eSGordon Ross 			*argp = mop->mo_arg;
1432*8329232eSGordon Ross 		return (1);
1433*8329232eSGordon Ross 	}
1434*8329232eSGordon Ross 	return (0);
1435*8329232eSGordon Ross }
1436*8329232eSGordon Ross 
1437*8329232eSGordon Ross 
1438*8329232eSGordon Ross int
1439*8329232eSGordon Ross vfs_optionisset(const struct vfs *vfsp, const char *opt, char **argp)
1440*8329232eSGordon Ross {
1441*8329232eSGordon Ross 	int ret;
1442*8329232eSGordon Ross 
1443*8329232eSGordon Ross 	vfs_list_read_lock();
1444*8329232eSGordon Ross 	ret = vfs_optionisset_nolock(&vfsp->vfs_mntopts, opt, argp);
1445*8329232eSGordon Ross 	vfs_list_unlock();
1446*8329232eSGordon Ross 	return (ret);
1447*8329232eSGordon Ross }
1448*8329232eSGordon Ross 
1449*8329232eSGordon Ross 
1450*8329232eSGordon Ross /*
1451*8329232eSGordon Ross  * Construct a comma separated string of the options set in the given
1452*8329232eSGordon Ross  * mount table, return the string in the given buffer.  Return non-zero if
1453*8329232eSGordon Ross  * the buffer would overflow.
1454*8329232eSGordon Ross  *
1455*8329232eSGordon Ross  * This function is *not* for general use by filesystems.
1456*8329232eSGordon Ross  *
1457*8329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
1458*8329232eSGordon Ross  *       to protect mp.
1459*8329232eSGordon Ross  */
1460*8329232eSGordon Ross int
1461*8329232eSGordon Ross vfs_buildoptionstr(const mntopts_t *mp, char *buf, int len)
1462*8329232eSGordon Ross {
1463*8329232eSGordon Ross 	char *cp;
1464*8329232eSGordon Ross 	uint_t i;
1465*8329232eSGordon Ross 
1466*8329232eSGordon Ross 	buf[0] = '\0';
1467*8329232eSGordon Ross 	cp = buf;
1468*8329232eSGordon Ross 	for (i = 0; i < mp->mo_count; i++) {
1469*8329232eSGordon Ross 		struct mntopt *mop;
1470*8329232eSGordon Ross 
1471*8329232eSGordon Ross 		mop = &mp->mo_list[i];
1472*8329232eSGordon Ross 		if (mop->mo_flags & MO_SET) {
1473*8329232eSGordon Ross 			int optlen, comma = 0;
1474*8329232eSGordon Ross 
1475*8329232eSGordon Ross 			if (buf[0] != '\0')
1476*8329232eSGordon Ross 				comma = 1;
1477*8329232eSGordon Ross 			optlen = strlen(mop->mo_name);
1478*8329232eSGordon Ross 			if (strlen(buf) + comma + optlen + 1 > len)
1479*8329232eSGordon Ross 				goto err;
1480*8329232eSGordon Ross 			if (comma)
1481*8329232eSGordon Ross 				*cp++ = ',';
1482*8329232eSGordon Ross 			(void) strcpy(cp, mop->mo_name);
1483*8329232eSGordon Ross 			cp += optlen;
1484*8329232eSGordon Ross 			/*
1485*8329232eSGordon Ross 			 * Append option value if there is one
1486*8329232eSGordon Ross 			 */
1487*8329232eSGordon Ross 			if (mop->mo_arg != NULL) {
1488*8329232eSGordon Ross 				int arglen;
1489*8329232eSGordon Ross 
1490*8329232eSGordon Ross 				arglen = strlen(mop->mo_arg);
1491*8329232eSGordon Ross 				if (strlen(buf) + arglen + 2 > len)
1492*8329232eSGordon Ross 					goto err;
1493*8329232eSGordon Ross 				*cp++ = '=';
1494*8329232eSGordon Ross 				(void) strcpy(cp, mop->mo_arg);
1495*8329232eSGordon Ross 				cp += arglen;
1496*8329232eSGordon Ross 			}
1497*8329232eSGordon Ross 		}
1498*8329232eSGordon Ross 	}
1499*8329232eSGordon Ross 	return (0);
1500*8329232eSGordon Ross err:
1501*8329232eSGordon Ross 	return (EOVERFLOW);
1502*8329232eSGordon Ross }
1503*8329232eSGordon Ross 
1504*8329232eSGordon Ross static void
1505*8329232eSGordon Ross vfs_freecancelopt(char **moc)
1506*8329232eSGordon Ross {
1507*8329232eSGordon Ross 	if (moc != NULL) {
1508*8329232eSGordon Ross 		int ccnt = 0;
1509*8329232eSGordon Ross 		char **cp;
1510*8329232eSGordon Ross 
1511*8329232eSGordon Ross 		for (cp = moc; *cp != NULL; cp++) {
1512*8329232eSGordon Ross 			kmem_free(*cp, strlen(*cp) + 1);
1513*8329232eSGordon Ross 			ccnt++;
1514*8329232eSGordon Ross 		}
1515*8329232eSGordon Ross 		kmem_free(moc, (ccnt + 1) * sizeof (char *));
1516*8329232eSGordon Ross 	}
1517*8329232eSGordon Ross }
1518*8329232eSGordon Ross 
1519*8329232eSGordon Ross static void
1520*8329232eSGordon Ross vfs_freeopt(mntopt_t *mop)
1521*8329232eSGordon Ross {
1522*8329232eSGordon Ross 	if (mop->mo_name != NULL)
1523*8329232eSGordon Ross 		kmem_free(mop->mo_name, strlen(mop->mo_name) + 1);
1524*8329232eSGordon Ross 
1525*8329232eSGordon Ross 	vfs_freecancelopt(mop->mo_cancel);
1526*8329232eSGordon Ross 
1527*8329232eSGordon Ross 	if (mop->mo_arg != NULL)
1528*8329232eSGordon Ross 		kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
1529*8329232eSGordon Ross }
1530*8329232eSGordon Ross 
1531*8329232eSGordon Ross /*
1532*8329232eSGordon Ross  * Free a mount options table
1533*8329232eSGordon Ross  *
1534*8329232eSGordon Ross  * This function is *not* for general use by filesystems.
1535*8329232eSGordon Ross  *
1536*8329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
1537*8329232eSGordon Ross  *       to protect mp.
1538*8329232eSGordon Ross  */
1539*8329232eSGordon Ross void
1540*8329232eSGordon Ross vfs_freeopttbl(mntopts_t *mp)
1541*8329232eSGordon Ross {
1542*8329232eSGordon Ross 	uint_t i, count;
1543*8329232eSGordon Ross 
1544*8329232eSGordon Ross 	count = mp->mo_count;
1545*8329232eSGordon Ross 	for (i = 0; i < count; i++) {
1546*8329232eSGordon Ross 		vfs_freeopt(&mp->mo_list[i]);
1547*8329232eSGordon Ross 	}
1548*8329232eSGordon Ross 	if (count) {
1549*8329232eSGordon Ross 		kmem_free(mp->mo_list, sizeof (mntopt_t) * count);
1550*8329232eSGordon Ross 		mp->mo_count = 0;
1551*8329232eSGordon Ross 		mp->mo_list = NULL;
1552*8329232eSGordon Ross 	}
1553*8329232eSGordon Ross }
1554*8329232eSGordon Ross 
1555*8329232eSGordon Ross // vfs_mntdummyread
1556*8329232eSGordon Ross // vfs_mntdummywrite
1557*8329232eSGordon Ross // vfs_mntdummygetattr
1558*8329232eSGordon Ross // vfs_mnttabvp_setup
1559*8329232eSGordon Ross // vfs_mnttab_rwop
1560*8329232eSGordon Ross // vfs_mnttab_writeop
1561*8329232eSGordon Ross // vfs_mnttab_readop
1562*8329232eSGordon Ross // vfs_freemnttab
1563*8329232eSGordon Ross // vfs_mnttab_modtime
1564*8329232eSGordon Ross // vfs_mnttab_poll
1565*8329232eSGordon Ross // vfs_mono_time
1566*8329232eSGordon Ross 
1567*8329232eSGordon Ross /*
1568*8329232eSGordon Ross  * Update the mnttab modification time...
1569*8329232eSGordon Ross  */
1570*8329232eSGordon Ross void
1571*8329232eSGordon Ross vfs_mnttab_modtimeupd()
1572*8329232eSGordon Ross {
1573*8329232eSGordon Ross }
1574*8329232eSGordon Ross 
1575*8329232eSGordon Ross /*
1576*8329232eSGordon Ross  * Unlike the real dounmount, we don't have
1577*8329232eSGordon Ross  * vn_vfswlock_held(coveredvp)
1578*8329232eSGordon Ross  */
1579*8329232eSGordon Ross int
1580*8329232eSGordon Ross fake_dounmount(struct vfs *vfsp, int flag)
1581*8329232eSGordon Ross {
1582*8329232eSGordon Ross 	cred_t *cr = CRED();
1583*8329232eSGordon Ross 	vnode_t *coveredvp;
1584*8329232eSGordon Ross 	int error;
1585*8329232eSGordon Ross 
1586*8329232eSGordon Ross 	/*
1587*8329232eSGordon Ross 	 * Get covered vnode. This will be NULL if the vfs is not linked
1588*8329232eSGordon Ross 	 * into the file system name space (i.e., domount() with MNT_NOSPICE).
1589*8329232eSGordon Ross 	 */
1590*8329232eSGordon Ross 	coveredvp = vfsp->vfs_vnodecovered;
1591*8329232eSGordon Ross 
1592*8329232eSGordon Ross 	/* For forcible umount, skip VFS_SYNC() since it may hang */
1593*8329232eSGordon Ross 	if ((flag & MS_FORCE) == 0)
1594*8329232eSGordon Ross 		(void) VFS_SYNC(vfsp, 0, cr);
1595*8329232eSGordon Ross 
1596*8329232eSGordon Ross 	/*
1597*8329232eSGordon Ross 	 * Test-jig specific:
1598*8329232eSGordon Ross 	 * Need to release rootdir before unmount or VFS_UNMOUNT
1599*8329232eSGordon Ross 	 * may fail due to that node being active.
1600*8329232eSGordon Ross 	 */
1601*8329232eSGordon Ross 	if (rootdir != NULL) {
1602*8329232eSGordon Ross 		ASSERT(rootdir != coveredvp);
1603*8329232eSGordon Ross 		VN_RELE(rootdir);
1604*8329232eSGordon Ross 		rootdir = NULL;
1605*8329232eSGordon Ross 	}
1606*8329232eSGordon Ross 
1607*8329232eSGordon Ross 	/*
1608*8329232eSGordon Ross 	 * Lock the vfs to maintain fs status quo during unmount.  This
1609*8329232eSGordon Ross 	 * has to be done after the sync because ufs_update tries to acquire
1610*8329232eSGordon Ross 	 * the vfs_reflock.
1611*8329232eSGordon Ross 	 */
1612*8329232eSGordon Ross 	vfs_lock_wait(vfsp);
1613*8329232eSGordon Ross 
1614*8329232eSGordon Ross 	if ((error = VFS_UNMOUNT(vfsp, flag, cr)) != 0) {
1615*8329232eSGordon Ross 		int err2;
1616*8329232eSGordon Ross 		vfs_unlock(vfsp);
1617*8329232eSGordon Ross 		/* Get rootdir back */
1618*8329232eSGordon Ross 		err2 = VFS_ROOT(vfsp, &rootdir);
1619*8329232eSGordon Ross 		if (err2 != 0) {
1620*8329232eSGordon Ross 			panic("fake_dounmount, get root %d\n", err2);
1621*8329232eSGordon Ross 		}
1622*8329232eSGordon Ross 	} else {
1623*8329232eSGordon Ross 		/*
1624*8329232eSGordon Ross 		 * Real dounmount does vfs_remove.
1625*8329232eSGordon Ross 		 *
1626*8329232eSGordon Ross 		 * Test-jig specific:
1627*8329232eSGordon Ross 		 * Restore the covered rootdir,
1628*8329232eSGordon Ross 		 * release the rootvfs hold and clear.
1629*8329232eSGordon Ross 		 */
1630*8329232eSGordon Ross 		if (coveredvp != NULL) {
1631*8329232eSGordon Ross 			// vfs_list_remove(vfsp);
1632*8329232eSGordon Ross 			vfsp->vfs_vnodecovered = NULL;
1633*8329232eSGordon Ross 			rootdir = coveredvp;
1634*8329232eSGordon Ross 		}
1635*8329232eSGordon Ross 		if (rootvfs == vfsp) {
1636*8329232eSGordon Ross 			VFS_RELE(vfsp);
1637*8329232eSGordon Ross 			rootvfs = NULL;
1638*8329232eSGordon Ross 		}
1639*8329232eSGordon Ross 
1640*8329232eSGordon Ross 		/*
1641*8329232eSGordon Ross 		 * Release the (final) reference to vfs
1642*8329232eSGordon Ross 		 */
1643*8329232eSGordon Ross 		vfs_unlock(vfsp);
1644*8329232eSGordon Ross 		VFS_RELE(vfsp);
1645*8329232eSGordon Ross 	}
1646*8329232eSGordon Ross 	return (error);
1647*8329232eSGordon Ross }
1648*8329232eSGordon Ross 
1649*8329232eSGordon Ross // vfs_unmountall(void)
1650*8329232eSGordon Ross // vfs_addmip
1651*8329232eSGordon Ross // vfs_delmip
1652*8329232eSGordon Ross // vfs_add
1653*8329232eSGordon Ross // vfs_remove
1654*8329232eSGordon Ross 
1655*8329232eSGordon Ross static krwlock_t vpvfsentry_ve_lock;
1656*8329232eSGordon Ross 
1657*8329232eSGordon Ross /*
1658*8329232eSGordon Ross  * Lock a filesystem to prevent access to it while mounting,
1659*8329232eSGordon Ross  * unmounting and syncing.  Return EBUSY immediately if lock
1660*8329232eSGordon Ross  * can't be acquired.
1661*8329232eSGordon Ross  */
1662*8329232eSGordon Ross int
1663*8329232eSGordon Ross vfs_lock(vfs_t *vfsp)
1664*8329232eSGordon Ross {
1665*8329232eSGordon Ross 
1666*8329232eSGordon Ross 	if (rw_tryenter(&vpvfsentry_ve_lock, RW_WRITER))
1667*8329232eSGordon Ross 		return (0);
1668*8329232eSGordon Ross 
1669*8329232eSGordon Ross 	return (EBUSY);
1670*8329232eSGordon Ross }
1671*8329232eSGordon Ross 
1672*8329232eSGordon Ross int
1673*8329232eSGordon Ross vfs_rlock(vfs_t *vfsp)
1674*8329232eSGordon Ross {
1675*8329232eSGordon Ross 
1676*8329232eSGordon Ross 	if (rw_tryenter(&vpvfsentry_ve_lock, RW_READER))
1677*8329232eSGordon Ross 		return (0);
1678*8329232eSGordon Ross 
1679*8329232eSGordon Ross 	return (EBUSY);
1680*8329232eSGordon Ross }
1681*8329232eSGordon Ross 
1682*8329232eSGordon Ross void
1683*8329232eSGordon Ross vfs_lock_wait(vfs_t *vfsp)
1684*8329232eSGordon Ross {
1685*8329232eSGordon Ross 
1686*8329232eSGordon Ross 	rw_enter(&vpvfsentry_ve_lock, RW_WRITER);
1687*8329232eSGordon Ross }
1688*8329232eSGordon Ross 
1689*8329232eSGordon Ross void
1690*8329232eSGordon Ross vfs_rlock_wait(vfs_t *vfsp)
1691*8329232eSGordon Ross {
1692*8329232eSGordon Ross 	rw_enter(&vpvfsentry_ve_lock, RW_READER);
1693*8329232eSGordon Ross }
1694*8329232eSGordon Ross 
1695*8329232eSGordon Ross /*
1696*8329232eSGordon Ross  * Unlock a locked filesystem.
1697*8329232eSGordon Ross  */
1698*8329232eSGordon Ross void
1699*8329232eSGordon Ross vfs_unlock(vfs_t *vfsp)
1700*8329232eSGordon Ross {
1701*8329232eSGordon Ross 
1702*8329232eSGordon Ross 	rw_exit(&vpvfsentry_ve_lock);
1703*8329232eSGordon Ross }
1704*8329232eSGordon Ross 
1705*8329232eSGordon Ross /*
1706*8329232eSGordon Ross  * Utility routine that allows a filesystem to construct its
1707*8329232eSGordon Ross  * fsid in "the usual way" - by munging some underlying dev_t and
1708*8329232eSGordon Ross  * the filesystem type number into the 64-bit fsid. ...
1709*8329232eSGordon Ross  */
1710*8329232eSGordon Ross void
1711*8329232eSGordon Ross vfs_make_fsid(fsid_t *fsi, dev_t dev, int val)
1712*8329232eSGordon Ross {
1713*8329232eSGordon Ross 	if (!cmpldev((dev32_t *)&fsi->val[0], dev))
1714*8329232eSGordon Ross 		panic("device number too big for fsid!");
1715*8329232eSGordon Ross 	fsi->val[1] = val;
1716*8329232eSGordon Ross }
1717*8329232eSGordon Ross 
1718*8329232eSGordon Ross int
1719*8329232eSGordon Ross vfs_lock_held(vfs_t *vfsp)
1720*8329232eSGordon Ross {
1721*8329232eSGordon Ross 	int held;
1722*8329232eSGordon Ross 
1723*8329232eSGordon Ross 	held = rw_write_held(&vpvfsentry_ve_lock);
1724*8329232eSGordon Ross 
1725*8329232eSGordon Ross 	return (held);
1726*8329232eSGordon Ross }
1727*8329232eSGordon Ross 
1728*8329232eSGordon Ross // vfs_lock_owner
1729*8329232eSGordon Ross 
1730*8329232eSGordon Ross /*
1731*8329232eSGordon Ross  * vfs list locking.
1732*8329232eSGordon Ross  */
1733*8329232eSGordon Ross 
1734*8329232eSGordon Ross void
1735*8329232eSGordon Ross vfs_list_lock()
1736*8329232eSGordon Ross {
1737*8329232eSGordon Ross 	rw_enter(&vfslist, RW_WRITER);
1738*8329232eSGordon Ross }
1739*8329232eSGordon Ross 
1740*8329232eSGordon Ross void
1741*8329232eSGordon Ross vfs_list_read_lock()
1742*8329232eSGordon Ross {
1743*8329232eSGordon Ross 	rw_enter(&vfslist, RW_READER);
1744*8329232eSGordon Ross }
1745*8329232eSGordon Ross 
1746*8329232eSGordon Ross void
1747*8329232eSGordon Ross vfs_list_unlock()
1748*8329232eSGordon Ross {
1749*8329232eSGordon Ross 	rw_exit(&vfslist);
1750*8329232eSGordon Ross }
1751*8329232eSGordon Ross 
1752*8329232eSGordon Ross /*
1753*8329232eSGordon Ross  * Low level worker routines for adding entries to and removing entries from
1754*8329232eSGordon Ross  * the vfs list.
1755*8329232eSGordon Ross  */
1756*8329232eSGordon Ross 
1757*8329232eSGordon Ross // vfs_hash_add
1758*8329232eSGordon Ross // vfs_hash_remove
1759*8329232eSGordon Ross // vfs_list_add
1760*8329232eSGordon Ross // vfs_list_remove
1761*8329232eSGordon Ross // getvfs
1762*8329232eSGordon Ross // vfs_devmounting
1763*8329232eSGordon Ross 
1764*8329232eSGordon Ross /*
1765*8329232eSGordon Ross  * Search the vfs list for a specified device.  Returns 1, if entry is found
1766*8329232eSGordon Ross  * or 0 if no suitable entry is found.
1767*8329232eSGordon Ross  */
1768*8329232eSGordon Ross 
1769*8329232eSGordon Ross int
1770*8329232eSGordon Ross vfs_devismounted(dev_t dev)
1771*8329232eSGordon Ross {
1772*8329232eSGordon Ross 	return (0);
1773*8329232eSGordon Ross }
1774*8329232eSGordon Ross 
1775*8329232eSGordon Ross // vfs_dev2vfsp
1776*8329232eSGordon Ross // vfs_mntpoint2vfsp
1777*8329232eSGordon Ross 
1778*8329232eSGordon Ross /*
1779*8329232eSGordon Ross  * Search the vfs list for a specified vfsops.
1780*8329232eSGordon Ross  * if vfs entry is found then return 1, else 0.
1781*8329232eSGordon Ross  */
1782*8329232eSGordon Ross int
1783*8329232eSGordon Ross vfs_opsinuse(vfsops_t *ops)
1784*8329232eSGordon Ross {
1785*8329232eSGordon Ross 	return (0);
1786*8329232eSGordon Ross }
1787*8329232eSGordon Ross 
1788*8329232eSGordon Ross /*
1789*8329232eSGordon Ross  * Allocate an entry in vfssw for a file system type
1790*8329232eSGordon Ross  */
1791*8329232eSGordon Ross struct vfssw *
1792*8329232eSGordon Ross allocate_vfssw(const char *type)
1793*8329232eSGordon Ross {
1794*8329232eSGordon Ross 	struct vfssw *vswp;
1795*8329232eSGordon Ross 
1796*8329232eSGordon Ross 	if (type[0] == '\0' || strlen(type) + 1 > _ST_FSTYPSZ) {
1797*8329232eSGordon Ross 		/*
1798*8329232eSGordon Ross 		 * The vfssw table uses the empty string to identify an
1799*8329232eSGordon Ross 		 * available entry; we cannot add any type which has
1800*8329232eSGordon Ross 		 * a leading NUL. The string length is limited to
1801*8329232eSGordon Ross 		 * the size of the st_fstype array in struct stat.
1802*8329232eSGordon Ross 		 */
1803*8329232eSGordon Ross 		return (NULL);
1804*8329232eSGordon Ross 	}
1805*8329232eSGordon Ross 
1806*8329232eSGordon Ross 	ASSERT(VFSSW_WRITE_LOCKED());
1807*8329232eSGordon Ross 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++)
1808*8329232eSGordon Ross 		if (!ALLOCATED_VFSSW(vswp)) {
1809*8329232eSGordon Ross 			vswp->vsw_name = kmem_alloc(strlen(type) + 1, KM_SLEEP);
1810*8329232eSGordon Ross 			(void) strcpy(vswp->vsw_name, type);
1811*8329232eSGordon Ross 			ASSERT(vswp->vsw_count == 0);
1812*8329232eSGordon Ross 			vswp->vsw_count = 1;
1813*8329232eSGordon Ross 			mutex_init(&vswp->vsw_lock, NULL, MUTEX_DEFAULT, NULL);
1814*8329232eSGordon Ross 			return (vswp);
1815*8329232eSGordon Ross 		}
1816*8329232eSGordon Ross 	return (NULL);
1817*8329232eSGordon Ross }
1818*8329232eSGordon Ross 
1819*8329232eSGordon Ross // vfs_to_modname
1820*8329232eSGordon Ross // vfs_getvfssw
1821*8329232eSGordon Ross 
1822*8329232eSGordon Ross /*
1823*8329232eSGordon Ross  * Find a vfssw entry given a file system type name.
1824*8329232eSGordon Ross  */
1825*8329232eSGordon Ross struct vfssw *
1826*8329232eSGordon Ross vfs_getvfssw(const char *type)
1827*8329232eSGordon Ross {
1828*8329232eSGordon Ross 	struct vfssw *vswp;
1829*8329232eSGordon Ross 
1830*8329232eSGordon Ross 	if (type == NULL || *type == '\0')
1831*8329232eSGordon Ross 		return (NULL);
1832*8329232eSGordon Ross 
1833*8329232eSGordon Ross 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
1834*8329232eSGordon Ross 		if (strcmp(type, vswp->vsw_name) == 0) {
1835*8329232eSGordon Ross 			return (vswp);
1836*8329232eSGordon Ross 		}
1837*8329232eSGordon Ross 	}
1838*8329232eSGordon Ross 
1839*8329232eSGordon Ross 	return (NULL);
1840*8329232eSGordon Ross 
1841*8329232eSGordon Ross }
1842*8329232eSGordon Ross 
1843*8329232eSGordon Ross /*
1844*8329232eSGordon Ross  * Find a vfssw entry given a file system type name.
1845*8329232eSGordon Ross  */
1846*8329232eSGordon Ross struct vfssw *
1847*8329232eSGordon Ross vfs_getvfsswbyname(const char *type)
1848*8329232eSGordon Ross {
1849*8329232eSGordon Ross 	struct vfssw *vswp;
1850*8329232eSGordon Ross 
1851*8329232eSGordon Ross 	ASSERT(VFSSW_LOCKED());
1852*8329232eSGordon Ross 	if (type == NULL || *type == '\0')
1853*8329232eSGordon Ross 		return (NULL);
1854*8329232eSGordon Ross 
1855*8329232eSGordon Ross 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
1856*8329232eSGordon Ross 		if (strcmp(type, vswp->vsw_name) == 0) {
1857*8329232eSGordon Ross 			vfs_refvfssw(vswp);
1858*8329232eSGordon Ross 			return (vswp);
1859*8329232eSGordon Ross 		}
1860*8329232eSGordon Ross 	}
1861*8329232eSGordon Ross 
1862*8329232eSGordon Ross 	return (NULL);
1863*8329232eSGordon Ross }
1864*8329232eSGordon Ross 
1865*8329232eSGordon Ross // vfs_getvfsswbyvfsops
1866*8329232eSGordon Ross 
1867*8329232eSGordon Ross /*
1868*8329232eSGordon Ross  * Reference a vfssw entry.
1869*8329232eSGordon Ross  */
1870*8329232eSGordon Ross void
1871*8329232eSGordon Ross vfs_refvfssw(struct vfssw *vswp)
1872*8329232eSGordon Ross {
1873*8329232eSGordon Ross 
1874*8329232eSGordon Ross 	mutex_enter(&vswp->vsw_lock);
1875*8329232eSGordon Ross 	vswp->vsw_count++;
1876*8329232eSGordon Ross 	mutex_exit(&vswp->vsw_lock);
1877*8329232eSGordon Ross }
1878*8329232eSGordon Ross 
1879*8329232eSGordon Ross /*
1880*8329232eSGordon Ross  * Unreference a vfssw entry.
1881*8329232eSGordon Ross  */
1882*8329232eSGordon Ross void
1883*8329232eSGordon Ross vfs_unrefvfssw(struct vfssw *vswp)
1884*8329232eSGordon Ross {
1885*8329232eSGordon Ross 
1886*8329232eSGordon Ross 	mutex_enter(&vswp->vsw_lock);
1887*8329232eSGordon Ross 	vswp->vsw_count--;
1888*8329232eSGordon Ross 	mutex_exit(&vswp->vsw_lock);
1889*8329232eSGordon Ross }
1890*8329232eSGordon Ross 
1891*8329232eSGordon Ross // vfs_syncall
1892*8329232eSGordon Ross 
1893*8329232eSGordon Ross /*
1894*8329232eSGordon Ross  * Map VFS flags to statvfs flags.  These shouldn't really be separate
1895*8329232eSGordon Ross  * flags at all.
1896*8329232eSGordon Ross  */
1897*8329232eSGordon Ross uint_t
1898*8329232eSGordon Ross vf_to_stf(uint_t vf)
1899*8329232eSGordon Ross {
1900*8329232eSGordon Ross 	uint_t stf = 0;
1901*8329232eSGordon Ross 
1902*8329232eSGordon Ross 	if (vf & VFS_RDONLY)
1903*8329232eSGordon Ross 		stf |= ST_RDONLY;
1904*8329232eSGordon Ross 	if (vf & VFS_NOSETUID)
1905*8329232eSGordon Ross 		stf |= ST_NOSUID;
1906*8329232eSGordon Ross 	if (vf & VFS_NOTRUNC)
1907*8329232eSGordon Ross 		stf |= ST_NOTRUNC;
1908*8329232eSGordon Ross 
1909*8329232eSGordon Ross 	return (stf);
1910*8329232eSGordon Ross }
1911*8329232eSGordon Ross 
1912*8329232eSGordon Ross // vfsstray_sync
1913*8329232eSGordon Ross // vfsstray
1914*8329232eSGordon Ross // vfs_EIO
1915*8329232eSGordon Ross // vfs_EIO_sync
1916*8329232eSGordon Ross // EIO_vfs
1917*8329232eSGordon Ross // EIO_vfsops
1918*8329232eSGordon Ross 
1919*8329232eSGordon Ross #pragma init(vfsinit)
1920*8329232eSGordon Ross 
1921*8329232eSGordon Ross /*
1922*8329232eSGordon Ross  * Called from startup() to initialize all loaded vfs's
1923*8329232eSGordon Ross  */
1924*8329232eSGordon Ross void
1925*8329232eSGordon Ross vfsinit(void)
1926*8329232eSGordon Ross {
1927*8329232eSGordon Ross 	vn_create_cache();
1928*8329232eSGordon Ross 
1929*8329232eSGordon Ross 	/* Temporary, until we mount root */
1930*8329232eSGordon Ross 	rootdir = vn_alloc(KM_SLEEP);
1931*8329232eSGordon Ross 	rootdir->v_type = VDIR;
1932*8329232eSGordon Ross }
1933*8329232eSGordon Ross 
1934*8329232eSGordon Ross vfs_t *
1935*8329232eSGordon Ross vfs_alloc(int kmflag)
1936*8329232eSGordon Ross {
1937*8329232eSGordon Ross 	vfs_t *vfsp;
1938*8329232eSGordon Ross 
1939*8329232eSGordon Ross 	vfsp = kmem_alloc(sizeof (struct vfs), kmflag);
1940*8329232eSGordon Ross 
1941*8329232eSGordon Ross 	/*
1942*8329232eSGordon Ross 	 * Do the simplest initialization here.
1943*8329232eSGordon Ross 	 * Everything else gets done in vfs_init()
1944*8329232eSGordon Ross 	 */
1945*8329232eSGordon Ross 	bzero(vfsp, sizeof (vfs_t));
1946*8329232eSGordon Ross 	return (vfsp);
1947*8329232eSGordon Ross }
1948*8329232eSGordon Ross 
1949*8329232eSGordon Ross void
1950*8329232eSGordon Ross vfs_free(vfs_t *vfsp)
1951*8329232eSGordon Ross {
1952*8329232eSGordon Ross 	/*
1953*8329232eSGordon Ross 	 * One would be tempted to assert that "vfsp->vfs_count == 0".
1954*8329232eSGordon Ross 	 * Don't.  See fs/vfs.c
1955*8329232eSGordon Ross 	 */
1956*8329232eSGordon Ross 
1957*8329232eSGordon Ross 	/* If FEM was in use, make sure everything gets cleaned up */
1958*8329232eSGordon Ross 
1959*8329232eSGordon Ross 	if (vfsp->vfs_implp)
1960*8329232eSGordon Ross 		vfsimpl_teardown(vfsp);
1961*8329232eSGordon Ross 	sema_destroy(&vfsp->vfs_reflock);
1962*8329232eSGordon Ross 	kmem_free(vfsp, sizeof (struct vfs));
1963*8329232eSGordon Ross }
1964*8329232eSGordon Ross 
1965*8329232eSGordon Ross /*
1966*8329232eSGordon Ross  * Increments the vfs reference count by one atomically.
1967*8329232eSGordon Ross  */
1968*8329232eSGordon Ross void
1969*8329232eSGordon Ross vfs_hold(vfs_t *vfsp)
1970*8329232eSGordon Ross {
1971*8329232eSGordon Ross 	atomic_inc_32(&vfsp->vfs_count);
1972*8329232eSGordon Ross 	ASSERT(vfsp->vfs_count != 0);
1973*8329232eSGordon Ross }
1974*8329232eSGordon Ross 
1975*8329232eSGordon Ross /*
1976*8329232eSGordon Ross  * Decrements the vfs reference count by one atomically. When
1977*8329232eSGordon Ross  * vfs reference count becomes zero, it calls the file system
1978*8329232eSGordon Ross  * specific vfs_freevfs() to free up the resources.
1979*8329232eSGordon Ross  */
1980*8329232eSGordon Ross void
1981*8329232eSGordon Ross vfs_rele(vfs_t *vfsp)
1982*8329232eSGordon Ross {
1983*8329232eSGordon Ross 	ASSERT(vfsp->vfs_count != 0);
1984*8329232eSGordon Ross 	if (atomic_dec_32_nv(&vfsp->vfs_count) == 0) {
1985*8329232eSGordon Ross 		VFS_FREEVFS(vfsp);
1986*8329232eSGordon Ross 		// lofi_remove(vfsp);
1987*8329232eSGordon Ross 		// zone_rele_ref...
1988*8329232eSGordon Ross 		// vfs_freemnttab(vfsp);
1989*8329232eSGordon Ross 		vfs_free(vfsp);
1990*8329232eSGordon Ross 	}
1991*8329232eSGordon Ross }
1992*8329232eSGordon Ross 
1993*8329232eSGordon Ross /*
1994*8329232eSGordon Ross  * Generic operations vector support.
1995*8329232eSGordon Ross  */
1996*8329232eSGordon Ross 
1997*8329232eSGordon Ross int
1998*8329232eSGordon Ross fs_build_vector(void *vector, int *unused_ops,
1999*8329232eSGordon Ross     const fs_operation_trans_def_t *translation,
2000*8329232eSGordon Ross     const fs_operation_def_t *operations)
2001*8329232eSGordon Ross {
2002*8329232eSGordon Ross 	int i, num_trans, num_ops, used;
2003*8329232eSGordon Ross 
2004*8329232eSGordon Ross 	/*
2005*8329232eSGordon Ross 	 * Count the number of translations and the number of supplied
2006*8329232eSGordon Ross 	 * operations.
2007*8329232eSGordon Ross 	 */
2008*8329232eSGordon Ross 
2009*8329232eSGordon Ross 	{
2010*8329232eSGordon Ross 		const fs_operation_trans_def_t *p;
2011*8329232eSGordon Ross 
2012*8329232eSGordon Ross 		for (num_trans = 0, p = translation;
2013*8329232eSGordon Ross 		    p->name != NULL;
2014*8329232eSGordon Ross 		    num_trans++, p++)
2015*8329232eSGordon Ross 			;
2016*8329232eSGordon Ross 	}
2017*8329232eSGordon Ross 
2018*8329232eSGordon Ross 	{
2019*8329232eSGordon Ross 		const fs_operation_def_t *p;
2020*8329232eSGordon Ross 
2021*8329232eSGordon Ross 		for (num_ops = 0, p = operations;
2022*8329232eSGordon Ross 		    p->name != NULL;
2023*8329232eSGordon Ross 		    num_ops++, p++)
2024*8329232eSGordon Ross 			;
2025*8329232eSGordon Ross 	}
2026*8329232eSGordon Ross 
2027*8329232eSGordon Ross 	/* Walk through each operation known to our caller.  There will be */
2028*8329232eSGordon Ross 	/* one entry in the supplied "translation table" for each. */
2029*8329232eSGordon Ross 
2030*8329232eSGordon Ross 	used = 0;
2031*8329232eSGordon Ross 
2032*8329232eSGordon Ross 	for (i = 0; i < num_trans; i++) {
2033*8329232eSGordon Ross 		int j, found;
2034*8329232eSGordon Ross 		char *curname;
2035*8329232eSGordon Ross 		fs_generic_func_p result;
2036*8329232eSGordon Ross 		fs_generic_func_p *location;
2037*8329232eSGordon Ross 
2038*8329232eSGordon Ross 		curname = translation[i].name;
2039*8329232eSGordon Ross 
2040*8329232eSGordon Ross 		/* Look for a matching operation in the list supplied by the */
2041*8329232eSGordon Ross 		/* file system. */
2042*8329232eSGordon Ross 
2043*8329232eSGordon Ross 		found = 0;
2044*8329232eSGordon Ross 
2045*8329232eSGordon Ross 		for (j = 0; j < num_ops; j++) {
2046*8329232eSGordon Ross 			if (strcmp(operations[j].name, curname) == 0) {
2047*8329232eSGordon Ross 				used++;
2048*8329232eSGordon Ross 				found = 1;
2049*8329232eSGordon Ross 				break;
2050*8329232eSGordon Ross 			}
2051*8329232eSGordon Ross 		}
2052*8329232eSGordon Ross 
2053*8329232eSGordon Ross 		/*
2054*8329232eSGordon Ross 		 * If the file system is using a "placeholder" for default
2055*8329232eSGordon Ross 		 * or error functions, grab the appropriate function out of
2056*8329232eSGordon Ross 		 * the translation table.  If the file system didn't supply
2057*8329232eSGordon Ross 		 * this operation at all, use the default function.
2058*8329232eSGordon Ross 		 */
2059*8329232eSGordon Ross 
2060*8329232eSGordon Ross 		if (found) {
2061*8329232eSGordon Ross 			result = operations[j].func.fs_generic;
2062*8329232eSGordon Ross 			if (result == fs_default) {
2063*8329232eSGordon Ross 				result = translation[i].defaultFunc;
2064*8329232eSGordon Ross 			} else if (result == fs_error) {
2065*8329232eSGordon Ross 				result = translation[i].errorFunc;
2066*8329232eSGordon Ross 			} else if (result == NULL) {
2067*8329232eSGordon Ross 				/* Null values are PROHIBITED */
2068*8329232eSGordon Ross 				return (EINVAL);
2069*8329232eSGordon Ross 			}
2070*8329232eSGordon Ross 		} else {
2071*8329232eSGordon Ross 			result = translation[i].defaultFunc;
2072*8329232eSGordon Ross 		}
2073*8329232eSGordon Ross 
2074*8329232eSGordon Ross 		/* Now store the function into the operations vector. */
2075*8329232eSGordon Ross 
2076*8329232eSGordon Ross 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2077*8329232eSGordon Ross 		location = (fs_generic_func_p *)
2078*8329232eSGordon Ross 		    (((char *)vector) + translation[i].offset);
2079*8329232eSGordon Ross 
2080*8329232eSGordon Ross 		*location = result;
2081*8329232eSGordon Ross 	}
2082*8329232eSGordon Ross 
2083*8329232eSGordon Ross 	*unused_ops = num_ops - used;
2084*8329232eSGordon Ross 
2085*8329232eSGordon Ross 	return (0);
2086*8329232eSGordon Ross }
2087*8329232eSGordon Ross 
2088*8329232eSGordon Ross /* Placeholder functions, should never be called. */
2089*8329232eSGordon Ross 
2090*8329232eSGordon Ross int
2091*8329232eSGordon Ross fs_error(void)
2092*8329232eSGordon Ross {
2093*8329232eSGordon Ross 	cmn_err(CE_PANIC, "fs_error called");
2094*8329232eSGordon Ross 	return (0);
2095*8329232eSGordon Ross }
2096*8329232eSGordon Ross 
2097*8329232eSGordon Ross int
2098*8329232eSGordon Ross fs_default(void)
2099*8329232eSGordon Ross {
2100*8329232eSGordon Ross 	cmn_err(CE_PANIC, "fs_default called");
2101*8329232eSGordon Ross 	return (0);
2102*8329232eSGordon Ross }
2103*8329232eSGordon Ross 
2104*8329232eSGordon Ross // rootconf
2105*8329232eSGordon Ross // getfsname
2106*8329232eSGordon Ross // getrootfs
2107*8329232eSGordon Ross 
2108*8329232eSGordon Ross /*
2109*8329232eSGordon Ross  * VFS feature routines
2110*8329232eSGordon Ross  */
2111*8329232eSGordon Ross 
2112*8329232eSGordon Ross #define	VFTINDEX(feature)	(((feature) >> 32) & 0xFFFFFFFF)
2113*8329232eSGordon Ross #define	VFTBITS(feature)	((feature) & 0xFFFFFFFFLL)
2114*8329232eSGordon Ross 
2115*8329232eSGordon Ross /* Register a feature in the vfs */
2116*8329232eSGordon Ross void
2117*8329232eSGordon Ross vfs_set_feature(vfs_t *vfsp, vfs_feature_t feature)
2118*8329232eSGordon Ross {
2119*8329232eSGordon Ross 	/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
2120*8329232eSGordon Ross 	if (vfsp->vfs_implp == NULL)
2121*8329232eSGordon Ross 		return;
2122*8329232eSGordon Ross 
2123*8329232eSGordon Ross 	vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature);
2124*8329232eSGordon Ross }
2125*8329232eSGordon Ross 
2126*8329232eSGordon Ross void
2127*8329232eSGordon Ross vfs_clear_feature(vfs_t *vfsp, vfs_feature_t feature)
2128*8329232eSGordon Ross {
2129*8329232eSGordon Ross 	/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
2130*8329232eSGordon Ross 	if (vfsp->vfs_implp == NULL)
2131*8329232eSGordon Ross 		return;
2132*8329232eSGordon Ross 	vfsp->vfs_featureset[VFTINDEX(feature)] &= VFTBITS(~feature);
2133*8329232eSGordon Ross }
2134*8329232eSGordon Ross 
2135*8329232eSGordon Ross /*
2136*8329232eSGordon Ross  * Query a vfs for a feature.
2137*8329232eSGordon Ross  * Returns 1 if feature is present, 0 if not
2138*8329232eSGordon Ross  */
2139*8329232eSGordon Ross int
2140*8329232eSGordon Ross vfs_has_feature(vfs_t *vfsp, vfs_feature_t feature)
2141*8329232eSGordon Ross {
2142*8329232eSGordon Ross 	int	ret = 0;
2143*8329232eSGordon Ross 
2144*8329232eSGordon Ross 	/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
2145*8329232eSGordon Ross 	if (vfsp->vfs_implp == NULL)
2146*8329232eSGordon Ross 		return (ret);
2147*8329232eSGordon Ross 
2148*8329232eSGordon Ross 	if (vfsp->vfs_featureset[VFTINDEX(feature)] & VFTBITS(feature))
2149*8329232eSGordon Ross 		ret = 1;
2150*8329232eSGordon Ross 
2151*8329232eSGordon Ross 	return (ret);
2152*8329232eSGordon Ross }
2153*8329232eSGordon Ross 
2154*8329232eSGordon Ross // vfs_propagate_features
2155*8329232eSGordon Ross // vfs_get_lofi
2156