1*76ca3cb0SRobert Mustacchi /* 2*76ca3cb0SRobert Mustacchi * This file and its contents are supplied under the terms of the 3*76ca3cb0SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0. 4*76ca3cb0SRobert Mustacchi * You may only use this file in accordance with the terms of version 5*76ca3cb0SRobert Mustacchi * 1.0 of the CDDL. 6*76ca3cb0SRobert Mustacchi * 7*76ca3cb0SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this 8*76ca3cb0SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at 9*76ca3cb0SRobert Mustacchi * http://www.illumos.org/license/CDDL. 10*76ca3cb0SRobert Mustacchi */ 11*76ca3cb0SRobert Mustacchi 12*76ca3cb0SRobert Mustacchi /* 13*76ca3cb0SRobert Mustacchi * Copyright (c) 2015 Joyent, Inc. 14*76ca3cb0SRobert Mustacchi */ 15*76ca3cb0SRobert Mustacchi 16*76ca3cb0SRobert Mustacchi #include <sys/errno.h> 17*76ca3cb0SRobert Mustacchi #include <sys/modctl.h> 18*76ca3cb0SRobert Mustacchi #include <sys/types.h> 19*76ca3cb0SRobert Mustacchi #include <sys/mkdev.h> 20*76ca3cb0SRobert Mustacchi #include <sys/ddi.h> 21*76ca3cb0SRobert Mustacchi #include <sys/sunddi.h> 22*76ca3cb0SRobert Mustacchi #include <sys/vfs.h> 23*76ca3cb0SRobert Mustacchi #include <sys/vfs_opreg.h> 24*76ca3cb0SRobert Mustacchi #include <sys/systm.h> 25*76ca3cb0SRobert Mustacchi #include <sys/id_space.h> 26*76ca3cb0SRobert Mustacchi #include <sys/cmn_err.h> 27*76ca3cb0SRobert Mustacchi #include <sys/ksynch.h> 28*76ca3cb0SRobert Mustacchi #include <sys/policy.h> 29*76ca3cb0SRobert Mustacchi #include <sys/mount.h> 30*76ca3cb0SRobert Mustacchi #include <sys/sysmacros.h> 31*76ca3cb0SRobert Mustacchi 32*76ca3cb0SRobert Mustacchi #include <sys/fs/bootfs_impl.h> 33*76ca3cb0SRobert Mustacchi 34*76ca3cb0SRobert Mustacchi /* 35*76ca3cb0SRobert Mustacchi * While booting, additional types of modules and files can be passed in to the 36*76ca3cb0SRobert Mustacchi * loader. These include the familiar boot archive, as well as, a module hash 37*76ca3cb0SRobert Mustacchi * and additional modules that are interpreted as files. As part of the handoff 38*76ca3cb0SRobert Mustacchi * in early boot, information about these modules are saved as properties on the 39*76ca3cb0SRobert Mustacchi * root of the devinfo tree, similar to other boot-time properties. 40*76ca3cb0SRobert Mustacchi * 41*76ca3cb0SRobert Mustacchi * This file system provides a read-only view of those additional files. Due to 42*76ca3cb0SRobert Mustacchi * its limited scope, it has a slightly simpler construction than several other 43*76ca3cb0SRobert Mustacchi * file systems. When mounted, it looks for the corresponding properties and 44*76ca3cb0SRobert Mustacchi * creates bootfs_node_t's and vnodes for all of the corresponding files and 45*76ca3cb0SRobert Mustacchi * directories that exist along the way. At this time, there are currently a 46*76ca3cb0SRobert Mustacchi * rather small number of files passed in this way. 47*76ca3cb0SRobert Mustacchi * 48*76ca3cb0SRobert Mustacchi * This does lead to one behavior that folks used to other file systems might 49*76ca3cb0SRobert Mustacchi * find peculiar. Because we are not always actively creating and destroying the 50*76ca3cb0SRobert Mustacchi * required vnodes on demand, the count on the root vnode will not be going up 51*76ca3cb0SRobert Mustacchi * accordingly with the existence of other vnodes. This means that a bootfs file 52*76ca3cb0SRobert Mustacchi * system that is not in use will have all of its vnodes exist with a v_count of 53*76ca3cb0SRobert Mustacchi * one. 54*76ca3cb0SRobert Mustacchi */ 55*76ca3cb0SRobert Mustacchi 56*76ca3cb0SRobert Mustacchi major_t bootfs_major; 57*76ca3cb0SRobert Mustacchi static int bootfs_fstype; 58*76ca3cb0SRobert Mustacchi static id_space_t *bootfs_idspace; 59*76ca3cb0SRobert Mustacchi static uint64_t bootfs_nactive; 60*76ca3cb0SRobert Mustacchi static kmutex_t bootfs_lock; 61*76ca3cb0SRobert Mustacchi 62*76ca3cb0SRobert Mustacchi static const char *bootfs_name = "bootfs"; 63*76ca3cb0SRobert Mustacchi 64*76ca3cb0SRobert Mustacchi static int 65*76ca3cb0SRobert Mustacchi bootfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 66*76ca3cb0SRobert Mustacchi { 67*76ca3cb0SRobert Mustacchi int ret; 68*76ca3cb0SRobert Mustacchi bootfs_t *bfs; 69*76ca3cb0SRobert Mustacchi struct pathname dpn; 70*76ca3cb0SRobert Mustacchi dev_t fsdev; 71*76ca3cb0SRobert Mustacchi 72*76ca3cb0SRobert Mustacchi if ((ret = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 73*76ca3cb0SRobert Mustacchi return (ret); 74*76ca3cb0SRobert Mustacchi 75*76ca3cb0SRobert Mustacchi if (mvp->v_type != VDIR) 76*76ca3cb0SRobert Mustacchi return (ENOTDIR); 77*76ca3cb0SRobert Mustacchi 78*76ca3cb0SRobert Mustacchi if (uap->flags & MS_REMOUNT) 79*76ca3cb0SRobert Mustacchi return (EBUSY); 80*76ca3cb0SRobert Mustacchi 81*76ca3cb0SRobert Mustacchi mutex_enter(&mvp->v_lock); 82*76ca3cb0SRobert Mustacchi if ((uap->flags & MS_OVERLAY) == 0 && 83*76ca3cb0SRobert Mustacchi (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 84*76ca3cb0SRobert Mustacchi mutex_exit(&mvp->v_lock); 85*76ca3cb0SRobert Mustacchi return (EBUSY); 86*76ca3cb0SRobert Mustacchi } 87*76ca3cb0SRobert Mustacchi mutex_exit(&mvp->v_lock); 88*76ca3cb0SRobert Mustacchi 89*76ca3cb0SRobert Mustacchi /* 90*76ca3cb0SRobert Mustacchi * We indicate that the backing store is bootfs. We don't want to use 91*76ca3cb0SRobert Mustacchi * swap, because folks might think that this is putting all the data 92*76ca3cb0SRobert Mustacchi * into memory ala tmpfs. Rather these modules are always in memory and 93*76ca3cb0SRobert Mustacchi * there's nothing to be done about that. 94*76ca3cb0SRobert Mustacchi */ 95*76ca3cb0SRobert Mustacchi vfs_setresource(vfsp, bootfs_name, 0); 96*76ca3cb0SRobert Mustacchi bfs = kmem_zalloc(sizeof (bootfs_t), KM_NOSLEEP | KM_NORMALPRI); 97*76ca3cb0SRobert Mustacchi if (bfs == NULL) 98*76ca3cb0SRobert Mustacchi return (ENOMEM); 99*76ca3cb0SRobert Mustacchi 100*76ca3cb0SRobert Mustacchi ret = pn_get(uap->dir, 101*76ca3cb0SRobert Mustacchi (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn); 102*76ca3cb0SRobert Mustacchi if (ret != 0) { 103*76ca3cb0SRobert Mustacchi kmem_free(bfs, sizeof (bfs)); 104*76ca3cb0SRobert Mustacchi return (ret); 105*76ca3cb0SRobert Mustacchi } 106*76ca3cb0SRobert Mustacchi 107*76ca3cb0SRobert Mustacchi bfs->bfs_minor = id_alloc(bootfs_idspace); 108*76ca3cb0SRobert Mustacchi bfs->bfs_kstat = kstat_create_zone("bootfs", bfs->bfs_minor, "bootfs", 109*76ca3cb0SRobert Mustacchi "fs", KSTAT_TYPE_NAMED, 110*76ca3cb0SRobert Mustacchi sizeof (bootfs_stat_t) / sizeof (kstat_named_t), 111*76ca3cb0SRobert Mustacchi KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID); 112*76ca3cb0SRobert Mustacchi if (bfs->bfs_kstat == NULL) { 113*76ca3cb0SRobert Mustacchi id_free(bootfs_idspace, bfs->bfs_minor); 114*76ca3cb0SRobert Mustacchi pn_free(&dpn); 115*76ca3cb0SRobert Mustacchi kmem_free(bfs, sizeof (bfs)); 116*76ca3cb0SRobert Mustacchi return (ENOMEM); 117*76ca3cb0SRobert Mustacchi } 118*76ca3cb0SRobert Mustacchi bfs->bfs_kstat->ks_data = &bfs->bfs_stat; 119*76ca3cb0SRobert Mustacchi 120*76ca3cb0SRobert Mustacchi fsdev = makedevice(bootfs_major, bfs->bfs_minor); 121*76ca3cb0SRobert Mustacchi bfs->bfs_vfsp = vfsp; 122*76ca3cb0SRobert Mustacchi 123*76ca3cb0SRobert Mustacchi vfsp->vfs_data = (caddr_t)bfs; 124*76ca3cb0SRobert Mustacchi vfsp->vfs_fstype = bootfs_fstype; 125*76ca3cb0SRobert Mustacchi vfsp->vfs_dev = fsdev; 126*76ca3cb0SRobert Mustacchi vfsp->vfs_bsize = PAGESIZE; 127*76ca3cb0SRobert Mustacchi vfsp->vfs_flag |= VFS_RDONLY | VFS_NOSETUID | VFS_NOTRUNC | 128*76ca3cb0SRobert Mustacchi VFS_UNLINKABLE; 129*76ca3cb0SRobert Mustacchi vfs_make_fsid(&vfsp->vfs_fsid, fsdev, bootfs_fstype); 130*76ca3cb0SRobert Mustacchi bfs->bfs_mntpath = kmem_alloc(dpn.pn_pathlen + 1, KM_SLEEP); 131*76ca3cb0SRobert Mustacchi bcopy(dpn.pn_path, bfs->bfs_mntpath, dpn.pn_pathlen); 132*76ca3cb0SRobert Mustacchi bfs->bfs_mntpath[dpn.pn_pathlen] = '\0'; 133*76ca3cb0SRobert Mustacchi pn_free(&dpn); 134*76ca3cb0SRobert Mustacchi list_create(&bfs->bfs_nodes, sizeof (bootfs_node_t), 135*76ca3cb0SRobert Mustacchi offsetof(bootfs_node_t, bvn_alink)); 136*76ca3cb0SRobert Mustacchi 137*76ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_nfiles, "nfiles", 138*76ca3cb0SRobert Mustacchi KSTAT_DATA_UINT32); 139*76ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_ndirs, "ndirs", 140*76ca3cb0SRobert Mustacchi KSTAT_DATA_UINT32); 141*76ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_nbytes, "nbytes", 142*76ca3cb0SRobert Mustacchi KSTAT_DATA_UINT64); 143*76ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_ndups, "ndup", 144*76ca3cb0SRobert Mustacchi KSTAT_DATA_UINT32); 145*76ca3cb0SRobert Mustacchi kstat_named_init(&bfs->bfs_stat.bfss_ndiscards, "ndiscard", 146*76ca3cb0SRobert Mustacchi KSTAT_DATA_UINT32); 147*76ca3cb0SRobert Mustacchi 148*76ca3cb0SRobert Mustacchi bootfs_construct(bfs); 149*76ca3cb0SRobert Mustacchi 150*76ca3cb0SRobert Mustacchi kstat_install(bfs->bfs_kstat); 151*76ca3cb0SRobert Mustacchi 152*76ca3cb0SRobert Mustacchi return (0); 153*76ca3cb0SRobert Mustacchi } 154*76ca3cb0SRobert Mustacchi 155*76ca3cb0SRobert Mustacchi static int 156*76ca3cb0SRobert Mustacchi bootfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) 157*76ca3cb0SRobert Mustacchi { 158*76ca3cb0SRobert Mustacchi int ret; 159*76ca3cb0SRobert Mustacchi bootfs_t *bfs = vfsp->vfs_data; 160*76ca3cb0SRobert Mustacchi bootfs_node_t *bnp; 161*76ca3cb0SRobert Mustacchi 162*76ca3cb0SRobert Mustacchi if ((ret = secpolicy_fs_unmount(cr, vfsp)) != 0) 163*76ca3cb0SRobert Mustacchi return (ret); 164*76ca3cb0SRobert Mustacchi 165*76ca3cb0SRobert Mustacchi if (flag & MS_FORCE) 166*76ca3cb0SRobert Mustacchi return (ENOTSUP); 167*76ca3cb0SRobert Mustacchi 168*76ca3cb0SRobert Mustacchi for (bnp = list_head(&bfs->bfs_nodes); bnp != NULL; 169*76ca3cb0SRobert Mustacchi bnp = list_next(&bfs->bfs_nodes, bnp)) { 170*76ca3cb0SRobert Mustacchi mutex_enter(&bnp->bvn_vnp->v_lock); 171*76ca3cb0SRobert Mustacchi if (bnp->bvn_vnp->v_count > 1) { 172*76ca3cb0SRobert Mustacchi mutex_exit(&bnp->bvn_vnp->v_lock); 173*76ca3cb0SRobert Mustacchi return (EBUSY); 174*76ca3cb0SRobert Mustacchi } 175*76ca3cb0SRobert Mustacchi mutex_exit(&bnp->bvn_vnp->v_lock); 176*76ca3cb0SRobert Mustacchi } 177*76ca3cb0SRobert Mustacchi 178*76ca3cb0SRobert Mustacchi kstat_delete(bfs->bfs_kstat); 179*76ca3cb0SRobert Mustacchi bootfs_destruct(bfs); 180*76ca3cb0SRobert Mustacchi list_destroy(&bfs->bfs_nodes); 181*76ca3cb0SRobert Mustacchi kmem_free(bfs->bfs_mntpath, strlen(bfs->bfs_mntpath) + 1); 182*76ca3cb0SRobert Mustacchi id_free(bootfs_idspace, bfs->bfs_minor); 183*76ca3cb0SRobert Mustacchi kmem_free(bfs, sizeof (bootfs_t)); 184*76ca3cb0SRobert Mustacchi return (0); 185*76ca3cb0SRobert Mustacchi } 186*76ca3cb0SRobert Mustacchi 187*76ca3cb0SRobert Mustacchi static int 188*76ca3cb0SRobert Mustacchi bootfs_root(vfs_t *vfsp, vnode_t **vpp) 189*76ca3cb0SRobert Mustacchi { 190*76ca3cb0SRobert Mustacchi bootfs_t *bfs; 191*76ca3cb0SRobert Mustacchi 192*76ca3cb0SRobert Mustacchi bfs = (bootfs_t *)vfsp->vfs_data; 193*76ca3cb0SRobert Mustacchi *vpp = bfs->bfs_rootvn->bvn_vnp; 194*76ca3cb0SRobert Mustacchi VN_HOLD(*vpp) 195*76ca3cb0SRobert Mustacchi 196*76ca3cb0SRobert Mustacchi return (0); 197*76ca3cb0SRobert Mustacchi } 198*76ca3cb0SRobert Mustacchi 199*76ca3cb0SRobert Mustacchi static int 200*76ca3cb0SRobert Mustacchi bootfs_statvfs(vfs_t *vfsp, struct statvfs64 *sbp) 201*76ca3cb0SRobert Mustacchi { 202*76ca3cb0SRobert Mustacchi const bootfs_t *bfs = (bootfs_t *)vfsp; 203*76ca3cb0SRobert Mustacchi dev32_t d32; 204*76ca3cb0SRobert Mustacchi 205*76ca3cb0SRobert Mustacchi sbp->f_bsize = PAGESIZE; 206*76ca3cb0SRobert Mustacchi sbp->f_frsize = PAGESIZE; 207*76ca3cb0SRobert Mustacchi 208*76ca3cb0SRobert Mustacchi sbp->f_blocks = bfs->bfs_stat.bfss_nbytes.value.ui64 >> PAGESHIFT; 209*76ca3cb0SRobert Mustacchi sbp->f_bfree = 0; 210*76ca3cb0SRobert Mustacchi sbp->f_bavail = 0; 211*76ca3cb0SRobert Mustacchi 212*76ca3cb0SRobert Mustacchi sbp->f_files = bfs->bfs_stat.bfss_nfiles.value.ui32 + 213*76ca3cb0SRobert Mustacchi bfs->bfs_stat.bfss_ndirs.value.ui32; 214*76ca3cb0SRobert Mustacchi sbp->f_ffree = 0; 215*76ca3cb0SRobert Mustacchi sbp->f_favail = 0; 216*76ca3cb0SRobert Mustacchi 217*76ca3cb0SRobert Mustacchi (void) cmpldev(&d32, vfsp->vfs_dev); 218*76ca3cb0SRobert Mustacchi sbp->f_fsid = d32; 219*76ca3cb0SRobert Mustacchi (void) strlcpy(sbp->f_basetype, bootfs_name, FSTYPSZ); 220*76ca3cb0SRobert Mustacchi bzero(sbp->f_fstr, sizeof (sbp->f_fstr)); 221*76ca3cb0SRobert Mustacchi 222*76ca3cb0SRobert Mustacchi return (0); 223*76ca3cb0SRobert Mustacchi } 224*76ca3cb0SRobert Mustacchi 225*76ca3cb0SRobert Mustacchi static const fs_operation_def_t bootfs_vfsops_tmpl[] = { 226*76ca3cb0SRobert Mustacchi VFSNAME_MOUNT, { .vfs_mount = bootfs_mount }, 227*76ca3cb0SRobert Mustacchi VFSNAME_UNMOUNT, { .vfs_unmount = bootfs_unmount }, 228*76ca3cb0SRobert Mustacchi VFSNAME_ROOT, { .vfs_root = bootfs_root }, 229*76ca3cb0SRobert Mustacchi VFSNAME_STATVFS, { .vfs_statvfs = bootfs_statvfs }, 230*76ca3cb0SRobert Mustacchi NULL, NULL 231*76ca3cb0SRobert Mustacchi }; 232*76ca3cb0SRobert Mustacchi 233*76ca3cb0SRobert Mustacchi static int 234*76ca3cb0SRobert Mustacchi bootfs_init(int fstype, char *name) 235*76ca3cb0SRobert Mustacchi { 236*76ca3cb0SRobert Mustacchi int ret; 237*76ca3cb0SRobert Mustacchi 238*76ca3cb0SRobert Mustacchi bootfs_fstype = fstype; 239*76ca3cb0SRobert Mustacchi ASSERT(bootfs_fstype != 0); 240*76ca3cb0SRobert Mustacchi 241*76ca3cb0SRobert Mustacchi ret = vfs_setfsops(fstype, bootfs_vfsops_tmpl, NULL); 242*76ca3cb0SRobert Mustacchi if (ret != 0) 243*76ca3cb0SRobert Mustacchi return (ret); 244*76ca3cb0SRobert Mustacchi 245*76ca3cb0SRobert Mustacchi ret = vn_make_ops(name, bootfs_vnodeops_template, &bootfs_vnodeops); 246*76ca3cb0SRobert Mustacchi if (ret != 0) { 247*76ca3cb0SRobert Mustacchi (void) vfs_freevfsops_by_type(bootfs_fstype); 248*76ca3cb0SRobert Mustacchi return (ret); 249*76ca3cb0SRobert Mustacchi } 250*76ca3cb0SRobert Mustacchi 251*76ca3cb0SRobert Mustacchi bootfs_major = getudev(); 252*76ca3cb0SRobert Mustacchi if (bootfs_major == (major_t)-1) { 253*76ca3cb0SRobert Mustacchi cmn_err(CE_WARN, "bootfs_init: Can't get unique device number"); 254*76ca3cb0SRobert Mustacchi bootfs_major = 0; 255*76ca3cb0SRobert Mustacchi } 256*76ca3cb0SRobert Mustacchi 257*76ca3cb0SRobert Mustacchi bootfs_nactive = 0; 258*76ca3cb0SRobert Mustacchi return (0); 259*76ca3cb0SRobert Mustacchi } 260*76ca3cb0SRobert Mustacchi 261*76ca3cb0SRobert Mustacchi static mntopts_t bootfs_mntopts = { 262*76ca3cb0SRobert Mustacchi 0, NULL 263*76ca3cb0SRobert Mustacchi }; 264*76ca3cb0SRobert Mustacchi 265*76ca3cb0SRobert Mustacchi static vfsdef_t bootfs_vfsdef = { 266*76ca3cb0SRobert Mustacchi VFSDEF_VERSION, 267*76ca3cb0SRobert Mustacchi "bootfs", 268*76ca3cb0SRobert Mustacchi bootfs_init, 269*76ca3cb0SRobert Mustacchi VSW_HASPROTO|VSW_STATS, 270*76ca3cb0SRobert Mustacchi &bootfs_mntopts 271*76ca3cb0SRobert Mustacchi }; 272*76ca3cb0SRobert Mustacchi 273*76ca3cb0SRobert Mustacchi static struct modlfs bootfs_modlfs = { 274*76ca3cb0SRobert Mustacchi &mod_fsops, "boot-time modules file system", &bootfs_vfsdef 275*76ca3cb0SRobert Mustacchi }; 276*76ca3cb0SRobert Mustacchi 277*76ca3cb0SRobert Mustacchi static struct modlinkage bootfs_modlinkage = { 278*76ca3cb0SRobert Mustacchi MODREV_1, &bootfs_modlfs, NULL 279*76ca3cb0SRobert Mustacchi }; 280*76ca3cb0SRobert Mustacchi 281*76ca3cb0SRobert Mustacchi int 282*76ca3cb0SRobert Mustacchi _init(void) 283*76ca3cb0SRobert Mustacchi { 284*76ca3cb0SRobert Mustacchi bootfs_node_cache = kmem_cache_create("bootfs_node_cache", 285*76ca3cb0SRobert Mustacchi sizeof (bootfs_node_t), 0, bootfs_node_constructor, 286*76ca3cb0SRobert Mustacchi bootfs_node_destructor, NULL, NULL, NULL, 0); 287*76ca3cb0SRobert Mustacchi bootfs_idspace = id_space_create("bootfs_minors", 1, INT32_MAX); 288*76ca3cb0SRobert Mustacchi mutex_init(&bootfs_lock, NULL, MUTEX_DEFAULT, NULL); 289*76ca3cb0SRobert Mustacchi 290*76ca3cb0SRobert Mustacchi return (mod_install(&bootfs_modlinkage)); 291*76ca3cb0SRobert Mustacchi } 292*76ca3cb0SRobert Mustacchi 293*76ca3cb0SRobert Mustacchi int 294*76ca3cb0SRobert Mustacchi _info(struct modinfo *modinfop) 295*76ca3cb0SRobert Mustacchi { 296*76ca3cb0SRobert Mustacchi return (mod_info(&bootfs_modlinkage, modinfop)); 297*76ca3cb0SRobert Mustacchi } 298*76ca3cb0SRobert Mustacchi 299*76ca3cb0SRobert Mustacchi int 300*76ca3cb0SRobert Mustacchi _fini(void) 301*76ca3cb0SRobert Mustacchi { 302*76ca3cb0SRobert Mustacchi int err; 303*76ca3cb0SRobert Mustacchi 304*76ca3cb0SRobert Mustacchi mutex_enter(&bootfs_lock); 305*76ca3cb0SRobert Mustacchi if (bootfs_nactive > 0) { 306*76ca3cb0SRobert Mustacchi mutex_exit(&bootfs_lock); 307*76ca3cb0SRobert Mustacchi return (EBUSY); 308*76ca3cb0SRobert Mustacchi } 309*76ca3cb0SRobert Mustacchi mutex_exit(&bootfs_lock); 310*76ca3cb0SRobert Mustacchi 311*76ca3cb0SRobert Mustacchi err = mod_remove(&bootfs_modlinkage); 312*76ca3cb0SRobert Mustacchi if (err != 0) 313*76ca3cb0SRobert Mustacchi return (err); 314*76ca3cb0SRobert Mustacchi 315*76ca3cb0SRobert Mustacchi (void) vfs_freevfsops_by_type(bootfs_fstype); 316*76ca3cb0SRobert Mustacchi vn_freevnodeops(bootfs_vnodeops); 317*76ca3cb0SRobert Mustacchi id_space_destroy(bootfs_idspace); 318*76ca3cb0SRobert Mustacchi mutex_destroy(&bootfs_lock); 319*76ca3cb0SRobert Mustacchi kmem_cache_destroy(bootfs_node_cache); 320*76ca3cb0SRobert Mustacchi return (err); 321*76ca3cb0SRobert Mustacchi } 322