xref: /titanic_51/usr/src/uts/common/fs/bootfs/bootfs_vfsops.c (revision 76ca3cb000306bc4052fe820a7e4a6998dbcf932)
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