1 /* $NetBSD: rumpfs.c,v 1.35 2009/12/03 12:35:35 pooka Exp $ */
4 * Copyright (c) 2009 Antti Kantee. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.35 2009/12/03 12:35:35 pooka Exp $");
31 #include <sys/param.h>
32 #include <sys/atomic.h>
33 #include <sys/dirent.h>
34 #include <sys/errno.h>
35 #include <sys/filedesc.h>
36 #include <sys/fcntl.h>
37 #include <sys/kauth.h>
38 #include <sys/malloc.h>
39 #include <sys/module.h>
40 #include <sys/mount.h>
41 #include <sys/namei.h>
43 #include <sys/lockf.h>
44 #include <sys/queue.h>
46 #include <sys/syscallargs.h>
47 #include <sys/vnode.h>
49 #include <miscfs/fifofs/fifo.h>
50 #include <miscfs/specfs/specdev.h>
51 #include <miscfs/genfs/genfs.h>
53 #include <rump/rumpuser.h>
55 #include "rump_private.h"
56 #include "rump_vfs_private.h"
58 static int rump_vop_lookup(void *);
59 static int rump_vop_getattr(void *);
60 static int rump_vop_mkdir(void *);
61 static int rump_vop_mknod(void *);
62 static int rump_vop_create(void *);
63 static int rump_vop_inactive(void *);
64 static int rump_vop_reclaim(void *);
65 static int rump_vop_success(void *);
66 static int rump_vop_spec(void *);
67 static int rump_vop_read(void *);
68 static int rump_vop_write(void *);
69 static int rump_vop_open(void *);
71 int (**fifo_vnodeop_p
)(void *);
72 const struct vnodeopv_entry_desc fifo_vnodeop_entries
[] = {
73 { &vop_default_desc
, vn_default_error
},
76 const struct vnodeopv_desc fifo_vnodeop_opv_desc
=
77 { &fifo_vnodeop_p
, fifo_vnodeop_entries
};
79 int (**rump_vnodeop_p
)(void *);
80 const struct vnodeopv_entry_desc rump_vnodeop_entries
[] = {
81 { &vop_default_desc
, vn_default_error
},
82 { &vop_lookup_desc
, rump_vop_lookup
},
83 { &vop_getattr_desc
, rump_vop_getattr
},
84 { &vop_mkdir_desc
, rump_vop_mkdir
},
85 { &vop_mknod_desc
, rump_vop_mknod
},
86 { &vop_create_desc
, rump_vop_create
},
87 { &vop_access_desc
, rump_vop_success
},
88 { &vop_read_desc
, rump_vop_read
},
89 { &vop_write_desc
, rump_vop_write
},
90 { &vop_open_desc
, rump_vop_open
},
91 { &vop_putpages_desc
, genfs_null_putpages
},
92 { &vop_fsync_desc
, rump_vop_success
},
93 { &vop_lock_desc
, genfs_lock
},
94 { &vop_unlock_desc
, genfs_unlock
},
95 { &vop_inactive_desc
, rump_vop_inactive
},
96 { &vop_reclaim_desc
, rump_vop_reclaim
},
99 const struct vnodeopv_desc rump_vnodeop_opv_desc
=
100 { &rump_vnodeop_p
, rump_vnodeop_entries
};
102 int (**rump_specop_p
)(void *);
103 const struct vnodeopv_entry_desc rump_specop_entries
[] = {
104 { &vop_default_desc
, rump_vop_spec
},
107 const struct vnodeopv_desc rump_specop_opv_desc
=
108 { &rump_specop_p
, rump_specop_entries
};
110 const struct vnodeopv_desc
* const rump_opv_descs
[] = {
111 &rump_vnodeop_opv_desc
,
112 &rump_specop_opv_desc
,
118 struct rumpfs_node
*rd_node
;
120 LIST_ENTRY(rumpfs_dent
) rd_entries
;
129 char *hostpath
; /* VREG */
134 LIST_HEAD(, rumpfs_dent
) dir
; /* VDIR */
137 #define rn_hostpath rn_u.reg.hostpath
138 #define rn_readfd rn_u.reg.readfd
139 #define rn_writefd rn_u.reg.writefd
140 #define rn_offset rn_u.reg.offset
141 #define rn_dir rn_u.dir
143 struct rumpfs_mount
{
144 struct vnode
*rfsmp_rvp
;
147 static struct rumpfs_node
*makeprivate(enum vtype
, dev_t
, off_t
);
150 * Extra Terrestrial stuff. We map a given key (pathname) to a file on
151 * the host FS. ET phones home only from the root node of rumpfs.
153 * When an etfs node is removed, a vnode potentially behind it is not
154 * immediately recycled.
158 char et_key
[MAXPATHLEN
];
161 LIST_ENTRY(etfs
) et_entries
;
163 struct rumpfs_node
*et_rn
;
165 static kmutex_t etfs_lock
;
166 static LIST_HEAD(, etfs
) etfs_list
= LIST_HEAD_INITIALIZER(etfs_list
);
169 ettype_to_vtype(enum rump_etfs_type et
)
184 panic("invalid et type: %d", et
);
191 etfs_find(const char *key
, struct rumpfs_node
**rnp
)
194 size_t keylen
= strlen(key
);
197 KASSERT(mutex_owned(&etfs_lock
));
199 LIST_FOREACH(et
, &etfs_list
, et_entries
) {
200 if (keylen
== et
->et_keylen
&& strcmp(key
, et
->et_key
) == 0) {
211 doregister(const char *key
, const char *hostpath
,
212 enum rump_etfs_type ftype
, uint64_t begin
, uint64_t size
)
215 struct rumpfs_node
*rn_dummy
, *rn
;
221 if (rumpuser_getfileinfo(hostpath
, &fsize
, &hft
, &error
))
224 /* check that we give sensible arguments */
227 if (size
== RUMP_ETFS_SIZE_ENDOFF
)
228 size
= fsize
- begin
;
229 if (begin
+ size
> fsize
)
232 if (ftype
== RUMP_ETFS_BLK
|| ftype
== RUMP_ETFS_CHR
) {
233 error
= rumpblk_register(hostpath
, &dmin
, begin
, size
);
237 rdev
= makedev(RUMPBLK
, dmin
);
240 et
= kmem_alloc(sizeof(*et
), KM_SLEEP
);
241 strcpy(et
->et_key
, key
);
242 et
->et_keylen
= strlen(et
->et_key
);
243 et
->et_rn
= rn
= makeprivate(ettype_to_vtype(ftype
), rdev
, size
);
244 if (ftype
== RUMP_ETFS_REG
) {
245 size_t len
= strlen(hostpath
)+1;
247 rn
->rn_hostpath
= malloc(len
, M_TEMP
, M_WAITOK
| M_ZERO
);
248 memcpy(rn
->rn_hostpath
, hostpath
, len
);
249 rn
->rn_offset
= begin
;
252 mutex_enter(&etfs_lock
);
253 if (etfs_find(key
, &rn_dummy
)) {
254 mutex_exit(&etfs_lock
);
255 kmem_free(et
, sizeof(*et
));
256 /* XXX: rumpblk_deregister(hostpath); */
259 LIST_INSERT_HEAD(&etfs_list
, et
, et_entries
);
260 mutex_exit(&etfs_lock
);
266 rump_etfs_register(const char *key
, const char *hostpath
,
267 enum rump_etfs_type ftype
)
270 return doregister(key
, hostpath
, ftype
, 0, RUMP_ETFS_SIZE_ENDOFF
);
274 rump_etfs_register_withsize(const char *key
, const char *hostpath
,
275 enum rump_etfs_type ftype
, uint64_t begin
, uint64_t size
)
279 * Check that we're mapping at block offsets. I guess this
280 * is not technically necessary except for BLK/CHR backends
281 * (i.e. what getfileinfo() returns, not ftype) and can be
282 * removed later if there are problems.
284 if ((begin
& (DEV_BSIZE
-1)) != 0)
286 if (size
!= RUMP_ETFS_SIZE_ENDOFF
&& (size
& (DEV_BSIZE
-1)) != 0)
289 return doregister(key
, hostpath
, ftype
, begin
, size
);
293 rump_etfs_remove(const char *key
)
296 size_t keylen
= strlen(key
);
298 mutex_enter(&etfs_lock
);
299 LIST_FOREACH(et
, &etfs_list
, et_entries
) {
300 if (keylen
== et
->et_keylen
&& strcmp(et
->et_key
, key
) == 0) {
301 LIST_REMOVE(et
, et_entries
);
302 kmem_free(et
, sizeof(*et
));
306 mutex_exit(&etfs_lock
);
317 static int lastino
= 1;
318 static kmutex_t reclock
;
320 static struct rumpfs_node
*
321 makeprivate(enum vtype vt
, dev_t rdev
, off_t size
)
323 struct rumpfs_node
*rn
;
327 rn
= kmem_zalloc(sizeof(*rn
), KM_SLEEP
);
331 LIST_INIT(&rn
->rn_dir
);
353 va
->va_fileid
= atomic_inc_uint_nv(&lastino
);
355 va
->va_blocksize
= 512;
359 va
->va_birthtime
= ts
;
371 makevnode(struct mount
*mp
, struct rumpfs_node
*rn
, struct vnode
**vpp
)
374 int (**vpops
)(void *);
375 struct vattr
*va
= &rn
->rn_va
;
378 KASSERT(mutex_owned(&reclock
));
380 if (va
->va_type
== VCHR
|| va
->va_type
== VBLK
) {
381 vpops
= rump_specop_p
;
383 vpops
= rump_vnodeop_p
;
385 if (vpops
!= rump_specop_p
&& va
->va_type
!= VDIR
386 && !(va
->va_type
== VREG
&& rn
->rn_hostpath
!= NULL
)
387 && va
->va_type
!= VSOCK
)
390 rv
= getnewvnode(VT_RUMP
, mp
, vpops
, &vp
);
394 vp
->v_size
= vp
->v_writesize
= va
->va_size
;
395 vp
->v_type
= va
->va_type
;
397 if (vpops
== rump_specop_p
) {
398 spec_node_init(vp
, va
->va_rdev
);
402 vn_lock(vp
, LK_RETRY
| LK_EXCLUSIVE
);
410 * Simple lookup for faking lookup of device entry for rump file systems
411 * and for locating/creating directories. Yes, this will panic if you
412 * call it with the wrong arguments.
414 * uhm, this is twisted. C F C C, hope of C C F C looming
417 rump_vop_lookup(void *v
)
419 struct vop_lookup_args
/* {
421 struct vnode **a_vpp;
422 struct componentname *a_cnp;
424 struct componentname
*cnp
= ap
->a_cnp
;
425 struct vnode
*dvp
= ap
->a_dvp
;
426 struct vnode
**vpp
= ap
->a_vpp
;
428 struct rumpfs_node
*rnd
= dvp
->v_data
, *rn
;
429 struct rumpfs_dent
*rd
= NULL
;
432 /* we handle only some "non-special" cases */
433 if (!(((cnp
->cn_flags
& ISLASTCN
) == 0)
434 || (cnp
->cn_nameiop
== LOOKUP
|| cnp
->cn_nameiop
== CREATE
)))
436 if (!((cnp
->cn_flags
& ISDOTDOT
) == 0))
439 /* check for dot, return directly if the case */
440 if (cnp
->cn_namelen
== 1 && cnp
->cn_nameptr
[0] == '.') {
446 /* check if we are returning a faked block device */
447 if (dvp
== rootvnode
&& cnp
->cn_nameiop
== LOOKUP
) {
448 mutex_enter(&etfs_lock
);
449 if (etfs_find(cnp
->cn_pnbuf
, &rn
)) {
450 mutex_exit(&etfs_lock
);
451 cnp
->cn_consume
= strlen(cnp
->cn_nameptr
453 cnp
->cn_flags
&= ~REQUIREDIR
;
456 mutex_exit(&etfs_lock
);
460 LIST_FOREACH(rd
, &rnd
->rn_dir
, rd_entries
) {
461 if (strlen(rd
->rd_name
) == cnp
->cn_namelen
&&
462 strncmp(rd
->rd_name
, cnp
->cn_nameptr
,
463 cnp
->cn_namelen
) == 0)
468 if (!rd
&& ((cnp
->cn_flags
& ISLASTCN
) == 0||cnp
->cn_nameiop
!= CREATE
))
471 if (!rd
&& (cnp
->cn_flags
& ISLASTCN
) && cnp
->cn_nameiop
== CREATE
) {
472 cnp
->cn_flags
|= SAVENAME
;
480 mutex_enter(&reclock
);
481 if ((vp
= rn
->rn_vp
)) {
482 mutex_enter(&vp
->v_interlock
);
483 mutex_exit(&reclock
);
484 if (vget(vp
, LK_EXCLUSIVE
| LK_INTERLOCK
))
488 rv
= makevnode(dvp
->v_mount
, rn
, vpp
);
490 mutex_exit(&reclock
);
500 rump_vop_getattr(void *v
)
502 struct vop_getattr_args
/* {
507 struct rumpfs_node
*rn
= ap
->a_vp
->v_data
;
509 memcpy(ap
->a_vap
, &rn
->rn_va
, sizeof(struct vattr
));
514 rump_vop_mkdir(void *v
)
516 struct vop_mkdir_args
/* {
518 struct vnode **a_vpp;
519 struct componentname *a_cnp;
522 struct vnode
*dvp
= ap
->a_dvp
;
523 struct vnode
**vpp
= ap
->a_vpp
;
524 struct componentname
*cnp
= ap
->a_cnp
;
525 struct rumpfs_node
*rnd
= dvp
->v_data
, *rn
;
526 struct rumpfs_dent
*rdent
;
529 rn
= makeprivate(VDIR
, NODEV
, DEV_BSIZE
);
530 mutex_enter(&reclock
);
531 rv
= makevnode(dvp
->v_mount
, rn
, vpp
);
532 mutex_exit(&reclock
);
536 rdent
= kmem_alloc(sizeof(*rdent
), KM_SLEEP
);
537 rdent
->rd_name
= kmem_alloc(cnp
->cn_namelen
+1, KM_SLEEP
);
538 rdent
->rd_node
= (*vpp
)->v_data
;
539 strlcpy(rdent
->rd_name
, cnp
->cn_nameptr
, cnp
->cn_namelen
+1);
541 LIST_INSERT_HEAD(&rnd
->rn_dir
, rdent
, rd_entries
);
549 rump_vop_mknod(void *v
)
551 struct vop_mknod_args
/* {
553 struct vnode **a_vpp;
554 struct componentname *a_cnp;
557 struct vnode
*dvp
= ap
->a_dvp
;
558 struct vnode
**vpp
= ap
->a_vpp
;
559 struct componentname
*cnp
= ap
->a_cnp
;
560 struct vattr
*va
= ap
->a_vap
;
561 struct rumpfs_node
*rnd
= dvp
->v_data
, *rn
;
562 struct rumpfs_dent
*rdent
;
565 rn
= makeprivate(va
->va_type
, va
->va_rdev
, DEV_BSIZE
);
566 mutex_enter(&reclock
);
567 rv
= makevnode(dvp
->v_mount
, rn
, vpp
);
568 mutex_exit(&reclock
);
572 rdent
= kmem_alloc(sizeof(*rdent
), KM_SLEEP
);
573 rdent
->rd_name
= kmem_alloc(cnp
->cn_namelen
+1, KM_SLEEP
);
574 rdent
->rd_node
= (*vpp
)->v_data
;
575 rdent
->rd_node
->rn_va
.va_rdev
= va
->va_rdev
;
576 strlcpy(rdent
->rd_name
, cnp
->cn_nameptr
, cnp
->cn_namelen
+1);
578 LIST_INSERT_HEAD(&rnd
->rn_dir
, rdent
, rd_entries
);
586 rump_vop_create(void *v
)
588 struct vop_create_args
/* {
590 struct vnode **a_vpp;
591 struct componentname *a_cnp;
594 struct vnode
*dvp
= ap
->a_dvp
;
595 struct vnode
**vpp
= ap
->a_vpp
;
596 struct componentname
*cnp
= ap
->a_cnp
;
597 struct vattr
*va
= ap
->a_vap
;
598 struct rumpfs_node
*rnd
= dvp
->v_data
, *rn
;
599 struct rumpfs_dent
*rdent
;
602 if (va
->va_type
!= VSOCK
) {
606 rn
= makeprivate(VSOCK
, NODEV
, DEV_BSIZE
);
607 mutex_enter(&reclock
);
608 rv
= makevnode(dvp
->v_mount
, rn
, vpp
);
609 mutex_exit(&reclock
);
613 rdent
= kmem_alloc(sizeof(*rdent
), KM_SLEEP
);
614 rdent
->rd_name
= kmem_alloc(cnp
->cn_namelen
+1, KM_SLEEP
);
615 rdent
->rd_node
= (*vpp
)->v_data
;
616 rdent
->rd_node
->rn_va
.va_rdev
= NODEV
;
617 strlcpy(rdent
->rd_name
, cnp
->cn_nameptr
, cnp
->cn_namelen
+1);
619 LIST_INSERT_HEAD(&rnd
->rn_dir
, rdent
, rd_entries
);
627 rump_vop_open(void *v
)
629 struct vop_open_args
/* {
634 struct vnode
*vp
= ap
->a_vp
;
635 struct rumpfs_node
*rn
= vp
->v_data
;
636 int mode
= ap
->a_mode
;
639 if (vp
->v_type
!= VREG
)
643 if (rn
->rn_readfd
!= -1)
645 rn
->rn_readfd
= rumpuser_open(rn
->rn_hostpath
,
647 } else if (mode
& FWRITE
) {
648 if (rn
->rn_writefd
!= -1)
650 rn
->rn_writefd
= rumpuser_open(rn
->rn_hostpath
,
658 rump_vop_read(void *v
)
660 struct vop_read_args
/* {
663 int ioflags a_ioflag;
666 struct vnode
*vp
= ap
->a_vp
;
667 struct rumpfs_node
*rn
= vp
->v_data
;
668 struct uio
*uio
= ap
->a_uio
;
673 bufsize
= uio
->uio_resid
;
674 buf
= kmem_alloc(bufsize
, KM_SLEEP
);
675 if (rumpuser_pread(rn
->rn_readfd
, buf
, bufsize
,
676 uio
->uio_offset
+ rn
->rn_offset
, &error
) == -1)
678 error
= uiomove(buf
, bufsize
, uio
);
681 kmem_free(buf
, bufsize
);
686 rump_vop_write(void *v
)
688 struct vop_read_args
/* {
691 int ioflags a_ioflag;
694 struct vnode
*vp
= ap
->a_vp
;
695 struct rumpfs_node
*rn
= vp
->v_data
;
696 struct uio
*uio
= ap
->a_uio
;
701 bufsize
= uio
->uio_resid
;
702 buf
= kmem_alloc(bufsize
, KM_SLEEP
);
703 error
= uiomove(buf
, bufsize
, uio
);
706 KASSERT(uio
->uio_resid
== 0);
707 rumpuser_pwrite(rn
->rn_writefd
, buf
, bufsize
,
708 uio
->uio_offset
+ rn
->rn_offset
, &error
);
711 kmem_free(buf
, bufsize
);
716 rump_vop_success(void *v
)
723 rump_vop_inactive(void *v
)
725 struct vop_inactive_args
*ap
= v
;
726 struct vnode
*vp
= ap
->a_vp
;
727 struct rumpfs_node
*rn
= vp
->v_data
;
730 if (vp
->v_type
== VREG
) {
731 if (rn
->rn_readfd
!= -1) {
732 rumpuser_close(rn
->rn_readfd
, &error
);
735 if (rn
->rn_writefd
!= -1) {
736 rumpuser_close(rn
->rn_writefd
, &error
);
746 rump_vop_reclaim(void *v
)
748 struct vop_reclaim_args
/* {
751 struct vnode
*vp
= ap
->a_vp
;
752 struct rumpfs_node
*rn
= vp
->v_data
;
754 mutex_enter(&reclock
);
756 mutex_exit(&reclock
);
763 rump_vop_spec(void *v
)
765 struct vop_generic_args
*ap
= v
;
766 int (**opvec
)(void *);
768 switch (ap
->a_desc
->vdesc_offset
) {
769 case VOP_ACCESS_DESCOFFSET
:
770 case VOP_GETATTR_DESCOFFSET
:
771 case VOP_LOCK_DESCOFFSET
:
772 case VOP_UNLOCK_DESCOFFSET
:
773 opvec
= rump_vnodeop_p
;
776 opvec
= spec_vnodeop_p
;
780 return VOCALL(opvec
, ap
->a_desc
->vdesc_offset
, v
);
784 * Begin vfs-level stuff
788 struct vfsops rumpfs_vfsops
= {
789 .vfs_name
= MOUNT_RUMPFS
,
790 .vfs_min_mount_data
= 0,
791 .vfs_mount
= rumpfs_mount
,
792 .vfs_start
= (void *)nullop
,
793 .vfs_unmount
= rumpfs_unmount
,
794 .vfs_root
= rumpfs_root
,
795 .vfs_quotactl
= (void *)eopnotsupp
,
796 .vfs_statvfs
= genfs_statvfs
,
797 .vfs_sync
= (void *)nullop
,
798 .vfs_vget
= rumpfs_vget
,
799 .vfs_fhtovp
= (void *)eopnotsupp
,
800 .vfs_vptofh
= (void *)eopnotsupp
,
801 .vfs_init
= rumpfs_init
,
803 .vfs_done
= rumpfs_done
,
804 .vfs_mountroot
= rumpfs_mountroot
,
805 .vfs_snapshot
= (void *)eopnotsupp
,
806 .vfs_extattrctl
= (void *)eopnotsupp
,
807 .vfs_suspendctl
= (void *)eopnotsupp
,
808 .vfs_opv_descs
= rump_opv_descs
,
814 rumpfs_mount(struct mount
*mp
, const char *mntpath
, void *arg
, size_t *alen
)
821 rumpfs_unmount(struct mount
*mp
, int flags
)
824 return EOPNOTSUPP
; /* ;) */
828 rumpfs_root(struct mount
*mp
, struct vnode
**vpp
)
830 struct rumpfs_mount
*rfsmp
= mp
->mnt_data
;
832 vget(rfsmp
->rfsmp_rvp
, LK_EXCLUSIVE
| LK_RETRY
);
833 *vpp
= rfsmp
->rfsmp_rvp
;
838 rumpfs_vget(struct mount
*mp
, ino_t ino
, struct vnode
**vpp
)
848 CTASSERT(RUMP_ETFS_SIZE_ENDOFF
== RUMPBLK_SIZENOTSET
);
850 mutex_init(&reclock
, MUTEX_DEFAULT
, IPL_NONE
);
851 mutex_init(&etfs_lock
, MUTEX_DEFAULT
, IPL_NONE
);
858 mutex_destroy(&reclock
);
859 mutex_destroy(&etfs_lock
);
866 struct rumpfs_mount
*rfsmp
;
867 struct rumpfs_node
*rn
;
870 if ((error
= vfs_rootmountalloc(MOUNT_RUMPFS
, "rootdev", &mp
)) != 0) {
875 rfsmp
= kmem_alloc(sizeof(*rfsmp
), KM_SLEEP
);
877 rn
= makeprivate(VDIR
, NODEV
, DEV_BSIZE
);
878 mutex_enter(&reclock
);
879 error
= makevnode(mp
, rn
, &rfsmp
->rfsmp_rvp
);
880 mutex_exit(&reclock
);
882 panic("could not create root vnode: %d", error
);
883 rfsmp
->rfsmp_rvp
->v_vflag
|= VV_ROOT
;
884 VOP_UNLOCK(rfsmp
->rfsmp_rvp
, 0);
886 mutex_enter(&mountlist_lock
);
887 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
888 mutex_exit(&mountlist_lock
);
890 mp
->mnt_data
= rfsmp
;
891 mp
->mnt_stat
.f_namemax
= MAXNAMLEN
;
892 mp
->mnt_flag
|= MNT_LOCAL
;
895 error
= set_statvfs_info("/", UIO_SYSSPACE
, "rumpfs", UIO_SYSSPACE
,
896 mp
->mnt_op
->vfs_name
, mp
, curlwp
);
898 panic("set statvfsinfo for rootfs failed");
900 vfs_unbusy(mp
, false, NULL
);