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. All rights reserved.
17 * This file takes care of reading the boot time modules and constructing them
18 * into the appropriate series of vnodes.
23 #include <sys/sunddi.h>
25 #include <sys/sysmacros.h>
28 #include <sys/fs/bootfs_impl.h>
30 kmem_cache_t
*bootfs_node_cache
;
32 static const vattr_t bootfs_vattr_dir
= {
35 S_IFDIR
| 0555, /* va_mode */
51 static const vattr_t bootfs_vattr_reg
= {
54 S_IFREG
| 0555, /* va_mode */
72 bootfs_node_constructor(void *buf
, void *arg
, int kmflags
)
74 bootfs_node_t
*bnp
= buf
;
76 bnp
->bvn_vnp
= vn_alloc(kmflags
);
77 if (bnp
->bvn_vnp
== NULL
)
85 bootfs_node_destructor(void *buf
, void *arg
)
87 bootfs_node_t
*bnp
= buf
;
89 vn_free(bnp
->bvn_vnp
);
93 bootfs_comparator(const void *a
, const void *b
)
95 const bootfs_node_t
*lfs
, *rfs
;
101 ret
= strcmp(lfs
->bvn_name
, rfs
->bvn_name
);
110 bootfs_node_init(bootfs_t
*bfs
, bootfs_node_t
*bnp
, const struct vattr
*vap
,
111 const char *name
, size_t namelen
)
115 vn_reinit(bnp
->bvn_vnp
);
117 bnp
->bvn_vnp
->v_flag
|= VNOSWAP
;
118 bnp
->bvn_vnp
->v_type
= vap
->va_type
;
119 bnp
->bvn_vnp
->v_vfsp
= bfs
->bfs_vfsp
;
120 bnp
->bvn_vnp
->v_rdev
= 0;
121 bnp
->bvn_vnp
->v_data
= (caddr_t
)bnp
;
122 vn_setops(bnp
->bvn_vnp
, &bootfs_vnodeops
);
124 bnp
->bvn_name
= kmem_alloc(namelen
+ 1, KM_SLEEP
);
125 bcopy(name
, bnp
->bvn_name
, namelen
);
126 bnp
->bvn_name
[namelen
] = '\0';
127 if (vap
->va_type
== VDIR
) {
128 avl_create(&bnp
->bvn_dir
, bootfs_comparator
,
129 sizeof (bootfs_node_t
),
130 offsetof(bootfs_node_t
, bvn_link
));
132 bzero(&bnp
->bvn_link
, sizeof (avl_node_t
));
133 bcopy(vap
, &bnp
->bvn_attr
, sizeof (vattr_t
));
136 bnp
->bvn_attr
.va_atime
= now
;
137 bnp
->bvn_attr
.va_ctime
= now
;
138 bnp
->bvn_attr
.va_mtime
= now
;
139 bnp
->bvn_attr
.va_fsid
= makedevice(bootfs_major
, bfs
->bfs_minor
);
140 bnp
->bvn_attr
.va_nodeid
= bfs
->bfs_ninode
;
141 bnp
->bvn_attr
.va_blksize
= PAGESIZE
;
143 list_insert_tail(&bfs
->bfs_nodes
, bnp
);
147 bootfs_mkroot(bootfs_t
*bfs
)
151 bnp
= kmem_cache_alloc(bootfs_node_cache
, KM_SLEEP
);
152 bootfs_node_init(bfs
, bnp
, &bootfs_vattr_dir
, "/", 1);
153 bnp
->bvn_vnp
->v_flag
|= VROOT
;
154 bnp
->bvn_parent
= bnp
;
155 bfs
->bfs_rootvn
= bnp
;
156 bfs
->bfs_stat
.bfss_ndirs
.value
.ui32
++;
157 vn_exists(bnp
->bvn_vnp
);
161 bootfs_mknode(bootfs_t
*bfs
, bootfs_node_t
*parent
, bootfs_node_t
**outp
,
162 const char *name
, size_t namelen
, const vattr_t
*vap
, uintptr_t addr
,
170 ASSERT(parent
->bvn_attr
.va_type
== VDIR
);
171 buf
= kmem_alloc(namelen
+ 1, KM_SLEEP
);
172 bcopy(name
, buf
, namelen
);
175 if ((bnp
= avl_find(&parent
->bvn_dir
, &sn
, &where
)) != NULL
) {
176 kmem_free(buf
, namelen
+ 1);
177 /* Directories can collide, files cannot */
178 if (vap
->va_type
== VDIR
) {
184 kmem_free(buf
, namelen
+ 1);
186 bnp
= kmem_cache_alloc(bootfs_node_cache
, KM_SLEEP
);
187 bootfs_node_init(bfs
, bnp
, vap
, name
, namelen
);
188 bnp
->bvn_parent
= parent
;
189 avl_add(&parent
->bvn_dir
, bnp
);
192 if (vap
->va_type
== VDIR
) {
193 parent
->bvn_attr
.va_size
++;
194 parent
->bvn_attr
.va_nlink
++;
195 bfs
->bfs_stat
.bfss_ndirs
.value
.ui32
++;
197 bnp
->bvn_addr
= addr
;
198 bnp
->bvn_size
= size
;
199 bfs
->bfs_stat
.bfss_nfiles
.value
.ui32
++;
200 bfs
->bfs_stat
.bfss_nbytes
.value
.ui64
+= size
;
201 bnp
->bvn_attr
.va_nblocks
= P2ROUNDUP(size
, 512) >> 9;
202 bnp
->bvn_attr
.va_size
= size
;
205 vn_exists(bnp
->bvn_vnp
);
211 * Given the address, size, and path a boot-time module would like, go through
212 * and create all of the directory entries that are required and then the file
213 * itself. If someone has passed in a module that has the same name as another
214 * one, we honor the first one.
217 bootfs_construct_entry(bootfs_t
*bfs
, uintptr_t addr
, uint64_t size
,
225 const char *p
= mname
;
226 bootfs_node_t
*bnp
= bfs
->bfs_rootvn
;
232 /* First eliminate all leading / characters. */
236 /* A name with all slashes or ending in a / */
243 nlen
= (ptrdiff_t)sp
- (ptrdiff_t)p
;
244 if (strncmp(p
, ".", nlen
) == 0) {
249 if (strncmp(p
, "..", nlen
) == 0) {
250 bnp
= bnp
->bvn_parent
;
255 VERIFY(bootfs_mknode(bfs
, bnp
, &nbnp
, p
, nlen
,
256 &bootfs_vattr_dir
, addr
, size
) == 0);
262 ret
= bootfs_mknode(bfs
, bnp
, &nbnp
, p
, nlen
, &bootfs_vattr_reg
,
271 * We're going to go through every boot time module and construct the
272 * appropriate vnodes for them now. Because there are very few of these that
273 * exist, generally on the order of a handful, we're going to create them all
274 * when the file system is initialized and then tear them all down when the
275 * module gets unloaded.
277 * The information about the modules is contained in properties on the root of
278 * the devinfo tree. Specifically there are three properties per module:
280 * - module-size-%d int64_t size, in bytes, of the boot time module.
281 * - module-addr-%d The address of the boot time module
282 * - module-name-%d The string name of the boot time module
284 * Note that the module-size and module-addr fields are always 64-bit values
285 * regardless of being on a 32-bit or 64-bit kernel. module-name is a string
288 * There is no property that indicates the total number of such modules. Modules
289 * start at 0 and work their way up incrementally. The first time we can't find
290 * a module or a property, then we stop.
293 bootfs_construct(bootfs_t
*bfs
)
296 char paddr
[64], psize
[64], pname
[64], *mname
;
302 root
= ddi_root_node();
305 if (id
== UINT32_MAX
)
308 if (snprintf(paddr
, sizeof (paddr
), "module-addr-%d", id
) >
312 if (snprintf(psize
, sizeof (paddr
), "module-size-%d", id
) >
316 if (snprintf(pname
, sizeof (paddr
), "module-name-%d", id
) >
320 addr
= (uint64_t)ddi_prop_get_int64(DDI_DEV_T_ANY
, root
,
321 DDI_PROP_DONTPASS
, paddr
, 0);
322 if (addr
== 0 || addr
== DDI_PROP_NOT_FOUND
)
325 size
= (uint64_t)ddi_prop_get_int64(DDI_DEV_T_ANY
, root
,
326 DDI_PROP_DONTPASS
, psize
, 0);
327 if (size
== 0 || size
== DDI_PROP_NOT_FOUND
)
330 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, root
,
331 DDI_PROP_DONTPASS
, pname
, &mname
) != DDI_PROP_SUCCESS
)
334 ret
= bootfs_construct_entry(bfs
, addr
, size
, mname
);
336 bfs
->bfs_stat
.bfss_ndiscards
.value
.ui32
++;
338 bfs
->bfs_stat
.bfss_ndups
.value
.ui32
++;
339 ddi_prop_free(mname
);
346 bootfs_destruct(bootfs_t
*bfs
)
350 while ((bnp
= list_remove_head(&bfs
->bfs_nodes
)) != NULL
) {
351 ASSERT(bnp
->bvn_vnp
->v_count
== 1);
352 VN_RELE(bnp
->bvn_vnp
);
353 kmem_free(bnp
->bvn_name
, strlen(bnp
->bvn_name
) + 1);
354 kmem_cache_free(bootfs_node_cache
, bnp
);