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