176ca3cb0SRobert Mustacchi /*
276ca3cb0SRobert Mustacchi * This file and its contents are supplied under the terms of the
376ca3cb0SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
476ca3cb0SRobert Mustacchi * You may only use this file in accordance with the terms of version
576ca3cb0SRobert Mustacchi * 1.0 of the CDDL.
676ca3cb0SRobert Mustacchi *
776ca3cb0SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
876ca3cb0SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
976ca3cb0SRobert Mustacchi * http://www.illumos.org/license/CDDL.
1076ca3cb0SRobert Mustacchi */
1176ca3cb0SRobert Mustacchi
1276ca3cb0SRobert Mustacchi /*
1376ca3cb0SRobert Mustacchi * Copyright (c) 2015 Joyent, Inc.
1476ca3cb0SRobert Mustacchi */
1576ca3cb0SRobert Mustacchi
1676ca3cb0SRobert Mustacchi #include <sys/errno.h>
1776ca3cb0SRobert Mustacchi #include <sys/modctl.h>
1876ca3cb0SRobert Mustacchi #include <sys/types.h>
1976ca3cb0SRobert Mustacchi #include <sys/mkdev.h>
2076ca3cb0SRobert Mustacchi #include <sys/ddi.h>
2176ca3cb0SRobert Mustacchi #include <sys/sunddi.h>
2276ca3cb0SRobert Mustacchi #include <sys/vfs.h>
2376ca3cb0SRobert Mustacchi #include <sys/vfs_opreg.h>
2476ca3cb0SRobert Mustacchi #include <sys/systm.h>
2576ca3cb0SRobert Mustacchi #include <sys/id_space.h>
2676ca3cb0SRobert Mustacchi #include <sys/cmn_err.h>
2776ca3cb0SRobert Mustacchi #include <sys/ksynch.h>
2876ca3cb0SRobert Mustacchi #include <sys/policy.h>
2976ca3cb0SRobert Mustacchi #include <sys/mount.h>
3076ca3cb0SRobert Mustacchi #include <sys/sysmacros.h>
3176ca3cb0SRobert Mustacchi
3276ca3cb0SRobert Mustacchi #include <sys/fs/bootfs_impl.h>
3376ca3cb0SRobert Mustacchi
3476ca3cb0SRobert Mustacchi /*
3576ca3cb0SRobert Mustacchi * While booting, additional types of modules and files can be passed in to the
3676ca3cb0SRobert Mustacchi * loader. These include the familiar boot archive, as well as, a module hash
3776ca3cb0SRobert Mustacchi * and additional modules that are interpreted as files. As part of the handoff
3876ca3cb0SRobert Mustacchi * in early boot, information about these modules are saved as properties on the
3976ca3cb0SRobert Mustacchi * root of the devinfo tree, similar to other boot-time properties.
4076ca3cb0SRobert Mustacchi *
4176ca3cb0SRobert Mustacchi * This file system provides a read-only view of those additional files. Due to
4276ca3cb0SRobert Mustacchi * its limited scope, it has a slightly simpler construction than several other
4376ca3cb0SRobert Mustacchi * file systems. When mounted, it looks for the corresponding properties and
4476ca3cb0SRobert Mustacchi * creates bootfs_node_t's and vnodes for all of the corresponding files and
4576ca3cb0SRobert Mustacchi * directories that exist along the way. At this time, there are currently a
4676ca3cb0SRobert Mustacchi * rather small number of files passed in this way.
4776ca3cb0SRobert Mustacchi *
4876ca3cb0SRobert Mustacchi * This does lead to one behavior that folks used to other file systems might
4976ca3cb0SRobert Mustacchi * find peculiar. Because we are not always actively creating and destroying the
5076ca3cb0SRobert Mustacchi * required vnodes on demand, the count on the root vnode will not be going up
5176ca3cb0SRobert Mustacchi * accordingly with the existence of other vnodes. This means that a bootfs file
5276ca3cb0SRobert Mustacchi * system that is not in use will have all of its vnodes exist with a v_count of
5376ca3cb0SRobert Mustacchi * one.
5476ca3cb0SRobert Mustacchi */
5576ca3cb0SRobert Mustacchi
5676ca3cb0SRobert Mustacchi major_t bootfs_major;
5776ca3cb0SRobert Mustacchi static int bootfs_fstype;
5876ca3cb0SRobert Mustacchi static id_space_t *bootfs_idspace;
5976ca3cb0SRobert Mustacchi static uint64_t bootfs_nactive;
6076ca3cb0SRobert Mustacchi static kmutex_t bootfs_lock;
6176ca3cb0SRobert Mustacchi
6276ca3cb0SRobert Mustacchi static const char *bootfs_name = "bootfs";
6376ca3cb0SRobert Mustacchi
6476ca3cb0SRobert Mustacchi static int
bootfs_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)6576ca3cb0SRobert Mustacchi bootfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
6676ca3cb0SRobert Mustacchi {
6776ca3cb0SRobert Mustacchi int ret;
6876ca3cb0SRobert Mustacchi bootfs_t *bfs;
6976ca3cb0SRobert Mustacchi struct pathname dpn;
7076ca3cb0SRobert Mustacchi dev_t fsdev;
7176ca3cb0SRobert Mustacchi
7276ca3cb0SRobert Mustacchi if ((ret = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
7376ca3cb0SRobert Mustacchi return (ret);
7476ca3cb0SRobert Mustacchi
7576ca3cb0SRobert Mustacchi if (mvp->v_type != VDIR)
7676ca3cb0SRobert Mustacchi return (ENOTDIR);
7776ca3cb0SRobert Mustacchi
7876ca3cb0SRobert Mustacchi if (uap->flags & MS_REMOUNT)
7976ca3cb0SRobert Mustacchi return (EBUSY);
8076ca3cb0SRobert Mustacchi
8176ca3cb0SRobert Mustacchi mutex_enter(&mvp->v_lock);
8276ca3cb0SRobert Mustacchi if ((uap->flags & MS_OVERLAY) == 0 &&
8376ca3cb0SRobert Mustacchi (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
8476ca3cb0SRobert Mustacchi mutex_exit(&mvp->v_lock);
8576ca3cb0SRobert Mustacchi return (EBUSY);
8676ca3cb0SRobert Mustacchi }
8776ca3cb0SRobert Mustacchi mutex_exit(&mvp->v_lock);
8876ca3cb0SRobert Mustacchi
8976ca3cb0SRobert Mustacchi /*
9076ca3cb0SRobert Mustacchi * We indicate that the backing store is bootfs. We don't want to use
9176ca3cb0SRobert Mustacchi * swap, because folks might think that this is putting all the data
9276ca3cb0SRobert Mustacchi * into memory ala tmpfs. Rather these modules are always in memory and
9376ca3cb0SRobert Mustacchi * there's nothing to be done about that.
9476ca3cb0SRobert Mustacchi */
9576ca3cb0SRobert Mustacchi vfs_setresource(vfsp, bootfs_name, 0);
96*ca783257SDan McDonald bfs = kmem_zalloc(sizeof (bootfs_t), KM_NOSLEEP_LAZY);
9776ca3cb0SRobert Mustacchi if (bfs == NULL)
9876ca3cb0SRobert Mustacchi return (ENOMEM);
9976ca3cb0SRobert Mustacchi
10076ca3cb0SRobert Mustacchi ret = pn_get(uap->dir,
10176ca3cb0SRobert Mustacchi (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn);
10276ca3cb0SRobert Mustacchi if (ret != 0) {
10376ca3cb0SRobert Mustacchi kmem_free(bfs, sizeof (bfs));
10476ca3cb0SRobert Mustacchi return (ret);
10576ca3cb0SRobert Mustacchi }
10676ca3cb0SRobert Mustacchi
10776ca3cb0SRobert Mustacchi bfs->bfs_minor = id_alloc(bootfs_idspace);
10876ca3cb0SRobert Mustacchi bfs->bfs_kstat = kstat_create_zone("bootfs", bfs->bfs_minor, "bootfs",
10976ca3cb0SRobert Mustacchi "fs", KSTAT_TYPE_NAMED,
11076ca3cb0SRobert Mustacchi sizeof (bootfs_stat_t) / sizeof (kstat_named_t),
11176ca3cb0SRobert Mustacchi KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID);
11276ca3cb0SRobert Mustacchi if (bfs->bfs_kstat == NULL) {
11376ca3cb0SRobert Mustacchi id_free(bootfs_idspace, bfs->bfs_minor);
11476ca3cb0SRobert Mustacchi pn_free(&dpn);
11576ca3cb0SRobert Mustacchi kmem_free(bfs, sizeof (bfs));
11676ca3cb0SRobert Mustacchi return (ENOMEM);
11776ca3cb0SRobert Mustacchi }
11876ca3cb0SRobert Mustacchi bfs->bfs_kstat->ks_data = &bfs->bfs_stat;
11976ca3cb0SRobert Mustacchi
12076ca3cb0SRobert Mustacchi fsdev = makedevice(bootfs_major, bfs->bfs_minor);
12176ca3cb0SRobert Mustacchi bfs->bfs_vfsp = vfsp;
12276ca3cb0SRobert Mustacchi
12376ca3cb0SRobert Mustacchi vfsp->vfs_data = (caddr_t)bfs;
12476ca3cb0SRobert Mustacchi vfsp->vfs_fstype = bootfs_fstype;
12576ca3cb0SRobert Mustacchi vfsp->vfs_dev = fsdev;
12676ca3cb0SRobert Mustacchi vfsp->vfs_bsize = PAGESIZE;
12776ca3cb0SRobert Mustacchi vfsp->vfs_flag |= VFS_RDONLY | VFS_NOSETUID | VFS_NOTRUNC |
12876ca3cb0SRobert Mustacchi VFS_UNLINKABLE;
12976ca3cb0SRobert Mustacchi vfs_make_fsid(&vfsp->vfs_fsid, fsdev, bootfs_fstype);
13076ca3cb0SRobert Mustacchi bfs->bfs_mntpath = kmem_alloc(dpn.pn_pathlen + 1, KM_SLEEP);
13176ca3cb0SRobert Mustacchi bcopy(dpn.pn_path, bfs->bfs_mntpath, dpn.pn_pathlen);
13276ca3cb0SRobert Mustacchi bfs->bfs_mntpath[dpn.pn_pathlen] = '\0';
13376ca3cb0SRobert Mustacchi pn_free(&dpn);
13476ca3cb0SRobert Mustacchi list_create(&bfs->bfs_nodes, sizeof (bootfs_node_t),
13576ca3cb0SRobert Mustacchi offsetof(bootfs_node_t, bvn_alink));
13676ca3cb0SRobert Mustacchi
13776ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_nfiles, "nfiles",
13876ca3cb0SRobert Mustacchi KSTAT_DATA_UINT32);
13976ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_ndirs, "ndirs",
14076ca3cb0SRobert Mustacchi KSTAT_DATA_UINT32);
14176ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_nbytes, "nbytes",
14276ca3cb0SRobert Mustacchi KSTAT_DATA_UINT64);
14376ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_ndups, "ndup",
14476ca3cb0SRobert Mustacchi KSTAT_DATA_UINT32);
14576ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_ndiscards, "ndiscard",
14676ca3cb0SRobert Mustacchi KSTAT_DATA_UINT32);
14776ca3cb0SRobert Mustacchi
14876ca3cb0SRobert Mustacchi bootfs_construct(bfs);
14976ca3cb0SRobert Mustacchi
15076ca3cb0SRobert Mustacchi kstat_install(bfs->bfs_kstat);
15176ca3cb0SRobert Mustacchi
15276ca3cb0SRobert Mustacchi return (0);
15376ca3cb0SRobert Mustacchi }
15476ca3cb0SRobert Mustacchi
15576ca3cb0SRobert Mustacchi static int
bootfs_unmount(vfs_t * vfsp,int flag,cred_t * cr)15676ca3cb0SRobert Mustacchi bootfs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
15776ca3cb0SRobert Mustacchi {
15876ca3cb0SRobert Mustacchi int ret;
15976ca3cb0SRobert Mustacchi bootfs_t *bfs = vfsp->vfs_data;
16076ca3cb0SRobert Mustacchi bootfs_node_t *bnp;
16176ca3cb0SRobert Mustacchi
16276ca3cb0SRobert Mustacchi if ((ret = secpolicy_fs_unmount(cr, vfsp)) != 0)
16376ca3cb0SRobert Mustacchi return (ret);
16476ca3cb0SRobert Mustacchi
16576ca3cb0SRobert Mustacchi if (flag & MS_FORCE)
16676ca3cb0SRobert Mustacchi return (ENOTSUP);
16776ca3cb0SRobert Mustacchi
16876ca3cb0SRobert Mustacchi for (bnp = list_head(&bfs->bfs_nodes); bnp != NULL;
16976ca3cb0SRobert Mustacchi bnp = list_next(&bfs->bfs_nodes, bnp)) {
17076ca3cb0SRobert Mustacchi mutex_enter(&bnp->bvn_vnp->v_lock);
17176ca3cb0SRobert Mustacchi if (bnp->bvn_vnp->v_count > 1) {
17276ca3cb0SRobert Mustacchi mutex_exit(&bnp->bvn_vnp->v_lock);
17376ca3cb0SRobert Mustacchi return (EBUSY);
17476ca3cb0SRobert Mustacchi }
17576ca3cb0SRobert Mustacchi mutex_exit(&bnp->bvn_vnp->v_lock);
17676ca3cb0SRobert Mustacchi }
17776ca3cb0SRobert Mustacchi
17876ca3cb0SRobert Mustacchi kstat_delete(bfs->bfs_kstat);
17976ca3cb0SRobert Mustacchi bootfs_destruct(bfs);
18076ca3cb0SRobert Mustacchi list_destroy(&bfs->bfs_nodes);
18176ca3cb0SRobert Mustacchi kmem_free(bfs->bfs_mntpath, strlen(bfs->bfs_mntpath) + 1);
18276ca3cb0SRobert Mustacchi id_free(bootfs_idspace, bfs->bfs_minor);
18376ca3cb0SRobert Mustacchi kmem_free(bfs, sizeof (bootfs_t));
18476ca3cb0SRobert Mustacchi return (0);
18576ca3cb0SRobert Mustacchi }
18676ca3cb0SRobert Mustacchi
18776ca3cb0SRobert Mustacchi static int
bootfs_root(vfs_t * vfsp,vnode_t ** vpp)18876ca3cb0SRobert Mustacchi bootfs_root(vfs_t *vfsp, vnode_t **vpp)
18976ca3cb0SRobert Mustacchi {
19076ca3cb0SRobert Mustacchi bootfs_t *bfs;
19176ca3cb0SRobert Mustacchi
19276ca3cb0SRobert Mustacchi bfs = (bootfs_t *)vfsp->vfs_data;
19376ca3cb0SRobert Mustacchi *vpp = bfs->bfs_rootvn->bvn_vnp;
19476ca3cb0SRobert Mustacchi VN_HOLD(*vpp)
19576ca3cb0SRobert Mustacchi
19676ca3cb0SRobert Mustacchi return (0);
19776ca3cb0SRobert Mustacchi }
19876ca3cb0SRobert Mustacchi
19976ca3cb0SRobert Mustacchi static int
bootfs_statvfs(vfs_t * vfsp,struct statvfs64 * sbp)20076ca3cb0SRobert Mustacchi bootfs_statvfs(vfs_t *vfsp, struct statvfs64 *sbp)
20176ca3cb0SRobert Mustacchi {
20276ca3cb0SRobert Mustacchi const bootfs_t *bfs = (bootfs_t *)vfsp;
20376ca3cb0SRobert Mustacchi dev32_t d32;
20476ca3cb0SRobert Mustacchi
20576ca3cb0SRobert Mustacchi sbp->f_bsize = PAGESIZE;
20676ca3cb0SRobert Mustacchi sbp->f_frsize = PAGESIZE;
20776ca3cb0SRobert Mustacchi
20876ca3cb0SRobert Mustacchi sbp->f_blocks = bfs->bfs_stat.bfss_nbytes.value.ui64 >> PAGESHIFT;
20976ca3cb0SRobert Mustacchi sbp->f_bfree = 0;
21076ca3cb0SRobert Mustacchi sbp->f_bavail = 0;
21176ca3cb0SRobert Mustacchi
21276ca3cb0SRobert Mustacchi sbp->f_files = bfs->bfs_stat.bfss_nfiles.value.ui32 +
21376ca3cb0SRobert Mustacchi bfs->bfs_stat.bfss_ndirs.value.ui32;
21476ca3cb0SRobert Mustacchi sbp->f_ffree = 0;
21576ca3cb0SRobert Mustacchi sbp->f_favail = 0;
21676ca3cb0SRobert Mustacchi
21776ca3cb0SRobert Mustacchi (void) cmpldev(&d32, vfsp->vfs_dev);
21876ca3cb0SRobert Mustacchi sbp->f_fsid = d32;
21976ca3cb0SRobert Mustacchi (void) strlcpy(sbp->f_basetype, bootfs_name, FSTYPSZ);
22076ca3cb0SRobert Mustacchi bzero(sbp->f_fstr, sizeof (sbp->f_fstr));
22176ca3cb0SRobert Mustacchi
22276ca3cb0SRobert Mustacchi return (0);
22376ca3cb0SRobert Mustacchi }
22476ca3cb0SRobert Mustacchi
22576ca3cb0SRobert Mustacchi static const fs_operation_def_t bootfs_vfsops_tmpl[] = {
22676ca3cb0SRobert Mustacchi VFSNAME_MOUNT, { .vfs_mount = bootfs_mount },
22776ca3cb0SRobert Mustacchi VFSNAME_UNMOUNT, { .vfs_unmount = bootfs_unmount },
22876ca3cb0SRobert Mustacchi VFSNAME_ROOT, { .vfs_root = bootfs_root },
22976ca3cb0SRobert Mustacchi VFSNAME_STATVFS, { .vfs_statvfs = bootfs_statvfs },
23076ca3cb0SRobert Mustacchi NULL, NULL
23176ca3cb0SRobert Mustacchi };
23276ca3cb0SRobert Mustacchi
23376ca3cb0SRobert Mustacchi static int
bootfs_init(int fstype,char * name)23476ca3cb0SRobert Mustacchi bootfs_init(int fstype, char *name)
23576ca3cb0SRobert Mustacchi {
23676ca3cb0SRobert Mustacchi int ret;
23776ca3cb0SRobert Mustacchi
23876ca3cb0SRobert Mustacchi bootfs_fstype = fstype;
23976ca3cb0SRobert Mustacchi ASSERT(bootfs_fstype != 0);
24076ca3cb0SRobert Mustacchi
24176ca3cb0SRobert Mustacchi ret = vfs_setfsops(fstype, bootfs_vfsops_tmpl, NULL);
24276ca3cb0SRobert Mustacchi if (ret != 0)
24376ca3cb0SRobert Mustacchi return (ret);
24476ca3cb0SRobert Mustacchi
24576ca3cb0SRobert Mustacchi ret = vn_make_ops(name, bootfs_vnodeops_template, &bootfs_vnodeops);
24676ca3cb0SRobert Mustacchi if (ret != 0) {
24776ca3cb0SRobert Mustacchi (void) vfs_freevfsops_by_type(bootfs_fstype);
24876ca3cb0SRobert Mustacchi return (ret);
24976ca3cb0SRobert Mustacchi }
25076ca3cb0SRobert Mustacchi
25176ca3cb0SRobert Mustacchi bootfs_major = getudev();
25276ca3cb0SRobert Mustacchi if (bootfs_major == (major_t)-1) {
25376ca3cb0SRobert Mustacchi cmn_err(CE_WARN, "bootfs_init: Can't get unique device number");
25476ca3cb0SRobert Mustacchi bootfs_major = 0;
25576ca3cb0SRobert Mustacchi }
25676ca3cb0SRobert Mustacchi
25776ca3cb0SRobert Mustacchi bootfs_nactive = 0;
25876ca3cb0SRobert Mustacchi return (0);
25976ca3cb0SRobert Mustacchi }
26076ca3cb0SRobert Mustacchi
26176ca3cb0SRobert Mustacchi static mntopts_t bootfs_mntopts = {
26276ca3cb0SRobert Mustacchi 0, NULL
26376ca3cb0SRobert Mustacchi };
26476ca3cb0SRobert Mustacchi
26576ca3cb0SRobert Mustacchi static vfsdef_t bootfs_vfsdef = {
26676ca3cb0SRobert Mustacchi VFSDEF_VERSION,
26776ca3cb0SRobert Mustacchi "bootfs",
26876ca3cb0SRobert Mustacchi bootfs_init,
26976ca3cb0SRobert Mustacchi VSW_HASPROTO|VSW_STATS,
27076ca3cb0SRobert Mustacchi &bootfs_mntopts
27176ca3cb0SRobert Mustacchi };
27276ca3cb0SRobert Mustacchi
27376ca3cb0SRobert Mustacchi static struct modlfs bootfs_modlfs = {
27476ca3cb0SRobert Mustacchi &mod_fsops, "boot-time modules file system", &bootfs_vfsdef
27576ca3cb0SRobert Mustacchi };
27676ca3cb0SRobert Mustacchi
27776ca3cb0SRobert Mustacchi static struct modlinkage bootfs_modlinkage = {
27876ca3cb0SRobert Mustacchi MODREV_1, &bootfs_modlfs, NULL
27976ca3cb0SRobert Mustacchi };
28076ca3cb0SRobert Mustacchi
28176ca3cb0SRobert Mustacchi int
_init(void)28276ca3cb0SRobert Mustacchi _init(void)
28376ca3cb0SRobert Mustacchi {
28476ca3cb0SRobert Mustacchi bootfs_node_cache = kmem_cache_create("bootfs_node_cache",
28576ca3cb0SRobert Mustacchi sizeof (bootfs_node_t), 0, bootfs_node_constructor,
28676ca3cb0SRobert Mustacchi bootfs_node_destructor, NULL, NULL, NULL, 0);
28776ca3cb0SRobert Mustacchi bootfs_idspace = id_space_create("bootfs_minors", 1, INT32_MAX);
28876ca3cb0SRobert Mustacchi mutex_init(&bootfs_lock, NULL, MUTEX_DEFAULT, NULL);
28976ca3cb0SRobert Mustacchi
29076ca3cb0SRobert Mustacchi return (mod_install(&bootfs_modlinkage));
29176ca3cb0SRobert Mustacchi }
29276ca3cb0SRobert Mustacchi
29376ca3cb0SRobert Mustacchi int
_info(struct modinfo * modinfop)29476ca3cb0SRobert Mustacchi _info(struct modinfo *modinfop)
29576ca3cb0SRobert Mustacchi {
29676ca3cb0SRobert Mustacchi return (mod_info(&bootfs_modlinkage, modinfop));
29776ca3cb0SRobert Mustacchi }
29876ca3cb0SRobert Mustacchi
29976ca3cb0SRobert Mustacchi int
_fini(void)30076ca3cb0SRobert Mustacchi _fini(void)
30176ca3cb0SRobert Mustacchi {
30276ca3cb0SRobert Mustacchi int err;
30376ca3cb0SRobert Mustacchi
30476ca3cb0SRobert Mustacchi mutex_enter(&bootfs_lock);
30576ca3cb0SRobert Mustacchi if (bootfs_nactive > 0) {
30676ca3cb0SRobert Mustacchi mutex_exit(&bootfs_lock);
30776ca3cb0SRobert Mustacchi return (EBUSY);
30876ca3cb0SRobert Mustacchi }
30976ca3cb0SRobert Mustacchi mutex_exit(&bootfs_lock);
31076ca3cb0SRobert Mustacchi
31176ca3cb0SRobert Mustacchi err = mod_remove(&bootfs_modlinkage);
31276ca3cb0SRobert Mustacchi if (err != 0)
31376ca3cb0SRobert Mustacchi return (err);
31476ca3cb0SRobert Mustacchi
31576ca3cb0SRobert Mustacchi (void) vfs_freevfsops_by_type(bootfs_fstype);
31676ca3cb0SRobert Mustacchi vn_freevnodeops(bootfs_vnodeops);
31776ca3cb0SRobert Mustacchi id_space_destroy(bootfs_idspace);
31876ca3cb0SRobert Mustacchi mutex_destroy(&bootfs_lock);
31976ca3cb0SRobert Mustacchi kmem_cache_destroy(bootfs_node_cache);
32076ca3cb0SRobert Mustacchi return (err);
32176ca3cb0SRobert Mustacchi }
322