18329232Gordon Ross/*
28329232Gordon Ross * CDDL HEADER START
38329232Gordon Ross *
48329232Gordon Ross * The contents of this file are subject to the terms of the
58329232Gordon Ross * Common Development and Distribution License (the "License").
68329232Gordon Ross * You may not use this file except in compliance with the License.
78329232Gordon Ross *
88329232Gordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98329232Gordon Ross * or http://www.opensolaris.org/os/licensing.
108329232Gordon Ross * See the License for the specific language governing permissions
118329232Gordon Ross * and limitations under the License.
128329232Gordon Ross *
138329232Gordon Ross * When distributing Covered Code, include this CDDL HEADER in each
148329232Gordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158329232Gordon Ross * If applicable, add the following below this CDDL HEADER, with the
168329232Gordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
178329232Gordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
188329232Gordon Ross *
198329232Gordon Ross * CDDL HEADER END
208329232Gordon Ross */
218329232Gordon Ross
228329232Gordon Ross/*
238329232Gordon Ross * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
248329232Gordon Ross * Copyright 2016 Joyent, Inc.
258329232Gordon Ross * Copyright 2016 Toomas Soome <tsoome@me.com>
268329232Gordon Ross * Copyright (c) 2016 by Delphix. All rights reserved.
278329232Gordon Ross * Copyright 2017 RackTop Systems.
288329232Gordon Ross * Copyright 2018 Nexenta Systems, Inc.
298329232Gordon Ross */
308329232Gordon Ross
318329232Gordon Ross/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
328329232Gordon Ross/*	  All Rights Reserved	*/
338329232Gordon Ross
348329232Gordon Ross/*
358329232Gordon Ross * University Copyright- Copyright (c) 1982, 1986, 1988
368329232Gordon Ross * The Regents of the University of California
378329232Gordon Ross * All Rights Reserved
388329232Gordon Ross *
398329232Gordon Ross * University Acknowledgment- Portions of this document are derived from
408329232Gordon Ross * software developed by the University of California, Berkeley, and its
418329232Gordon Ross * contributors.
428329232Gordon Ross */
438329232Gordon Ross
448329232Gordon Ross/*
458329232Gordon Ross * This file contains those functions from fs/vfs.c that can be
468329232Gordon Ross * used with relatively little change.  Functions that differ
478329232Gordon Ross * significantly from that are in other files.
488329232Gordon Ross */
498329232Gordon Ross
508329232Gordon Ross#include <sys/types.h>
518329232Gordon Ross#include <sys/t_lock.h>
528329232Gordon Ross#include <sys/param.h>
538329232Gordon Ross#include <sys/errno.h>
548329232Gordon Ross#include <sys/user.h>
558329232Gordon Ross#include <sys/fstyp.h>
568329232Gordon Ross#include <sys/kmem.h>
578329232Gordon Ross#include <sys/systm.h>
588329232Gordon Ross#include <sys/proc.h>
598329232Gordon Ross#include <sys/mount.h>
608329232Gordon Ross#include <sys/vfs.h>
618329232Gordon Ross#include <sys/vfs_opreg.h>
628329232Gordon Ross#include <sys/fem.h>
638329232Gordon Ross#include <sys/mntent.h>
648329232Gordon Ross#include <sys/stat.h>
658329232Gordon Ross#include <sys/statvfs.h>
668329232Gordon Ross#include <sys/statfs.h>
678329232Gordon Ross#include <sys/cred.h>
688329232Gordon Ross#include <sys/vnode.h>
698329232Gordon Ross#include <sys/rwstlock.h>
708329232Gordon Ross#include <sys/dnlc.h>
718329232Gordon Ross#include <sys/file.h>
728329232Gordon Ross#include <sys/time.h>
738329232Gordon Ross#include <sys/atomic.h>
748329232Gordon Ross#include <sys/cmn_err.h>
758329232Gordon Ross#include <sys/buf.h>
768329232Gordon Ross#include <sys/debug.h>
778329232Gordon Ross#include <sys/vnode.h>
788329232Gordon Ross#include <sys/ddi.h>
798329232Gordon Ross#include <sys/pathname.h>
808329232Gordon Ross#include <sys/poll.h>
818329232Gordon Ross#include <sys/sunddi.h>
828329232Gordon Ross#include <sys/sysmacros.h>
838329232Gordon Ross#include <sys/zone.h>
848329232Gordon Ross#include <sys/policy.h>
858329232Gordon Ross#include <sys/attr.h>
868329232Gordon Ross#include <fs/fs_subr.h>
878329232Gordon Ross
888329232Gordon Ross#include <libfksmbfs.h>
898329232Gordon Ross
908329232Gordon Rossstatic void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
918329232Gordon Rossstatic void vfs_setmntopt_nolock(mntopts_t *, const char *,
928329232Gordon Ross    const char *, int, int);
938329232Gordon Rossstatic int  vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
948329232Gordon Ross// static void vfs_freemnttab(struct vfs *);
958329232Gordon Rossstatic void vfs_freeopt(mntopt_t *);
968329232Gordon Rossstatic void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
978329232Gordon Rossstatic void vfs_swapopttbl(mntopts_t *, mntopts_t *);
988329232Gordon Rossstatic void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
998329232Gordon Ross// static void vfs_createopttbl_extend(mntopts_t *, const char *,
1008329232Gordon Ross//    const mntopts_t *);
1018329232Gordon Ross// static char **vfs_copycancelopt_extend(char **const, int);
1028329232Gordon Rossstatic void vfs_freecancelopt(char **);
1038329232Gordon Ross
1048329232Gordon Ross/*
1058329232Gordon Ross * VFS global data.
1068329232Gordon Ross */
1078329232Gordon Rossvnode_t *rootdir;		/* pointer to root inode vnode. */
1088329232Gordon Rossstruct vfs *rootvfs = NULL;	/* pointer to root vfs; head of VFS list. */
1098329232Gordon Rossstatic krwlock_t vfslist;
1108329232Gordon Rossstruct vfs	*zone_vfslist;	/* list of FS's mounted in zone */
1118329232Gordon Ross
1128329232Gordon Ross/* from os/vfs_conf.c */
1138329232Gordon Rossconst int nfstype = 5;
1148329232Gordon Rossstruct vfssw vfssw[10] = {
1158329232Gordon Ross	{ "BADVFS" },				/* 0:invalid */
1168329232Gordon Ross	{ "" },					/* reserved for loadable fs */
1178329232Gordon Ross	{ "" },
1188329232Gordon Ross	{ "" },
1198329232Gordon Ross	{ "" },
1208329232Gordon Ross};
1218329232Gordon Ross
1228329232Gordon Ross/*
1238329232Gordon Ross * Table for generic options recognized in the VFS layer and acted
1248329232Gordon Ross * on at this level before parsing file system specific options.
1258329232Gordon Ross * The nosuid option is stronger than any of the devices and setuid
1268329232Gordon Ross * options, so those are canceled when nosuid is seen.
1278329232Gordon Ross *
1288329232Gordon Ross * All options which are added here need to be added to the
1298329232Gordon Ross * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
1308329232Gordon Ross */
1318329232Gordon Ross/*
1328329232Gordon Ross * VFS Mount options table
1338329232Gordon Ross */
1348329232Gordon Rossstatic char *ro_cancel[] = { MNTOPT_RW, NULL };
1358329232Gordon Rossstatic char *rw_cancel[] = { MNTOPT_RO, NULL };
1368329232Gordon Rossstatic char *suid_cancel[] = { MNTOPT_NOSUID, NULL };
1378329232Gordon Rossstatic char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES,
1388329232Gordon Ross    MNTOPT_NOSETUID, MNTOPT_SETUID, NULL };
1398329232Gordon Rossstatic char *devices_cancel[] = { MNTOPT_NODEVICES, NULL };
1408329232Gordon Rossstatic char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL };
1418329232Gordon Rossstatic char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL };
1428329232Gordon Rossstatic char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL };
1438329232Gordon Rossstatic char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL };
1448329232Gordon Rossstatic char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL };
1458329232Gordon Rossstatic char *exec_cancel[] = { MNTOPT_NOEXEC, NULL };
1468329232Gordon Rossstatic char *noexec_cancel[] = { MNTOPT_EXEC, NULL };
1478329232Gordon Ross
1488329232Gordon Rossstatic const mntopt_t mntopts[] = {
1498329232Gordon Ross/*
1508329232Gordon Ross *	option name		cancel options		default arg	flags
1518329232Gordon Ross */
1528329232Gordon Ross	{ MNTOPT_REMOUNT,	NULL,			NULL,
1538329232Gordon Ross		MO_NODISPLAY, (void *)0 },
1548329232Gordon Ross	{ MNTOPT_RO,		ro_cancel,		NULL,		0,
1558329232Gordon Ross		(void *)0 },
1568329232Gordon Ross	{ MNTOPT_RW,		rw_cancel,		NULL,		0,
1578329232Gordon Ross		(void *)0 },
1588329232Gordon Ross	{ MNTOPT_SUID,		suid_cancel,		NULL,		0,
1598329232Gordon Ross		(void *)0 },
1608329232Gordon Ross	{ MNTOPT_NOSUID,	nosuid_cancel,		NULL,		0,
1618329232Gordon Ross		(void *)0 },
1628329232Gordon Ross	{ MNTOPT_DEVICES,	devices_cancel,		NULL,		0,
1638329232Gordon Ross		(void *)0 },
1648329232Gordon Ross	{ MNTOPT_NODEVICES,	nodevices_cancel,	NULL,		0,
1658329232Gordon Ross		(void *)0 },
1668329232Gordon Ross	{ MNTOPT_SETUID,	setuid_cancel,		NULL,		0,
1678329232Gordon Ross		(void *)0 },
1688329232Gordon Ross	{ MNTOPT_NOSETUID,	nosetuid_cancel,	NULL,		0,
1698329232Gordon Ross		(void *)0 },
1708329232Gordon Ross	{ MNTOPT_NBMAND,	nbmand_cancel,		NULL,		0,
1718329232Gordon Ross		(void *)0 },
1728329232Gordon Ross	{ MNTOPT_NONBMAND,	nonbmand_cancel,	NULL,		0,
1738329232Gordon Ross		(void *)0 },
1748329232Gordon Ross	{ MNTOPT_EXEC,		exec_cancel,		NULL,		0,
1758329232Gordon Ross		(void *)0 },
1768329232Gordon Ross	{ MNTOPT_NOEXEC,	noexec_cancel,		NULL,		0,
1778329232Gordon Ross		(void *)0 },
1788329232Gordon Ross};
1798329232Gordon Ross
1808329232Gordon Rossconst mntopts_t vfs_mntopts = {
1818329232Gordon Ross	sizeof (mntopts) / sizeof (mntopt_t),
1828329232Gordon Ross	(mntopt_t *)&mntopts[0]
1838329232Gordon Ross};
1848329232Gordon Ross
1858329232Gordon Ross/*
1868329232Gordon Ross * File system operation dispatch functions.
1878329232Gordon Ross */
1888329232Gordon Ross
1898329232Gordon Rossint
1908329232Gordon Rossfsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
1918329232Gordon Ross{
1928329232Gordon Ross	return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr);
1938329232Gordon Ross}
1948329232Gordon Ross
1958329232Gordon Rossint
1968329232Gordon Rossfsop_unmount(vfs_t *vfsp, int flag, cred_t *cr)
1978329232Gordon Ross{
1988329232Gordon Ross	return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr);
1998329232Gordon Ross}
2008329232Gordon Ross
2018329232Gordon Rossint
2028329232Gordon Rossfsop_root(vfs_t *vfsp, vnode_t **vpp)
2038329232Gordon Ross{
2048329232Gordon Ross	return ((*(vfsp)->vfs_op->vfs_root)(vfsp, vpp));
2058329232Gordon Ross}
2068329232Gordon Ross
2078329232Gordon Rossint
2088329232Gordon Rossfsop_statfs(vfs_t *vfsp, statvfs64_t *sp)
2098329232Gordon Ross{
2108329232Gordon Ross	return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp);
2118329232Gordon Ross}
2128329232Gordon Ross
2138329232Gordon Rossint
2148329232Gordon Rossfsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
2158329232Gordon Ross{
2168329232Gordon Ross	return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr);
2178329232Gordon Ross}
2188329232Gordon Ross
2198329232Gordon Rossint
2208329232Gordon Rossfsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
2218329232Gordon Ross{
2228329232Gordon Ross	return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
2238329232Gordon Ross}
2248329232Gordon Ross
2258329232Gordon Rossint
2268329232Gordon Rossfsop_mountroot(vfs_t *vfsp, enum whymountroot reason)
2278329232Gordon Ross{
2288329232Gordon Ross	return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason);
2298329232Gordon Ross}
2308329232Gordon Ross
2318329232Gordon Rossvoid
2328329232Gordon Rossfsop_freefs(vfs_t *vfsp)
2338329232Gordon Ross{
2348329232Gordon Ross	(*(vfsp)->vfs_op->vfs_freevfs)(vfsp);
2358329232Gordon Ross}
2368329232Gordon Ross
2378329232Gordon Rossint
2388329232Gordon Rossfsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
2398329232Gordon Ross{
2408329232Gordon Ross	return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate));
2418329232Gordon Ross}
2428329232Gordon Ross
2438329232Gordon Rossint
2448329232Gordon Rossfsop_sync_by_kind(int fstype, short flag, cred_t *cr)
2458329232Gordon Ross{
2468329232Gordon Ross	ASSERT((fstype >= 0) && (fstype < nfstype));
2478329232Gordon Ross
2488329232Gordon Ross	if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype]))
2498329232Gordon Ross		return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr);
2508329232Gordon Ross	else
2518329232Gordon Ross		return (ENOTSUP);
2528329232Gordon Ross}
2538329232Gordon Ross
2548329232Gordon Ross/*
2558329232Gordon Ross * File system initialization.  vfs_setfsops() must be called from a file
2568329232Gordon Ross * system's init routine.
2578329232Gordon Ross */
2588329232Gordon Ross
2598329232Gordon Rossstatic int
2608329232Gordon Rossfs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual,
2618329232Gordon Ross    int *unused_ops)
2628329232Gordon Ross{
2638329232Gordon Ross	static const fs_operation_trans_def_t vfs_ops_table[] = {
2648329232Gordon Ross		VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount),
2658329232Gordon Ross			fs_nosys, fs_nosys,
2668329232Gordon Ross
2678329232Gordon Ross		VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount),
2688329232Gordon Ross			fs_nosys, fs_nosys,
2698329232Gordon Ross
2708329232Gordon Ross		VFSNAME_ROOT, offsetof(vfsops_t, vfs_root),
2718329232Gordon Ross			fs_nosys, fs_nosys,
2728329232Gordon Ross
2738329232Gordon Ross		VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs),
2748329232Gordon Ross			fs_nosys, fs_nosys,
2758329232Gordon Ross
2768329232Gordon Ross		VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync),
2778329232Gordon Ross			(fs_generic_func_p) fs_sync,
2788329232Gordon Ross			(fs_generic_func_p) fs_sync,	/* No errors allowed */
2798329232Gordon Ross
2808329232Gordon Ross		VFSNAME_VGET, offsetof(vfsops_t, vfs_vget),
2818329232Gordon Ross			fs_nosys, fs_nosys,
2828329232Gordon Ross
2838329232Gordon Ross		VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot),
2848329232Gordon Ross			fs_nosys, fs_nosys,
2858329232Gordon Ross
2868329232Gordon Ross		VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs),
2878329232Gordon Ross			(fs_generic_func_p)fs_freevfs,
2888329232Gordon Ross			(fs_generic_func_p)fs_freevfs,	/* Shouldn't fail */
2898329232Gordon Ross
2908329232Gordon Ross		VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate),
2918329232Gordon Ross			(fs_generic_func_p)fs_nosys,
2928329232Gordon Ross			(fs_generic_func_p)fs_nosys,
2938329232Gordon Ross
2948329232Gordon Ross		NULL, 0, NULL, NULL
2958329232Gordon Ross	};
2968329232Gordon Ross
2978329232Gordon Ross	return (fs_build_vector(actual, unused_ops, vfs_ops_table, template));
2988329232Gordon Ross}
2998329232Gordon Ross
3008329232Gordon Ross/* zfs_boot_init() */
3018329232Gordon Ross
3028329232Gordon Rossint
3038329232Gordon Rossvfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual)
3048329232Gordon Ross{
3058329232Gordon Ross	int error;
3068329232Gordon Ross	int unused_ops;
3078329232Gordon Ross
3088329232Gordon Ross	/*
3098329232Gordon Ross	 * Verify that fstype refers to a valid fs.  Note that
3108329232Gordon Ross	 * 0 is valid since it's used to set "stray" ops.
3118329232Gordon Ross	 */
3128329232Gordon Ross	if ((fstype < 0) || (fstype >= nfstype))
3138329232Gordon Ross		return (EINVAL);
3148329232Gordon Ross
3158329232Gordon Ross	if (!ALLOCATED_VFSSW(&vfssw[fstype]))
3168329232Gordon Ross		return (EINVAL);
3178329232Gordon Ross
3188329232Gordon Ross	/* Set up the operations vector. */
3198329232Gordon Ross
3208329232Gordon Ross	error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops);
3218329232Gordon Ross
3228329232Gordon Ross	if (error != 0)
3238329232Gordon Ross		return (error);
3248329232Gordon Ross
3258329232Gordon Ross	vfssw[fstype].vsw_flag |= VSW_INSTALLED;
3268329232Gordon Ross
3278329232Gordon Ross	if (actual != NULL)
3288329232Gordon Ross		*actual = &vfssw[fstype].vsw_vfsops;
3298329232Gordon Ross
3308329232Gordon Ross#if DEBUG
3318329232Gordon Ross	if (unused_ops != 0)
3328329232Gordon Ross		cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied "
3338329232Gordon Ross		    "but not used", vfssw[fstype].vsw_name, unused_ops);
3348329232Gordon Ross#endif
3358329232Gordon Ross
3368329232Gordon Ross	return (0);
3378329232Gordon Ross}
3388329232Gordon Ross
3398329232Gordon Rossint
3408329232Gordon Rossvfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual)
3418329232Gordon Ross{
3428329232Gordon Ross	int error;
3438329232Gordon Ross	int unused_ops;
3448329232Gordon Ross
3458329232Gordon Ross	*actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP);
3468329232Gordon Ross
3478329232Gordon Ross	error = fs_copyfsops(template, *actual, &unused_ops);
3488329232Gordon Ross	if (error != 0) {
3498329232Gordon Ross		kmem_free(*actual, sizeof (vfsops_t));
3508329232Gordon Ross		*actual = NULL;
3518329232Gordon Ross		return (error);
3528329232Gordon Ross	}
3538329232Gordon Ross
3548329232Gordon Ross	return (0);
3558329232Gordon Ross}
3568329232Gordon Ross
3578329232Gordon Ross/*
3588329232Gordon Ross * Free a vfsops structure created as a result of vfs_makefsops().
3598329232Gordon Ross * NOTE: For a vfsops structure initialized by vfs_setfsops(), use
3608329232Gordon Ross * vfs_freevfsops_by_type().
3618329232Gordon Ross */
3628329232Gordon Rossvoid
3638329232Gordon Rossvfs_freevfsops(vfsops_t *vfsops)
3648329232Gordon Ross{
3658329232Gordon Ross	kmem_free(vfsops, sizeof (vfsops_t));
3668329232Gordon Ross}
3678329232Gordon Ross
3688329232Gordon Ross/*
3698329232Gordon Ross * Since the vfsops structure is part of the vfssw table and wasn't
3708329232Gordon Ross * really allocated, we're not really freeing anything.  We keep
3718329232Gordon Ross * the name for consistency with vfs_freevfsops().  We do, however,
3728329232Gordon Ross * need to take care of a little bookkeeping.
3738329232Gordon Ross * NOTE: For a vfsops structure created by vfs_setfsops(), use
3748329232Gordon Ross * vfs_freevfsops_by_type().
3758329232Gordon Ross */
3768329232Gordon Rossint
3778329232Gordon Rossvfs_freevfsops_by_type(int fstype)
3788329232Gordon Ross{
3798329232Gordon Ross
3808329232Gordon Ross	/* Verify that fstype refers to a loaded fs (and not fsid 0). */
3818329232Gordon Ross	if ((fstype <= 0) || (fstype >= nfstype))
3828329232Gordon Ross		return (EINVAL);
3838329232Gordon Ross
3848329232Gordon Ross	WLOCK_VFSSW();
3858329232Gordon Ross	if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) {
3868329232Gordon Ross		WUNLOCK_VFSSW();
3878329232Gordon Ross		return (EINVAL);
3888329232Gordon Ross	}
3898329232Gordon Ross
3908329232Gordon Ross	vfssw[fstype].vsw_flag &= ~VSW_INSTALLED;
3918329232Gordon Ross	WUNLOCK_VFSSW();
3928329232Gordon Ross
3938329232Gordon Ross	return (0);
3948329232Gordon Ross}
3958329232Gordon Ross
3968329232Gordon Ross/* Support routines used to reference vfs_op */
3978329232Gordon Ross
3988329232Gordon Ross/* Set the operations vector for a vfs */
3998329232Gordon Rossvoid
4008329232Gordon Rossvfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
4018329232Gordon Ross{
4028329232Gordon Ross
4038329232Gordon Ross	ASSERT(vfsp != NULL);
4048329232Gordon Ross	ASSERT(vfsops != NULL);
4058329232Gordon Ross
4068329232Gordon Ross	vfsp->vfs_op = vfsops;
4078329232Gordon Ross}
4088329232Gordon Ross
4098329232Gordon Ross/* Retrieve the operations vector for a vfs */
4108329232Gordon Rossvfsops_t *
4118329232Gordon Rossvfs_getops(vfs_t *vfsp)
4128329232Gordon Ross{
4138329232Gordon Ross
4148329232Gordon Ross	ASSERT(vfsp != NULL);
4158329232Gordon Ross
4168329232Gordon Ross	return (vfsp->vfs_op);
4178329232Gordon Ross}
4188329232Gordon Ross
4198329232Gordon Ross/*
4208329232Gordon Ross * Returns non-zero (1) if the vfsops matches that of the vfs.
4218329232Gordon Ross * Returns zero (0) if not.
4228329232Gordon Ross */
4238329232Gordon Rossint
4248329232Gordon Rossvfs_matchops(vfs_t *vfsp, vfsops_t *vfsops)
4258329232Gordon Ross{
4268329232Gordon Ross	return (vfs_getops(vfsp) == vfsops);
4278329232Gordon Ross}
4288329232Gordon Ross
4298329232Gordon Ross/*
4308329232Gordon Ross * Returns non-zero (1) if the file system has installed a non-default,
4318329232Gordon Ross * non-error vfs_sync routine.  Returns zero (0) otherwise.
4328329232Gordon Ross */
4338329232Gordon Rossint
4348329232Gordon Rossvfs_can_sync(vfs_t *vfsp)
4358329232Gordon Ross{
4368329232Gordon Ross	/* vfs_sync() routine is not the default/error function */
4378329232Gordon Ross	return (vfs_getops(vfsp)->vfs_sync != fs_sync);
4388329232Gordon Ross}
4398329232Gordon Ross
4408329232Gordon Ross/*
4418329232Gordon Ross * Initialize a vfs structure.
4428329232Gordon Ross */
4438329232Gordon Rossvoid
4448329232Gordon Rossvfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
4458329232Gordon Ross{
4468329232Gordon Ross	/* Always do full init, like vfs_alloc() */
4478329232Gordon Ross	bzero(vfsp, sizeof (vfs_t));
4488329232Gordon Ross	vfsp->vfs_count = 0;
4498329232Gordon Ross	vfsp->vfs_next = vfsp;
4508329232Gordon Ross	vfsp->vfs_prev = vfsp;
4518329232Gordon Ross	vfsp->vfs_zone_next = vfsp;
4528329232Gordon Ross	vfsp->vfs_zone_prev = vfsp;
4538329232Gordon Ross	vfsp->vfs_lofi_id = 0;
4548329232Gordon Ross	sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
4558329232Gordon Ross	vfsimpl_setup(vfsp);
4568329232Gordon Ross	vfsp->vfs_data = (data);
4578329232Gordon Ross	vfs_setops((vfsp), (op));
4588329232Gordon Ross}
4598329232Gordon Ross
4608329232Gordon Ross/*
4618329232Gordon Ross * Allocate and initialize the vfs implementation private data
4628329232Gordon Ross * structure, vfs_impl_t.
4638329232Gordon Ross */
4648329232Gordon Rossvoid
4658329232Gordon Rossvfsimpl_setup(vfs_t *vfsp)
4668329232Gordon Ross{
4678329232Gordon Ross	int i;
4688329232Gordon Ross
4698329232Gordon Ross	if (vfsp->vfs_implp != NULL) {
4708329232Gordon Ross		return;
4718329232Gordon Ross	}
4728329232Gordon Ross
4738329232Gordon Ross	vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP);
4748329232Gordon Ross	/* Note that these are #define'd in vfs.h */
4758329232Gordon Ross	vfsp->vfs_vskap = NULL;
4768329232Gordon Ross	vfsp->vfs_fstypevsp = NULL;
4778329232Gordon Ross
4788329232Gordon Ross	/* Set size of counted array, then zero the array */
4798329232Gordon Ross	vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1;
4808329232Gordon Ross	for (i = 1; i <  VFS_FEATURE_MAXSZ; i++) {
4818329232Gordon Ross		vfsp->vfs_featureset[i] = 0;
4828329232Gordon Ross	}
4838329232Gordon Ross}
4848329232Gordon Ross
4858329232Gordon Ross/*
4868329232Gordon Ross * Release the vfs_impl_t structure, if it exists. Some unbundled
4878329232Gordon Ross * filesystems may not use the newer version of vfs and thus
4888329232Gordon Ross * would not contain this implementation private data structure.
4898329232Gordon Ross */
4908329232Gordon Rossvoid
4918329232Gordon Rossvfsimpl_teardown(vfs_t *vfsp)
4928329232Gordon Ross{
4938329232Gordon Ross	vfs_impl_t	*vip = vfsp->vfs_implp;
4948329232Gordon Ross
4958329232Gordon Ross	if (vip == NULL)
4968329232Gordon Ross		return;
4978329232Gordon Ross
4988329232Gordon Ross	kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t));
4998329232Gordon Ross	vfsp->vfs_implp = NULL;
5008329232Gordon Ross}
5018329232Gordon Ross
5028329232Gordon Ross/*
5038329232Gordon Ross * VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs,
5048329232Gordon Ross * fstatvfs, and sysfs moved to common/syscall.
5058329232Gordon Ross */
5068329232Gordon Ross
5078329232Gordon Ross// vfs_sync, sync
5088329232Gordon Ross
5098329232Gordon Ross/*
5108329232Gordon Ross * External routines.
5118329232Gordon Ross */
5128329232Gordon Ross
5138329232Gordon Rosskrwlock_t vfssw_lock;	/* lock accesses to vfssw */
5148329232Gordon Ross
5158329232Gordon Ross/*
5168329232Gordon Ross * Lock for accessing the vfs linked list.  Initialized in vfs_mountroot(),
5178329232Gordon Ross * but otherwise should be accessed only via vfs_list_lock() and
5188329232Gordon Ross * vfs_list_unlock().  Also used to protect the timestamp for mods to the list.
5198329232Gordon Ross */
5208329232Gordon Rossstatic krwlock_t vfslist;
5218329232Gordon Ross
5228329232Gordon Ross// vfs_mountdevices(void)
5238329232Gordon Ross// vfs_mountdev1(void)
5248329232Gordon Ross// vfs_mountfs()
5258329232Gordon Ross// vfs_mountroot()
5268329232Gordon Ross// lofi_add, lofi_remove
5278329232Gordon Ross
5288329232Gordon Ross
5298329232Gordon Ross/*
5308329232Gordon Ross * Mount the FS for the test jig.  Based on domount()
5318329232Gordon Ross */
5328329232Gordon Rossint
5338329232Gordon Rossfake_domount(char *fsname, struct mounta *uap, struct vfs **vfspp)
5348329232Gordon Ross{
5358329232Gordon Ross	vnode_t		*vp;
5368329232Gordon Ross	struct cred	*credp;
5378329232Gordon Ross	struct vfssw	*vswp;
5388329232Gordon Ross	vfsops_t	*vfsops;
5398329232Gordon Ross	struct vfs	*vfsp = NULL;
5408329232Gordon Ross	mntopts_t	mnt_mntopts;
5418329232Gordon Ross	int		error = 0;
5428329232Gordon Ross	int		copyout_error = 0;
5438329232Gordon Ross	char		*opts = uap->optptr;
5448329232Gordon Ross	char		*inargs = opts;
5458329232Gordon Ross	int		optlen = uap->optlen;
5468329232Gordon Ross
5478329232Gordon Ross	credp = CRED();
5488329232Gordon Ross
5498329232Gordon Ross	/*
5508329232Gordon Ross	 * Test jig specific: mount on rootdir
5518329232Gordon Ross	 */
5528329232Gordon Ross	if (rootvfs != NULL)
5538329232Gordon Ross		return (EBUSY);
5548329232Gordon Ross	vp = rootdir;
5558329232Gordon Ross
5568329232Gordon Ross	/*
5578329232Gordon Ross	 * The v_flag value for the mount point vp is permanently set
5588329232Gordon Ross	 * to VVFSLOCK so that no one bypasses the vn_vfs*locks routine
5598329232Gordon Ross	 * for mount point locking.
5608329232Gordon Ross	 */
5618329232Gordon Ross	mutex_enter(&vp->v_lock);
5628329232Gordon Ross	vp->v_flag |= VVFSLOCK;
5638329232Gordon Ross	mutex_exit(&vp->v_lock);
5648329232Gordon Ross
5658329232Gordon Ross	mnt_mntopts.mo_count = 0;
5668329232Gordon Ross
5678329232Gordon Ross	/*
5688329232Gordon Ross	 * Find the ops vector to use to invoke the file system-specific mount
5698329232Gordon Ross	 * method.  If the fsname argument is non-NULL, use it directly.
5708329232Gordon Ross	 */
5718329232Gordon Ross	if ((vswp = vfs_getvfssw(fsname)) == NULL) {
5728329232Gordon Ross		return (EINVAL);
5738329232Gordon Ross	}
5748329232Gordon Ross	if (!VFS_INSTALLED(vswp))
5758329232Gordon Ross		return (EINVAL);
5768329232Gordon Ross
5778329232Gordon Ross	// secpolicy_fs_allowed_mount(fsname)
5788329232Gordon Ross
5798329232Gordon Ross	vfsops = &vswp->vsw_vfsops;
5808329232Gordon Ross
5818329232Gordon Ross	vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts);
5828329232Gordon Ross
5838329232Gordon Ross	/*
5848329232Gordon Ross	 * Fetch mount options and parse them for generic vfs options
5858329232Gordon Ross	 */
5868329232Gordon Ross	if (uap->flags & MS_OPTIONSTR) {
5878329232Gordon Ross		/*
5888329232Gordon Ross		 * Limit the buffer size
5898329232Gordon Ross		 */
5908329232Gordon Ross		if (optlen < 0 || optlen > MAX_MNTOPT_STR) {
5918329232Gordon Ross			error = EINVAL;
5928329232Gordon Ross			goto errout;
5938329232Gordon Ross		}
5948329232Gordon Ross		if ((uap->flags & MS_SYSSPACE) == 0) {
5958329232Gordon Ross			inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
5968329232Gordon Ross			inargs[0] = '\0';
5978329232Gordon Ross			if (optlen) {
5988329232Gordon Ross				error = copyinstr(opts, inargs, (size_t)optlen,
5998329232Gordon Ross				    NULL);
6008329232Gordon Ross				if (error) {
6018329232Gordon Ross					goto errout;
6028329232Gordon Ross				}
6038329232Gordon Ross			}
6048329232Gordon Ross		}
6058329232Gordon Ross		vfs_parsemntopts(&mnt_mntopts, inargs, 0);
6068329232Gordon Ross	}
6078329232Gordon Ross	/*
6088329232Gordon Ross	 * Flag bits override the options string.
6098329232Gordon Ross	 */
6108329232Gordon Ross	if (uap->flags & MS_REMOUNT)
6118329232Gordon Ross		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0);
6128329232Gordon Ross	if (uap->flags & MS_RDONLY)
6138329232Gordon Ross		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0);
6148329232Gordon Ross	if (uap->flags & MS_NOSUID)
6158329232Gordon Ross		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
6168329232Gordon Ross
6178329232Gordon Ross	/*
6188329232Gordon Ross	 * Check if this is a remount; must be set in the option string and
6198329232Gordon Ross	 * the file system must support a remount option.
6208329232Gordon Ross	 */
6218329232Gordon Ross	if (vfs_optionisset_nolock(&mnt_mntopts,
6228329232Gordon Ross	    MNTOPT_REMOUNT, NULL)) {
6238329232Gordon Ross		/* disallow here */
6248329232Gordon Ross		error = ENOTSUP;
6258329232Gordon Ross		goto errout;
6268329232Gordon Ross	}
6278329232Gordon Ross
6288329232Gordon Ross	/*
6298329232Gordon Ross	 * uap->flags and vfs_optionisset() should agree.
6308329232Gordon Ross	 */
6318329232Gordon Ross	if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) {
6328329232Gordon Ross		uap->flags |= MS_RDONLY;
6338329232Gordon Ross	}
6348329232Gordon Ross	if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) {
6358329232Gordon Ross		uap->flags |= MS_NOSUID;
6368329232Gordon Ross	}
6378329232Gordon Ross	// nbmand ...
6388329232Gordon Ross
6398329232Gordon Ross	/*
6408329232Gordon Ross	 * If we are splicing the fs into the namespace,
6418329232Gordon Ross	 * perform mount point checks...
6428329232Gordon Ross	 * (always splice=0 here)
6438329232Gordon Ross	 */
6448329232Gordon Ross
6458329232Gordon Ross	if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) {
6468329232Gordon Ross		uap->dataptr = NULL;
6478329232Gordon Ross		uap->datalen = 0;
6488329232Gordon Ross	}
6498329232Gordon Ross
6508329232Gordon Ross	/*
6518329232Gordon Ross	 * If this is a remount, ... (never here)
6528329232Gordon Ross	 */
6538329232Gordon Ross	vfsp = vfs_alloc(KM_SLEEP);
6548329232Gordon Ross	VFS_INIT(vfsp, vfsops, NULL);
6558329232Gordon Ross
6568329232Gordon Ross	VFS_HOLD(vfsp);
6578329232Gordon Ross
6588329232Gordon Ross	// lofi_add(fsname, vfsp, &mnt_mntopts, uap)
6598329232Gordon Ross
6608329232Gordon Ross	/*
6618329232Gordon Ross	 * PRIV_SYS_MOUNT doesn't mean you can become root.
6628329232Gordon Ross	 */
6638329232Gordon Ross	uap->flags |= MS_NOSUID;
6648329232Gordon Ross	vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
6658329232Gordon Ross
6668329232Gordon Ross	/*
6678329232Gordon Ross	 * The vfs_reflock...
6688329232Gordon Ross	 */
6698329232Gordon Ross
6708329232Gordon Ross	/*
6718329232Gordon Ross	 * Lock the vfs...
6728329232Gordon Ross	 */
6738329232Gordon Ross	if ((error = vfs_lock(vfsp)) != 0) {
6748329232Gordon Ross		vfs_free(vfsp);
6758329232Gordon Ross		vfsp = NULL;
6768329232Gordon Ross		goto errout;
6778329232Gordon Ross	}
6788329232Gordon Ross
6798329232Gordon Ross	/*
6808329232Gordon Ross	 * Add device to mount in progress table...
6818329232Gordon Ross	 */
6828329232Gordon Ross	/*
6838329232Gordon Ross	 * Invalidate cached entry for the mount point.
6848329232Gordon Ross	 */
6858329232Gordon Ross
6868329232Gordon Ross	/*
6878329232Gordon Ross	 * If have an option string but the filesystem doesn't supply a
6888329232Gordon Ross	 * prototype options table, create a table...
6898329232Gordon Ross	 */
6908329232Gordon Ross
6918329232Gordon Ross	/*
6928329232Gordon Ross	 * Serialize with zone state transitions...
6938329232Gordon Ross	 */
6948329232Gordon Ross
6958329232Gordon Ross	// mount_in_progress(zone);
6968329232Gordon Ross
6978329232Gordon Ross	/*
6988329232Gordon Ross	 * Instantiate (or reinstantiate) the file system...
6998329232Gordon Ross	 */
7008329232Gordon Ross	vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
7018329232Gordon Ross
7028329232Gordon Ross	vfs_setresource(vfsp, uap->spec, 0);
7038329232Gordon Ross	vfs_setmntpoint(vfsp, uap->dir, 0);
7048329232Gordon Ross
7058329232Gordon Ross	/*
7068329232Gordon Ross	 * going to mount on this vnode, so notify.
7078329232Gordon Ross	 */
7088329232Gordon Ross	// vnevent_mountedover(vp, NULL);
7098329232Gordon Ross	error = VFS_MOUNT(vfsp, vp, uap, credp);
7108329232Gordon Ross
7118329232Gordon Ross	if (uap->flags & MS_RDONLY)
7128329232Gordon Ross		vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
7138329232Gordon Ross	if (uap->flags & MS_NOSUID)
7148329232Gordon Ross		vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
7158329232Gordon Ross	if (uap->flags & MS_GLOBAL)
7168329232Gordon Ross		vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
7178329232Gordon Ross
7188329232Gordon Ross	if (error) {
7198329232Gordon Ross		// lofi_remove(vfsp);
7208329232Gordon Ross
7218329232Gordon Ross		// (remount == 0)
7228329232Gordon Ross		vfs_unlock(vfsp);
7238329232Gordon Ross		// vfs_freemnttab(vfsp);
7248329232Gordon Ross		vfs_free(vfsp);
7258329232Gordon Ross		vfsp = NULL;
7268329232Gordon Ross	} else {
7278329232Gordon Ross		/*
7288329232Gordon Ross		 * Set the mount time to now
7298329232Gordon Ross		 */
7308329232Gordon Ross		// vfsp->vfs_mtime = ddi_get_time();
7318329232Gordon Ross		// if (remount) ...
7328329232Gordon Ross		// else if (splice) vfs_add(vp, vfsp, flags)
7338329232Gordon Ross		// else VFS_HOLD(vfsp);
7348329232Gordon Ross
7358329232Gordon Ross		/*
7368329232Gordon Ross		 * Test jig specific:
7378329232Gordon Ross		 * Do sort of like vfs_add for vp=rootdir
7388329232Gordon Ross		 * Already have hold on vp.
7398329232Gordon Ross		 */
7408329232Gordon Ross		vfsp->vfs_vnodecovered = vp;
7418329232Gordon Ross		vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
7428329232Gordon Ross		VFS_HOLD(vfsp);
7438329232Gordon Ross		rootvfs = vfsp;
7448329232Gordon Ross
7458329232Gordon Ross		/*
7468329232Gordon Ross		 * Set flags for global options encountered
7478329232Gordon Ross		 */
7488329232Gordon Ross		if (vfs_optionisset(vfsp, MNTOPT_RO, NULL))
7498329232Gordon Ross			vfsp->vfs_flag |= VFS_RDONLY;
7508329232Gordon Ross		else
7518329232Gordon Ross			vfsp->vfs_flag &= ~VFS_RDONLY;
7528329232Gordon Ross		if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) {
7538329232Gordon Ross			vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
7548329232Gordon Ross		} else {
7558329232Gordon Ross			if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL))
7568329232Gordon Ross				vfsp->vfs_flag |= VFS_NODEVICES;
7578329232Gordon Ross			else
7588329232Gordon Ross				vfsp->vfs_flag &= ~VFS_NODEVICES;
7598329232Gordon Ross			if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))
7608329232Gordon Ross				vfsp->vfs_flag |= VFS_NOSETUID;
7618329232Gordon Ross			else
7628329232Gordon Ross				vfsp->vfs_flag &= ~VFS_NOSETUID;
7638329232Gordon Ross		}
7648329232Gordon Ross		if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL))
7658329232Gordon Ross			vfsp->vfs_flag |= VFS_NBMAND;
7668329232Gordon Ross		else
7678329232Gordon Ross			vfsp->vfs_flag &= ~VFS_NBMAND;
7688329232Gordon Ross
7698329232Gordon Ross		if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL))
7708329232Gordon Ross			vfsp->vfs_flag |= VFS_XATTR;
7718329232Gordon Ross		else
7728329232Gordon Ross			vfsp->vfs_flag &= ~VFS_XATTR;
7738329232Gordon Ross
7748329232Gordon Ross		if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL))
7758329232Gordon Ross			vfsp->vfs_flag |= VFS_NOEXEC;
7768329232Gordon Ross		else
7778329232Gordon Ross			vfsp->vfs_flag &= ~VFS_NOEXEC;
7788329232Gordon Ross
7798329232Gordon Ross		/*
7808329232Gordon Ross		 * Now construct the output option string of options
7818329232Gordon Ross		 * we recognized.
7828329232Gordon Ross		 */
7838329232Gordon Ross		if (uap->flags & MS_OPTIONSTR) {
7848329232Gordon Ross			vfs_list_read_lock();
7858329232Gordon Ross			copyout_error = vfs_buildoptionstr(
7868329232Gordon Ross			    &vfsp->vfs_mntopts, inargs, optlen);
7878329232Gordon Ross			vfs_list_unlock();
7888329232Gordon Ross			if (copyout_error == 0 &&
7898329232Gordon Ross			    (uap->flags & MS_SYSSPACE) == 0) {
7908329232Gordon Ross				copyout_error = copyout(inargs, opts, optlen);
7918329232Gordon Ross			}
7928329232Gordon Ross		}
7938329232Gordon Ross
7948329232Gordon Ross		/*
7958329232Gordon Ross		 * If this isn't a remount, set up the vopstats...
7968329232Gordon Ross		 */
7978329232Gordon Ross		if (vswp->vsw_flag & VSW_XID)
7988329232Gordon Ross			vfsp->vfs_flag |= VFS_XID;
7998329232Gordon Ross
8008329232Gordon Ross		vfs_unlock(vfsp);
8018329232Gordon Ross
8028329232Gordon Ross		/*
8038329232Gordon Ross		 * Test jig specicific:
8048329232Gordon Ross		 * Replace rootdir with the mounted root.
8058329232Gordon Ross		 */
8068329232Gordon Ross		error = VFS_ROOT(vfsp, &rootdir);
8078329232Gordon Ross		if (error != 0) {
8088329232Gordon Ross			panic("fake_domount, get root %d\n", error);
8098329232Gordon Ross		}
8108329232Gordon Ross	}
8118329232Gordon Ross	// mount_completed(zone);
8128329232Gordon Ross	// zone_rele(zone);
8138329232Gordon Ross
8148329232Gordon Ross	// if (splice)
8158329232Gordon Ross	//	vn_vfsunlock(vp);
8168329232Gordon Ross
8178329232Gordon Ross	if ((error == 0) && (copyout_error == 0)) {
8188329232Gordon Ross		/* get_vskstat_anchor() */
8198329232Gordon Ross		/* Return vfsp to caller. */
8208329232Gordon Ross		*vfspp = vfsp;
8218329232Gordon Ross	}
8228329232Gordon Rosserrout:
8238329232Gordon Ross	vfs_freeopttbl(&mnt_mntopts);
8248329232Gordon Ross	/* resource, mountpt not allocated */
8258329232Gordon Ross	/* no addmip, delmip */
8268329232Gordon Ross	ASSERT(vswp != NULL);
8278329232Gordon Ross	vfs_unrefvfssw(vswp);
8288329232Gordon Ross	if (inargs != opts)
8298329232Gordon Ross		kmem_free(inargs, MAX_MNTOPT_STR);
8308329232Gordon Ross	if (copyout_error) {
8318329232Gordon Ross		if (vfsp != NULL) {
8328329232Gordon Ross			// lofi_remove(vfsp);
8338329232Gordon Ross			VFS_RELE(vfsp);
8348329232Gordon Ross		}
8358329232Gordon Ross		error = copyout_error;
8368329232Gordon Ross	}
8378329232Gordon Ross	return (error);
8388329232Gordon Ross}
8398329232Gordon Ross
8408329232Gordon Ross
8418329232Gordon Rossstatic void
8428329232Gordon Rossvfs_setpath(
8438329232Gordon Ross    struct vfs *vfsp,		/* vfs being updated */
8448329232Gordon Ross    refstr_t **refp,		/* Ref-count string to contain the new path */
8458329232Gordon Ross    const char *newpath,	/* Path to add to refp (above) */
8468329232Gordon Ross    uint32_t flag)		/* flag */
8478329232Gordon Ross{
8488329232Gordon Ross	// size_t len;
8498329232Gordon Ross	refstr_t *ref;
8508329232Gordon Ross	// char *sp;
8518329232Gordon Ross	int have_list_lock = 0;
8528329232Gordon Ross
8538329232Gordon Ross	ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp));
8548329232Gordon Ross
8558329232Gordon Ross	/*
8568329232Gordon Ross	 * New path must be less than MAXPATHLEN because mntfs
8578329232Gordon Ross	 * will only display up to MAXPATHLEN bytes. This is currently
8588329232Gordon Ross	 * safe, because domount() uses pn_get(), and other callers
8598329232Gordon Ross	 * similarly cap the size to fewer than MAXPATHLEN bytes.
8608329232Gordon Ross	 */
8618329232Gordon Ross
8628329232Gordon Ross	ASSERT(strlen(newpath) < MAXPATHLEN);
8638329232Gordon Ross
8648329232Gordon Ross	/* mntfs requires consistency while vfs list lock is held */
8658329232Gordon Ross
8668329232Gordon Ross	if (VFS_ON_LIST(vfsp)) {
8678329232Gordon Ross		have_list_lock = 1;
8688329232Gordon Ross		vfs_list_lock();
8698329232Gordon Ross	}
8708329232Gordon Ross
8718329232Gordon Ross	if (*refp != NULL)
8728329232Gordon Ross		refstr_rele(*refp);
8738329232Gordon Ross
8748329232Gordon Ross	/*
8758329232Gordon Ross	 * If we are in a non-global zone... (do something else)
8768329232Gordon Ross	 */
8778329232Gordon Ross	ref = refstr_alloc(newpath);
8788329232Gordon Ross	*refp = ref;
8798329232Gordon Ross
8808329232Gordon Ross	if (have_list_lock) {
8818329232Gordon Ross		vfs_mnttab_modtimeupd();
8828329232Gordon Ross		vfs_list_unlock();
8838329232Gordon Ross	}
8848329232Gordon Ross}
8858329232Gordon Ross
8868329232Gordon Ross/*
8878329232Gordon Ross * Record a mounted resource name in a vfs structure.
8888329232Gordon Ross * If vfsp is already mounted, caller must hold the vfs lock.
8898329232Gordon Ross */
8908329232Gordon Rossvoid
8918329232Gordon Rossvfs_setresource(struct vfs *vfsp, const char *resource, uint32_t flag)
8928329232Gordon Ross{
8938329232Gordon Ross	if (resource == NULL || resource[0] == '\0')
8948329232Gordon Ross		resource = VFS_NORESOURCE;
8958329232Gordon Ross	vfs_setpath(vfsp, &vfsp->vfs_resource, resource, flag);
8968329232Gordon Ross}
8978329232Gordon Ross
8988329232Gordon Ross/*
8998329232Gordon Ross * Record a mount point name in a vfs structure.
9008329232Gordon Ross * If vfsp is already mounted, caller must hold the vfs lock.
9018329232Gordon Ross */
9028329232Gordon Rossvoid
9038329232Gordon Rossvfs_setmntpoint(struct vfs *vfsp, const char *mntpt, uint32_t flag)
9048329232Gordon Ross{
9058329232Gordon Ross	if (mntpt == NULL || mntpt[0] == '\0')
9068329232Gordon Ross		mntpt = VFS_NOMNTPT;
9078329232Gordon Ross	vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt, flag);
9088329232Gordon Ross}
9098329232Gordon Ross
9108329232Gordon Ross/* Returns the vfs_resource. Caller must call refstr_rele() when finished. */
9118329232Gordon Ross
9128329232Gordon Rossrefstr_t *
9138329232Gordon Rossvfs_getresource(const struct vfs *vfsp)
9148329232Gordon Ross{
9158329232Gordon Ross	refstr_t *resource;
9168329232Gordon Ross
9178329232Gordon Ross	vfs_list_read_lock();
9188329232Gordon Ross	resource = vfsp->vfs_resource;
9198329232Gordon Ross	refstr_hold(resource);
9208329232Gordon Ross	vfs_list_unlock();
9218329232Gordon Ross
9228329232Gordon Ross	return (resource);
9238329232Gordon Ross}
9248329232Gordon Ross
9258329232Gordon Ross/* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */
9268329232Gordon Ross
9278329232Gordon Rossrefstr_t *
9288329232Gordon Rossvfs_getmntpoint(const struct vfs *vfsp)
9298329232Gordon Ross{
9308329232Gordon Ross	refstr_t *mntpt;
9318329232Gordon Ross
9328329232Gordon Ross	vfs_list_read_lock();
9338329232Gordon Ross	mntpt = vfsp->vfs_mntpt;
9348329232Gordon Ross	refstr_hold(mntpt);
9358329232Gordon Ross	vfs_list_unlock();
9368329232Gordon Ross
9378329232Gordon Ross	return (mntpt);
9388329232Gordon Ross}
9398329232Gordon Ross
9408329232Gordon Ross// vfs_createopttbl_extend
9418329232Gordon Ross// vfs_createopttbl
9428329232Gordon Ross
9438329232Gordon Ross/*
9448329232Gordon Ross * Swap two mount options tables
9458329232Gordon Ross */
9468329232Gordon Rossstatic void
9478329232Gordon Rossvfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2)
9488329232Gordon Ross{
9498329232Gordon Ross	uint_t tmpcnt;
9508329232Gordon Ross	mntopt_t *tmplist;
9518329232Gordon Ross
9528329232Gordon Ross	tmpcnt = optbl2->mo_count;
9538329232Gordon Ross	tmplist = optbl2->mo_list;
9548329232Gordon Ross	optbl2->mo_count = optbl1->mo_count;
9558329232Gordon Ross	optbl2->mo_list = optbl1->mo_list;
9568329232Gordon Ross	optbl1->mo_count = tmpcnt;
9578329232Gordon Ross	optbl1->mo_list = tmplist;
9588329232Gordon Ross}
9598329232Gordon Ross
9608329232Gordon Rossstatic void
9618329232Gordon Rossvfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2)
9628329232Gordon Ross{
9638329232Gordon Ross	vfs_list_lock();
9648329232Gordon Ross	vfs_swapopttbl_nolock(optbl1, optbl2);
9658329232Gordon Ross	vfs_mnttab_modtimeupd();
9668329232Gordon Ross	vfs_list_unlock();
9678329232Gordon Ross}
9688329232Gordon Ross
9698329232Gordon Rossstatic char **
9708329232Gordon Rossvfs_copycancelopt_extend(char **const moc, int extend)
9718329232Gordon Ross{
9728329232Gordon Ross	int i = 0;
9738329232Gordon Ross	int j;
9748329232Gordon Ross	char **result;
9758329232Gordon Ross
9768329232Gordon Ross	if (moc != NULL) {
9778329232Gordon Ross		for (; moc[i] != NULL; i++)
9788329232Gordon Ross			/* count number of options to cancel */;
9798329232Gordon Ross	}
9808329232Gordon Ross
9818329232Gordon Ross	if (i + extend == 0)
9828329232Gordon Ross		return (NULL);
9838329232Gordon Ross
9848329232Gordon Ross	result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP);
9858329232Gordon Ross
9868329232Gordon Ross	for (j = 0; j < i; j++) {
9878329232Gordon Ross		result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP);
9888329232Gordon Ross		(void) strcpy(result[j], moc[j]);
9898329232Gordon Ross	}
9908329232Gordon Ross	for (; j <= i + extend; j++)
9918329232Gordon Ross		result[j] = NULL;
9928329232Gordon Ross
9938329232Gordon Ross	return (result);
9948329232Gordon Ross}
9958329232Gordon Ross
9968329232Gordon Rossstatic void
9978329232Gordon Rossvfs_copyopt(const mntopt_t *s, mntopt_t *d)
9988329232Gordon Ross{
9998329232Gordon Ross	char *sp, *dp;
10008329232Gordon Ross
10018329232Gordon Ross	d->mo_flags = s->mo_flags;
10028329232Gordon Ross	d->mo_data = s->mo_data;
10038329232Gordon Ross	sp = s->mo_name;
10048329232Gordon Ross	if (sp != NULL) {
10058329232Gordon Ross		dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
10068329232Gordon Ross		(void) strcpy(dp, sp);
10078329232Gordon Ross		d->mo_name = dp;
10088329232Gordon Ross	} else {
10098329232Gordon Ross		d->mo_name = NULL; /* should never happen */
10108329232Gordon Ross	}
10118329232Gordon Ross
10128329232Gordon Ross	d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0);
10138329232Gordon Ross
10148329232Gordon Ross	sp = s->mo_arg;
10158329232Gordon Ross	if (sp != NULL) {
10168329232Gordon Ross		dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
10178329232Gordon Ross		(void) strcpy(dp, sp);
10188329232Gordon Ross		d->mo_arg = dp;
10198329232Gordon Ross	} else {
10208329232Gordon Ross		d->mo_arg = NULL;
10218329232Gordon Ross	}
10228329232Gordon Ross}
10238329232Gordon Ross
10248329232Gordon Ross// vfs_copyopttbl_extend
10258329232Gordon Ross// vfs_copyopttbl
10268329232Gordon Ross
10278329232Gordon Ross/*
10288329232Gordon Ross * Copy a mount options table, possibly allocating some spare
10298329232Gordon Ross * slots at the end.  It is permissible to copy_extend the NULL table.
10308329232Gordon Ross */
10318329232Gordon Rossstatic void
10328329232Gordon Rossvfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra)
10338329232Gordon Ross{
10348329232Gordon Ross	uint_t i, count;
10358329232Gordon Ross	mntopt_t *motbl;
10368329232Gordon Ross
10378329232Gordon Ross	/*
10388329232Gordon Ross	 * Clear out any existing stuff in the options table being initialized
10398329232Gordon Ross	 */
10408329232Gordon Ross	vfs_freeopttbl(dmo);
10418329232Gordon Ross	count = (smo == NULL) ? 0 : smo->mo_count;
10428329232Gordon Ross	if ((count + extra) == 0)	/* nothing to do */
10438329232Gordon Ross		return;
10448329232Gordon Ross	dmo->mo_count = count + extra;
10458329232Gordon Ross	motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP);
10468329232Gordon Ross	dmo->mo_list = motbl;
10478329232Gordon Ross	for (i = 0; i < count; i++) {
10488329232Gordon Ross		vfs_copyopt(&smo->mo_list[i], &motbl[i]);
10498329232Gordon Ross	}
10508329232Gordon Ross	for (i = count; i < count + extra; i++) {
10518329232Gordon Ross		motbl[i].mo_flags = MO_EMPTY;
10528329232Gordon Ross	}
10538329232Gordon Ross}
10548329232Gordon Ross