18329232eSGordon Ross /*
28329232eSGordon Ross  * CDDL HEADER START
38329232eSGordon Ross  *
48329232eSGordon Ross  * The contents of this file are subject to the terms of the
58329232eSGordon Ross  * Common Development and Distribution License (the "License").
68329232eSGordon Ross  * You may not use this file except in compliance with the License.
78329232eSGordon Ross  *
88329232eSGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98329232eSGordon Ross  * or http://www.opensolaris.org/os/licensing.
108329232eSGordon Ross  * See the License for the specific language governing permissions
118329232eSGordon Ross  * and limitations under the License.
128329232eSGordon Ross  *
138329232eSGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
148329232eSGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158329232eSGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
168329232eSGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
178329232eSGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
188329232eSGordon Ross  *
198329232eSGordon Ross  * CDDL HEADER END
208329232eSGordon Ross  */
218329232eSGordon Ross 
228329232eSGordon Ross /*
238329232eSGordon Ross  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
248329232eSGordon Ross  * Copyright 2016 Joyent, Inc.
258329232eSGordon Ross  * Copyright 2016 Toomas Soome <tsoome@me.com>
268329232eSGordon Ross  * Copyright (c) 2016 by Delphix. All rights reserved.
278329232eSGordon Ross  * Copyright 2017 RackTop Systems.
288329232eSGordon Ross  * Copyright 2018 Nexenta Systems, Inc.
298329232eSGordon Ross  */
308329232eSGordon Ross 
318329232eSGordon Ross /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
328329232eSGordon Ross /*	  All Rights Reserved	*/
338329232eSGordon Ross 
348329232eSGordon Ross /*
358329232eSGordon Ross  * University Copyright- Copyright (c) 1982, 1986, 1988
368329232eSGordon Ross  * The Regents of the University of California
378329232eSGordon Ross  * All Rights Reserved
388329232eSGordon Ross  *
398329232eSGordon Ross  * University Acknowledgment- Portions of this document are derived from
408329232eSGordon Ross  * software developed by the University of California, Berkeley, and its
418329232eSGordon Ross  * contributors.
428329232eSGordon Ross  */
438329232eSGordon Ross 
448329232eSGordon Ross /*
458329232eSGordon Ross  * This file contains those functions from fs/vfs.c that can be
468329232eSGordon Ross  * used with relatively little change.  Functions that differ
478329232eSGordon Ross  * significantly from that are in other files.
488329232eSGordon Ross  */
498329232eSGordon Ross 
508329232eSGordon Ross #include <sys/types.h>
518329232eSGordon Ross #include <sys/t_lock.h>
528329232eSGordon Ross #include <sys/param.h>
538329232eSGordon Ross #include <sys/errno.h>
548329232eSGordon Ross #include <sys/user.h>
558329232eSGordon Ross #include <sys/fstyp.h>
568329232eSGordon Ross #include <sys/kmem.h>
578329232eSGordon Ross #include <sys/systm.h>
588329232eSGordon Ross #include <sys/proc.h>
598329232eSGordon Ross #include <sys/mount.h>
608329232eSGordon Ross #include <sys/vfs.h>
618329232eSGordon Ross #include <sys/vfs_opreg.h>
628329232eSGordon Ross #include <sys/fem.h>
638329232eSGordon Ross #include <sys/mntent.h>
648329232eSGordon Ross #include <sys/stat.h>
658329232eSGordon Ross #include <sys/statvfs.h>
668329232eSGordon Ross #include <sys/statfs.h>
678329232eSGordon Ross #include <sys/cred.h>
688329232eSGordon Ross #include <sys/vnode.h>
698329232eSGordon Ross #include <sys/rwstlock.h>
708329232eSGordon Ross #include <sys/dnlc.h>
718329232eSGordon Ross #include <sys/file.h>
728329232eSGordon Ross #include <sys/time.h>
738329232eSGordon Ross #include <sys/atomic.h>
748329232eSGordon Ross #include <sys/cmn_err.h>
758329232eSGordon Ross #include <sys/buf.h>
768329232eSGordon Ross #include <sys/debug.h>
778329232eSGordon Ross #include <sys/vnode.h>
788329232eSGordon Ross #include <sys/ddi.h>
798329232eSGordon Ross #include <sys/pathname.h>
808329232eSGordon Ross #include <sys/poll.h>
818329232eSGordon Ross #include <sys/sunddi.h>
828329232eSGordon Ross #include <sys/sysmacros.h>
838329232eSGordon Ross #include <sys/zone.h>
848329232eSGordon Ross #include <sys/policy.h>
858329232eSGordon Ross #include <sys/attr.h>
868329232eSGordon Ross #include <fs/fs_subr.h>
878329232eSGordon Ross 
888329232eSGordon Ross #include <libfksmbfs.h>
898329232eSGordon Ross 
908329232eSGordon Ross static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
918329232eSGordon Ross static void vfs_setmntopt_nolock(mntopts_t *, const char *,
928329232eSGordon Ross     const char *, int, int);
938329232eSGordon Ross static int  vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
948329232eSGordon Ross // static void vfs_freemnttab(struct vfs *);
958329232eSGordon Ross static void vfs_freeopt(mntopt_t *);
968329232eSGordon Ross static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
978329232eSGordon Ross static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
988329232eSGordon Ross static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
998329232eSGordon Ross // static void vfs_createopttbl_extend(mntopts_t *, const char *,
1008329232eSGordon Ross //    const mntopts_t *);
1018329232eSGordon Ross // static char **vfs_copycancelopt_extend(char **const, int);
1028329232eSGordon Ross static void vfs_freecancelopt(char **);
1038329232eSGordon Ross 
1048329232eSGordon Ross /*
1058329232eSGordon Ross  * VFS global data.
1068329232eSGordon Ross  */
1078329232eSGordon Ross vnode_t *rootdir;		/* pointer to root inode vnode. */
1088329232eSGordon Ross struct vfs *rootvfs = NULL;	/* pointer to root vfs; head of VFS list. */
1098329232eSGordon Ross static krwlock_t vfslist;
1108329232eSGordon Ross struct vfs	*zone_vfslist;	/* list of FS's mounted in zone */
1118329232eSGordon Ross 
1128329232eSGordon Ross /* from os/vfs_conf.c */
1138329232eSGordon Ross const int nfstype = 5;
1148329232eSGordon Ross struct vfssw vfssw[10] = {
1158329232eSGordon Ross 	{ "BADVFS" },				/* 0:invalid */
1168329232eSGordon Ross 	{ "" },					/* reserved for loadable fs */
1178329232eSGordon Ross 	{ "" },
1188329232eSGordon Ross 	{ "" },
1198329232eSGordon Ross 	{ "" },
1208329232eSGordon Ross };
1218329232eSGordon Ross 
1228329232eSGordon Ross /*
1238329232eSGordon Ross  * Table for generic options recognized in the VFS layer and acted
1248329232eSGordon Ross  * on at this level before parsing file system specific options.
1258329232eSGordon Ross  * The nosuid option is stronger than any of the devices and setuid
1268329232eSGordon Ross  * options, so those are canceled when nosuid is seen.
1278329232eSGordon Ross  *
1288329232eSGordon Ross  * All options which are added here need to be added to the
1298329232eSGordon Ross  * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
1308329232eSGordon Ross  */
1318329232eSGordon Ross /*
1328329232eSGordon Ross  * VFS Mount options table
1338329232eSGordon Ross  */
1348329232eSGordon Ross static char *ro_cancel[] = { MNTOPT_RW, NULL };
1358329232eSGordon Ross static char *rw_cancel[] = { MNTOPT_RO, NULL };
1368329232eSGordon Ross static char *suid_cancel[] = { MNTOPT_NOSUID, NULL };
1378329232eSGordon Ross static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES,
1388329232eSGordon Ross     MNTOPT_NOSETUID, MNTOPT_SETUID, NULL };
1398329232eSGordon Ross static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL };
1408329232eSGordon Ross static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL };
1418329232eSGordon Ross static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL };
1428329232eSGordon Ross static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL };
1438329232eSGordon Ross static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL };
1448329232eSGordon Ross static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL };
1458329232eSGordon Ross static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL };
1468329232eSGordon Ross static char *noexec_cancel[] = { MNTOPT_EXEC, NULL };
1478329232eSGordon Ross 
1488329232eSGordon Ross static const mntopt_t mntopts[] = {
1498329232eSGordon Ross /*
1508329232eSGordon Ross  *	option name		cancel options		default arg	flags
1518329232eSGordon Ross  */
1528329232eSGordon Ross 	{ MNTOPT_REMOUNT,	NULL,			NULL,
1538329232eSGordon Ross 		MO_NODISPLAY, (void *)0 },
1548329232eSGordon Ross 	{ MNTOPT_RO,		ro_cancel,		NULL,		0,
1558329232eSGordon Ross 		(void *)0 },
1568329232eSGordon Ross 	{ MNTOPT_RW,		rw_cancel,		NULL,		0,
1578329232eSGordon Ross 		(void *)0 },
1588329232eSGordon Ross 	{ MNTOPT_SUID,		suid_cancel,		NULL,		0,
1598329232eSGordon Ross 		(void *)0 },
1608329232eSGordon Ross 	{ MNTOPT_NOSUID,	nosuid_cancel,		NULL,		0,
1618329232eSGordon Ross 		(void *)0 },
1628329232eSGordon Ross 	{ MNTOPT_DEVICES,	devices_cancel,		NULL,		0,
1638329232eSGordon Ross 		(void *)0 },
1648329232eSGordon Ross 	{ MNTOPT_NODEVICES,	nodevices_cancel,	NULL,		0,
1658329232eSGordon Ross 		(void *)0 },
1668329232eSGordon Ross 	{ MNTOPT_SETUID,	setuid_cancel,		NULL,		0,
1678329232eSGordon Ross 		(void *)0 },
1688329232eSGordon Ross 	{ MNTOPT_NOSETUID,	nosetuid_cancel,	NULL,		0,
1698329232eSGordon Ross 		(void *)0 },
1708329232eSGordon Ross 	{ MNTOPT_NBMAND,	nbmand_cancel,		NULL,		0,
1718329232eSGordon Ross 		(void *)0 },
1728329232eSGordon Ross 	{ MNTOPT_NONBMAND,	nonbmand_cancel,	NULL,		0,
1738329232eSGordon Ross 		(void *)0 },
1748329232eSGordon Ross 	{ MNTOPT_EXEC,		exec_cancel,		NULL,		0,
1758329232eSGordon Ross 		(void *)0 },
1768329232eSGordon Ross 	{ MNTOPT_NOEXEC,	noexec_cancel,		NULL,		0,
1778329232eSGordon Ross 		(void *)0 },
1788329232eSGordon Ross };
1798329232eSGordon Ross 
1808329232eSGordon Ross const mntopts_t vfs_mntopts = {
1818329232eSGordon Ross 	sizeof (mntopts) / sizeof (mntopt_t),
1828329232eSGordon Ross 	(mntopt_t *)&mntopts[0]
1838329232eSGordon Ross };
1848329232eSGordon Ross 
1858329232eSGordon Ross /*
1868329232eSGordon Ross  * File system operation dispatch functions.
1878329232eSGordon Ross  */
1888329232eSGordon Ross 
1898329232eSGordon Ross int
fsop_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)1908329232eSGordon Ross fsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
1918329232eSGordon Ross {
1928329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr);
1938329232eSGordon Ross }
1948329232eSGordon Ross 
1958329232eSGordon Ross int
fsop_unmount(vfs_t * vfsp,int flag,cred_t * cr)1968329232eSGordon Ross fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr)
1978329232eSGordon Ross {
1988329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr);
1998329232eSGordon Ross }
2008329232eSGordon Ross 
2018329232eSGordon Ross int
fsop_root(vfs_t * vfsp,vnode_t ** vpp)2028329232eSGordon Ross fsop_root(vfs_t *vfsp, vnode_t **vpp)
2038329232eSGordon Ross {
2048329232eSGordon Ross 	return ((*(vfsp)->vfs_op->vfs_root)(vfsp, vpp));
2058329232eSGordon Ross }
2068329232eSGordon Ross 
2078329232eSGordon Ross int
fsop_statfs(vfs_t * vfsp,statvfs64_t * sp)2088329232eSGordon Ross fsop_statfs(vfs_t *vfsp, statvfs64_t *sp)
2098329232eSGordon Ross {
2108329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp);
2118329232eSGordon Ross }
2128329232eSGordon Ross 
2138329232eSGordon Ross int
fsop_sync(vfs_t * vfsp,short flag,cred_t * cr)2148329232eSGordon Ross fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
2158329232eSGordon Ross {
2168329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr);
2178329232eSGordon Ross }
2188329232eSGordon Ross 
2198329232eSGordon Ross int
fsop_vget(vfs_t * vfsp,vnode_t ** vpp,fid_t * fidp)2208329232eSGordon Ross fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
2218329232eSGordon Ross {
2228329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
2238329232eSGordon Ross }
2248329232eSGordon Ross 
2258329232eSGordon Ross int
fsop_mountroot(vfs_t * vfsp,enum whymountroot reason)2268329232eSGordon Ross fsop_mountroot(vfs_t *vfsp, enum whymountroot reason)
2278329232eSGordon Ross {
2288329232eSGordon Ross 	return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason);
2298329232eSGordon Ross }
2308329232eSGordon Ross 
2318329232eSGordon Ross void
fsop_freefs(vfs_t * vfsp)2328329232eSGordon Ross fsop_freefs(vfs_t *vfsp)
2338329232eSGordon Ross {
2348329232eSGordon Ross 	(*(vfsp)->vfs_op->vfs_freevfs)(vfsp);
2358329232eSGordon Ross }
2368329232eSGordon Ross 
2378329232eSGordon Ross int
fsop_vnstate(vfs_t * vfsp,vnode_t * vp,vntrans_t nstate)2388329232eSGordon Ross fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
2398329232eSGordon Ross {
2408329232eSGordon Ross 	return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate));
2418329232eSGordon Ross }
2428329232eSGordon Ross 
2438329232eSGordon Ross int
fsop_sync_by_kind(int fstype,short flag,cred_t * cr)2448329232eSGordon Ross fsop_sync_by_kind(int fstype, short flag, cred_t *cr)
2458329232eSGordon Ross {
2468329232eSGordon Ross 	ASSERT((fstype >= 0) && (fstype < nfstype));
2478329232eSGordon Ross 
2488329232eSGordon Ross 	if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype]))
2498329232eSGordon Ross 		return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr);
2508329232eSGordon Ross 	else
2518329232eSGordon Ross 		return (ENOTSUP);
2528329232eSGordon Ross }
2538329232eSGordon Ross 
2548329232eSGordon Ross /*
2558329232eSGordon Ross  * File system initialization.  vfs_setfsops() must be called from a file
2568329232eSGordon Ross  * system's init routine.
2578329232eSGordon Ross  */
2588329232eSGordon Ross 
2598329232eSGordon Ross static int
fs_copyfsops(const fs_operation_def_t * template,vfsops_t * actual,int * unused_ops)2608329232eSGordon Ross fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual,
2618329232eSGordon Ross     int *unused_ops)
2628329232eSGordon Ross {
2638329232eSGordon Ross 	static const fs_operation_trans_def_t vfs_ops_table[] = {
2648329232eSGordon Ross 		VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount),
2658329232eSGordon Ross 			fs_nosys, fs_nosys,
2668329232eSGordon Ross 
2678329232eSGordon Ross 		VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount),
2688329232eSGordon Ross 			fs_nosys, fs_nosys,
2698329232eSGordon Ross 
2708329232eSGordon Ross 		VFSNAME_ROOT, offsetof(vfsops_t, vfs_root),
2718329232eSGordon Ross 			fs_nosys, fs_nosys,
2728329232eSGordon Ross 
2738329232eSGordon Ross 		VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs),
2748329232eSGordon Ross 			fs_nosys, fs_nosys,
2758329232eSGordon Ross 
2768329232eSGordon Ross 		VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync),
2778329232eSGordon Ross 			(fs_generic_func_p) fs_sync,
2788329232eSGordon Ross 			(fs_generic_func_p) fs_sync,	/* No errors allowed */
2798329232eSGordon Ross 
2808329232eSGordon Ross 		VFSNAME_VGET, offsetof(vfsops_t, vfs_vget),
2818329232eSGordon Ross 			fs_nosys, fs_nosys,
2828329232eSGordon Ross 
2838329232eSGordon Ross 		VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot),
2848329232eSGordon Ross 			fs_nosys, fs_nosys,
2858329232eSGordon Ross 
2868329232eSGordon Ross 		VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs),
287*8bbe90c1SToomas Soome 			(fs_generic_func_p)(uintptr_t)fs_freevfs,
288*8bbe90c1SToomas Soome 			(fs_generic_func_p)(uintptr_t)
289*8bbe90c1SToomas Soome 			fs_freevfs,	/* Shouldn't fail */
2908329232eSGordon Ross 
2918329232eSGordon Ross 		VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate),
2928329232eSGordon Ross 			(fs_generic_func_p)fs_nosys,
2938329232eSGordon Ross 			(fs_generic_func_p)fs_nosys,
2948329232eSGordon Ross 
2958329232eSGordon Ross 		NULL, 0, NULL, NULL
2968329232eSGordon Ross 	};
2978329232eSGordon Ross 
2988329232eSGordon Ross 	return (fs_build_vector(actual, unused_ops, vfs_ops_table, template));
2998329232eSGordon Ross }
3008329232eSGordon Ross 
3018329232eSGordon Ross /* zfs_boot_init() */
3028329232eSGordon Ross 
3038329232eSGordon Ross int
vfs_setfsops(int fstype,const fs_operation_def_t * template,vfsops_t ** actual)3048329232eSGordon Ross vfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual)
3058329232eSGordon Ross {
3068329232eSGordon Ross 	int error;
3078329232eSGordon Ross 	int unused_ops;
3088329232eSGordon Ross 
3098329232eSGordon Ross 	/*
3108329232eSGordon Ross 	 * Verify that fstype refers to a valid fs.  Note that
3118329232eSGordon Ross 	 * 0 is valid since it's used to set "stray" ops.
3128329232eSGordon Ross 	 */
3138329232eSGordon Ross 	if ((fstype < 0) || (fstype >= nfstype))
3148329232eSGordon Ross 		return (EINVAL);
3158329232eSGordon Ross 
3168329232eSGordon Ross 	if (!ALLOCATED_VFSSW(&vfssw[fstype]))
3178329232eSGordon Ross 		return (EINVAL);
3188329232eSGordon Ross 
3198329232eSGordon Ross 	/* Set up the operations vector. */
3208329232eSGordon Ross 
3218329232eSGordon Ross 	error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops);
3228329232eSGordon Ross 
3238329232eSGordon Ross 	if (error != 0)
3248329232eSGordon Ross 		return (error);
3258329232eSGordon Ross 
3268329232eSGordon Ross 	vfssw[fstype].vsw_flag |= VSW_INSTALLED;
3278329232eSGordon Ross 
3288329232eSGordon Ross 	if (actual != NULL)
3298329232eSGordon Ross 		*actual = &vfssw[fstype].vsw_vfsops;
3308329232eSGordon Ross 
3318329232eSGordon Ross #if DEBUG
3328329232eSGordon Ross 	if (unused_ops != 0)
3338329232eSGordon Ross 		cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied "
3348329232eSGordon Ross 		    "but not used", vfssw[fstype].vsw_name, unused_ops);
3358329232eSGordon Ross #endif
3368329232eSGordon Ross 
3378329232eSGordon Ross 	return (0);
3388329232eSGordon Ross }
3398329232eSGordon Ross 
3408329232eSGordon Ross int
vfs_makefsops(const fs_operation_def_t * template,vfsops_t ** actual)3418329232eSGordon Ross vfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual)
3428329232eSGordon Ross {
3438329232eSGordon Ross 	int error;
3448329232eSGordon Ross 	int unused_ops;
3458329232eSGordon Ross 
3468329232eSGordon Ross 	*actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP);
3478329232eSGordon Ross 
3488329232eSGordon Ross 	error = fs_copyfsops(template, *actual, &unused_ops);
3498329232eSGordon Ross 	if (error != 0) {
3508329232eSGordon Ross 		kmem_free(*actual, sizeof (vfsops_t));
3518329232eSGordon Ross 		*actual = NULL;
3528329232eSGordon Ross 		return (error);
3538329232eSGordon Ross 	}
3548329232eSGordon Ross 
3558329232eSGordon Ross 	return (0);
3568329232eSGordon Ross }
3578329232eSGordon Ross 
3588329232eSGordon Ross /*
3598329232eSGordon Ross  * Free a vfsops structure created as a result of vfs_makefsops().
3608329232eSGordon Ross  * NOTE: For a vfsops structure initialized by vfs_setfsops(), use
3618329232eSGordon Ross  * vfs_freevfsops_by_type().
3628329232eSGordon Ross  */
3638329232eSGordon Ross void
vfs_freevfsops(vfsops_t * vfsops)3648329232eSGordon Ross vfs_freevfsops(vfsops_t *vfsops)
3658329232eSGordon Ross {
3668329232eSGordon Ross 	kmem_free(vfsops, sizeof (vfsops_t));
3678329232eSGordon Ross }
3688329232eSGordon Ross 
3698329232eSGordon Ross /*
3708329232eSGordon Ross  * Since the vfsops structure is part of the vfssw table and wasn't
3718329232eSGordon Ross  * really allocated, we're not really freeing anything.  We keep
3728329232eSGordon Ross  * the name for consistency with vfs_freevfsops().  We do, however,
3738329232eSGordon Ross  * need to take care of a little bookkeeping.
3748329232eSGordon Ross  * NOTE: For a vfsops structure created by vfs_setfsops(), use
3758329232eSGordon Ross  * vfs_freevfsops_by_type().
3768329232eSGordon Ross  */
3778329232eSGordon Ross int
vfs_freevfsops_by_type(int fstype)3788329232eSGordon Ross vfs_freevfsops_by_type(int fstype)
3798329232eSGordon Ross {
3808329232eSGordon Ross 
3818329232eSGordon Ross 	/* Verify that fstype refers to a loaded fs (and not fsid 0). */
3828329232eSGordon Ross 	if ((fstype <= 0) || (fstype >= nfstype))
3838329232eSGordon Ross 		return (EINVAL);
3848329232eSGordon Ross 
3858329232eSGordon Ross 	WLOCK_VFSSW();
3868329232eSGordon Ross 	if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) {
3878329232eSGordon Ross 		WUNLOCK_VFSSW();
3888329232eSGordon Ross 		return (EINVAL);
3898329232eSGordon Ross 	}
3908329232eSGordon Ross 
3918329232eSGordon Ross 	vfssw[fstype].vsw_flag &= ~VSW_INSTALLED;
3928329232eSGordon Ross 	WUNLOCK_VFSSW();
3938329232eSGordon Ross 
3948329232eSGordon Ross 	return (0);
3958329232eSGordon Ross }
3968329232eSGordon Ross 
3978329232eSGordon Ross /* Support routines used to reference vfs_op */
3988329232eSGordon Ross 
3998329232eSGordon Ross /* Set the operations vector for a vfs */
4008329232eSGordon Ross void
vfs_setops(vfs_t * vfsp,vfsops_t * vfsops)4018329232eSGordon Ross vfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
4028329232eSGordon Ross {
4038329232eSGordon Ross 
4048329232eSGordon Ross 	ASSERT(vfsp != NULL);
4058329232eSGordon Ross 	ASSERT(vfsops != NULL);
4068329232eSGordon Ross 
4078329232eSGordon Ross 	vfsp->vfs_op = vfsops;
4088329232eSGordon Ross }
4098329232eSGordon Ross 
4108329232eSGordon Ross /* Retrieve the operations vector for a vfs */
4118329232eSGordon Ross vfsops_t *
vfs_getops(vfs_t * vfsp)4128329232eSGordon Ross vfs_getops(vfs_t *vfsp)
4138329232eSGordon Ross {
4148329232eSGordon Ross 
4158329232eSGordon Ross 	ASSERT(vfsp != NULL);
4168329232eSGordon Ross 
4178329232eSGordon Ross 	return (vfsp->vfs_op);
4188329232eSGordon Ross }
4198329232eSGordon Ross 
4208329232eSGordon Ross /*
4218329232eSGordon Ross  * Returns non-zero (1) if the vfsops matches that of the vfs.
4228329232eSGordon Ross  * Returns zero (0) if not.
4238329232eSGordon Ross  */
4248329232eSGordon Ross int
vfs_matchops(vfs_t * vfsp,vfsops_t * vfsops)4258329232eSGordon Ross vfs_matchops(vfs_t *vfsp, vfsops_t *vfsops)
4268329232eSGordon Ross {
4278329232eSGordon Ross 	return (vfs_getops(vfsp) == vfsops);
4288329232eSGordon Ross }
4298329232eSGordon Ross 
4308329232eSGordon Ross /*
4318329232eSGordon Ross  * Returns non-zero (1) if the file system has installed a non-default,
4328329232eSGordon Ross  * non-error vfs_sync routine.  Returns zero (0) otherwise.
4338329232eSGordon Ross  */
4348329232eSGordon Ross int
vfs_can_sync(vfs_t * vfsp)4358329232eSGordon Ross vfs_can_sync(vfs_t *vfsp)
4368329232eSGordon Ross {
4378329232eSGordon Ross 	/* vfs_sync() routine is not the default/error function */
4388329232eSGordon Ross 	return (vfs_getops(vfsp)->vfs_sync != fs_sync);
4398329232eSGordon Ross }
4408329232eSGordon Ross 
4418329232eSGordon Ross /*
4428329232eSGordon Ross  * Initialize a vfs structure.
4438329232eSGordon Ross  */
4448329232eSGordon Ross void
vfs_init(vfs_t * vfsp,vfsops_t * op,void * data)4458329232eSGordon Ross vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
4468329232eSGordon Ross {
4478329232eSGordon Ross 	/* Always do full init, like vfs_alloc() */
4488329232eSGordon Ross 	bzero(vfsp, sizeof (vfs_t));
4498329232eSGordon Ross 	vfsp->vfs_count = 0;
4508329232eSGordon Ross 	vfsp->vfs_next = vfsp;
4518329232eSGordon Ross 	vfsp->vfs_prev = vfsp;
4528329232eSGordon Ross 	vfsp->vfs_zone_next = vfsp;
4538329232eSGordon Ross 	vfsp->vfs_zone_prev = vfsp;
4548329232eSGordon Ross 	vfsp->vfs_lofi_id = 0;
4558329232eSGordon Ross 	sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
4568329232eSGordon Ross 	vfsimpl_setup(vfsp);
4578329232eSGordon Ross 	vfsp->vfs_data = (data);
4588329232eSGordon Ross 	vfs_setops((vfsp), (op));
4598329232eSGordon Ross }
4608329232eSGordon Ross 
4618329232eSGordon Ross /*
4628329232eSGordon Ross  * Allocate and initialize the vfs implementation private data
4638329232eSGordon Ross  * structure, vfs_impl_t.
4648329232eSGordon Ross  */
4658329232eSGordon Ross void
vfsimpl_setup(vfs_t * vfsp)4668329232eSGordon Ross vfsimpl_setup(vfs_t *vfsp)
4678329232eSGordon Ross {
4688329232eSGordon Ross 	int i;
4698329232eSGordon Ross 
4708329232eSGordon Ross 	if (vfsp->vfs_implp != NULL) {
4718329232eSGordon Ross 		return;
4728329232eSGordon Ross 	}
4738329232eSGordon Ross 
4748329232eSGordon Ross 	vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP);
4758329232eSGordon Ross 	/* Note that these are #define'd in vfs.h */
4768329232eSGordon Ross 	vfsp->vfs_vskap = NULL;
4778329232eSGordon Ross 	vfsp->vfs_fstypevsp = NULL;
4788329232eSGordon Ross 
4798329232eSGordon Ross 	/* Set size of counted array, then zero the array */
4808329232eSGordon Ross 	vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1;
4818329232eSGordon Ross 	for (i = 1; i <  VFS_FEATURE_MAXSZ; i++) {
4828329232eSGordon Ross 		vfsp->vfs_featureset[i] = 0;
4838329232eSGordon Ross 	}
4848329232eSGordon Ross }
4858329232eSGordon Ross 
4868329232eSGordon Ross /*
4878329232eSGordon Ross  * Release the vfs_impl_t structure, if it exists. Some unbundled
4888329232eSGordon Ross  * filesystems may not use the newer version of vfs and thus
4898329232eSGordon Ross  * would not contain this implementation private data structure.
4908329232eSGordon Ross  */
4918329232eSGordon Ross void
vfsimpl_teardown(vfs_t * vfsp)4928329232eSGordon Ross vfsimpl_teardown(vfs_t *vfsp)
4938329232eSGordon Ross {
4948329232eSGordon Ross 	vfs_impl_t	*vip = vfsp->vfs_implp;
4958329232eSGordon Ross 
4968329232eSGordon Ross 	if (vip == NULL)
4978329232eSGordon Ross 		return;
4988329232eSGordon Ross 
4998329232eSGordon Ross 	kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t));
5008329232eSGordon Ross 	vfsp->vfs_implp = NULL;
5018329232eSGordon Ross }
5028329232eSGordon Ross 
5038329232eSGordon Ross /*
5048329232eSGordon Ross  * VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs,
5058329232eSGordon Ross  * fstatvfs, and sysfs moved to common/syscall.
5068329232eSGordon Ross  */
5078329232eSGordon Ross 
5088329232eSGordon Ross // vfs_sync, sync
5098329232eSGordon Ross 
5108329232eSGordon Ross /*
5118329232eSGordon Ross  * External routines.
5128329232eSGordon Ross  */
5138329232eSGordon Ross 
5148329232eSGordon Ross krwlock_t vfssw_lock;	/* lock accesses to vfssw */
5158329232eSGordon Ross 
5168329232eSGordon Ross /*
5178329232eSGordon Ross  * Lock for accessing the vfs linked list.  Initialized in vfs_mountroot(),
5188329232eSGordon Ross  * but otherwise should be accessed only via vfs_list_lock() and
5198329232eSGordon Ross  * vfs_list_unlock().  Also used to protect the timestamp for mods to the list.
5208329232eSGordon Ross  */
5218329232eSGordon Ross static krwlock_t vfslist;
5228329232eSGordon Ross 
5238329232eSGordon Ross // vfs_mountdevices(void)
5248329232eSGordon Ross // vfs_mountdev1(void)
5258329232eSGordon Ross // vfs_mountfs()
5268329232eSGordon Ross // vfs_mountroot()
5278329232eSGordon Ross // lofi_add, lofi_remove
5288329232eSGordon Ross 
5298329232eSGordon Ross 
5308329232eSGordon Ross /*
5318329232eSGordon Ross  * Mount the FS for the test jig.  Based on domount()
5328329232eSGordon Ross  */
5338329232eSGordon Ross int
fake_domount(char * fsname,struct mounta * uap,struct vfs ** vfspp)5348329232eSGordon Ross fake_domount(char *fsname, struct mounta *uap, struct vfs **vfspp)
5358329232eSGordon Ross {
5368329232eSGordon Ross 	vnode_t		*vp;
5378329232eSGordon Ross 	struct cred	*credp;
5388329232eSGordon Ross 	struct vfssw	*vswp;
5398329232eSGordon Ross 	vfsops_t	*vfsops;
5408329232eSGordon Ross 	struct vfs	*vfsp = NULL;
5418329232eSGordon Ross 	mntopts_t	mnt_mntopts;
5428329232eSGordon Ross 	int		error = 0;
5438329232eSGordon Ross 	int		copyout_error = 0;
5448329232eSGordon Ross 	char		*opts = uap->optptr;
5458329232eSGordon Ross 	char		*inargs = opts;
5468329232eSGordon Ross 	int		optlen = uap->optlen;
5478329232eSGordon Ross 
5488329232eSGordon Ross 	credp = CRED();
5498329232eSGordon Ross 
5508329232eSGordon Ross 	/*
5518329232eSGordon Ross 	 * Test jig specific: mount on rootdir
5528329232eSGordon Ross 	 */
5538329232eSGordon Ross 	if (rootvfs != NULL)
5548329232eSGordon Ross 		return (EBUSY);
5558329232eSGordon Ross 	vp = rootdir;
5568329232eSGordon Ross 
5578329232eSGordon Ross 	/*
5588329232eSGordon Ross 	 * The v_flag value for the mount point vp is permanently set
5598329232eSGordon Ross 	 * to VVFSLOCK so that no one bypasses the vn_vfs*locks routine
5608329232eSGordon Ross 	 * for mount point locking.
5618329232eSGordon Ross 	 */
5628329232eSGordon Ross 	mutex_enter(&vp->v_lock);
5638329232eSGordon Ross 	vp->v_flag |= VVFSLOCK;
5648329232eSGordon Ross 	mutex_exit(&vp->v_lock);
5658329232eSGordon Ross 
5668329232eSGordon Ross 	mnt_mntopts.mo_count = 0;
5678329232eSGordon Ross 
5688329232eSGordon Ross 	/*
5698329232eSGordon Ross 	 * Find the ops vector to use to invoke the file system-specific mount
5708329232eSGordon Ross 	 * method.  If the fsname argument is non-NULL, use it directly.
5718329232eSGordon Ross 	 */
5728329232eSGordon Ross 	if ((vswp = vfs_getvfssw(fsname)) == NULL) {
5738329232eSGordon Ross 		return (EINVAL);
5748329232eSGordon Ross 	}
5758329232eSGordon Ross 	if (!VFS_INSTALLED(vswp))
5768329232eSGordon Ross 		return (EINVAL);
5778329232eSGordon Ross 
5788329232eSGordon Ross 	// secpolicy_fs_allowed_mount(fsname)
5798329232eSGordon Ross 
5808329232eSGordon Ross 	vfsops = &vswp->vsw_vfsops;
5818329232eSGordon Ross 
5828329232eSGordon Ross 	vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts);
5838329232eSGordon Ross 
5848329232eSGordon Ross 	/*
5858329232eSGordon Ross 	 * Fetch mount options and parse them for generic vfs options
5868329232eSGordon Ross 	 */
5878329232eSGordon Ross 	if (uap->flags & MS_OPTIONSTR) {
5888329232eSGordon Ross 		/*
5898329232eSGordon Ross 		 * Limit the buffer size
5908329232eSGordon Ross 		 */
5918329232eSGordon Ross 		if (optlen < 0 || optlen > MAX_MNTOPT_STR) {
5928329232eSGordon Ross 			error = EINVAL;
5938329232eSGordon Ross 			goto errout;
5948329232eSGordon Ross 		}
5958329232eSGordon Ross 		if ((uap->flags & MS_SYSSPACE) == 0) {
5968329232eSGordon Ross 			inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
5978329232eSGordon Ross 			inargs[0] = '\0';
5988329232eSGordon Ross 			if (optlen) {
5998329232eSGordon Ross 				error = copyinstr(opts, inargs, (size_t)optlen,
6008329232eSGordon Ross 				    NULL);
6018329232eSGordon Ross 				if (error) {
6028329232eSGordon Ross 					goto errout;
6038329232eSGordon Ross 				}
6048329232eSGordon Ross 			}
6058329232eSGordon Ross 		}
6068329232eSGordon Ross 		vfs_parsemntopts(&mnt_mntopts, inargs, 0);
6078329232eSGordon Ross 	}
6088329232eSGordon Ross 	/*
6098329232eSGordon Ross 	 * Flag bits override the options string.
6108329232eSGordon Ross 	 */
6118329232eSGordon Ross 	if (uap->flags & MS_REMOUNT)
6128329232eSGordon Ross 		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0);
6138329232eSGordon Ross 	if (uap->flags & MS_RDONLY)
6148329232eSGordon Ross 		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0);
6158329232eSGordon Ross 	if (uap->flags & MS_NOSUID)
6168329232eSGordon Ross 		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
6178329232eSGordon Ross 
6188329232eSGordon Ross 	/*
6198329232eSGordon Ross 	 * Check if this is a remount; must be set in the option string and
6208329232eSGordon Ross 	 * the file system must support a remount option.
6218329232eSGordon Ross 	 */
6228329232eSGordon Ross 	if (vfs_optionisset_nolock(&mnt_mntopts,
6238329232eSGordon Ross 	    MNTOPT_REMOUNT, NULL)) {
6248329232eSGordon Ross 		/* disallow here */
6258329232eSGordon Ross 		error = ENOTSUP;
6268329232eSGordon Ross 		goto errout;
6278329232eSGordon Ross 	}
6288329232eSGordon Ross 
6298329232eSGordon Ross 	/*
6308329232eSGordon Ross 	 * uap->flags and vfs_optionisset() should agree.
6318329232eSGordon Ross 	 */
6328329232eSGordon Ross 	if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) {
6338329232eSGordon Ross 		uap->flags |= MS_RDONLY;
6348329232eSGordon Ross 	}
6358329232eSGordon Ross 	if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) {
6368329232eSGordon Ross 		uap->flags |= MS_NOSUID;
6378329232eSGordon Ross 	}
6388329232eSGordon Ross 	// nbmand ...
6398329232eSGordon Ross 
6408329232eSGordon Ross 	/*
6418329232eSGordon Ross 	 * If we are splicing the fs into the namespace,
6428329232eSGordon Ross 	 * perform mount point checks...
6438329232eSGordon Ross 	 * (always splice=0 here)
6448329232eSGordon Ross 	 */
6458329232eSGordon Ross 
6468329232eSGordon Ross 	if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) {
6478329232eSGordon Ross 		uap->dataptr = NULL;
6488329232eSGordon Ross 		uap->datalen = 0;
6498329232eSGordon Ross 	}
6508329232eSGordon Ross 
6518329232eSGordon Ross 	/*
6528329232eSGordon Ross 	 * If this is a remount, ... (never here)
6538329232eSGordon Ross 	 */
6548329232eSGordon Ross 	vfsp = vfs_alloc(KM_SLEEP);
6558329232eSGordon Ross 	VFS_INIT(vfsp, vfsops, NULL);
6568329232eSGordon Ross 
6578329232eSGordon Ross 	VFS_HOLD(vfsp);
6588329232eSGordon Ross 
6598329232eSGordon Ross 	// lofi_add(fsname, vfsp, &mnt_mntopts, uap)
6608329232eSGordon Ross 
6618329232eSGordon Ross 	/*
6628329232eSGordon Ross 	 * PRIV_SYS_MOUNT doesn't mean you can become root.
6638329232eSGordon Ross 	 */
6648329232eSGordon Ross 	uap->flags |= MS_NOSUID;
6658329232eSGordon Ross 	vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
6668329232eSGordon Ross 
6678329232eSGordon Ross 	/*
6688329232eSGordon Ross 	 * The vfs_reflock...
6698329232eSGordon Ross 	 */
6708329232eSGordon Ross 
6718329232eSGordon Ross 	/*
6728329232eSGordon Ross 	 * Lock the vfs...
6738329232eSGordon Ross 	 */
6748329232eSGordon Ross 	if ((error = vfs_lock(vfsp)) != 0) {
6758329232eSGordon Ross 		vfs_free(vfsp);
6768329232eSGordon Ross 		vfsp = NULL;
6778329232eSGordon Ross 		goto errout;
6788329232eSGordon Ross 	}
6798329232eSGordon Ross 
6808329232eSGordon Ross 	/*
6818329232eSGordon Ross 	 * Add device to mount in progress table...
6828329232eSGordon Ross 	 */
6838329232eSGordon Ross 	/*
6848329232eSGordon Ross 	 * Invalidate cached entry for the mount point.
6858329232eSGordon Ross 	 */
6868329232eSGordon Ross 
6878329232eSGordon Ross 	/*
6888329232eSGordon Ross 	 * If have an option string but the filesystem doesn't supply a
6898329232eSGordon Ross 	 * prototype options table, create a table...
6908329232eSGordon Ross 	 */
6918329232eSGordon Ross 
6928329232eSGordon Ross 	/*
6938329232eSGordon Ross 	 * Serialize with zone state transitions...
6948329232eSGordon Ross 	 */
6958329232eSGordon Ross 
6968329232eSGordon Ross 	// mount_in_progress(zone);
6978329232eSGordon Ross 
6988329232eSGordon Ross 	/*
6998329232eSGordon Ross 	 * Instantiate (or reinstantiate) the file system...
7008329232eSGordon Ross 	 */
7018329232eSGordon Ross 	vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
7028329232eSGordon Ross 
7038329232eSGordon Ross 	vfs_setresource(vfsp, uap->spec, 0);
7048329232eSGordon Ross 	vfs_setmntpoint(vfsp, uap->dir, 0);
7058329232eSGordon Ross 
7068329232eSGordon Ross 	/*
7078329232eSGordon Ross 	 * going to mount on this vnode, so notify.
7088329232eSGordon Ross 	 */
7098329232eSGordon Ross 	// vnevent_mountedover(vp, NULL);
7108329232eSGordon Ross 	error = VFS_MOUNT(vfsp, vp, uap, credp);
7118329232eSGordon Ross 
7128329232eSGordon Ross 	if (uap->flags & MS_RDONLY)
7138329232eSGordon Ross 		vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
7148329232eSGordon Ross 	if (uap->flags & MS_NOSUID)
7158329232eSGordon Ross 		vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
7168329232eSGordon Ross 	if (uap->flags & MS_GLOBAL)
7178329232eSGordon Ross 		vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
7188329232eSGordon Ross 
7198329232eSGordon Ross 	if (error) {
7208329232eSGordon Ross 		// lofi_remove(vfsp);
7218329232eSGordon Ross 
7228329232eSGordon Ross 		// (remount == 0)
7238329232eSGordon Ross 		vfs_unlock(vfsp);
7248329232eSGordon Ross 		// vfs_freemnttab(vfsp);
7258329232eSGordon Ross 		vfs_free(vfsp);
7268329232eSGordon Ross 		vfsp = NULL;
7278329232eSGordon Ross 	} else {
7288329232eSGordon Ross 		/*
7298329232eSGordon Ross 		 * Set the mount time to now
7308329232eSGordon Ross 		 */
7318329232eSGordon Ross 		// vfsp->vfs_mtime = ddi_get_time();
7328329232eSGordon Ross 		// if (remount) ...
7338329232eSGordon Ross 		// else if (splice) vfs_add(vp, vfsp, flags)
7348329232eSGordon Ross 		// else VFS_HOLD(vfsp);
7358329232eSGordon Ross 
7368329232eSGordon Ross 		/*
7378329232eSGordon Ross 		 * Test jig specific:
7388329232eSGordon Ross 		 * Do sort of like vfs_add for vp=rootdir
7398329232eSGordon Ross 		 * Already have hold on vp.
7408329232eSGordon Ross 		 */
7418329232eSGordon Ross 		vfsp->vfs_vnodecovered = vp;
7428329232eSGordon Ross 		vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
7438329232eSGordon Ross 		VFS_HOLD(vfsp);
7448329232eSGordon Ross 		rootvfs = vfsp;
7458329232eSGordon Ross 
7468329232eSGordon Ross 		/*
7478329232eSGordon Ross 		 * Set flags for global options encountered
7488329232eSGordon Ross 		 */
7498329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_RO, NULL))
7508329232eSGordon Ross 			vfsp->vfs_flag |= VFS_RDONLY;
7518329232eSGordon Ross 		else
7528329232eSGordon Ross 			vfsp->vfs_flag &= ~VFS_RDONLY;
7538329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) {
7548329232eSGordon Ross 			vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
7558329232eSGordon Ross 		} else {
7568329232eSGordon Ross 			if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL))
7578329232eSGordon Ross 				vfsp->vfs_flag |= VFS_NODEVICES;
7588329232eSGordon Ross 			else
7598329232eSGordon Ross 				vfsp->vfs_flag &= ~VFS_NODEVICES;
7608329232eSGordon Ross 			if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))
7618329232eSGordon Ross 				vfsp->vfs_flag |= VFS_NOSETUID;
7628329232eSGordon Ross 			else
7638329232eSGordon Ross 				vfsp->vfs_flag &= ~VFS_NOSETUID;
7648329232eSGordon Ross 		}
7658329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL))
7668329232eSGordon Ross 			vfsp->vfs_flag |= VFS_NBMAND;
7678329232eSGordon Ross 		else
7688329232eSGordon Ross 			vfsp->vfs_flag &= ~VFS_NBMAND;
7698329232eSGordon Ross 
7708329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL))
7718329232eSGordon Ross 			vfsp->vfs_flag |= VFS_XATTR;
7728329232eSGordon Ross 		else
7738329232eSGordon Ross 			vfsp->vfs_flag &= ~VFS_XATTR;
7748329232eSGordon Ross 
7758329232eSGordon Ross 		if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL))
7768329232eSGordon Ross 			vfsp->vfs_flag |= VFS_NOEXEC;
7778329232eSGordon Ross 		else
7788329232eSGordon Ross 			vfsp->vfs_flag &= ~VFS_NOEXEC;
7798329232eSGordon Ross 
7808329232eSGordon Ross 		/*
7818329232eSGordon Ross 		 * Now construct the output option string of options
7828329232eSGordon Ross 		 * we recognized.
7838329232eSGordon Ross 		 */
7848329232eSGordon Ross 		if (uap->flags & MS_OPTIONSTR) {
7858329232eSGordon Ross 			vfs_list_read_lock();
7868329232eSGordon Ross 			copyout_error = vfs_buildoptionstr(
7878329232eSGordon Ross 			    &vfsp->vfs_mntopts, inargs, optlen);
7888329232eSGordon Ross 			vfs_list_unlock();
7898329232eSGordon Ross 			if (copyout_error == 0 &&
7908329232eSGordon Ross 			    (uap->flags & MS_SYSSPACE) == 0) {
7918329232eSGordon Ross 				copyout_error = copyout(inargs, opts, optlen);
7928329232eSGordon Ross 			}
7938329232eSGordon Ross 		}
7948329232eSGordon Ross 
7958329232eSGordon Ross 		/*
7968329232eSGordon Ross 		 * If this isn't a remount, set up the vopstats...
7978329232eSGordon Ross 		 */
7988329232eSGordon Ross 		if (vswp->vsw_flag & VSW_XID)
7998329232eSGordon Ross 			vfsp->vfs_flag |= VFS_XID;
8008329232eSGordon Ross 
8018329232eSGordon Ross 		vfs_unlock(vfsp);
8028329232eSGordon Ross 
8038329232eSGordon Ross 		/*
8048329232eSGordon Ross 		 * Test jig specicific:
8058329232eSGordon Ross 		 * Replace rootdir with the mounted root.
8068329232eSGordon Ross 		 */
8078329232eSGordon Ross 		error = VFS_ROOT(vfsp, &rootdir);
8088329232eSGordon Ross 		if (error != 0) {
8098329232eSGordon Ross 			panic("fake_domount, get root %d\n", error);
8108329232eSGordon Ross 		}
8118329232eSGordon Ross 	}
8128329232eSGordon Ross 	// mount_completed(zone);
8138329232eSGordon Ross 	// zone_rele(zone);
8148329232eSGordon Ross 
8158329232eSGordon Ross 	// if (splice)
8168329232eSGordon Ross 	//	vn_vfsunlock(vp);
8178329232eSGordon Ross 
8188329232eSGordon Ross 	if ((error == 0) && (copyout_error == 0)) {
8198329232eSGordon Ross 		/* get_vskstat_anchor() */
8208329232eSGordon Ross 		/* Return vfsp to caller. */
8218329232eSGordon Ross 		*vfspp = vfsp;
8228329232eSGordon Ross 	}
8238329232eSGordon Ross errout:
8248329232eSGordon Ross 	vfs_freeopttbl(&mnt_mntopts);
8258329232eSGordon Ross 	/* resource, mountpt not allocated */
8268329232eSGordon Ross 	/* no addmip, delmip */
8278329232eSGordon Ross 	ASSERT(vswp != NULL);
8288329232eSGordon Ross 	vfs_unrefvfssw(vswp);
8298329232eSGordon Ross 	if (inargs != opts)
8308329232eSGordon Ross 		kmem_free(inargs, MAX_MNTOPT_STR);
8318329232eSGordon Ross 	if (copyout_error) {
8328329232eSGordon Ross 		if (vfsp != NULL) {
8338329232eSGordon Ross 			// lofi_remove(vfsp);
8348329232eSGordon Ross 			VFS_RELE(vfsp);
8358329232eSGordon Ross 		}
8368329232eSGordon Ross 		error = copyout_error;
8378329232eSGordon Ross 	}
8388329232eSGordon Ross 	return (error);
8398329232eSGordon Ross }
8408329232eSGordon Ross 
8418329232eSGordon Ross 
8428329232eSGordon Ross static void
vfs_setpath(struct vfs * vfsp,refstr_t ** refp,const char * newpath,uint32_t flag)8438329232eSGordon Ross vfs_setpath(
8448329232eSGordon Ross     struct vfs *vfsp,		/* vfs being updated */
8458329232eSGordon Ross     refstr_t **refp,		/* Ref-count string to contain the new path */
8468329232eSGordon Ross     const char *newpath,	/* Path to add to refp (above) */
8478329232eSGordon Ross     uint32_t flag)		/* flag */
8488329232eSGordon Ross {
8498329232eSGordon Ross 	// size_t len;
8508329232eSGordon Ross 	refstr_t *ref;
8518329232eSGordon Ross 	// char *sp;
8528329232eSGordon Ross 	int have_list_lock = 0;
8538329232eSGordon Ross 
8548329232eSGordon Ross 	ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp));
8558329232eSGordon Ross 
8568329232eSGordon Ross 	/*
8578329232eSGordon Ross 	 * New path must be less than MAXPATHLEN because mntfs
8588329232eSGordon Ross 	 * will only display up to MAXPATHLEN bytes. This is currently
8598329232eSGordon Ross 	 * safe, because domount() uses pn_get(), and other callers
8608329232eSGordon Ross 	 * similarly cap the size to fewer than MAXPATHLEN bytes.
8618329232eSGordon Ross 	 */
8628329232eSGordon Ross 
8638329232eSGordon Ross 	ASSERT(strlen(newpath) < MAXPATHLEN);
8648329232eSGordon Ross 
8658329232eSGordon Ross 	/* mntfs requires consistency while vfs list lock is held */
8668329232eSGordon Ross 
8678329232eSGordon Ross 	if (VFS_ON_LIST(vfsp)) {
8688329232eSGordon Ross 		have_list_lock = 1;
8698329232eSGordon Ross 		vfs_list_lock();
8708329232eSGordon Ross 	}
8718329232eSGordon Ross 
8728329232eSGordon Ross 	if (*refp != NULL)
8738329232eSGordon Ross 		refstr_rele(*refp);
8748329232eSGordon Ross 
8758329232eSGordon Ross 	/*
8768329232eSGordon Ross 	 * If we are in a non-global zone... (do something else)
8778329232eSGordon Ross 	 */
8788329232eSGordon Ross 	ref = refstr_alloc(newpath);
8798329232eSGordon Ross 	*refp = ref;
8808329232eSGordon Ross 
8818329232eSGordon Ross 	if (have_list_lock) {
8828329232eSGordon Ross 		vfs_mnttab_modtimeupd();
8838329232eSGordon Ross 		vfs_list_unlock();
8848329232eSGordon Ross 	}
8858329232eSGordon Ross }
8868329232eSGordon Ross 
8878329232eSGordon Ross /*
8888329232eSGordon Ross  * Record a mounted resource name in a vfs structure.
8898329232eSGordon Ross  * If vfsp is already mounted, caller must hold the vfs lock.
8908329232eSGordon Ross  */
8918329232eSGordon Ross void
vfs_setresource(struct vfs * vfsp,const char * resource,uint32_t flag)8928329232eSGordon Ross vfs_setresource(struct vfs *vfsp, const char *resource, uint32_t flag)
8938329232eSGordon Ross {
8948329232eSGordon Ross 	if (resource == NULL || resource[0] == '\0')
8958329232eSGordon Ross 		resource = VFS_NORESOURCE;
8968329232eSGordon Ross 	vfs_setpath(vfsp, &vfsp->vfs_resource, resource, flag);
8978329232eSGordon Ross }
8988329232eSGordon Ross 
8998329232eSGordon Ross /*
9008329232eSGordon Ross  * Record a mount point name in a vfs structure.
9018329232eSGordon Ross  * If vfsp is already mounted, caller must hold the vfs lock.
9028329232eSGordon Ross  */
9038329232eSGordon Ross void
vfs_setmntpoint(struct vfs * vfsp,const char * mntpt,uint32_t flag)9048329232eSGordon Ross vfs_setmntpoint(struct vfs *vfsp, const char *mntpt, uint32_t flag)
9058329232eSGordon Ross {
9068329232eSGordon Ross 	if (mntpt == NULL || mntpt[0] == '\0')
9078329232eSGordon Ross 		mntpt = VFS_NOMNTPT;
9088329232eSGordon Ross 	vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt, flag);
9098329232eSGordon Ross }
9108329232eSGordon Ross 
9118329232eSGordon Ross /* Returns the vfs_resource. Caller must call refstr_rele() when finished. */
9128329232eSGordon Ross 
9138329232eSGordon Ross refstr_t *
vfs_getresource(const struct vfs * vfsp)9148329232eSGordon Ross vfs_getresource(const struct vfs *vfsp)
9158329232eSGordon Ross {
9168329232eSGordon Ross 	refstr_t *resource;
9178329232eSGordon Ross 
9188329232eSGordon Ross 	vfs_list_read_lock();
9198329232eSGordon Ross 	resource = vfsp->vfs_resource;
9208329232eSGordon Ross 	refstr_hold(resource);
9218329232eSGordon Ross 	vfs_list_unlock();
9228329232eSGordon Ross 
9238329232eSGordon Ross 	return (resource);
9248329232eSGordon Ross }
9258329232eSGordon Ross 
9268329232eSGordon Ross /* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */
9278329232eSGordon Ross 
9288329232eSGordon Ross refstr_t *
vfs_getmntpoint(const struct vfs * vfsp)9298329232eSGordon Ross vfs_getmntpoint(const struct vfs *vfsp)
9308329232eSGordon Ross {
9318329232eSGordon Ross 	refstr_t *mntpt;
9328329232eSGordon Ross 
9338329232eSGordon Ross 	vfs_list_read_lock();
9348329232eSGordon Ross 	mntpt = vfsp->vfs_mntpt;
9358329232eSGordon Ross 	refstr_hold(mntpt);
9368329232eSGordon Ross 	vfs_list_unlock();
9378329232eSGordon Ross 
9388329232eSGordon Ross 	return (mntpt);
9398329232eSGordon Ross }
9408329232eSGordon Ross 
9418329232eSGordon Ross // vfs_createopttbl_extend
9428329232eSGordon Ross // vfs_createopttbl
9438329232eSGordon Ross 
9448329232eSGordon Ross /*
9458329232eSGordon Ross  * Swap two mount options tables
9468329232eSGordon Ross  */
9478329232eSGordon Ross static void
vfs_swapopttbl_nolock(mntopts_t * optbl1,mntopts_t * optbl2)9488329232eSGordon Ross vfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2)
9498329232eSGordon Ross {
9508329232eSGordon Ross 	uint_t tmpcnt;
9518329232eSGordon Ross 	mntopt_t *tmplist;
9528329232eSGordon Ross 
9538329232eSGordon Ross 	tmpcnt = optbl2->mo_count;
9548329232eSGordon Ross 	tmplist = optbl2->mo_list;
9558329232eSGordon Ross 	optbl2->mo_count = optbl1->mo_count;
9568329232eSGordon Ross 	optbl2->mo_list = optbl1->mo_list;
9578329232eSGordon Ross 	optbl1->mo_count = tmpcnt;
9588329232eSGordon Ross 	optbl1->mo_list = tmplist;
9598329232eSGordon Ross }
9608329232eSGordon Ross 
9618329232eSGordon Ross static void
vfs_swapopttbl(mntopts_t * optbl1,mntopts_t * optbl2)9628329232eSGordon Ross vfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2)
9638329232eSGordon Ross {
9648329232eSGordon Ross 	vfs_list_lock();
9658329232eSGordon Ross 	vfs_swapopttbl_nolock(optbl1, optbl2);
9668329232eSGordon Ross 	vfs_mnttab_modtimeupd();
9678329232eSGordon Ross 	vfs_list_unlock();
9688329232eSGordon Ross }
9698329232eSGordon Ross 
9708329232eSGordon Ross static char **
vfs_copycancelopt_extend(char ** const moc,int extend)9718329232eSGordon Ross vfs_copycancelopt_extend(char **const moc, int extend)
9728329232eSGordon Ross {
9738329232eSGordon Ross 	int i = 0;
9748329232eSGordon Ross 	int j;
9758329232eSGordon Ross 	char **result;
9768329232eSGordon Ross 
9778329232eSGordon Ross 	if (moc != NULL) {
9788329232eSGordon Ross 		for (; moc[i] != NULL; i++)
9798329232eSGordon Ross 			/* count number of options to cancel */;
9808329232eSGordon Ross 	}
9818329232eSGordon Ross 
9828329232eSGordon Ross 	if (i + extend == 0)
9838329232eSGordon Ross 		return (NULL);
9848329232eSGordon Ross 
9858329232eSGordon Ross 	result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP);
9868329232eSGordon Ross 
9878329232eSGordon Ross 	for (j = 0; j < i; j++) {
9888329232eSGordon Ross 		result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP);
9898329232eSGordon Ross 		(void) strcpy(result[j], moc[j]);
9908329232eSGordon Ross 	}
9918329232eSGordon Ross 	for (; j <= i + extend; j++)
9928329232eSGordon Ross 		result[j] = NULL;
9938329232eSGordon Ross 
9948329232eSGordon Ross 	return (result);
9958329232eSGordon Ross }
9968329232eSGordon Ross 
9978329232eSGordon Ross static void
vfs_copyopt(const mntopt_t * s,mntopt_t * d)9988329232eSGordon Ross vfs_copyopt(const mntopt_t *s, mntopt_t *d)
9998329232eSGordon Ross {
10008329232eSGordon Ross 	char *sp, *dp;
10018329232eSGordon Ross 
10028329232eSGordon Ross 	d->mo_flags = s->mo_flags;
10038329232eSGordon Ross 	d->mo_data = s->mo_data;
10048329232eSGordon Ross 	sp = s->mo_name;
10058329232eSGordon Ross 	if (sp != NULL) {
10068329232eSGordon Ross 		dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
10078329232eSGordon Ross 		(void) strcpy(dp, sp);
10088329232eSGordon Ross 		d->mo_name = dp;
10098329232eSGordon Ross 	} else {
10108329232eSGordon Ross 		d->mo_name = NULL; /* should never happen */
10118329232eSGordon Ross 	}
10128329232eSGordon Ross 
10138329232eSGordon Ross 	d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0);
10148329232eSGordon Ross 
10158329232eSGordon Ross 	sp = s->mo_arg;
10168329232eSGordon Ross 	if (sp != NULL) {
10178329232eSGordon Ross 		dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
10188329232eSGordon Ross 		(void) strcpy(dp, sp);
10198329232eSGordon Ross 		d->mo_arg = dp;
10208329232eSGordon Ross 	} else {
10218329232eSGordon Ross 		d->mo_arg = NULL;
10228329232eSGordon Ross 	}
10238329232eSGordon Ross }
10248329232eSGordon Ross 
10258329232eSGordon Ross // vfs_copyopttbl_extend
10268329232eSGordon Ross // vfs_copyopttbl
10278329232eSGordon Ross 
10288329232eSGordon Ross /*
10298329232eSGordon Ross  * Copy a mount options table, possibly allocating some spare
10308329232eSGordon Ross  * slots at the end.  It is permissible to copy_extend the NULL table.
10318329232eSGordon Ross  */
10328329232eSGordon Ross static void
vfs_copyopttbl_extend(const mntopts_t * smo,mntopts_t * dmo,int extra)10338329232eSGordon Ross vfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra)
10348329232eSGordon Ross {
10358329232eSGordon Ross 	uint_t i, count;
10368329232eSGordon Ross 	mntopt_t *motbl;
10378329232eSGordon Ross 
10388329232eSGordon Ross 	/*
10398329232eSGordon Ross 	 * Clear out any existing stuff in the options table being initialized
10408329232eSGordon Ross 	 */
10418329232eSGordon Ross 	vfs_freeopttbl(dmo);
10428329232eSGordon Ross 	count = (smo == NULL) ? 0 : smo->mo_count;
10438329232eSGordon Ross 	if ((count + extra) == 0)	/* nothing to do */
10448329232eSGordon Ross 		return;
10458329232eSGordon Ross 	dmo->mo_count = count + extra;
10468329232eSGordon Ross 	motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP);
10478329232eSGordon Ross 	dmo->mo_list = motbl;
10488329232eSGordon Ross 	for (i = 0; i < count; i++) {
10498329232eSGordon Ross 		vfs_copyopt(&smo->mo_list[i], &motbl[i]);
10508329232eSGordon Ross 	}
10518329232eSGordon Ross 	for (i = count; i < count + extra; i++) {
10528329232eSGordon Ross 		motbl[i].mo_flags = MO_EMPTY;
10538329232eSGordon Ross 	}
10548329232eSGordon Ross }
10558329232eSGordon Ross 
10568329232eSGordon Ross /*
10578329232eSGordon Ross  * Copy a mount options table.
10588329232eSGordon Ross  *
10598329232eSGordon Ross  * This function is *not* for general use by filesystems.
10608329232eSGordon Ross  *
10618329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
10628329232eSGordon Ross  *       to protect smo and dmo.
10638329232eSGordon Ross  */
10648329232eSGordon Ross void
vfs_copyopttbl(const mntopts_t * smo,mntopts_t * dmo)10658329232eSGordon Ross vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo)
10668329232eSGordon Ross {
10678329232eSGordon Ross 	vfs_copyopttbl_extend(smo, dmo, 0);
10688329232eSGordon Ross }
10698329232eSGordon Ross 
10708329232eSGordon Ross static char **
vfs_mergecancelopts(const mntopt_t * mop1,const mntopt_t * mop2)10718329232eSGordon Ross vfs_mergecancelopts(const mntopt_t *mop1, const mntopt_t *mop2)
10728329232eSGordon Ross {
10738329232eSGordon Ross 	int c1 = 0;
10748329232eSGordon Ross 	int c2 = 0;
10758329232eSGordon Ross 	char **result;
10768329232eSGordon Ross 	char **sp1, **sp2, **dp;
10778329232eSGordon Ross 
10788329232eSGordon Ross 	/*
10798329232eSGordon Ross 	 * First we count both lists of cancel options.
10808329232eSGordon Ross 	 * If either is NULL or has no elements, we return a copy of
10818329232eSGordon Ross 	 * the other.
10828329232eSGordon Ross 	 */
10838329232eSGordon Ross 	if (mop1->mo_cancel != NULL) {
10848329232eSGordon Ross 		for (; mop1->mo_cancel[c1] != NULL; c1++)
10858329232eSGordon Ross 			/* count cancel options in mop1 */;
10868329232eSGordon Ross 	}
10878329232eSGordon Ross 
10888329232eSGordon Ross 	if (c1 == 0)
10898329232eSGordon Ross 		return (vfs_copycancelopt_extend(mop2->mo_cancel, 0));
10908329232eSGordon Ross 
10918329232eSGordon Ross 	if (mop2->mo_cancel != NULL) {
10928329232eSGordon Ross 		for (; mop2->mo_cancel[c2] != NULL; c2++)
10938329232eSGordon Ross 			/* count cancel options in mop2 */;
10948329232eSGordon Ross 	}
10958329232eSGordon Ross 
10968329232eSGordon Ross 	result = vfs_copycancelopt_extend(mop1->mo_cancel, c2);
10978329232eSGordon Ross 
10988329232eSGordon Ross 	if (c2 == 0)
10998329232eSGordon Ross 		return (result);
11008329232eSGordon Ross 
11018329232eSGordon Ross 	/*
11028329232eSGordon Ross 	 * When we get here, we've got two sets of cancel options;
11038329232eSGordon Ross 	 * we need to merge the two sets.  We know that the result
11048329232eSGordon Ross 	 * array has "c1+c2+1" entries and in the end we might shrink
11058329232eSGordon Ross 	 * it.
11068329232eSGordon Ross 	 * Result now has a copy of the c1 entries from mop1; we'll
11078329232eSGordon Ross 	 * now lookup all the entries of mop2 in mop1 and copy it if
11088329232eSGordon Ross 	 * it is unique.
11098329232eSGordon Ross 	 * This operation is O(n^2) but it's only called once per
11108329232eSGordon Ross 	 * filesystem per duplicate option.  This is a situation
11118329232eSGordon Ross 	 * which doesn't arise with the filesystems in ON and
11128329232eSGordon Ross 	 * n is generally 1.
11138329232eSGordon Ross 	 */
11148329232eSGordon Ross 
11158329232eSGordon Ross 	dp = &result[c1];
11168329232eSGordon Ross 	for (sp2 = mop2->mo_cancel; *sp2 != NULL; sp2++) {
11178329232eSGordon Ross 		for (sp1 = mop1->mo_cancel; *sp1 != NULL; sp1++) {
11188329232eSGordon Ross 			if (strcmp(*sp1, *sp2) == 0)
11198329232eSGordon Ross 				break;
11208329232eSGordon Ross 		}
11218329232eSGordon Ross 		if (*sp1 == NULL) {
11228329232eSGordon Ross 			/*
11238329232eSGordon Ross 			 * Option *sp2 not found in mop1, so copy it.
11248329232eSGordon Ross 			 * The calls to vfs_copycancelopt_extend()
11258329232eSGordon Ross 			 * guarantee that there's enough room.
11268329232eSGordon Ross 			 */
11278329232eSGordon Ross 			*dp = kmem_alloc(strlen(*sp2) + 1, KM_SLEEP);
11288329232eSGordon Ross 			(void) strcpy(*dp++, *sp2);
11298329232eSGordon Ross 		}
11308329232eSGordon Ross 	}
11318329232eSGordon Ross 	if (dp != &result[c1+c2]) {
11328329232eSGordon Ross 		size_t bytes = (dp - result + 1) * sizeof (char *);
11338329232eSGordon Ross 		char **nres = kmem_alloc(bytes, KM_SLEEP);
11348329232eSGordon Ross 
11358329232eSGordon Ross 		bcopy(result, nres, bytes);
11368329232eSGordon Ross 		kmem_free(result, (c1 + c2 + 1) * sizeof (char *));
11378329232eSGordon Ross 		result = nres;
11388329232eSGordon Ross 	}
11398329232eSGordon Ross 	return (result);
11408329232eSGordon Ross }
11418329232eSGordon Ross 
11428329232eSGordon Ross /*
11438329232eSGordon Ross  * Merge two mount option tables (outer and inner) into one.  This is very
11448329232eSGordon Ross  * similar to "merging" global variables and automatic variables in C.
11458329232eSGordon Ross  *
11468329232eSGordon Ross  * This isn't (and doesn't have to be) fast.
11478329232eSGordon Ross  *
11488329232eSGordon Ross  * This function is *not* for general use by filesystems.
11498329232eSGordon Ross  *
11508329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
11518329232eSGordon Ross  *       to protect omo, imo & dmo.
11528329232eSGordon Ross  */
11538329232eSGordon Ross void
vfs_mergeopttbl(const mntopts_t * omo,const mntopts_t * imo,mntopts_t * dmo)11548329232eSGordon Ross vfs_mergeopttbl(const mntopts_t *omo, const mntopts_t *imo, mntopts_t *dmo)
11558329232eSGordon Ross {
11568329232eSGordon Ross 	uint_t i, count;
11578329232eSGordon Ross 	mntopt_t *mop, *motbl;
11588329232eSGordon Ross 	uint_t freeidx;
11598329232eSGordon Ross 
11608329232eSGordon Ross 	/*
11618329232eSGordon Ross 	 * First determine how much space we need to allocate.
11628329232eSGordon Ross 	 */
11638329232eSGordon Ross 	count = omo->mo_count;
11648329232eSGordon Ross 	for (i = 0; i < imo->mo_count; i++) {
11658329232eSGordon Ross 		if (imo->mo_list[i].mo_flags & MO_EMPTY)
11668329232eSGordon Ross 			continue;
11678329232eSGordon Ross 		if (vfs_hasopt(omo, imo->mo_list[i].mo_name) == NULL)
11688329232eSGordon Ross 			count++;
11698329232eSGordon Ross 	}
11708329232eSGordon Ross 	ASSERT(count >= omo->mo_count &&
11718329232eSGordon Ross 	    count <= omo->mo_count + imo->mo_count);
11728329232eSGordon Ross 	motbl = kmem_alloc(count * sizeof (mntopt_t), KM_SLEEP);
11738329232eSGordon Ross 	for (i = 0; i < omo->mo_count; i++)
11748329232eSGordon Ross 		vfs_copyopt(&omo->mo_list[i], &motbl[i]);
11758329232eSGordon Ross 	freeidx = omo->mo_count;
11768329232eSGordon Ross 	for (i = 0; i < imo->mo_count; i++) {
11778329232eSGordon Ross 		if (imo->mo_list[i].mo_flags & MO_EMPTY)
11788329232eSGordon Ross 			continue;
11798329232eSGordon Ross 		if ((mop = vfs_hasopt(omo, imo->mo_list[i].mo_name)) != NULL) {
11808329232eSGordon Ross 			char **newcanp;
11818329232eSGordon Ross 			uint_t index = mop - omo->mo_list;
11828329232eSGordon Ross 
11838329232eSGordon Ross 			newcanp = vfs_mergecancelopts(mop, &motbl[index]);
11848329232eSGordon Ross 
11858329232eSGordon Ross 			vfs_freeopt(&motbl[index]);
11868329232eSGordon Ross 			vfs_copyopt(&imo->mo_list[i], &motbl[index]);
11878329232eSGordon Ross 
11888329232eSGordon Ross 			vfs_freecancelopt(motbl[index].mo_cancel);
11898329232eSGordon Ross 			motbl[index].mo_cancel = newcanp;
11908329232eSGordon Ross 		} else {
11918329232eSGordon Ross 			/*
11928329232eSGordon Ross 			 * If it's a new option, just copy it over to the first
11938329232eSGordon Ross 			 * free location.
11948329232eSGordon Ross 			 */
11958329232eSGordon Ross 			vfs_copyopt(&imo->mo_list[i], &motbl[freeidx++]);
11968329232eSGordon Ross 		}
11978329232eSGordon Ross 	}
11988329232eSGordon Ross 	dmo->mo_count = count;
11998329232eSGordon Ross 	dmo->mo_list = motbl;
12008329232eSGordon Ross }
12018329232eSGordon Ross 
12028329232eSGordon Ross /*
12038329232eSGordon Ross  * Functions to set and clear mount options in a mount options table.
12048329232eSGordon Ross  */
12058329232eSGordon Ross 
12068329232eSGordon Ross /*
12078329232eSGordon Ross  * Clear a mount option, if it exists.
12088329232eSGordon Ross  *
12098329232eSGordon Ross  * The update_mnttab arg indicates whether mops is part of a vfs that is on
12108329232eSGordon Ross  * the vfs list.
12118329232eSGordon Ross  */
12128329232eSGordon Ross static void
vfs_clearmntopt_nolock(mntopts_t * mops,const char * opt,int update_mnttab)12138329232eSGordon Ross vfs_clearmntopt_nolock(mntopts_t *mops, const char *opt, int update_mnttab)
12148329232eSGordon Ross {
12158329232eSGordon Ross 	struct mntopt *mop;
12168329232eSGordon Ross 	uint_t i, count;
12178329232eSGordon Ross 
12188329232eSGordon Ross 	ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
12198329232eSGordon Ross 
12208329232eSGordon Ross 	count = mops->mo_count;
12218329232eSGordon Ross 	for (i = 0; i < count; i++) {
12228329232eSGordon Ross 		mop = &mops->mo_list[i];
12238329232eSGordon Ross 
12248329232eSGordon Ross 		if (mop->mo_flags & MO_EMPTY)
12258329232eSGordon Ross 			continue;
12268329232eSGordon Ross 		if (strcmp(opt, mop->mo_name))
12278329232eSGordon Ross 			continue;
12288329232eSGordon Ross 		mop->mo_flags &= ~MO_SET;
12298329232eSGordon Ross 		if (mop->mo_arg != NULL) {
12308329232eSGordon Ross 			kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
12318329232eSGordon Ross 		}
12328329232eSGordon Ross 		mop->mo_arg = NULL;
12338329232eSGordon Ross 		if (update_mnttab)
12348329232eSGordon Ross 			vfs_mnttab_modtimeupd();
12358329232eSGordon Ross 		break;
12368329232eSGordon Ross 	}
12378329232eSGordon Ross }
12388329232eSGordon Ross 
12398329232eSGordon Ross void
vfs_clearmntopt(struct vfs * vfsp,const char * opt)12408329232eSGordon Ross vfs_clearmntopt(struct vfs *vfsp, const char *opt)
12418329232eSGordon Ross {
12428329232eSGordon Ross 	int gotlock = 0;
12438329232eSGordon Ross 
12448329232eSGordon Ross 	if (VFS_ON_LIST(vfsp)) {
12458329232eSGordon Ross 		gotlock = 1;
12468329232eSGordon Ross 		vfs_list_lock();
12478329232eSGordon Ross 	}
12488329232eSGordon Ross 	vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, opt, gotlock);
12498329232eSGordon Ross 	if (gotlock)
12508329232eSGordon Ross 		vfs_list_unlock();
12518329232eSGordon Ross }
12528329232eSGordon Ross 
12538329232eSGordon Ross 
12548329232eSGordon Ross /*
12558329232eSGordon Ross  * Set a mount option on...
12568329232eSGordon Ross  */
12578329232eSGordon Ross static void
vfs_setmntopt_nolock(mntopts_t * mops,const char * opt,const char * arg,int flags,int update_mnttab)12588329232eSGordon Ross vfs_setmntopt_nolock(mntopts_t *mops, const char *opt,
12598329232eSGordon Ross     const char *arg, int flags, int update_mnttab)
12608329232eSGordon Ross {
12618329232eSGordon Ross 	mntopt_t *mop;
12628329232eSGordon Ross 	uint_t i, count;
12638329232eSGordon Ross 	char *sp;
12648329232eSGordon Ross 
12658329232eSGordon Ross 	ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
12668329232eSGordon Ross 
12678329232eSGordon Ross 	if (flags & VFS_CREATEOPT) {
12688329232eSGordon Ross 		if (vfs_hasopt(mops, opt) != NULL) {
12698329232eSGordon Ross 			flags &= ~VFS_CREATEOPT;
12708329232eSGordon Ross 		}
12718329232eSGordon Ross 	}
12728329232eSGordon Ross 	count = mops->mo_count;
12738329232eSGordon Ross 	for (i = 0; i < count; i++) {
12748329232eSGordon Ross 		mop = &mops->mo_list[i];
12758329232eSGordon Ross 
12768329232eSGordon Ross 		if (mop->mo_flags & MO_EMPTY) {
12778329232eSGordon Ross 			if ((flags & VFS_CREATEOPT) == 0)
12788329232eSGordon Ross 				continue;
12798329232eSGordon Ross 			sp = kmem_alloc(strlen(opt) + 1, KM_SLEEP);
12808329232eSGordon Ross 			(void) strcpy(sp, opt);
12818329232eSGordon Ross 			mop->mo_name = sp;
12828329232eSGordon Ross 			if (arg != NULL)
12838329232eSGordon Ross 				mop->mo_flags = MO_HASVALUE;
12848329232eSGordon Ross 			else
12858329232eSGordon Ross 				mop->mo_flags = 0;
12868329232eSGordon Ross 		} else if (strcmp(opt, mop->mo_name)) {
12878329232eSGordon Ross 			continue;
12888329232eSGordon Ross 		}
12898329232eSGordon Ross 		if ((mop->mo_flags & MO_IGNORE) && (flags & VFS_NOFORCEOPT))
12908329232eSGordon Ross 			break;
12918329232eSGordon Ross 		if (arg != NULL && (mop->mo_flags & MO_HASVALUE) != 0) {
12928329232eSGordon Ross 			sp = kmem_alloc(strlen(arg) + 1, KM_SLEEP);
12938329232eSGordon Ross 			(void) strcpy(sp, arg);
12948329232eSGordon Ross 		} else {
12958329232eSGordon Ross 			sp = NULL;
12968329232eSGordon Ross 		}
12978329232eSGordon Ross 		if (mop->mo_arg != NULL)
12988329232eSGordon Ross 			kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
12998329232eSGordon Ross 		mop->mo_arg = sp;
13008329232eSGordon Ross 		if (flags & VFS_DISPLAY)
13018329232eSGordon Ross 			mop->mo_flags &= ~MO_NODISPLAY;
13028329232eSGordon Ross 		if (flags & VFS_NODISPLAY)
13038329232eSGordon Ross 			mop->mo_flags |= MO_NODISPLAY;
13048329232eSGordon Ross 		mop->mo_flags |= MO_SET;
13058329232eSGordon Ross 		if (mop->mo_cancel != NULL) {
13068329232eSGordon Ross 			char **cp;
13078329232eSGordon Ross 
13088329232eSGordon Ross 			for (cp = mop->mo_cancel; *cp != NULL; cp++)
13098329232eSGordon Ross 				vfs_clearmntopt_nolock(mops, *cp, 0);
13108329232eSGordon Ross 		}
13118329232eSGordon Ross 		if (update_mnttab)
13128329232eSGordon Ross 			vfs_mnttab_modtimeupd();
13138329232eSGordon Ross 		break;
13148329232eSGordon Ross 	}
13158329232eSGordon Ross }
13168329232eSGordon Ross 
13178329232eSGordon Ross void
vfs_setmntopt(struct vfs * vfsp,const char * opt,const char * arg,int flags)13188329232eSGordon Ross vfs_setmntopt(struct vfs *vfsp, const char *opt, const char *arg, int flags)
13198329232eSGordon Ross {
13208329232eSGordon Ross 	int gotlock = 0;
13218329232eSGordon Ross 
13228329232eSGordon Ross 	if (VFS_ON_LIST(vfsp)) {
13238329232eSGordon Ross 		gotlock = 1;
13248329232eSGordon Ross 		vfs_list_lock();
13258329232eSGordon Ross 	}
13268329232eSGordon Ross 	vfs_setmntopt_nolock(&vfsp->vfs_mntopts, opt, arg, flags, gotlock);
13278329232eSGordon Ross 	if (gotlock)
13288329232eSGordon Ross 		vfs_list_unlock();
13298329232eSGordon Ross }
13308329232eSGordon Ross 
13318329232eSGordon Ross // vfs_addtag
13328329232eSGordon Ross // vfs_settag
13338329232eSGordon Ross // vfs_clrtag
13348329232eSGordon Ross 
13358329232eSGordon Ross /*
13368329232eSGordon Ross  * Function to parse an option string and fill in a mount options table.
13378329232eSGordon Ross  * Unknown options are silently ignored.  The input option string is modified
13388329232eSGordon Ross  * by replacing separators with nulls.  If the create flag is set, options
13398329232eSGordon Ross  * not found in the table are just added on the fly.  The table must have
13408329232eSGordon Ross  * an option slot marked MO_EMPTY to add an option on the fly.
13418329232eSGordon Ross  *
13428329232eSGordon Ross  * This function is *not* for general use by filesystems.
13438329232eSGordon Ross  *
13448329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
13458329232eSGordon Ross  *       to protect mops..
13468329232eSGordon Ross  */
13478329232eSGordon Ross void
vfs_parsemntopts(mntopts_t * mops,char * osp,int create)13488329232eSGordon Ross vfs_parsemntopts(mntopts_t *mops, char *osp, int create)
13498329232eSGordon Ross {
13508329232eSGordon Ross 	char *s = osp, *p, *nextop, *valp, *cp, *ep = NULL;
13518329232eSGordon Ross 	int setflg = VFS_NOFORCEOPT;
13528329232eSGordon Ross 
13538329232eSGordon Ross 	if (osp == NULL)
13548329232eSGordon Ross 		return;
13558329232eSGordon Ross 	while (*s != '\0') {
13568329232eSGordon Ross 		p = strchr(s, ',');	/* find next option */
13578329232eSGordon Ross 		if (p == NULL) {
13588329232eSGordon Ross 			cp = NULL;
13598329232eSGordon Ross 			p = s + strlen(s);
13608329232eSGordon Ross 		} else {
13618329232eSGordon Ross 			cp = p;		/* save location of comma */
13628329232eSGordon Ross 			*p++ = '\0';	/* mark end and point to next option */
13638329232eSGordon Ross 		}
13648329232eSGordon Ross 		nextop = p;
13658329232eSGordon Ross 		p = strchr(s, '=');	/* look for value */
13668329232eSGordon Ross 		if (p == NULL) {
13678329232eSGordon Ross 			valp = NULL;	/* no value supplied */
13688329232eSGordon Ross 			ep = NULL;
13698329232eSGordon Ross 		} else {
13708329232eSGordon Ross 			ep = p;		/* save location of equals */
13718329232eSGordon Ross 			*p++ = '\0';	/* end option and point to value */
13728329232eSGordon Ross 			valp = p;
13738329232eSGordon Ross 		}
13748329232eSGordon Ross 		/*
13758329232eSGordon Ross 		 * set option into options table
13768329232eSGordon Ross 		 */
13778329232eSGordon Ross 		if (create)
13788329232eSGordon Ross 			setflg |= VFS_CREATEOPT;
13798329232eSGordon Ross 		vfs_setmntopt_nolock(mops, s, valp, setflg, 0);
13808329232eSGordon Ross 		if (cp != NULL)
13818329232eSGordon Ross 			*cp = ',';	/* restore the comma */
13828329232eSGordon Ross 		if (valp != NULL)
13838329232eSGordon Ross 			*ep = '=';	/* restore the equals */
13848329232eSGordon Ross 		s = nextop;
13858329232eSGordon Ross 	}
13868329232eSGordon Ross }
13878329232eSGordon Ross 
13888329232eSGordon Ross /*
13898329232eSGordon Ross  * Function to inquire if an option exists in a mount options table.
13908329232eSGordon Ross  * Returns a pointer to the option if it exists, else NULL.
13918329232eSGordon Ross  */
13928329232eSGordon Ross struct mntopt *
vfs_hasopt(const mntopts_t * mops,const char * opt)13938329232eSGordon Ross vfs_hasopt(const mntopts_t *mops, const char *opt)
13948329232eSGordon Ross {
13958329232eSGordon Ross 	struct mntopt *mop;
13968329232eSGordon Ross 	uint_t i, count;
13978329232eSGordon Ross 
13988329232eSGordon Ross 	count = mops->mo_count;
13998329232eSGordon Ross 	for (i = 0; i < count; i++) {
14008329232eSGordon Ross 		mop = &mops->mo_list[i];
14018329232eSGordon Ross 
14028329232eSGordon Ross 		if (mop->mo_flags & MO_EMPTY)
14038329232eSGordon Ross 			continue;
14048329232eSGordon Ross 		if (strcmp(opt, mop->mo_name) == 0)
14058329232eSGordon Ross 			return (mop);
14068329232eSGordon Ross 	}
14078329232eSGordon Ross 	return (NULL);
14088329232eSGordon Ross }
14098329232eSGordon Ross 
14108329232eSGordon Ross /*
14118329232eSGordon Ross  * Function to inquire if an option is set in a mount options table.
14128329232eSGordon Ross  * Returns non-zero if set and fills in the arg pointer with a pointer to
14138329232eSGordon Ross  * the argument string or NULL if there is no argument string.
14148329232eSGordon Ross  */
14158329232eSGordon Ross static int
vfs_optionisset_nolock(const mntopts_t * mops,const char * opt,char ** argp)14168329232eSGordon Ross vfs_optionisset_nolock(const mntopts_t *mops, const char *opt, char **argp)
14178329232eSGordon Ross {
14188329232eSGordon Ross 	struct mntopt *mop;
14198329232eSGordon Ross 	uint_t i, count;
14208329232eSGordon Ross 
14218329232eSGordon Ross 	count = mops->mo_count;
14228329232eSGordon Ross 	for (i = 0; i < count; i++) {
14238329232eSGordon Ross 		mop = &mops->mo_list[i];
14248329232eSGordon Ross 
14258329232eSGordon Ross 		if (mop->mo_flags & MO_EMPTY)
14268329232eSGordon Ross 			continue;
14278329232eSGordon Ross 		if (strcmp(opt, mop->mo_name))
14288329232eSGordon Ross 			continue;
14298329232eSGordon Ross 		if ((mop->mo_flags & MO_SET) == 0)
14308329232eSGordon Ross 			return (0);
14318329232eSGordon Ross 		if (argp != NULL && (mop->mo_flags & MO_HASVALUE) != 0)
14328329232eSGordon Ross 			*argp = mop->mo_arg;
14338329232eSGordon Ross 		return (1);
14348329232eSGordon Ross 	}
14358329232eSGordon Ross 	return (0);
14368329232eSGordon Ross }
14378329232eSGordon Ross 
14388329232eSGordon Ross 
14398329232eSGordon Ross int
vfs_optionisset(const struct vfs * vfsp,const char * opt,char ** argp)14408329232eSGordon Ross vfs_optionisset(const struct vfs *vfsp, const char *opt, char **argp)
14418329232eSGordon Ross {
14428329232eSGordon Ross 	int ret;
14438329232eSGordon Ross 
14448329232eSGordon Ross 	vfs_list_read_lock();
14458329232eSGordon Ross 	ret = vfs_optionisset_nolock(&vfsp->vfs_mntopts, opt, argp);
14468329232eSGordon Ross 	vfs_list_unlock();
14478329232eSGordon Ross 	return (ret);
14488329232eSGordon Ross }
14498329232eSGordon Ross 
14508329232eSGordon Ross 
14518329232eSGordon Ross /*
14528329232eSGordon Ross  * Construct a comma separated string of the options set in the given
14538329232eSGordon Ross  * mount table, return the string in the given buffer.  Return non-zero if
14548329232eSGordon Ross  * the buffer would overflow.
14558329232eSGordon Ross  *
14568329232eSGordon Ross  * This function is *not* for general use by filesystems.
14578329232eSGordon Ross  *
14588329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
14598329232eSGordon Ross  *       to protect mp.
14608329232eSGordon Ross  */
14618329232eSGordon Ross int
vfs_buildoptionstr(const mntopts_t * mp,char * buf,int len)14628329232eSGordon Ross vfs_buildoptionstr(const mntopts_t *mp, char *buf, int len)
14638329232eSGordon Ross {
14648329232eSGordon Ross 	char *cp;
14658329232eSGordon Ross 	uint_t i;
14668329232eSGordon Ross 
14678329232eSGordon Ross 	buf[0] = '\0';
14688329232eSGordon Ross 	cp = buf;
14698329232eSGordon Ross 	for (i = 0; i < mp->mo_count; i++) {
14708329232eSGordon Ross 		struct mntopt *mop;
14718329232eSGordon Ross 
14728329232eSGordon Ross 		mop = &mp->mo_list[i];
14738329232eSGordon Ross 		if (mop->mo_flags & MO_SET) {
14748329232eSGordon Ross 			int optlen, comma = 0;
14758329232eSGordon Ross 
14768329232eSGordon Ross 			if (buf[0] != '\0')
14778329232eSGordon Ross 				comma = 1;
14788329232eSGordon Ross 			optlen = strlen(mop->mo_name);
14798329232eSGordon Ross 			if (strlen(buf) + comma + optlen + 1 > len)
14808329232eSGordon Ross 				goto err;
14818329232eSGordon Ross 			if (comma)
14828329232eSGordon Ross 				*cp++ = ',';
14838329232eSGordon Ross 			(void) strcpy(cp, mop->mo_name);
14848329232eSGordon Ross 			cp += optlen;
14858329232eSGordon Ross 			/*
14868329232eSGordon Ross 			 * Append option value if there is one
14878329232eSGordon Ross 			 */
14888329232eSGordon Ross 			if (mop->mo_arg != NULL) {
14898329232eSGordon Ross 				int arglen;
14908329232eSGordon Ross 
14918329232eSGordon Ross 				arglen = strlen(mop->mo_arg);
14928329232eSGordon Ross 				if (strlen(buf) + arglen + 2 > len)
14938329232eSGordon Ross 					goto err;
14948329232eSGordon Ross 				*cp++ = '=';
14958329232eSGordon Ross 				(void) strcpy(cp, mop->mo_arg);
14968329232eSGordon Ross 				cp += arglen;
14978329232eSGordon Ross 			}
14988329232eSGordon Ross 		}
14998329232eSGordon Ross 	}
15008329232eSGordon Ross 	return (0);
15018329232eSGordon Ross err:
15028329232eSGordon Ross 	return (EOVERFLOW);
15038329232eSGordon Ross }
15048329232eSGordon Ross 
15058329232eSGordon Ross static void
vfs_freecancelopt(char ** moc)15068329232eSGordon Ross vfs_freecancelopt(char **moc)
15078329232eSGordon Ross {
15088329232eSGordon Ross 	if (moc != NULL) {
15098329232eSGordon Ross 		int ccnt = 0;
15108329232eSGordon Ross 		char **cp;
15118329232eSGordon Ross 
15128329232eSGordon Ross 		for (cp = moc; *cp != NULL; cp++) {
15138329232eSGordon Ross 			kmem_free(*cp, strlen(*cp) + 1);
15148329232eSGordon Ross 			ccnt++;
15158329232eSGordon Ross 		}
15168329232eSGordon Ross 		kmem_free(moc, (ccnt + 1) * sizeof (char *));
15178329232eSGordon Ross 	}
15188329232eSGordon Ross }
15198329232eSGordon Ross 
15208329232eSGordon Ross static void
vfs_freeopt(mntopt_t * mop)15218329232eSGordon Ross vfs_freeopt(mntopt_t *mop)
15228329232eSGordon Ross {
15238329232eSGordon Ross 	if (mop->mo_name != NULL)
15248329232eSGordon Ross 		kmem_free(mop->mo_name, strlen(mop->mo_name) + 1);
15258329232eSGordon Ross 
15268329232eSGordon Ross 	vfs_freecancelopt(mop->mo_cancel);
15278329232eSGordon Ross 
15288329232eSGordon Ross 	if (mop->mo_arg != NULL)
15298329232eSGordon Ross 		kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
15308329232eSGordon Ross }
15318329232eSGordon Ross 
15328329232eSGordon Ross /*
15338329232eSGordon Ross  * Free a mount options table
15348329232eSGordon Ross  *
15358329232eSGordon Ross  * This function is *not* for general use by filesystems.
15368329232eSGordon Ross  *
15378329232eSGordon Ross  * Note: caller is responsible for locking the vfs list, if needed,
15388329232eSGordon Ross  *       to protect mp.
15398329232eSGordon Ross  */
15408329232eSGordon Ross void
vfs_freeopttbl(mntopts_t * mp)15418329232eSGordon Ross vfs_freeopttbl(mntopts_t *mp)
15428329232eSGordon Ross {
15438329232eSGordon Ross 	uint_t i, count;
15448329232eSGordon Ross 
15458329232eSGordon Ross 	count = mp->mo_count;
15468329232eSGordon Ross 	for (i = 0; i < count; i++) {
15478329232eSGordon Ross 		vfs_freeopt(&mp->mo_list[i]);
15488329232eSGordon Ross 	}
15498329232eSGordon Ross 	if (count) {
15508329232eSGordon Ross 		kmem_free(mp->mo_list, sizeof (mntopt_t) * count);
15518329232eSGordon Ross 		mp->mo_count = 0;
15528329232eSGordon Ross 		mp->mo_list = NULL;
15538329232eSGordon Ross 	}
15548329232eSGordon Ross }
15558329232eSGordon Ross 
15568329232eSGordon Ross // vfs_mntdummyread
15578329232eSGordon Ross // vfs_mntdummywrite
15588329232eSGordon Ross // vfs_mntdummygetattr
15598329232eSGordon Ross // vfs_mnttabvp_setup
15608329232eSGordon Ross // vfs_mnttab_rwop
15618329232eSGordon Ross // vfs_mnttab_writeop
15628329232eSGordon Ross // vfs_mnttab_readop
15638329232eSGordon Ross // vfs_freemnttab
15648329232eSGordon Ross // vfs_mnttab_modtime
15658329232eSGordon Ross // vfs_mnttab_poll
15668329232eSGordon Ross // vfs_mono_time
15678329232eSGordon Ross 
15688329232eSGordon Ross /*
15698329232eSGordon Ross  * Update the mnttab modification time...
15708329232eSGordon Ross  */
15718329232eSGordon Ross void
vfs_mnttab_modtimeupd()15728329232eSGordon Ross vfs_mnttab_modtimeupd()
15738329232eSGordon Ross {
15748329232eSGordon Ross }
15758329232eSGordon Ross 
15768329232eSGordon Ross /*
15778329232eSGordon Ross  * Unlike the real dounmount, we don't have
15788329232eSGordon Ross  * vn_vfswlock_held(coveredvp)
15798329232eSGordon Ross  */
15808329232eSGordon Ross int
fake_dounmount(struct vfs * vfsp,int flag)15818329232eSGordon Ross fake_dounmount(struct vfs *vfsp, int flag)
15828329232eSGordon Ross {
15838329232eSGordon Ross 	cred_t *cr = CRED();
15848329232eSGordon Ross 	vnode_t *coveredvp;
15858329232eSGordon Ross 	int error;
15868329232eSGordon Ross 
15878329232eSGordon Ross 	/*
15888329232eSGordon Ross 	 * Get covered vnode. This will be NULL if the vfs is not linked
15898329232eSGordon Ross 	 * into the file system name space (i.e., domount() with MNT_NOSPICE).
15908329232eSGordon Ross 	 */
15918329232eSGordon Ross 	coveredvp = vfsp->vfs_vnodecovered;
15928329232eSGordon Ross 
15938329232eSGordon Ross 	/* For forcible umount, skip VFS_SYNC() since it may hang */
15948329232eSGordon Ross 	if ((flag & MS_FORCE) == 0)
15958329232eSGordon Ross 		(void) VFS_SYNC(vfsp, 0, cr);
15968329232eSGordon Ross 
15978329232eSGordon Ross 	/*
15988329232eSGordon Ross 	 * Test-jig specific:
15998329232eSGordon Ross 	 * Need to release rootdir before unmount or VFS_UNMOUNT
16008329232eSGordon Ross 	 * may fail due to that node being active.
16018329232eSGordon Ross 	 */
16028329232eSGordon Ross 	if (rootdir != NULL) {
16038329232eSGordon Ross 		ASSERT(rootdir != coveredvp);
16048329232eSGordon Ross 		VN_RELE(rootdir);
16058329232eSGordon Ross 		rootdir = NULL;
16068329232eSGordon Ross 	}
16078329232eSGordon Ross 
16088329232eSGordon Ross 	/*
16098329232eSGordon Ross 	 * Lock the vfs to maintain fs status quo during unmount.  This
16108329232eSGordon Ross 	 * has to be done after the sync because ufs_update tries to acquire
16118329232eSGordon Ross 	 * the vfs_reflock.
16128329232eSGordon Ross 	 */
16138329232eSGordon Ross 	vfs_lock_wait(vfsp);
16148329232eSGordon Ross 
16158329232eSGordon Ross 	if ((error = VFS_UNMOUNT(vfsp, flag, cr)) != 0) {
16168329232eSGordon Ross 		int err2;
16178329232eSGordon Ross 		vfs_unlock(vfsp);
16188329232eSGordon Ross 		/* Get rootdir back */
16198329232eSGordon Ross 		err2 = VFS_ROOT(vfsp, &rootdir);
16208329232eSGordon Ross 		if (err2 != 0) {
16218329232eSGordon Ross 			panic("fake_dounmount, get root %d\n", err2);
16228329232eSGordon Ross 		}
16238329232eSGordon Ross 	} else {
16248329232eSGordon Ross 		/*
16258329232eSGordon Ross 		 * Real dounmount does vfs_remove.
16268329232eSGordon Ross 		 *
16278329232eSGordon Ross 		 * Test-jig specific:
16288329232eSGordon Ross 		 * Restore the covered rootdir,
16298329232eSGordon Ross 		 * release the rootvfs hold and clear.
16308329232eSGordon Ross 		 */
16318329232eSGordon Ross 		if (coveredvp != NULL) {
16328329232eSGordon Ross 			// vfs_list_remove(vfsp);
16338329232eSGordon Ross 			vfsp->vfs_vnodecovered = NULL;
16348329232eSGordon Ross 			rootdir = coveredvp;
16358329232eSGordon Ross 		}
16368329232eSGordon Ross 		if (rootvfs == vfsp) {
16378329232eSGordon Ross 			VFS_RELE(vfsp);
16388329232eSGordon Ross 			rootvfs = NULL;
16398329232eSGordon Ross 		}
16408329232eSGordon Ross 
16418329232eSGordon Ross 		/*
16428329232eSGordon Ross 		 * Release the (final) reference to vfs
16438329232eSGordon Ross 		 */
16448329232eSGordon Ross 		vfs_unlock(vfsp);
16458329232eSGordon Ross 		VFS_RELE(vfsp);
16468329232eSGordon Ross 	}
16478329232eSGordon Ross 	return (error);
16488329232eSGordon Ross }
16498329232eSGordon Ross 
16508329232eSGordon Ross // vfs_unmountall(void)
16518329232eSGordon Ross // vfs_addmip
16528329232eSGordon Ross // vfs_delmip
16538329232eSGordon Ross // vfs_add
16548329232eSGordon Ross // vfs_remove
16558329232eSGordon Ross 
16568329232eSGordon Ross static krwlock_t vpvfsentry_ve_lock;
16578329232eSGordon Ross 
16588329232eSGordon Ross /*
16598329232eSGordon Ross  * Lock a filesystem to prevent access to it while mounting,
16608329232eSGordon Ross  * unmounting and syncing.  Return EBUSY immediately if lock
16618329232eSGordon Ross  * can't be acquired.
16628329232eSGordon Ross  */
16638329232eSGordon Ross int
vfs_lock(vfs_t * vfsp)16648329232eSGordon Ross vfs_lock(vfs_t *vfsp)
16658329232eSGordon Ross {
16668329232eSGordon Ross 
16678329232eSGordon Ross 	if (rw_tryenter(&vpvfsentry_ve_lock, RW_WRITER))
16688329232eSGordon Ross 		return (0);
16698329232eSGordon Ross 
16708329232eSGordon Ross 	return (EBUSY);
16718329232eSGordon Ross }
16728329232eSGordon Ross 
16738329232eSGordon Ross int
vfs_rlock(vfs_t * vfsp)16748329232eSGordon Ross vfs_rlock(vfs_t *vfsp)
16758329232eSGordon Ross {
16768329232eSGordon Ross 
16778329232eSGordon Ross 	if (rw_tryenter(&vpvfsentry_ve_lock, RW_READER))
16788329232eSGordon Ross 		return (0);
16798329232eSGordon Ross 
16808329232eSGordon Ross 	return (EBUSY);
16818329232eSGordon Ross }
16828329232eSGordon Ross 
16838329232eSGordon Ross void
vfs_lock_wait(vfs_t * vfsp)16848329232eSGordon Ross vfs_lock_wait(vfs_t *vfsp)
16858329232eSGordon Ross {
16868329232eSGordon Ross 
16878329232eSGordon Ross 	rw_enter(&vpvfsentry_ve_lock, RW_WRITER);
16888329232eSGordon Ross }
16898329232eSGordon Ross 
16908329232eSGordon Ross void
vfs_rlock_wait(vfs_t * vfsp)16918329232eSGordon Ross vfs_rlock_wait(vfs_t *vfsp)
16928329232eSGordon Ross {
16938329232eSGordon Ross 	rw_enter(&vpvfsentry_ve_lock, RW_READER);
16948329232eSGordon Ross }
16958329232eSGordon Ross 
16968329232eSGordon Ross /*
16978329232eSGordon Ross  * Unlock a locked filesystem.
16988329232eSGordon Ross  */
16998329232eSGordon Ross void
vfs_unlock(vfs_t * vfsp)17008329232eSGordon Ross vfs_unlock(vfs_t *vfsp)
17018329232eSGordon Ross {
17028329232eSGordon Ross 
17038329232eSGordon Ross 	rw_exit(&vpvfsentry_ve_lock);
17048329232eSGordon Ross }
17058329232eSGordon Ross 
17068329232eSGordon Ross /*
17078329232eSGordon Ross  * Utility routine that allows a filesystem to construct its
17088329232eSGordon Ross  * fsid in "the usual way" - by munging some underlying dev_t and
17098329232eSGordon Ross  * the filesystem type number into the 64-bit fsid. ...
17108329232eSGordon Ross  */
17118329232eSGordon Ross void
vfs_make_fsid(fsid_t * fsi,dev_t dev,int val)17128329232eSGordon Ross vfs_make_fsid(fsid_t *fsi, dev_t dev, int val)
17138329232eSGordon Ross {
17148329232eSGordon Ross 	if (!cmpldev((dev32_t *)&fsi->val[0], dev))
17158329232eSGordon Ross 		panic("device number too big for fsid!");
17168329232eSGordon Ross 	fsi->val[1] = val;
17178329232eSGordon Ross }
17188329232eSGordon Ross 
17198329232eSGordon Ross int
vfs_lock_held(vfs_t * vfsp)17208329232eSGordon Ross vfs_lock_held(vfs_t *vfsp)
17218329232eSGordon Ross {
17228329232eSGordon Ross 	int held;
17238329232eSGordon Ross 
17248329232eSGordon Ross 	held = rw_write_held(&vpvfsentry_ve_lock);
17258329232eSGordon Ross 
17268329232eSGordon Ross 	return (held);
17278329232eSGordon Ross }
17288329232eSGordon Ross 
17298329232eSGordon Ross // vfs_lock_owner
17308329232eSGordon Ross 
17318329232eSGordon Ross /*
17328329232eSGordon Ross  * vfs list locking.
17338329232eSGordon Ross  */
17348329232eSGordon Ross 
17358329232eSGordon Ross void
vfs_list_lock()17368329232eSGordon Ross vfs_list_lock()
17378329232eSGordon Ross {
17388329232eSGordon Ross 	rw_enter(&vfslist, RW_WRITER);
17398329232eSGordon Ross }
17408329232eSGordon Ross 
17418329232eSGordon Ross void
vfs_list_read_lock()17428329232eSGordon Ross vfs_list_read_lock()
17438329232eSGordon Ross {
17448329232eSGordon Ross 	rw_enter(&vfslist, RW_READER);
17458329232eSGordon Ross }
17468329232eSGordon Ross 
17478329232eSGordon Ross void
vfs_list_unlock()17488329232eSGordon Ross vfs_list_unlock()
17498329232eSGordon Ross {
17508329232eSGordon Ross 	rw_exit(&vfslist);
17518329232eSGordon Ross }
17528329232eSGordon Ross 
17538329232eSGordon Ross /*
17548329232eSGordon Ross  * Low level worker routines for adding entries to and removing entries from
17558329232eSGordon Ross  * the vfs list.
17568329232eSGordon Ross  */
17578329232eSGordon Ross 
17588329232eSGordon Ross // vfs_hash_add
17598329232eSGordon Ross // vfs_hash_remove
17608329232eSGordon Ross // vfs_list_add
17618329232eSGordon Ross // vfs_list_remove
17628329232eSGordon Ross // getvfs
17638329232eSGordon Ross // vfs_devmounting
17648329232eSGordon Ross 
17658329232eSGordon Ross /*
17668329232eSGordon Ross  * Search the vfs list for a specified device.  Returns 1, if entry is found
17678329232eSGordon Ross  * or 0 if no suitable entry is found.
17688329232eSGordon Ross  */
17698329232eSGordon Ross 
17708329232eSGordon Ross int
vfs_devismounted(dev_t dev)17718329232eSGordon Ross vfs_devismounted(dev_t dev)
17728329232eSGordon Ross {
17738329232eSGordon Ross 	return (0);
17748329232eSGordon Ross }
17758329232eSGordon Ross 
17768329232eSGordon Ross // vfs_dev2vfsp
17778329232eSGordon Ross // vfs_mntpoint2vfsp
17788329232eSGordon Ross 
17798329232eSGordon Ross /*
17808329232eSGordon Ross  * Search the vfs list for a specified vfsops.
17818329232eSGordon Ross  * if vfs entry is found then return 1, else 0.
17828329232eSGordon Ross  */
17838329232eSGordon Ross int
vfs_opsinuse(vfsops_t * ops)17848329232eSGordon Ross vfs_opsinuse(vfsops_t *ops)
17858329232eSGordon Ross {
17868329232eSGordon Ross 	return (0);
17878329232eSGordon Ross }
17888329232eSGordon Ross 
17898329232eSGordon Ross /*
17908329232eSGordon Ross  * Allocate an entry in vfssw for a file system type
17918329232eSGordon Ross  */
17928329232eSGordon Ross struct vfssw *
allocate_vfssw(const char * type)17938329232eSGordon Ross allocate_vfssw(const char *type)
17948329232eSGordon Ross {
17958329232eSGordon Ross 	struct vfssw *vswp;
17968329232eSGordon Ross 
17978329232eSGordon Ross 	if (type[0] == '\0' || strlen(type) + 1 > _ST_FSTYPSZ) {
17988329232eSGordon Ross 		/*
17998329232eSGordon Ross 		 * The vfssw table uses the empty string to identify an
18008329232eSGordon Ross 		 * available entry; we cannot add any type which has
18018329232eSGordon Ross 		 * a leading NUL. The string length is limited to
18028329232eSGordon Ross 		 * the size of the st_fstype array in struct stat.
18038329232eSGordon Ross 		 */
18048329232eSGordon Ross 		return (NULL);
18058329232eSGordon Ross 	}
18068329232eSGordon Ross 
18078329232eSGordon Ross 	ASSERT(VFSSW_WRITE_LOCKED());
18088329232eSGordon Ross 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++)
18098329232eSGordon Ross 		if (!ALLOCATED_VFSSW(vswp)) {
18108329232eSGordon Ross 			vswp->vsw_name = kmem_alloc(strlen(type) + 1, KM_SLEEP);
18118329232eSGordon Ross 			(void) strcpy(vswp->vsw_name, type);
18128329232eSGordon Ross 			ASSERT(vswp->vsw_count == 0);
18138329232eSGordon Ross 			vswp->vsw_count = 1;
18148329232eSGordon Ross 			mutex_init(&vswp->vsw_lock, NULL, MUTEX_DEFAULT, NULL);
18158329232eSGordon Ross 			return (vswp);
18168329232eSGordon Ross 		}
18178329232eSGordon Ross 	return (NULL);
18188329232eSGordon Ross }
18198329232eSGordon Ross 
18208329232eSGordon Ross // vfs_to_modname
18218329232eSGordon Ross // vfs_getvfssw
18228329232eSGordon Ross 
18238329232eSGordon Ross /*
18248329232eSGordon Ross  * Find a vfssw entry given a file system type name.
18258329232eSGordon Ross  */
18268329232eSGordon Ross struct vfssw *
vfs_getvfssw(const char * type)18278329232eSGordon Ross vfs_getvfssw(const char *type)
18288329232eSGordon Ross {
18298329232eSGordon Ross 	struct vfssw *vswp;
18308329232eSGordon Ross 
18318329232eSGordon Ross 	if (type == NULL || *type == '\0')
18328329232eSGordon Ross 		return (NULL);
18338329232eSGordon Ross 
18348329232eSGordon Ross 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
18358329232eSGordon Ross 		if (strcmp(type, vswp->vsw_name) == 0) {
18368329232eSGordon Ross 			return (vswp);
18378329232eSGordon Ross 		}
18388329232eSGordon Ross 	}
18398329232eSGordon Ross 
18408329232eSGordon Ross 	return (NULL);
18418329232eSGordon Ross 
18428329232eSGordon Ross }
18438329232eSGordon Ross 
18448329232eSGordon Ross /*
18458329232eSGordon Ross  * Find a vfssw entry given a file system type name.
18468329232eSGordon Ross  */
18478329232eSGordon Ross struct vfssw *
vfs_getvfsswbyname(const char * type)18488329232eSGordon Ross vfs_getvfsswbyname(const char *type)
18498329232eSGordon Ross {
18508329232eSGordon Ross 	struct vfssw *vswp;
18518329232eSGordon Ross 
18528329232eSGordon Ross 	ASSERT(VFSSW_LOCKED());
18538329232eSGordon Ross 	if (type == NULL || *type == '\0')
18548329232eSGordon Ross 		return (NULL);
18558329232eSGordon Ross 
18568329232eSGordon Ross 	for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
18578329232eSGordon Ross 		if (strcmp(type, vswp->vsw_name) == 0) {
18588329232eSGordon Ross 			vfs_refvfssw(vswp);
18598329232eSGordon Ross 			return (vswp);
18608329232eSGordon Ross 		}
18618329232eSGordon Ross 	}
18628329232eSGordon Ross 
18638329232eSGordon Ross 	return (NULL);
18648329232eSGordon Ross }
18658329232eSGordon Ross 
18668329232eSGordon Ross // vfs_getvfsswbyvfsops
18678329232eSGordon Ross 
18688329232eSGordon Ross /*
18698329232eSGordon Ross  * Reference a vfssw entry.
18708329232eSGordon Ross  */
18718329232eSGordon Ross void
vfs_refvfssw(struct vfssw * vswp)18728329232eSGordon Ross vfs_refvfssw(struct vfssw *vswp)
18738329232eSGordon Ross {
18748329232eSGordon Ross 
18758329232eSGordon Ross 	mutex_enter(&vswp->vsw_lock);
18768329232eSGordon Ross 	vswp->vsw_count++;
18778329232eSGordon Ross 	mutex_exit(&vswp->vsw_lock);
18788329232eSGordon Ross }
18798329232eSGordon Ross 
18808329232eSGordon Ross /*
18818329232eSGordon Ross  * Unreference a vfssw entry.
18828329232eSGordon Ross  */
18838329232eSGordon Ross void
vfs_unrefvfssw(struct vfssw * vswp)18848329232eSGordon Ross vfs_unrefvfssw(struct vfssw *vswp)
18858329232eSGordon Ross {
18868329232eSGordon Ross 
18878329232eSGordon Ross 	mutex_enter(&vswp->vsw_lock);
18888329232eSGordon Ross 	vswp->vsw_count--;
18898329232eSGordon Ross 	mutex_exit(&vswp->vsw_lock);
18908329232eSGordon Ross }
18918329232eSGordon Ross 
18928329232eSGordon Ross // vfs_syncall
18938329232eSGordon Ross 
18948329232eSGordon Ross /*
18958329232eSGordon Ross  * Map VFS flags to statvfs flags.  These shouldn't really be separate
18968329232eSGordon Ross  * flags at all.
18978329232eSGordon Ross  */
18988329232eSGordon Ross uint_t
vf_to_stf(uint_t vf)18998329232eSGordon Ross vf_to_stf(uint_t vf)
19008329232eSGordon Ross {
19018329232eSGordon Ross 	uint_t stf = 0;
19028329232eSGordon Ross 
19038329232eSGordon Ross 	if (vf & VFS_RDONLY)
19048329232eSGordon Ross 		stf |= ST_RDONLY;
19058329232eSGordon Ross 	if (vf & VFS_NOSETUID)
19068329232eSGordon Ross 		stf |= ST_NOSUID;
19078329232eSGordon Ross 	if (vf & VFS_NOTRUNC)
19088329232eSGordon Ross 		stf |= ST_NOTRUNC;
19098329232eSGordon Ross 
19108329232eSGordon Ross 	return (stf);
19118329232eSGordon Ross }
19128329232eSGordon Ross 
19138329232eSGordon Ross // vfsstray_sync
19148329232eSGordon Ross // vfsstray
19158329232eSGordon Ross // vfs_EIO
19168329232eSGordon Ross // vfs_EIO_sync
19178329232eSGordon Ross // EIO_vfs
19188329232eSGordon Ross // EIO_vfsops
19198329232eSGordon Ross 
19208329232eSGordon Ross #pragma init(vfsinit)
19218329232eSGordon Ross 
19228329232eSGordon Ross /*
19238329232eSGordon Ross  * Called from startup() to initialize all loaded vfs's
19248329232eSGordon Ross  */
19258329232eSGordon Ross void
vfsinit(void)19268329232eSGordon Ross vfsinit(void)
19278329232eSGordon Ross {
19288329232eSGordon Ross 	vn_create_cache();
19298329232eSGordon Ross 
19308329232eSGordon Ross 	/* Temporary, until we mount root */
19318329232eSGordon Ross 	rootdir = vn_alloc(KM_SLEEP);
19328329232eSGordon Ross 	rootdir->v_type = VDIR;
19338329232eSGordon Ross }
19348329232eSGordon Ross 
19358329232eSGordon Ross vfs_t *
vfs_alloc(int kmflag)19368329232eSGordon Ross vfs_alloc(int kmflag)
19378329232eSGordon Ross {
19388329232eSGordon Ross 	vfs_t *vfsp;
19398329232eSGordon Ross 
19408329232eSGordon Ross 	vfsp = kmem_alloc(sizeof (struct vfs), kmflag);
19418329232eSGordon Ross 
19428329232eSGordon Ross 	/*
19438329232eSGordon Ross 	 * Do the simplest initialization here.
19448329232eSGordon Ross 	 * Everything else gets done in vfs_init()
19458329232eSGordon Ross 	 */
19468329232eSGordon Ross 	bzero(vfsp, sizeof (vfs_t));
19478329232eSGordon Ross 	return (vfsp);
19488329232eSGordon Ross }
19498329232eSGordon Ross 
19508329232eSGordon Ross void
vfs_free(vfs_t * vfsp)19518329232eSGordon Ross vfs_free(vfs_t *vfsp)
19528329232eSGordon Ross {
19538329232eSGordon Ross 	/*
19548329232eSGordon Ross 	 * One would be tempted to assert that "vfsp->vfs_count == 0".
19558329232eSGordon Ross 	 * Don't.  See fs/vfs.c
19568329232eSGordon Ross 	 */
19578329232eSGordon Ross 
19588329232eSGordon Ross 	/* If FEM was in use, make sure everything gets cleaned up */
19598329232eSGordon Ross 
19608329232eSGordon Ross 	if (vfsp->vfs_implp)
19618329232eSGordon Ross 		vfsimpl_teardown(vfsp);
19628329232eSGordon Ross 	sema_destroy(&vfsp->vfs_reflock);
19638329232eSGordon Ross 	kmem_free(vfsp, sizeof (struct vfs));
19648329232eSGordon Ross }
19658329232eSGordon Ross 
19668329232eSGordon Ross /*
19678329232eSGordon Ross  * Increments the vfs reference count by one atomically.
19688329232eSGordon Ross  */
19698329232eSGordon Ross void
vfs_hold(vfs_t * vfsp)19708329232eSGordon Ross vfs_hold(vfs_t *vfsp)
19718329232eSGordon Ross {
19728329232eSGordon Ross 	atomic_inc_32(&vfsp->vfs_count);
19738329232eSGordon Ross 	ASSERT(vfsp->vfs_count != 0);
19748329232eSGordon Ross }
19758329232eSGordon Ross 
19768329232eSGordon Ross /*
19778329232eSGordon Ross  * Decrements the vfs reference count by one atomically. When
19788329232eSGordon Ross  * vfs reference count becomes zero, it calls the file system
19798329232eSGordon Ross  * specific vfs_freevfs() to free up the resources.
19808329232eSGordon Ross  */
19818329232eSGordon Ross void
vfs_rele(vfs_t * vfsp)19828329232eSGordon Ross vfs_rele(vfs_t *vfsp)
19838329232eSGordon Ross {
19848329232eSGordon Ross 	ASSERT(vfsp->vfs_count != 0);
19858329232eSGordon Ross 	if (atomic_dec_32_nv(&vfsp->vfs_count) == 0) {
19868329232eSGordon Ross 		VFS_FREEVFS(vfsp);
19878329232eSGordon Ross 		// lofi_remove(vfsp);
19888329232eSGordon Ross 		// zone_rele_ref...
19898329232eSGordon Ross 		// vfs_freemnttab(vfsp);
19908329232eSGordon Ross 		vfs_free(vfsp);
19918329232eSGordon Ross 	}
19928329232eSGordon Ross }
19938329232eSGordon Ross 
19948329232eSGordon Ross /*
19958329232eSGordon Ross  * Generic operations vector support.
19968329232eSGordon Ross  */
19978329232eSGordon Ross 
19988329232eSGordon Ross int
fs_build_vector(void * vector,int * unused_ops,const fs_operation_trans_def_t * translation,const fs_operation_def_t * operations)19998329232eSGordon Ross fs_build_vector(void *vector, int *unused_ops,
20008329232eSGordon Ross     const fs_operation_trans_def_t *translation,
20018329232eSGordon Ross     const fs_operation_def_t *operations)
20028329232eSGordon Ross {
20038329232eSGordon Ross 	int i, num_trans, num_ops, used;
20048329232eSGordon Ross 
20058329232eSGordon Ross 	/*
20068329232eSGordon Ross 	 * Count the number of translations and the number of supplied
20078329232eSGordon Ross 	 * operations.
20088329232eSGordon Ross 	 */
20098329232eSGordon Ross 
20108329232eSGordon Ross 	{
20118329232eSGordon Ross 		const fs_operation_trans_def_t *p;
20128329232eSGordon Ross 
20138329232eSGordon Ross 		for (num_trans = 0, p = translation;
20148329232eSGordon Ross 		    p->name != NULL;
20158329232eSGordon Ross 		    num_trans++, p++)
20168329232eSGordon Ross 			;
20178329232eSGordon Ross 	}
20188329232eSGordon Ross 
20198329232eSGordon Ross 	{
20208329232eSGordon Ross 		const fs_operation_def_t *p;
20218329232eSGordon Ross 
20228329232eSGordon Ross 		for (num_ops = 0, p = operations;
20238329232eSGordon Ross 		    p->name != NULL;
20248329232eSGordon Ross 		    num_ops++, p++)
20258329232eSGordon Ross 			;
20268329232eSGordon Ross 	}
20278329232eSGordon Ross 
20288329232eSGordon Ross 	/* Walk through each operation known to our caller.  There will be */
20298329232eSGordon Ross 	/* one entry in the supplied "translation table" for each. */
20308329232eSGordon Ross 
20318329232eSGordon Ross 	used = 0;
20328329232eSGordon Ross 
20338329232eSGordon Ross 	for (i = 0; i < num_trans; i++) {
20348329232eSGordon Ross 		int j, found;
20358329232eSGordon Ross 		char *curname;
20368329232eSGordon Ross 		fs_generic_func_p result;
20378329232eSGordon Ross 		fs_generic_func_p *location;
20388329232eSGordon Ross 
20398329232eSGordon Ross 		curname = translation[i].name;
20408329232eSGordon Ross 
20418329232eSGordon Ross 		/* Look for a matching operation in the list supplied by the */
20428329232eSGordon Ross 		/* file system. */
20438329232eSGordon Ross 
20448329232eSGordon Ross 		found = 0;
20458329232eSGordon Ross 
20468329232eSGordon Ross 		for (j = 0; j < num_ops; j++) {
20478329232eSGordon Ross 			if (strcmp(operations[j].name, curname) == 0) {
20488329232eSGordon Ross 				used++;
20498329232eSGordon Ross 				found = 1;
20508329232eSGordon Ross 				break;
20518329232eSGordon Ross 			}
20528329232eSGordon Ross 		}
20538329232eSGordon Ross 
20548329232eSGordon Ross 		/*
20558329232eSGordon Ross 		 * If the file system is using a "placeholder" for default
20568329232eSGordon Ross 		 * or error functions, grab the appropriate function out of
20578329232eSGordon Ross 		 * the translation table.  If the file system didn't supply
20588329232eSGordon Ross 		 * this operation at all, use the default function.
20598329232eSGordon Ross 		 */
20608329232eSGordon Ross 
20618329232eSGordon Ross 		if (found) {
20628329232eSGordon Ross 			result = operations[j].func.fs_generic;
20638329232eSGordon Ross 			if (result == fs_default) {
20648329232eSGordon Ross 				result = translation[i].defaultFunc;
20658329232eSGordon Ross 			} else if (result == fs_error) {
20668329232eSGordon Ross 				result = translation[i].errorFunc;
20678329232eSGordon Ross 			} else if (result == NULL) {
20688329232eSGordon Ross 				/* Null values are PROHIBITED */
20698329232eSGordon Ross 				return (EINVAL);
20708329232eSGordon Ross 			}
20718329232eSGordon Ross 		} else {
20728329232eSGordon Ross 			result = translation[i].defaultFunc;
20738329232eSGordon Ross 		}
20748329232eSGordon Ross 
20758329232eSGordon Ross 		/* Now store the function into the operations vector. */
20768329232eSGordon Ross 
20778329232eSGordon Ross 		/* LINTED E_BAD_PTR_CAST_ALIGN */
20788329232eSGordon Ross 		location = (fs_generic_func_p *)
20798329232eSGordon Ross 		    (((char *)vector) + translation[i].offset);
20808329232eSGordon Ross 
20818329232eSGordon Ross 		*location = result;
20828329232eSGordon Ross 	}
20838329232eSGordon Ross 
20848329232eSGordon Ross 	*unused_ops = num_ops - used;
20858329232eSGordon Ross 
20868329232eSGordon Ross 	return (0);
20878329232eSGordon Ross }
20888329232eSGordon Ross 
20898329232eSGordon Ross /* Placeholder functions, should never be called. */
20908329232eSGordon Ross 
20918329232eSGordon Ross int
fs_error(void)20928329232eSGordon Ross fs_error(void)
20938329232eSGordon Ross {
20948329232eSGordon Ross 	cmn_err(CE_PANIC, "fs_error called");
20958329232eSGordon Ross 	return (0);
20968329232eSGordon Ross }
20978329232eSGordon Ross 
20988329232eSGordon Ross int
fs_default(void)20998329232eSGordon Ross fs_default(void)
21008329232eSGordon Ross {
21018329232eSGordon Ross 	cmn_err(CE_PANIC, "fs_default called");
21028329232eSGordon Ross 	return (0);
21038329232eSGordon Ross }
21048329232eSGordon Ross 
21058329232eSGordon Ross // rootconf
21068329232eSGordon Ross // getfsname
21078329232eSGordon Ross // getrootfs
21088329232eSGordon Ross 
21098329232eSGordon Ross /*
21108329232eSGordon Ross  * VFS feature routines
21118329232eSGordon Ross  */
21128329232eSGordon Ross 
21138329232eSGordon Ross #define	VFTINDEX(feature)	(((feature) >> 32) & 0xFFFFFFFF)
21148329232eSGordon Ross #define	VFTBITS(feature)	((feature) & 0xFFFFFFFFLL)
21158329232eSGordon Ross 
21168329232eSGordon Ross /* Register a feature in the vfs */
21178329232eSGordon Ross void
vfs_set_feature(vfs_t * vfsp,vfs_feature_t feature)21188329232eSGordon Ross vfs_set_feature(vfs_t *vfsp, vfs_feature_t feature)
21198329232eSGordon Ross {
21208329232eSGordon Ross 	/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
21218329232eSGordon Ross 	if (vfsp->vfs_implp == NULL)
21228329232eSGordon Ross 		return;
21238329232eSGordon Ross 
21248329232eSGordon Ross 	vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature);
21258329232eSGordon Ross }
21268329232eSGordon Ross 
21278329232eSGordon Ross void
vfs_clear_feature(vfs_t * vfsp,vfs_feature_t feature)21288329232eSGordon Ross vfs_clear_feature(vfs_t *vfsp, vfs_feature_t feature)
21298329232eSGordon Ross {
21308329232eSGordon Ross 	/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
21318329232eSGordon Ross 	if (vfsp->vfs_implp == NULL)
21328329232eSGordon Ross 		return;
21338329232eSGordon Ross 	vfsp->vfs_featureset[VFTINDEX(feature)] &= VFTBITS(~feature);
21348329232eSGordon Ross }
21358329232eSGordon Ross 
21368329232eSGordon Ross /*
21378329232eSGordon Ross  * Query a vfs for a feature.
21388329232eSGordon Ross  * Returns 1 if feature is present, 0 if not
21398329232eSGordon Ross  */
21408329232eSGordon Ross int
vfs_has_feature(vfs_t * vfsp,vfs_feature_t feature)21418329232eSGordon Ross vfs_has_feature(vfs_t *vfsp, vfs_feature_t feature)
21428329232eSGordon Ross {
21438329232eSGordon Ross 	int	ret = 0;
21448329232eSGordon Ross 
21458329232eSGordon Ross 	/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
21468329232eSGordon Ross 	if (vfsp->vfs_implp == NULL)
21478329232eSGordon Ross 		return (ret);
21488329232eSGordon Ross 
21498329232eSGordon Ross 	if (vfsp->vfs_featureset[VFTINDEX(feature)] & VFTBITS(feature))
21508329232eSGordon Ross 		ret = 1;
21518329232eSGordon Ross 
21528329232eSGordon Ross 	return (ret);
21538329232eSGordon Ross }
21548329232eSGordon Ross 
21558329232eSGordon Ross // vfs_propagate_features
21568329232eSGordon Ross // vfs_get_lofi
2157