2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright (c) 2015 Joyent, Inc.
16 #include <sys/errno.h>
17 #include <sys/modctl.h>
18 #include <sys/types.h>
19 #include <sys/mkdev.h>
21 #include <sys/sunddi.h>
23 #include <sys/pathname.h>
24 #include <sys/systm.h>
25 #include <sys/id_space.h>
26 #include <sys/cmn_err.h>
27 #include <sys/ksynch.h>
28 #include <sys/policy.h>
29 #include <sys/mount.h>
30 #include <sys/sysmacros.h>
32 #include <sys/fs/bootfs_impl.h>
35 * While booting, additional types of modules and files can be passed in to the
36 * loader. These include the familiar boot archive, as well as, a module hash
37 * and additional modules that are interpreted as files. As part of the handoff
38 * in early boot, information about these modules are saved as properties on the
39 * root of the devinfo tree, similar to other boot-time properties.
41 * This file system provides a read-only view of those additional files. Due to
42 * its limited scope, it has a slightly simpler construction than several other
43 * file systems. When mounted, it looks for the corresponding properties and
44 * creates bootfs_node_t's and vnodes for all of the corresponding files and
45 * directories that exist along the way. At this time, there are currently a
46 * rather small number of files passed in this way.
48 * This does lead to one behavior that folks used to other file systems might
49 * find peculiar. Because we are not always actively creating and destroying the
50 * required vnodes on demand, the count on the root vnode will not be going up
51 * accordingly with the existence of other vnodes. This means that a bootfs file
52 * system that is not in use will have all of its vnodes exist with a v_count of
57 static int bootfs_fstype
;
58 static id_space_t
*bootfs_idspace
;
59 static uint64_t bootfs_nactive
;
60 static kmutex_t bootfs_lock
;
62 static const char *bootfs_name
= "bootfs";
65 bootfs_mount(vfs_t
*vfsp
, vnode_t
*mvp
, struct mounta
*uap
, cred_t
*cr
)
72 if ((ret
= secpolicy_fs_mount(cr
, mvp
, vfsp
)) != 0)
75 if (mvp
->v_type
!= VDIR
)
78 if (uap
->flags
& MS_REMOUNT
)
81 mutex_enter(&mvp
->v_lock
);
82 if ((uap
->flags
& MS_OVERLAY
) == 0 &&
83 (mvp
->v_count
!= 1 || (mvp
->v_flag
& VROOT
))) {
84 mutex_exit(&mvp
->v_lock
);
87 mutex_exit(&mvp
->v_lock
);
90 * We indicate that the backing store is bootfs. We don't want to use
91 * swap, because folks might think that this is putting all the data
92 * into memory ala tmpfs. Rather these modules are always in memory and
93 * there's nothing to be done about that.
95 vfs_setresource(vfsp
, bootfs_name
, 0);
96 bfs
= kmem_zalloc(sizeof (bootfs_t
), KM_NOSLEEP
| KM_NORMALPRI
);
100 ret
= pn_get(uap
->dir
,
101 (uap
->flags
& MS_SYSSPACE
) ? UIO_SYSSPACE
: UIO_USERSPACE
, &dpn
);
103 kmem_free(bfs
, sizeof (bfs
));
107 bfs
->bfs_minor
= id_alloc(bootfs_idspace
);
108 bfs
->bfs_kstat
= kstat_create_zone("bootfs", bfs
->bfs_minor
, "bootfs",
109 "fs", KSTAT_TYPE_NAMED
,
110 sizeof (bootfs_stat_t
) / sizeof (kstat_named_t
),
111 KSTAT_FLAG_VIRTUAL
, GLOBAL_ZONEID
);
112 if (bfs
->bfs_kstat
== NULL
) {
113 id_free(bootfs_idspace
, bfs
->bfs_minor
);
115 kmem_free(bfs
, sizeof (bfs
));
118 bfs
->bfs_kstat
->ks_data
= &bfs
->bfs_stat
;
120 fsdev
= makedevice(bootfs_major
, bfs
->bfs_minor
);
121 bfs
->bfs_vfsp
= vfsp
;
123 vfsp
->vfs_data
= (caddr_t
)bfs
;
124 vfsp
->vfs_fstype
= bootfs_fstype
;
125 vfsp
->vfs_dev
= fsdev
;
126 vfsp
->vfs_bsize
= PAGESIZE
;
127 vfsp
->vfs_flag
|= VFS_RDONLY
| VFS_NOSETUID
| VFS_NOTRUNC
|
129 vfs_make_fsid(&vfsp
->vfs_fsid
, fsdev
, bootfs_fstype
);
130 bfs
->bfs_mntpath
= kmem_alloc(dpn
.pn_pathlen
+ 1, KM_SLEEP
);
131 bcopy(dpn
.pn_path
, bfs
->bfs_mntpath
, dpn
.pn_pathlen
);
132 bfs
->bfs_mntpath
[dpn
.pn_pathlen
] = '\0';
134 list_create(&bfs
->bfs_nodes
, sizeof (bootfs_node_t
),
135 offsetof(bootfs_node_t
, bvn_alink
));
137 kstat_named_init(&bfs
->bfs_stat
.bfss_nfiles
, "nfiles",
139 kstat_named_init(&bfs
->bfs_stat
.bfss_ndirs
, "ndirs",
141 kstat_named_init(&bfs
->bfs_stat
.bfss_nbytes
, "nbytes",
143 kstat_named_init(&bfs
->bfs_stat
.bfss_ndups
, "ndup",
145 kstat_named_init(&bfs
->bfs_stat
.bfss_ndiscards
, "ndiscard",
148 bootfs_construct(bfs
);
150 kstat_install(bfs
->bfs_kstat
);
156 bootfs_unmount(vfs_t
*vfsp
, int flag
, cred_t
*cr
)
159 bootfs_t
*bfs
= vfsp
->vfs_data
;
162 if ((ret
= secpolicy_fs_unmount(cr
, vfsp
)) != 0)
168 for (bnp
= list_head(&bfs
->bfs_nodes
); bnp
!= NULL
;
169 bnp
= list_next(&bfs
->bfs_nodes
, bnp
)) {
170 mutex_enter(&bnp
->bvn_vnp
->v_lock
);
171 if (bnp
->bvn_vnp
->v_count
> 1) {
172 mutex_exit(&bnp
->bvn_vnp
->v_lock
);
175 mutex_exit(&bnp
->bvn_vnp
->v_lock
);
178 kstat_delete(bfs
->bfs_kstat
);
179 bootfs_destruct(bfs
);
180 list_destroy(&bfs
->bfs_nodes
);
181 kmem_free(bfs
->bfs_mntpath
, strlen(bfs
->bfs_mntpath
) + 1);
182 id_free(bootfs_idspace
, bfs
->bfs_minor
);
183 kmem_free(bfs
, sizeof (bootfs_t
));
188 bootfs_root(vfs_t
*vfsp
, vnode_t
**vpp
)
192 bfs
= (bootfs_t
*)vfsp
->vfs_data
;
193 *vpp
= bfs
->bfs_rootvn
->bvn_vnp
;
200 bootfs_statvfs(vfs_t
*vfsp
, struct statvfs64
*sbp
)
202 const bootfs_t
*bfs
= (bootfs_t
*)vfsp
;
205 sbp
->f_bsize
= PAGESIZE
;
206 sbp
->f_frsize
= PAGESIZE
;
208 sbp
->f_blocks
= bfs
->bfs_stat
.bfss_nbytes
.value
.ui64
>> PAGESHIFT
;
212 sbp
->f_files
= bfs
->bfs_stat
.bfss_nfiles
.value
.ui32
+
213 bfs
->bfs_stat
.bfss_ndirs
.value
.ui32
;
217 (void) cmpldev(&d32
, vfsp
->vfs_dev
);
219 (void) strlcpy(sbp
->f_basetype
, bootfs_name
, FSTYPSZ
);
220 bzero(sbp
->f_fstr
, sizeof (sbp
->f_fstr
));
225 static const struct vfsops bootfs_vfsops
= {
226 .vfs_mount
= bootfs_mount
,
227 .vfs_unmount
= bootfs_unmount
,
228 .vfs_root
= bootfs_root
,
229 .vfs_statvfs
= bootfs_statvfs
,
233 bootfs_init(int fstype
, char *name
)
237 bootfs_fstype
= fstype
;
238 ASSERT(bootfs_fstype
!= 0);
240 ret
= vfs_setfsops(fstype
, &bootfs_vfsops
);
244 bootfs_major
= getudev();
245 if (bootfs_major
== (major_t
)-1) {
246 cmn_err(CE_WARN
, "bootfs_init: Can't get unique device number");
254 static mntopts_t bootfs_mntopts
= {
258 static vfsdef_t bootfs_vfsdef
= {
262 VSW_HASPROTO
|VSW_STATS
,
266 static struct modlfs bootfs_modlfs
= {
267 &mod_fsops
, "boot-time modules file system", &bootfs_vfsdef
270 static struct modlinkage bootfs_modlinkage
= {
271 MODREV_1
, &bootfs_modlfs
, NULL
277 bootfs_node_cache
= kmem_cache_create("bootfs_node_cache",
278 sizeof (bootfs_node_t
), 0, bootfs_node_constructor
,
279 bootfs_node_destructor
, NULL
, NULL
, NULL
, 0);
280 bootfs_idspace
= id_space_create("bootfs_minors", 1, INT32_MAX
);
281 mutex_init(&bootfs_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
283 return (mod_install(&bootfs_modlinkage
));
287 _info(struct modinfo
*modinfop
)
289 return (mod_info(&bootfs_modlinkage
, modinfop
));
297 mutex_enter(&bootfs_lock
);
298 if (bootfs_nactive
> 0) {
299 mutex_exit(&bootfs_lock
);
302 mutex_exit(&bootfs_lock
);
304 err
= mod_remove(&bootfs_modlinkage
);
308 (void) vfs_freevfsops_by_type(bootfs_fstype
);
309 id_space_destroy(bootfs_idspace
);
310 mutex_destroy(&bootfs_lock
);
311 kmem_cache_destroy(bootfs_node_cache
);