1 /* $NetBSD: rumpfs.c,v 1.167 2023/06/27 19:30:27 andvar Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2010, 2011 Antti Kantee. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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. 14 * 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 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.167 2023/06/27 19:30:27 andvar Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/atomic.h> 33 #include <sys/buf.h> 34 #include <sys/dirent.h> 35 #include <sys/errno.h> 36 #include <sys/filedesc.h> 37 #include <sys/fcntl.h> 38 #include <sys/kauth.h> 39 #include <sys/malloc.h> 40 #include <sys/module.h> 41 #include <sys/mount.h> 42 #include <sys/namei.h> 43 #include <sys/lock.h> 44 #include <sys/lockf.h> 45 #include <sys/queue.h> 46 #include <sys/stat.h> 47 #include <sys/syscallargs.h> 48 #include <sys/vnode.h> 49 #include <sys/fstrans.h> 50 #include <sys/unistd.h> 51 52 #include <miscfs/specfs/specdev.h> 53 #include <miscfs/genfs/genfs.h> 54 #include <miscfs/genfs/genfs_node.h> 55 56 #include <uvm/uvm_extern.h> 57 58 #include <rump-sys/kern.h> 59 #include <rump-sys/vfs.h> 60 61 #include <rump/rumpfs.h> 62 #include <rump/rumpuser.h> 63 64 static int rump_vop_parsepath(void *); 65 static int rump_vop_lookup(void *); 66 static int rump_vop_getattr(void *); 67 static int rump_vop_setattr(void *); 68 static int rump_vop_mkdir(void *); 69 static int rump_vop_rmdir(void *); 70 static int rump_vop_remove(void *); 71 static int rump_vop_mknod(void *); 72 static int rump_vop_create(void *); 73 static int rump_vop_inactive(void *); 74 static int rump_vop_reclaim(void *); 75 static int rump_vop_success(void *); 76 static int rump_vop_readdir(void *); 77 static int rump_vop_spec(void *); 78 static int rump_vop_read(void *); 79 static int rump_vop_write(void *); 80 static int rump_vop_open(void *); 81 static int rump_vop_symlink(void *); 82 static int rump_vop_readlink(void *); 83 static int rump_vop_whiteout(void *); 84 static int rump_vop_pathconf(void *); 85 static int rump_vop_bmap(void *); 86 static int rump_vop_strategy(void *); 87 static int rump_vop_advlock(void *); 88 static int rump_vop_access(void *); 89 static int rump_vop_fcntl(void *); 90 91 int (**rump_vnodeop_p)(void *); 92 const struct vnodeopv_entry_desc rump_vnodeop_entries[] = { 93 { &vop_default_desc, vn_default_error }, 94 { &vop_parsepath_desc, rump_vop_parsepath }, 95 { &vop_lookup_desc, rump_vop_lookup }, 96 { &vop_getattr_desc, rump_vop_getattr }, 97 { &vop_setattr_desc, rump_vop_setattr }, 98 { &vop_mkdir_desc, rump_vop_mkdir }, 99 { &vop_rmdir_desc, rump_vop_rmdir }, 100 { &vop_remove_desc, rump_vop_remove }, 101 { &vop_mknod_desc, rump_vop_mknod }, 102 { &vop_create_desc, rump_vop_create }, 103 { &vop_symlink_desc, rump_vop_symlink }, 104 { &vop_readlink_desc, rump_vop_readlink }, 105 { &vop_access_desc, rump_vop_access }, 106 { &vop_accessx_desc, genfs_accessx }, 107 { &vop_readdir_desc, rump_vop_readdir }, 108 { &vop_read_desc, rump_vop_read }, 109 { &vop_write_desc, rump_vop_write }, 110 { &vop_open_desc, rump_vop_open }, 111 { &vop_close_desc, genfs_nullop }, 112 { &vop_seek_desc, genfs_seek }, 113 { &vop_getpages_desc, genfs_getpages }, 114 { &vop_putpages_desc, genfs_putpages }, 115 { &vop_whiteout_desc, rump_vop_whiteout }, 116 { &vop_fsync_desc, rump_vop_success }, 117 { &vop_lock_desc, genfs_lock }, 118 { &vop_unlock_desc, genfs_unlock }, 119 { &vop_islocked_desc, genfs_islocked }, 120 { &vop_inactive_desc, rump_vop_inactive }, 121 { &vop_reclaim_desc, rump_vop_reclaim }, 122 { &vop_link_desc, genfs_eopnotsupp }, 123 { &vop_pathconf_desc, rump_vop_pathconf }, 124 { &vop_bmap_desc, rump_vop_bmap }, 125 { &vop_strategy_desc, rump_vop_strategy }, 126 { &vop_advlock_desc, rump_vop_advlock }, 127 { &vop_fcntl_desc, rump_vop_fcntl }, 128 { NULL, NULL } 129 }; 130 const struct vnodeopv_desc rump_vnodeop_opv_desc = 131 { &rump_vnodeop_p, rump_vnodeop_entries }; 132 133 int (**rump_specop_p)(void *); 134 const struct vnodeopv_entry_desc rump_specop_entries[] = { 135 { &vop_default_desc, rump_vop_spec }, 136 { NULL, NULL } 137 }; 138 const struct vnodeopv_desc rump_specop_opv_desc = 139 { &rump_specop_p, rump_specop_entries }; 140 141 const struct vnodeopv_desc * const rump_opv_descs[] = { 142 &rump_vnodeop_opv_desc, 143 &rump_specop_opv_desc, 144 NULL 145 }; 146 147 #define RUMPFS_WHITEOUT ((void *)-1) 148 #define RDENT_ISWHITEOUT(rdp) (rdp->rd_node == RUMPFS_WHITEOUT) 149 struct rumpfs_dent { 150 char *rd_name; 151 int rd_namelen; 152 struct rumpfs_node *rd_node; 153 154 LIST_ENTRY(rumpfs_dent) rd_entries; 155 }; 156 157 struct genfs_ops rumpfs_genfsops = { 158 .gop_size = genfs_size, 159 .gop_write = genfs_gop_write, 160 .gop_putrange = genfs_gop_putrange, 161 162 /* optional */ 163 .gop_alloc = NULL, 164 .gop_markupdate = NULL, 165 }; 166 167 struct rumpfs_node { 168 struct genfs_node rn_gn; 169 struct vattr rn_va; 170 struct vnode *rn_vp; 171 char *rn_hostpath; 172 int rn_flags; 173 struct lockf *rn_lockf; 174 175 union { 176 struct { /* VREG */ 177 int readfd; 178 int writefd; 179 uint64_t offset; 180 } reg; 181 struct { 182 void *data; 183 size_t dlen; 184 } reg_noet; 185 struct { /* VDIR */ 186 LIST_HEAD(, rumpfs_dent) dents; 187 struct rumpfs_node *parent; 188 int flags; 189 } dir; 190 struct { 191 char *target; 192 size_t len; 193 } link; 194 } rn_u; 195 }; 196 #define rn_readfd rn_u.reg.readfd 197 #define rn_writefd rn_u.reg.writefd 198 #define rn_offset rn_u.reg.offset 199 #define rn_data rn_u.reg_noet.data 200 #define rn_dlen rn_u.reg_noet.dlen 201 #define rn_dir rn_u.dir.dents 202 #define rn_parent rn_u.dir.parent 203 #define rn_linktarg rn_u.link.target 204 #define rn_linklen rn_u.link.len 205 206 #define RUMPNODE_CANRECLAIM 0x01 207 #define RUMPNODE_DIR_ET 0x02 208 #define RUMPNODE_DIR_ETSUBS 0x04 209 #define RUMPNODE_ET_PHONE_HOST 0x10 210 #define RUMPNODE_EXTSTORAGE 0x20 211 212 struct rumpfs_mount { 213 struct vnode *rfsmp_rvp; 214 }; 215 216 #define INO_WHITEOUT 1 217 static int lastino = 2; 218 static kmutex_t reclock; 219 220 #define RUMPFS_DEFAULTMODE 0755 221 static void freedir(struct rumpfs_node *, struct componentname *); 222 static struct rumpfs_node *makeprivate(enum vtype, mode_t, dev_t, off_t, bool); 223 static void freeprivate(struct rumpfs_node *); 224 225 /* 226 * Extra Terrestrial stuff. We map a given key (pathname) to a file on 227 * the host FS. ET phones home only from the root node of rumpfs. 228 * 229 * When an etfs node is removed, a vnode potentially behind it is not 230 * immediately recycled. 231 */ 232 233 struct etfs { 234 char et_key[MAXPATHLEN]; 235 size_t et_keylen; 236 bool et_prefixkey; 237 bool et_removing; 238 devminor_t et_blkmin; 239 240 LIST_ENTRY(etfs) et_entries; 241 242 struct rumpfs_node *et_rn; 243 }; 244 static kmutex_t etfs_lock; 245 static LIST_HEAD(, etfs) etfs_list = LIST_HEAD_INITIALIZER(etfs_list); 246 247 static enum vtype 248 ettype_to_vtype(enum rump_etfs_type et) 249 { 250 enum vtype vt; 251 252 switch (et) { 253 case RUMP_ETFS_REG: 254 vt = VREG; 255 break; 256 case RUMP_ETFS_BLK: 257 vt = VBLK; 258 break; 259 case RUMP_ETFS_CHR: 260 vt = VCHR; 261 break; 262 case RUMP_ETFS_DIR: 263 vt = VDIR; 264 break; 265 case RUMP_ETFS_DIR_SUBDIRS: 266 vt = VDIR; 267 break; 268 default: 269 panic("invalid et type: %d", et); 270 } 271 272 return vt; 273 } 274 275 static enum vtype 276 hft_to_vtype(int hft) 277 { 278 enum vtype vt; 279 280 switch (hft) { 281 case RUMPUSER_FT_OTHER: 282 vt = VNON; 283 break; 284 case RUMPUSER_FT_DIR: 285 vt = VDIR; 286 break; 287 case RUMPUSER_FT_REG: 288 vt = VREG; 289 break; 290 case RUMPUSER_FT_BLK: 291 vt = VBLK; 292 break; 293 case RUMPUSER_FT_CHR: 294 vt = VCHR; 295 break; 296 default: 297 vt = VNON; 298 break; 299 } 300 301 return vt; 302 } 303 304 static bool 305 etfs_find(const char *key, struct etfs **etp, bool forceprefix) 306 { 307 struct etfs *et; 308 size_t keylen = strlen(key); 309 310 KASSERT(mutex_owned(&etfs_lock)); 311 312 LIST_FOREACH(et, &etfs_list, et_entries) { 313 if ((keylen == et->et_keylen || et->et_prefixkey || forceprefix) 314 && strncmp(key, et->et_key, et->et_keylen) == 0) { 315 if (etp) 316 *etp = et; 317 return true; 318 } 319 } 320 321 return false; 322 } 323 324 #define REGDIR(ftype) \ 325 ((ftype) == RUMP_ETFS_DIR || (ftype) == RUMP_ETFS_DIR_SUBDIRS) 326 static int 327 etfsregister(const char *key, const char *hostpath, 328 enum rump_etfs_type ftype, uint64_t begin, uint64_t size) 329 { 330 char buf[9]; 331 struct etfs *et; 332 struct rumpfs_node *rn; 333 uint64_t fsize; 334 dev_t rdev = NODEV; 335 devminor_t dmin = -1; 336 int hft, error; 337 338 if (key[0] != '/') { 339 return EINVAL; 340 } 341 while (key[0] == '/') { 342 key++; 343 } 344 345 if ((error = rumpuser_getfileinfo(hostpath, &fsize, &hft)) != 0) 346 return error; 347 348 /* etfs directory requires a directory on the host */ 349 if (REGDIR(ftype)) { 350 if (hft != RUMPUSER_FT_DIR) 351 return ENOTDIR; 352 if (begin != 0) 353 return EISDIR; 354 if (size != RUMP_ETFS_SIZE_ENDOFF) 355 return EISDIR; 356 size = fsize; 357 } else { 358 if (begin > fsize) 359 return EINVAL; 360 if (size == RUMP_ETFS_SIZE_ENDOFF) 361 size = fsize - begin; 362 if (begin + size > fsize) 363 return EINVAL; 364 } 365 366 if (ftype == RUMP_ETFS_BLK || ftype == RUMP_ETFS_CHR) { 367 error = rumpblk_register(hostpath, &dmin, begin, size); 368 if (error != 0) { 369 return error; 370 } 371 rdev = makedev(RUMPBLK_DEVMAJOR, dmin); 372 } 373 374 et = kmem_alloc(sizeof(*et), KM_SLEEP); 375 strcpy(et->et_key, key); 376 et->et_keylen = strlen(et->et_key); 377 et->et_rn = rn = makeprivate(ettype_to_vtype(ftype), RUMPFS_DEFAULTMODE, 378 rdev, size, true); 379 et->et_removing = false; 380 et->et_blkmin = dmin; 381 382 rn->rn_flags |= RUMPNODE_ET_PHONE_HOST; 383 384 if (ftype == RUMP_ETFS_REG || REGDIR(ftype) || et->et_blkmin != -1) { 385 size_t len = strlen(hostpath)+1; 386 387 rn->rn_hostpath = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 388 memcpy(rn->rn_hostpath, hostpath, len); 389 rn->rn_offset = begin; 390 } 391 392 if (REGDIR(ftype)) { 393 rn->rn_flags |= RUMPNODE_DIR_ET; 394 et->et_prefixkey = true; 395 } else { 396 et->et_prefixkey = false; 397 } 398 399 if (ftype == RUMP_ETFS_DIR_SUBDIRS) 400 rn->rn_flags |= RUMPNODE_DIR_ETSUBS; 401 402 mutex_enter(&etfs_lock); 403 if (etfs_find(key, NULL, REGDIR(ftype))) { 404 mutex_exit(&etfs_lock); 405 if (et->et_blkmin != -1) 406 rumpblk_deregister(hostpath); 407 if (et->et_rn->rn_hostpath != NULL) 408 free(et->et_rn->rn_hostpath, M_TEMP); 409 freeprivate(et->et_rn); 410 kmem_free(et, sizeof(*et)); 411 return EEXIST; 412 } 413 LIST_INSERT_HEAD(&etfs_list, et, et_entries); 414 mutex_exit(&etfs_lock); 415 416 if (ftype == RUMP_ETFS_BLK) { 417 format_bytes(buf, sizeof(buf), size); 418 aprint_verbose("/%s: hostpath %s (%s)\n", key, hostpath, buf); 419 } 420 421 return 0; 422 } 423 #undef REGDIR 424 425 /* remove etfs mapping. caller's responsibility to make sure it's not in use */ 426 static int 427 etfsremove(const char *key) 428 { 429 struct etfs *et; 430 size_t keylen; 431 int rv __diagused; 432 433 if (key[0] != '/') { 434 return EINVAL; 435 } 436 while (key[0] == '/') { 437 key++; 438 } 439 440 keylen = strlen(key); 441 442 mutex_enter(&etfs_lock); 443 LIST_FOREACH(et, &etfs_list, et_entries) { 444 if (keylen == et->et_keylen && strcmp(et->et_key, key) == 0) { 445 if (et->et_removing) 446 et = NULL; 447 else 448 et->et_removing = true; 449 break; 450 } 451 } 452 mutex_exit(&etfs_lock); 453 if (!et) 454 return ENOENT; 455 456 /* 457 * ok, we know what we want to remove and have signalled there 458 * actually are men at work. first, unregister from rumpblk 459 */ 460 if (et->et_blkmin != -1) { 461 rv = rumpblk_deregister(et->et_rn->rn_hostpath); 462 } else { 463 rv = 0; 464 } 465 KASSERT(rv == 0); 466 467 /* then do the actual removal */ 468 mutex_enter(&etfs_lock); 469 LIST_REMOVE(et, et_entries); 470 mutex_exit(&etfs_lock); 471 472 /* node is unreachable, safe to nuke all device copies */ 473 if (et->et_blkmin != -1) { 474 vdevgone(RUMPBLK_DEVMAJOR, et->et_blkmin, et->et_blkmin, VBLK); 475 } else { 476 struct vnode *vp; 477 struct mount *mp; 478 struct rumpfs_node *rn; 479 480 mutex_enter(&reclock); 481 if ((vp = et->et_rn->rn_vp) != NULL) { 482 mp = vp->v_mount; 483 rn = vp->v_data; 484 KASSERT(rn == et->et_rn); 485 } else { 486 mp = NULL; 487 } 488 mutex_exit(&reclock); 489 if (mp && vcache_get(mp, &rn, sizeof(rn), &vp) == 0) { 490 rv = vfs_suspend(mp, 0); 491 KASSERT(rv == 0); 492 vgone(vp); 493 vfs_resume(mp); 494 } 495 } 496 497 if (et->et_rn->rn_hostpath != NULL) 498 free(et->et_rn->rn_hostpath, M_TEMP); 499 freeprivate(et->et_rn); 500 kmem_free(et, sizeof(*et)); 501 502 return 0; 503 } 504 505 /* 506 * rumpfs 507 */ 508 509 static struct rumpfs_node * 510 makeprivate(enum vtype vt, mode_t mode, dev_t rdev, off_t size, bool et) 511 { 512 struct rumpfs_node *rn; 513 struct vattr *va; 514 struct timespec ts; 515 516 KASSERT((mode & ~ALLPERMS) == 0); 517 rn = kmem_zalloc(sizeof(*rn), KM_SLEEP); 518 519 switch (vt) { 520 case VDIR: 521 LIST_INIT(&rn->rn_dir); 522 break; 523 case VREG: 524 if (et) { 525 rn->rn_readfd = -1; 526 rn->rn_writefd = -1; 527 } 528 break; 529 default: 530 break; 531 } 532 533 nanotime(&ts); 534 535 va = &rn->rn_va; 536 va->va_type = vt; 537 va->va_mode = mode; 538 if (vt == VDIR) 539 va->va_nlink = 2; 540 else 541 va->va_nlink = 1; 542 va->va_uid = 0; 543 va->va_gid = 0; 544 va->va_fsid = 545 va->va_fileid = atomic_inc_uint_nv(&lastino); 546 va->va_size = size; 547 va->va_blocksize = 512; 548 va->va_atime = ts; 549 va->va_mtime = ts; 550 va->va_ctime = ts; 551 va->va_birthtime = ts; 552 va->va_gen = 0; 553 va->va_flags = 0; 554 va->va_rdev = rdev; 555 va->va_bytes = 512; 556 va->va_filerev = 0; 557 va->va_vaflags = 0; 558 559 return rn; 560 } 561 562 static void 563 freeprivate(struct rumpfs_node *rn) 564 { 565 566 kmem_free(rn, sizeof(*rn)); 567 } 568 569 static void 570 makedir(struct rumpfs_node *rnd, 571 struct componentname *cnp, struct rumpfs_node *rn) 572 { 573 struct rumpfs_dent *rdent; 574 575 rdent = kmem_alloc(sizeof(*rdent), KM_SLEEP); 576 rdent->rd_name = kmem_alloc(cnp->cn_namelen+1, KM_SLEEP); 577 rdent->rd_node = rn; 578 strlcpy(rdent->rd_name, cnp->cn_nameptr, cnp->cn_namelen+1); 579 rdent->rd_namelen = strlen(rdent->rd_name); 580 581 if ((cnp->cn_flags & ISWHITEOUT) != 0) { 582 KASSERT((cnp->cn_flags & DOWHITEOUT) == 0); 583 freedir(rnd, cnp); 584 } 585 LIST_INSERT_HEAD(&rnd->rn_dir, rdent, rd_entries); 586 } 587 588 static void 589 freedir(struct rumpfs_node *rnd, struct componentname *cnp) 590 { 591 struct rumpfs_dent *rd = NULL; 592 593 LIST_FOREACH(rd, &rnd->rn_dir, rd_entries) { 594 if (rd->rd_namelen == cnp->cn_namelen && 595 strncmp(rd->rd_name, cnp->cn_nameptr, 596 cnp->cn_namelen) == 0) 597 break; 598 } 599 if (rd == NULL) 600 panic("could not find directory entry: %s", cnp->cn_nameptr); 601 602 if (cnp->cn_flags & DOWHITEOUT) { 603 rd->rd_node = RUMPFS_WHITEOUT; 604 } else { 605 LIST_REMOVE(rd, rd_entries); 606 kmem_free(rd->rd_name, rd->rd_namelen+1); 607 kmem_free(rd, sizeof(*rd)); 608 } 609 } 610 611 #define RUMPFS_ACCESS 1 612 #define RUMPFS_MODIFY 2 613 #define RUMPFS_CHANGE 4 614 615 static int 616 rumpfs_update(int flags, struct vnode *vp, const struct timespec *acc, 617 const struct timespec *mod, const struct timespec *chg) 618 { 619 struct rumpfs_node *rn = vp->v_data; 620 621 if (flags == 0) 622 return 0; 623 624 if (vp->v_mount->mnt_flag & MNT_RDONLY) 625 return EROFS; 626 627 if (flags & RUMPFS_ACCESS) 628 rn->rn_va.va_atime = *acc; 629 if (flags & RUMPFS_MODIFY) 630 rn->rn_va.va_mtime = *mod; 631 if (flags & RUMPFS_CHANGE) 632 rn->rn_va.va_ctime = *chg; 633 634 return 0; 635 } 636 637 /* 638 * parsepath for rump file systems - check for etfs entries. 639 */ 640 static int 641 rump_vop_parsepath(void *v) 642 { 643 struct vop_parsepath_args /* { 644 struct vnode *a_dvp; 645 const char *a_name; 646 size_t *a_retval; 647 }; */ *ap = v; 648 struct etfs *et; 649 bool found; 650 651 /* check for etfs */ 652 if (ap->a_dvp == rootvnode) { 653 mutex_enter(&etfs_lock); 654 found = etfs_find(ap->a_name, &et, false); 655 mutex_exit(&etfs_lock); 656 if (found) { 657 *ap->a_retval = et->et_keylen; 658 return 0; 659 } 660 } 661 return genfs_parsepath(v); 662 } 663 664 /* 665 * Simple lookup for rump file systems. 666 * 667 * uhm, this is twisted. C F C C, hope of C C F C looming 668 */ 669 static int 670 rump_vop_lookup(void *v) 671 { 672 struct vop_lookup_v2_args /* { 673 struct vnode *a_dvp; 674 struct vnode **a_vpp; 675 struct componentname *a_cnp; 676 }; */ *ap = v; 677 struct componentname *cnp = ap->a_cnp; 678 struct vnode *dvp = ap->a_dvp; 679 struct vnode **vpp = ap->a_vpp; 680 struct rumpfs_node *rnd = dvp->v_data, *rn; 681 struct rumpfs_dent *rd = NULL; 682 struct etfs *et; 683 bool dotdot = (cnp->cn_flags & ISDOTDOT) != 0; 684 int rv = 0; 685 686 *vpp = NULL; 687 688 rv = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred); 689 if (rv) 690 return rv; 691 692 if ((cnp->cn_flags & ISLASTCN) 693 && (dvp->v_mount->mnt_flag & MNT_RDONLY) 694 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 695 return EROFS; 696 697 /* check for dot, return directly if the case */ 698 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 699 vref(dvp); 700 *vpp = dvp; 701 return 0; 702 } 703 704 /* we don't do rename */ 705 if (!(((cnp->cn_flags & ISLASTCN) == 0) || (cnp->cn_nameiop != RENAME))) 706 return EOPNOTSUPP; 707 708 /* check for etfs */ 709 if (dvp == rootvnode && 710 (cnp->cn_nameiop == LOOKUP || cnp->cn_nameiop == CREATE)) { 711 bool found; 712 mutex_enter(&etfs_lock); 713 found = etfs_find(cnp->cn_nameptr, &et, false); 714 mutex_exit(&etfs_lock); 715 716 if (found) { 717 if (et->et_keylen != cnp->cn_namelen) { 718 /* 719 * This can theoretically happen if an 720 * etfs entry is added or removed 721 * while lookups are being done as we 722 * don't hold etfs_lock across here 723 * and parsepath. Won't ordinarily be 724 * the case. No biggie, just retry. 725 */ 726 return ERESTART; 727 } 728 rn = et->et_rn; 729 goto getvnode; 730 } 731 } 732 733 if (rnd->rn_flags & RUMPNODE_DIR_ET) { 734 uint64_t fsize; 735 char *newpath; 736 size_t newpathlen; 737 int hft, error; 738 739 if (dotdot) 740 return EOPNOTSUPP; 741 742 newpathlen = strlen(rnd->rn_hostpath) + 1 + cnp->cn_namelen + 1; 743 newpath = malloc(newpathlen, M_TEMP, M_WAITOK); 744 745 strlcpy(newpath, rnd->rn_hostpath, newpathlen); 746 strlcat(newpath, "/", newpathlen); 747 strlcat(newpath, cnp->cn_nameptr, newpathlen); 748 749 if ((error = rumpuser_getfileinfo(newpath, &fsize, &hft)) != 0){ 750 free(newpath, M_TEMP); 751 return error; 752 } 753 754 /* allow only dirs and regular files */ 755 if (hft != RUMPUSER_FT_REG && hft != RUMPUSER_FT_DIR) { 756 free(newpath, M_TEMP); 757 return ENOENT; 758 } 759 760 rn = makeprivate(hft_to_vtype(hft), RUMPFS_DEFAULTMODE, 761 NODEV, fsize, true); 762 rn->rn_flags |= RUMPNODE_CANRECLAIM; 763 if (rnd->rn_flags & RUMPNODE_DIR_ETSUBS) { 764 rn->rn_flags |= RUMPNODE_DIR_ET | RUMPNODE_DIR_ETSUBS; 765 rn->rn_flags |= RUMPNODE_ET_PHONE_HOST; 766 } 767 rn->rn_hostpath = newpath; 768 769 goto getvnode; 770 } else { 771 if (dotdot) { 772 if ((rn = rnd->rn_parent) != NULL) 773 goto getvnode; 774 } else { 775 LIST_FOREACH(rd, &rnd->rn_dir, rd_entries) { 776 if (rd->rd_namelen == cnp->cn_namelen && 777 strncmp(rd->rd_name, cnp->cn_nameptr, 778 cnp->cn_namelen) == 0) 779 break; 780 } 781 } 782 } 783 784 if (!rd && ((cnp->cn_flags & ISLASTCN) == 0||cnp->cn_nameiop != CREATE)) 785 return ENOENT; 786 787 if (!rd && (cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) { 788 if (dvp->v_mount->mnt_flag & MNT_RDONLY) 789 return EROFS; 790 rv = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred); 791 if (rv) 792 return rv; 793 return EJUSTRETURN; 794 } 795 796 if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == DELETE) { 797 rv = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred); 798 if (rv) 799 return rv; 800 } 801 802 if (RDENT_ISWHITEOUT(rd)) { 803 cnp->cn_flags |= ISWHITEOUT; 804 if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) 805 return EJUSTRETURN; 806 return ENOENT; 807 } 808 809 rn = rd->rd_node; 810 811 getvnode: 812 KASSERT(rn); 813 rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp); 814 if (rv) { 815 if (rnd->rn_flags & RUMPNODE_DIR_ET) 816 freeprivate(rn); 817 return rv; 818 } 819 820 return 0; 821 } 822 823 static int 824 rump_check_possible(struct vnode *vp, struct rumpfs_node *rnode, 825 mode_t mode) 826 { 827 828 if ((mode & VWRITE) == 0) 829 return 0; 830 831 switch (vp->v_type) { 832 case VDIR: 833 case VLNK: 834 case VREG: 835 break; 836 default: 837 /* special file is always writable. */ 838 return 0; 839 } 840 841 return vp->v_mount->mnt_flag & MNT_RDONLY ? EROFS : 0; 842 } 843 844 static int 845 rump_check_permitted(struct vnode *vp, struct rumpfs_node *rnode, 846 accmode_t accmode, kauth_cred_t cred) 847 { 848 struct vattr *attr = &rnode->rn_va; 849 850 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode, 851 vp->v_type, attr->va_mode), vp, NULL, genfs_can_access(vp, cred, 852 attr->va_uid, attr->va_gid, attr->va_mode, NULL, accmode)); 853 } 854 855 int 856 rump_vop_access(void *v) 857 { 858 struct vop_access_args /* { 859 const struct vnodeop_desc *a_desc; 860 struct vnode *a_vp; 861 int a_mode; 862 kauth_cred_t a_cred; 863 } */ *ap = v; 864 struct vnode *vp = ap->a_vp; 865 struct rumpfs_node *rn = vp->v_data; 866 int error; 867 868 error = rump_check_possible(vp, rn, ap->a_accmode); 869 if (error) 870 return error; 871 872 error = rump_check_permitted(vp, rn, ap->a_accmode, ap->a_cred); 873 874 return error; 875 } 876 877 static int 878 rump_vop_getattr(void *v) 879 { 880 struct vop_getattr_args /* { 881 struct vnode *a_vp; 882 struct vattr *a_vap; 883 kauth_cred_t a_cred; 884 } */ *ap = v; 885 struct vnode *vp = ap->a_vp; 886 struct rumpfs_node *rn = vp->v_data; 887 struct vattr *vap = ap->a_vap; 888 889 memcpy(vap, &rn->rn_va, sizeof(struct vattr)); 890 vap->va_size = vp->v_size; 891 return 0; 892 } 893 894 static int 895 rump_vop_setattr(void *v) 896 { 897 struct vop_setattr_args /* { 898 struct vnode *a_vp; 899 struct vattr *a_vap; 900 kauth_cred_t a_cred; 901 } */ *ap = v; 902 struct vnode *vp = ap->a_vp; 903 struct vattr *vap = ap->a_vap; 904 struct rumpfs_node *rn = vp->v_data; 905 struct vattr *attr = &rn->rn_va; 906 struct timespec now; 907 kauth_cred_t cred = ap->a_cred; 908 int error; 909 910 #define CHANGED(a, t) (vap->a != (t)VNOVAL) 911 #define SETIFVAL(a,t) if (CHANGED(a, t)) rn->rn_va.a = vap->a 912 if (CHANGED(va_atime.tv_sec, time_t) || 913 CHANGED(va_ctime.tv_sec, time_t) || 914 CHANGED(va_mtime.tv_sec, time_t) || 915 CHANGED(va_birthtime.tv_sec, time_t) || 916 CHANGED(va_atime.tv_nsec, long) || 917 CHANGED(va_ctime.tv_nsec, long) || 918 CHANGED(va_mtime.tv_nsec, long) || 919 CHANGED(va_birthtime.tv_nsec, long)) { 920 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, 921 NULL, genfs_can_chtimes(vp, cred, attr->va_uid, 922 vap->va_vaflags)); 923 if (error) 924 return error; 925 } 926 927 int flags = 0; 928 getnanotime(&now); 929 if (vap->va_atime.tv_sec != VNOVAL) 930 if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) 931 flags |= RUMPFS_ACCESS; 932 if (vap->va_mtime.tv_sec != VNOVAL) { 933 flags |= RUMPFS_CHANGE | RUMPFS_MODIFY; 934 if (vp->v_mount->mnt_flag & MNT_RELATIME) 935 flags |= RUMPFS_ACCESS; 936 } else if (vap->va_size == 0) { 937 flags |= RUMPFS_MODIFY; 938 vap->va_mtime = now; 939 } 940 SETIFVAL(va_birthtime.tv_sec, time_t); 941 SETIFVAL(va_birthtime.tv_nsec, long); 942 flags |= RUMPFS_CHANGE; 943 error = rumpfs_update(flags, vp, &vap->va_atime, &vap->va_mtime, &now); 944 if (error) 945 return error; 946 947 if (CHANGED(va_flags, u_long)) { 948 /* XXX Can we handle system flags here...? */ 949 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_FLAGS, vp, 950 NULL, genfs_can_chflags(vp, cred, attr->va_uid, false)); 951 if (error) 952 return error; 953 } 954 955 SETIFVAL(va_flags, u_long); 956 #undef SETIFVAL 957 #undef CHANGED 958 959 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (uid_t)VNOVAL) { 960 uid_t uid = 961 (vap->va_uid != (uid_t)VNOVAL) ? vap->va_uid : attr->va_uid; 962 gid_t gid = 963 (vap->va_gid != (gid_t)VNOVAL) ? vap->va_gid : attr->va_gid; 964 error = kauth_authorize_vnode(cred, 965 KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL, 966 genfs_can_chown(vp, cred, attr->va_uid, attr->va_gid, uid, 967 gid)); 968 if (error) 969 return error; 970 attr->va_uid = uid; 971 attr->va_gid = gid; 972 } 973 974 if (vap->va_mode != (mode_t)VNOVAL) { 975 mode_t mode = vap->va_mode; 976 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, 977 vp, NULL, genfs_can_chmod(vp, cred, attr->va_uid, 978 attr->va_gid, mode)); 979 if (error) 980 return error; 981 attr->va_mode = mode; 982 } 983 984 if (vp->v_type == VREG && 985 vap->va_size != VSIZENOTSET && 986 vap->va_size != rn->rn_dlen && 987 (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) == 0) { 988 void *newdata; 989 size_t copylen, newlen; 990 991 newlen = vap->va_size; 992 newdata = rump_hypermalloc(newlen, 0, false, "rumpfs"); 993 if (newdata == NULL) 994 return ENOSPC; 995 996 copylen = MIN(rn->rn_dlen, newlen); 997 if (copylen > 0) 998 memcpy(newdata, rn->rn_data, copylen); 999 memset((char *)newdata + copylen, 0, newlen - copylen); 1000 1001 if ((rn->rn_flags & RUMPNODE_EXTSTORAGE) == 0) { 1002 rump_hyperfree(rn->rn_data, rn->rn_dlen); 1003 } else { 1004 rn->rn_flags &= ~RUMPNODE_EXTSTORAGE; 1005 } 1006 1007 rn->rn_data = newdata; 1008 rn->rn_dlen = newlen; 1009 uvm_vnp_setsize(vp, newlen); 1010 } 1011 return 0; 1012 } 1013 1014 static int 1015 rump_vop_mkdir(void *v) 1016 { 1017 struct vop_mkdir_v3_args /* { 1018 struct vnode *a_dvp; 1019 struct vnode **a_vpp; 1020 struct componentname *a_cnp; 1021 struct vattr *a_vap; 1022 }; */ *ap = v; 1023 struct vnode *dvp = ap->a_dvp; 1024 struct vnode **vpp = ap->a_vpp; 1025 struct componentname *cnp = ap->a_cnp; 1026 struct vattr *va = ap->a_vap; 1027 struct rumpfs_node *rnd = dvp->v_data, *rn; 1028 int rv = 0; 1029 1030 rn = makeprivate(VDIR, va->va_mode & ALLPERMS, NODEV, DEV_BSIZE, false); 1031 if ((cnp->cn_flags & ISWHITEOUT) != 0) 1032 rn->rn_va.va_flags |= UF_OPAQUE; 1033 rn->rn_parent = rnd; 1034 rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp); 1035 if (rv) { 1036 freeprivate(rn); 1037 return rv; 1038 } 1039 1040 makedir(rnd, cnp, rn); 1041 1042 return rv; 1043 } 1044 1045 static int 1046 rump_vop_rmdir(void *v) 1047 { 1048 struct vop_rmdir_v2_args /* { 1049 struct vnode *a_dvp; 1050 struct vnode *a_vp; 1051 struct componentname *a_cnp; 1052 }; */ *ap = v; 1053 struct vnode *dvp = ap->a_dvp; 1054 struct vnode *vp = ap->a_vp; 1055 struct componentname *cnp = ap->a_cnp; 1056 struct rumpfs_node *rnd = dvp->v_data; 1057 struct rumpfs_node *rn = vp->v_data; 1058 struct rumpfs_dent *rd; 1059 int rv = 0; 1060 1061 LIST_FOREACH(rd, &rn->rn_dir, rd_entries) { 1062 if (rd->rd_node != RUMPFS_WHITEOUT) { 1063 rv = ENOTEMPTY; 1064 goto out; 1065 } 1066 } 1067 while ((rd = LIST_FIRST(&rn->rn_dir)) != NULL) { 1068 KASSERT(rd->rd_node == RUMPFS_WHITEOUT); 1069 LIST_REMOVE(rd, rd_entries); 1070 kmem_free(rd->rd_name, rd->rd_namelen+1); 1071 kmem_free(rd, sizeof(*rd)); 1072 } 1073 1074 freedir(rnd, cnp); 1075 rn->rn_flags |= RUMPNODE_CANRECLAIM; 1076 rn->rn_parent = NULL; 1077 rn->rn_va.va_nlink = 0; 1078 1079 out: 1080 vput(vp); 1081 return rv; 1082 } 1083 1084 static int 1085 rump_vop_remove(void *v) 1086 { 1087 struct vop_remove_v3_args /* { 1088 struct vnode *a_dvp; 1089 struct vnode *a_vp; 1090 struct componentname *a_cnp; 1091 nlink_t ctx_vp_new_nlink; 1092 }; */ *ap = v; 1093 struct vnode *dvp = ap->a_dvp; 1094 struct vnode *vp = ap->a_vp; 1095 struct componentname *cnp = ap->a_cnp; 1096 struct rumpfs_node *rnd = dvp->v_data; 1097 struct rumpfs_node *rn = vp->v_data; 1098 int rv = 0; 1099 1100 if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) 1101 return EOPNOTSUPP; 1102 1103 freedir(rnd, cnp); 1104 rn->rn_flags |= RUMPNODE_CANRECLAIM; 1105 rn->rn_va.va_nlink = 0; 1106 1107 vput(vp); 1108 return rv; 1109 } 1110 1111 static int 1112 rump_vop_mknod(void *v) 1113 { 1114 struct vop_mknod_v3_args /* { 1115 struct vnode *a_dvp; 1116 struct vnode **a_vpp; 1117 struct componentname *a_cnp; 1118 struct vattr *a_vap; 1119 }; */ *ap = v; 1120 struct vnode *dvp = ap->a_dvp; 1121 struct vnode **vpp = ap->a_vpp; 1122 struct componentname *cnp = ap->a_cnp; 1123 struct vattr *va = ap->a_vap; 1124 struct rumpfs_node *rnd = dvp->v_data, *rn; 1125 int rv; 1126 1127 rn = makeprivate(va->va_type, va->va_mode & ALLPERMS, va->va_rdev, 1128 DEV_BSIZE, false); 1129 if ((cnp->cn_flags & ISWHITEOUT) != 0) 1130 rn->rn_va.va_flags |= UF_OPAQUE; 1131 rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp); 1132 if (rv) { 1133 freeprivate(rn); 1134 return rv; 1135 } 1136 1137 makedir(rnd, cnp, rn); 1138 1139 return rv; 1140 } 1141 1142 static int 1143 rump_vop_create(void *v) 1144 { 1145 struct vop_create_v3_args /* { 1146 struct vnode *a_dvp; 1147 struct vnode **a_vpp; 1148 struct componentname *a_cnp; 1149 struct vattr *a_vap; 1150 }; */ *ap = v; 1151 struct vnode *dvp = ap->a_dvp; 1152 struct vnode **vpp = ap->a_vpp; 1153 struct componentname *cnp = ap->a_cnp; 1154 struct vattr *va = ap->a_vap; 1155 struct rumpfs_node *rnd = dvp->v_data, *rn; 1156 off_t newsize; 1157 int rv; 1158 1159 newsize = va->va_type == VSOCK ? DEV_BSIZE : 0; 1160 rn = makeprivate(va->va_type, va->va_mode & ALLPERMS, NODEV, 1161 newsize, false); 1162 if ((cnp->cn_flags & ISWHITEOUT) != 0) 1163 rn->rn_va.va_flags |= UF_OPAQUE; 1164 rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp); 1165 if (rv) { 1166 freeprivate(rn); 1167 return rv; 1168 } 1169 1170 makedir(rnd, cnp, rn); 1171 1172 return rv; 1173 } 1174 1175 static int 1176 rump_vop_symlink(void *v) 1177 { 1178 struct vop_symlink_v3_args /* { 1179 struct vnode *a_dvp; 1180 struct vnode **a_vpp; 1181 struct componentname *a_cnp; 1182 struct vattr *a_vap; 1183 char *a_target; 1184 }; */ *ap = v; 1185 struct vnode *dvp = ap->a_dvp; 1186 struct vnode **vpp = ap->a_vpp; 1187 struct componentname *cnp = ap->a_cnp; 1188 struct vattr *va = ap->a_vap; 1189 struct rumpfs_node *rnd = dvp->v_data, *rn; 1190 const char *target = ap->a_target; 1191 size_t linklen; 1192 int rv; 1193 1194 linklen = strlen(target); 1195 KASSERT(linklen < MAXPATHLEN); 1196 rn = makeprivate(VLNK, va->va_mode & ALLPERMS, NODEV, linklen, false); 1197 if ((cnp->cn_flags & ISWHITEOUT) != 0) 1198 rn->rn_va.va_flags |= UF_OPAQUE; 1199 rv = vcache_get(dvp->v_mount, &rn, sizeof(rn), vpp); 1200 if (rv) { 1201 freeprivate(rn); 1202 return rv; 1203 } 1204 1205 makedir(rnd, cnp, rn); 1206 1207 KASSERT(linklen < MAXPATHLEN); 1208 rn->rn_linktarg = PNBUF_GET(); 1209 rn->rn_linklen = linklen; 1210 strcpy(rn->rn_linktarg, target); 1211 1212 return rv; 1213 } 1214 1215 static int 1216 rump_vop_readlink(void *v) 1217 { 1218 struct vop_readlink_args /* { 1219 struct vnode *a_vp; 1220 struct uio *a_uio; 1221 kauth_cred_t a_cred; 1222 }; */ *ap = v; 1223 struct vnode *vp = ap->a_vp; 1224 struct rumpfs_node *rn = vp->v_data; 1225 struct uio *uio = ap->a_uio; 1226 1227 return uiomove(rn->rn_linktarg, rn->rn_linklen, uio); 1228 } 1229 1230 static int 1231 rump_vop_whiteout(void *v) 1232 { 1233 struct vop_whiteout_args /* { 1234 struct vnode *a_dvp; 1235 struct componentname *a_cnp; 1236 int a_flags; 1237 } */ *ap = v; 1238 struct vnode *dvp = ap->a_dvp; 1239 struct rumpfs_node *rnd = dvp->v_data; 1240 struct componentname *cnp = ap->a_cnp; 1241 int flags = ap->a_flags; 1242 1243 switch (flags) { 1244 case LOOKUP: 1245 break; 1246 case CREATE: 1247 makedir(rnd, cnp, RUMPFS_WHITEOUT); 1248 break; 1249 case DELETE: 1250 cnp->cn_flags &= ~DOWHITEOUT; /* cargo culting never fails ? */ 1251 freedir(rnd, cnp); 1252 break; 1253 default: 1254 panic("unknown whiteout op %d", flags); 1255 } 1256 1257 return 0; 1258 } 1259 1260 static int 1261 rump_vop_open(void *v) 1262 { 1263 struct vop_open_args /* { 1264 struct vnode *a_vp; 1265 int a_mode; 1266 kauth_cred_t a_cred; 1267 } */ *ap = v; 1268 struct vnode *vp = ap->a_vp; 1269 struct rumpfs_node *rn = vp->v_data; 1270 int mode = ap->a_mode; 1271 int error = EINVAL; 1272 1273 if (vp->v_type != VREG || (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) == 0) 1274 return 0; 1275 1276 if (mode & FREAD) { 1277 if (rn->rn_readfd != -1) 1278 return 0; 1279 error = rumpuser_open(rn->rn_hostpath, 1280 RUMPUSER_OPEN_RDONLY, &rn->rn_readfd); 1281 } 1282 1283 if (mode & FWRITE) { 1284 if (rn->rn_writefd != -1) 1285 return 0; 1286 error = rumpuser_open(rn->rn_hostpath, 1287 RUMPUSER_OPEN_WRONLY, &rn->rn_writefd); 1288 } 1289 1290 return error; 1291 } 1292 1293 /* simple readdir. even omits dotstuff and periods */ 1294 static int 1295 rump_vop_readdir(void *v) 1296 { 1297 struct vop_readdir_args /* { 1298 struct vnode *a_vp; 1299 struct uio *a_uio; 1300 kauth_cred_t a_cred; 1301 int *a_eofflag; 1302 off_t **a_cookies; 1303 int *a_ncookies; 1304 } */ *ap = v; 1305 struct vnode *vp = ap->a_vp; 1306 struct uio *uio = ap->a_uio; 1307 struct rumpfs_node *rnd = vp->v_data; 1308 struct rumpfs_dent *rdent; 1309 struct dirent *dentp = NULL; 1310 unsigned i; 1311 int rv = 0; 1312 1313 /* seek to current entry */ 1314 for (i = 0, rdent = LIST_FIRST(&rnd->rn_dir); 1315 (i < uio->uio_offset) && rdent; 1316 i++, rdent = LIST_NEXT(rdent, rd_entries)) 1317 continue; 1318 if (!rdent) 1319 goto out; 1320 1321 /* copy entries */ 1322 dentp = kmem_alloc(sizeof(*dentp), KM_SLEEP); 1323 for (; rdent && uio->uio_resid > 0; 1324 rdent = LIST_NEXT(rdent, rd_entries), i++) { 1325 strlcpy(dentp->d_name, rdent->rd_name, sizeof(dentp->d_name)); 1326 dentp->d_namlen = strlen(dentp->d_name); 1327 dentp->d_reclen = _DIRENT_RECLEN(dentp, dentp->d_namlen); 1328 1329 if (__predict_false(RDENT_ISWHITEOUT(rdent))) { 1330 dentp->d_fileno = INO_WHITEOUT; 1331 dentp->d_type = DT_WHT; 1332 } else { 1333 dentp->d_fileno = rdent->rd_node->rn_va.va_fileid; 1334 dentp->d_type = vtype2dt(rdent->rd_node->rn_va.va_type); 1335 } 1336 1337 if (uio->uio_resid < dentp->d_reclen) { 1338 i--; 1339 break; 1340 } 1341 1342 rv = uiomove(dentp, dentp->d_reclen, uio); 1343 if (rv) { 1344 i--; 1345 break; 1346 } 1347 } 1348 kmem_free(dentp, sizeof(*dentp)); 1349 dentp = NULL; 1350 1351 out: 1352 KASSERT(dentp == NULL); 1353 if (ap->a_cookies) { 1354 *ap->a_ncookies = 0; 1355 *ap->a_cookies = NULL; 1356 } 1357 if (rdent) 1358 *ap->a_eofflag = 0; 1359 else 1360 *ap->a_eofflag = 1; 1361 uio->uio_offset = i; 1362 1363 return rv; 1364 } 1365 1366 static int 1367 etread(struct rumpfs_node *rn, struct uio *uio) 1368 { 1369 struct rumpuser_iovec iov; 1370 uint8_t *buf; 1371 size_t bufsize, n; 1372 int error = 0; 1373 1374 bufsize = uio->uio_resid; 1375 if (bufsize == 0) 1376 return 0; 1377 buf = kmem_alloc(bufsize, KM_SLEEP); 1378 1379 iov.iov_base = buf; 1380 iov.iov_len = bufsize; 1381 if ((error = rumpuser_iovread(rn->rn_readfd, &iov, 1, 1382 uio->uio_offset + rn->rn_offset, &n)) == 0) { 1383 KASSERT(n <= bufsize); 1384 error = uiomove(buf, n, uio); 1385 } 1386 1387 kmem_free(buf, bufsize); 1388 return error; 1389 } 1390 1391 static int 1392 rump_vop_read(void *v) 1393 { 1394 struct vop_read_args /* { 1395 struct vnode *a_vp; 1396 struct uio *a_uio; 1397 int ioflags a_ioflag; 1398 kauth_cred_t a_cred; 1399 }; */ *ap = v; 1400 struct vnode *vp = ap->a_vp; 1401 struct rumpfs_node *rn = vp->v_data; 1402 struct uio *uio = ap->a_uio; 1403 const int advice = IO_ADV_DECODE(ap->a_ioflag); 1404 off_t chunk; 1405 int error = 0; 1406 struct timespec ts; 1407 1408 if (vp->v_type == VDIR) 1409 return EISDIR; 1410 1411 /* et op? */ 1412 if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) 1413 return etread(rn, uio); 1414 1415 getnanotime(&ts); 1416 (void)rumpfs_update(RUMPFS_ACCESS, vp, &ts, &ts, &ts); 1417 1418 /* otherwise, it's off to ubc with us */ 1419 while (uio->uio_resid > 0) { 1420 chunk = MIN(uio->uio_resid, (off_t)rn->rn_dlen-uio->uio_offset); 1421 if (chunk == 0) 1422 break; 1423 error = ubc_uiomove(&vp->v_uobj, uio, chunk, advice, 1424 UBC_READ | UBC_PARTIALOK | UBC_VNODE_FLAGS(vp)); 1425 if (error) 1426 break; 1427 } 1428 1429 return error; 1430 } 1431 1432 static int 1433 etwrite(struct rumpfs_node *rn, struct uio *uio) 1434 { 1435 struct rumpuser_iovec iov; 1436 uint8_t *buf; 1437 size_t bufsize, n; 1438 int error = 0; 1439 1440 bufsize = uio->uio_resid; 1441 if (bufsize == 0) 1442 return 0; 1443 buf = kmem_alloc(bufsize, KM_SLEEP); 1444 error = uiomove(buf, bufsize, uio); 1445 if (error) 1446 goto out; 1447 1448 KASSERT(uio->uio_resid == 0); 1449 iov.iov_base = buf; 1450 iov.iov_len = bufsize; 1451 if ((error = rumpuser_iovwrite(rn->rn_writefd, &iov, 1, 1452 (uio->uio_offset-bufsize) + rn->rn_offset, &n)) == 0) { 1453 KASSERT(n <= bufsize); 1454 uio->uio_resid = bufsize - n; 1455 } 1456 1457 out: 1458 kmem_free(buf, bufsize); 1459 return error; 1460 } 1461 1462 static int 1463 rump_vop_write(void *v) 1464 { 1465 struct vop_write_args /* { 1466 struct vnode *a_vp; 1467 struct uio *a_uio; 1468 int ioflags a_ioflag; 1469 kauth_cred_t a_cred; 1470 }; */ *ap = v; 1471 struct vnode *vp = ap->a_vp; 1472 struct rumpfs_node *rn = vp->v_data; 1473 struct uio *uio = ap->a_uio; 1474 const int advice = IO_ADV_DECODE(ap->a_ioflag); 1475 void *olddata; 1476 size_t oldlen, newlen; 1477 off_t chunk; 1478 int error = 0; 1479 bool allocd = false; 1480 struct timespec ts; 1481 1482 getnanotime(&ts); 1483 (void)rumpfs_update(RUMPFS_MODIFY, vp, &ts, &ts, &ts); 1484 1485 if (ap->a_ioflag & IO_APPEND) 1486 uio->uio_offset = vp->v_size; 1487 1488 /* consult et? */ 1489 if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) 1490 return etwrite(rn, uio); 1491 1492 /* 1493 * Otherwise, it's a case of ubcmove. 1494 */ 1495 1496 /* 1497 * First, make sure we have enough storage. 1498 * 1499 * No, you don't need to tell me it's not very efficient. 1500 * No, it doesn't really support sparse files, just fakes it. 1501 */ 1502 newlen = uio->uio_offset + uio->uio_resid; 1503 oldlen = 0; /* XXXgcc */ 1504 olddata = NULL; 1505 if (rn->rn_dlen < newlen) { 1506 oldlen = rn->rn_dlen; 1507 olddata = rn->rn_data; 1508 1509 rn->rn_data = rump_hypermalloc(newlen, 0, false, "rumpfs"); 1510 if (rn->rn_data == NULL) 1511 return ENOSPC; 1512 rn->rn_dlen = newlen; 1513 memset(rn->rn_data, 0, newlen); 1514 if (oldlen > 0) 1515 memcpy(rn->rn_data, olddata, oldlen); 1516 allocd = true; 1517 uvm_vnp_setsize(vp, newlen); 1518 } 1519 1520 /* ok, we have enough storage. write */ 1521 while (uio->uio_resid > 0) { 1522 chunk = MIN(uio->uio_resid, (off_t)rn->rn_dlen-uio->uio_offset); 1523 if (chunk == 0) 1524 break; 1525 error = ubc_uiomove(&vp->v_uobj, uio, chunk, advice, 1526 UBC_WRITE | UBC_PARTIALOK | UBC_VNODE_FLAGS(vp)); 1527 if (error) 1528 break; 1529 } 1530 1531 if (allocd) { 1532 if (error) { 1533 rump_hyperfree(rn->rn_data, newlen); 1534 rn->rn_data = olddata; 1535 rn->rn_dlen = oldlen; 1536 uvm_vnp_setsize(vp, oldlen); 1537 } else { 1538 if ((rn->rn_flags & RUMPNODE_EXTSTORAGE) == 0) { 1539 rump_hyperfree(olddata, oldlen); 1540 } else { 1541 rn->rn_flags &= ~RUMPNODE_EXTSTORAGE; 1542 } 1543 } 1544 } 1545 1546 return error; 1547 } 1548 1549 static int 1550 rump_vop_bmap(void *v) 1551 { 1552 struct vop_bmap_args /* { 1553 struct vnode *a_vp; 1554 daddr_t a_bn; 1555 struct vnode **a_vpp; 1556 daddr_t *a_bnp; 1557 int *a_runp; 1558 } */ *ap = v; 1559 1560 /* 1:1 mapping */ 1561 if (ap->a_vpp) 1562 *ap->a_vpp = ap->a_vp; 1563 if (ap->a_bnp) 1564 *ap->a_bnp = ap->a_bn; 1565 if (ap->a_runp) 1566 *ap->a_runp = 16; 1567 1568 return 0; 1569 } 1570 1571 static int 1572 rump_vop_strategy(void *v) 1573 { 1574 struct vop_strategy_args /* { 1575 struct vnode *a_vp; 1576 struct buf *a_bp; 1577 } */ *ap = v; 1578 struct vnode *vp = ap->a_vp; 1579 struct rumpfs_node *rn = vp->v_data; 1580 struct buf *bp = ap->a_bp; 1581 off_t copylen, copyoff; 1582 int error; 1583 1584 if (vp->v_type != VREG || rn->rn_flags & RUMPNODE_ET_PHONE_HOST) { 1585 error = EINVAL; 1586 goto out; 1587 } 1588 1589 copyoff = bp->b_blkno << DEV_BSHIFT; 1590 copylen = MIN(rn->rn_dlen - copyoff, bp->b_bcount); 1591 if (BUF_ISWRITE(bp)) { 1592 memcpy((uint8_t *)rn->rn_data + copyoff, bp->b_data, copylen); 1593 } else { 1594 memset((uint8_t*)bp->b_data + copylen, 0, bp->b_bcount-copylen); 1595 memcpy(bp->b_data, (uint8_t *)rn->rn_data + copyoff, copylen); 1596 } 1597 bp->b_resid = 0; 1598 error = 0; 1599 1600 out: 1601 bp->b_error = error; 1602 biodone(bp); 1603 return 0; 1604 } 1605 1606 static int 1607 rump_vop_pathconf(void *v) 1608 { 1609 struct vop_pathconf_args /* { 1610 struct vnode *a_vp; 1611 int a_name; 1612 register_t *a_retval; 1613 }; */ *ap = v; 1614 int name = ap->a_name; 1615 register_t *retval = ap->a_retval; 1616 1617 switch (name) { 1618 case _PC_LINK_MAX: 1619 *retval = LINK_MAX; 1620 return 0; 1621 case _PC_NAME_MAX: 1622 *retval = RUMPFS_MAXNAMLEN; 1623 return 0; 1624 case _PC_PATH_MAX: 1625 *retval = PATH_MAX; 1626 return 0; 1627 case _PC_PIPE_BUF: 1628 *retval = PIPE_BUF; 1629 return 0; 1630 case _PC_CHOWN_RESTRICTED: 1631 *retval = 1; 1632 return 0; 1633 case _PC_NO_TRUNC: 1634 *retval = 1; 1635 return 0; 1636 case _PC_SYNC_IO: 1637 *retval = 1; 1638 return 0; 1639 case _PC_FILESIZEBITS: 1640 *retval = 43; /* this one goes to 11 */ 1641 return 0; 1642 case _PC_SYMLINK_MAX: 1643 *retval = MAXPATHLEN; 1644 return 0; 1645 case _PC_2_SYMLINKS: 1646 *retval = 1; 1647 return 0; 1648 default: 1649 return EINVAL; 1650 } 1651 } 1652 1653 static int 1654 rump_vop_success(void *v) 1655 { 1656 1657 return 0; 1658 } 1659 1660 static int 1661 rump_vop_inactive(void *v) 1662 { 1663 struct vop_inactive_v2_args /* { 1664 struct vnode *a_vp; 1665 bool *a_recycle; 1666 } */ *ap = v; 1667 struct vnode *vp = ap->a_vp; 1668 struct rumpfs_node *rn = vp->v_data; 1669 1670 if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST && vp->v_type == VREG) { 1671 if (rn->rn_readfd != -1) { 1672 rumpuser_close(rn->rn_readfd); 1673 rn->rn_readfd = -1; 1674 } 1675 if (rn->rn_writefd != -1) { 1676 rumpuser_close(rn->rn_writefd); 1677 rn->rn_writefd = -1; 1678 } 1679 } 1680 *ap->a_recycle = (rn->rn_flags & RUMPNODE_CANRECLAIM) ? true : false; 1681 1682 return 0; 1683 } 1684 1685 static int 1686 rump_vop_reclaim(void *v) 1687 { 1688 struct vop_reclaim_v2_args /* { 1689 struct vnode *a_vp; 1690 } */ *ap = v; 1691 struct vnode *vp = ap->a_vp; 1692 struct rumpfs_node *rn = vp->v_data; 1693 1694 VOP_UNLOCK(vp); 1695 1696 mutex_enter(&reclock); 1697 rn->rn_vp = NULL; 1698 mutex_exit(&reclock); 1699 genfs_node_destroy(vp); 1700 vp->v_data = NULL; 1701 1702 if (rn->rn_flags & RUMPNODE_CANRECLAIM) { 1703 if (vp->v_type == VREG 1704 && (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) == 0 1705 && rn->rn_data) { 1706 if ((rn->rn_flags & RUMPNODE_EXTSTORAGE) == 0) { 1707 rump_hyperfree(rn->rn_data, rn->rn_dlen); 1708 } else { 1709 rn->rn_flags &= ~RUMPNODE_EXTSTORAGE; 1710 } 1711 rn->rn_data = NULL; 1712 } 1713 1714 if (vp->v_type == VLNK) 1715 PNBUF_PUT(rn->rn_linktarg); 1716 if (rn->rn_hostpath) 1717 free(rn->rn_hostpath, M_TEMP); 1718 freeprivate(rn); 1719 } 1720 1721 return 0; 1722 } 1723 1724 static int 1725 rump_vop_spec(void *v) 1726 { 1727 struct vop_generic_args *ap = v; 1728 int (**opvec)(void *); 1729 1730 switch (ap->a_desc->vdesc_offset) { 1731 case VOP_ACCESS_DESCOFFSET: 1732 case VOP_ACCESSX_DESCOFFSET: 1733 case VOP_GETATTR_DESCOFFSET: 1734 case VOP_SETATTR_DESCOFFSET: 1735 case VOP_LOCK_DESCOFFSET: 1736 case VOP_UNLOCK_DESCOFFSET: 1737 case VOP_ISLOCKED_DESCOFFSET: 1738 case VOP_INACTIVE_DESCOFFSET: 1739 case VOP_RECLAIM_DESCOFFSET: 1740 opvec = rump_vnodeop_p; 1741 break; 1742 default: 1743 opvec = spec_vnodeop_p; 1744 break; 1745 } 1746 1747 return VOCALL(opvec, ap->a_desc->vdesc_offset, v); 1748 } 1749 1750 static int 1751 rump_vop_advlock(void *v) 1752 { 1753 struct vop_advlock_args /* { 1754 const struct vnodeop_desc *a_desc; 1755 struct vnode *a_vp; 1756 void *a_id; 1757 int a_op; 1758 struct flock *a_fl; 1759 int a_flags; 1760 } */ *ap = v; 1761 struct vnode *vp = ap->a_vp; 1762 struct rumpfs_node *rn = vp->v_data; 1763 1764 return lf_advlock(ap, &rn->rn_lockf, vp->v_size); 1765 } 1766 1767 static int 1768 rump_vop_fcntl(void *v) 1769 { 1770 struct vop_fcntl_args /* { 1771 struct vnode *a_vp; 1772 u_int a_command; 1773 void *a_data; 1774 int a_fflag; 1775 kauth_cred_t a_cred; 1776 } */ *ap = v; 1777 struct proc *p = curproc; 1778 struct vnode *vp = ap->a_vp; 1779 struct rumpfs_node *rn = vp->v_data; 1780 u_int cmd = ap->a_command; 1781 int fflag = ap->a_fflag; 1782 struct rumpfs_extstorage *rfse = ap->a_data; 1783 int error = 0; 1784 1785 /* none of the current rumpfs fcntlops are defined for remotes */ 1786 if (!RUMP_LOCALPROC_P(p)) 1787 return EINVAL; 1788 1789 switch (cmd) { 1790 case RUMPFS_FCNTL_EXTSTORAGE_ADD: 1791 break; 1792 default: 1793 return EINVAL; 1794 } 1795 1796 if ((fflag & FWRITE) == 0) 1797 return EBADF; 1798 1799 if (vp->v_type != VREG || (rn->rn_flags & RUMPNODE_ET_PHONE_HOST)) 1800 return EINVAL; 1801 1802 if (rfse->rfse_flags != 0) 1803 return EINVAL; 1804 1805 /* 1806 * Ok, we are good to go. Process. 1807 */ 1808 1809 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1810 1811 KASSERT(cmd == RUMPFS_FCNTL_EXTSTORAGE_ADD); 1812 if (rn->rn_data && (rn->rn_flags & RUMPNODE_EXTSTORAGE) == 0) { 1813 rump_hyperfree(rn->rn_data, rn->rn_dlen); 1814 } 1815 1816 rn->rn_data = rfse->rfse_data; 1817 rn->rn_dlen = rfse->rfse_dlen; 1818 uvm_vnp_setsize(vp, rn->rn_dlen); 1819 rn->rn_flags |= RUMPNODE_EXTSTORAGE; 1820 1821 VOP_UNLOCK(vp); 1822 1823 return error; 1824 } 1825 1826 /* 1827 * Begin vfs-level stuff 1828 */ 1829 1830 VFS_PROTOS(rumpfs); 1831 struct vfsops rumpfs_vfsops = { 1832 .vfs_name = MOUNT_RUMPFS, 1833 .vfs_min_mount_data = 0, 1834 .vfs_mount = rumpfs_mount, 1835 .vfs_start = (void *)nullop, 1836 .vfs_unmount = rumpfs_unmount, 1837 .vfs_root = rumpfs_root, 1838 .vfs_quotactl = (void *)eopnotsupp, 1839 .vfs_statvfs = genfs_statvfs, 1840 .vfs_sync = (void *)nullop, 1841 .vfs_vget = rumpfs_vget, 1842 .vfs_loadvnode = rumpfs_loadvnode, 1843 .vfs_fhtovp = (void *)eopnotsupp, 1844 .vfs_vptofh = (void *)eopnotsupp, 1845 .vfs_init = rumpfs_init, 1846 .vfs_reinit = NULL, 1847 .vfs_done = rumpfs_done, 1848 .vfs_mountroot = rumpfs_mountroot, 1849 .vfs_snapshot = (void *)eopnotsupp, 1850 .vfs_extattrctl = (void *)eopnotsupp, 1851 .vfs_suspendctl = genfs_suspendctl, 1852 .vfs_renamelock_enter = genfs_renamelock_enter, 1853 .vfs_renamelock_exit = genfs_renamelock_exit, 1854 .vfs_opv_descs = rump_opv_descs, 1855 /* vfs_refcount */ 1856 /* vfs_list */ 1857 }; 1858 1859 static int 1860 rumpfs_mountfs(struct mount *mp) 1861 { 1862 struct rumpfs_mount *rfsmp; 1863 struct rumpfs_node *rn; 1864 int error; 1865 1866 rfsmp = kmem_alloc(sizeof(*rfsmp), KM_SLEEP); 1867 1868 rn = makeprivate(VDIR, RUMPFS_DEFAULTMODE, NODEV, DEV_BSIZE, false); 1869 rn->rn_parent = rn; 1870 if ((error = vcache_get(mp, &rn, sizeof(rn), &rfsmp->rfsmp_rvp)) 1871 != 0) { 1872 freeprivate(rn); 1873 kmem_free(rfsmp, sizeof(*rfsmp)); 1874 return error; 1875 } 1876 1877 rfsmp->rfsmp_rvp->v_vflag |= VV_ROOT; 1878 1879 mp->mnt_data = rfsmp; 1880 mp->mnt_stat.f_namemax = RUMPFS_MAXNAMLEN; 1881 mp->mnt_stat.f_iosize = 512; 1882 mp->mnt_flag |= MNT_LOCAL; 1883 mp->mnt_iflag |= IMNT_MPSAFE | IMNT_CAN_RWTORO; 1884 mp->mnt_fs_bshift = DEV_BSHIFT; 1885 vfs_getnewfsid(mp); 1886 1887 return 0; 1888 } 1889 1890 int 1891 rumpfs_mount(struct mount *mp, const char *mntpath, void *arg, size_t *alen) 1892 { 1893 int error, flags; 1894 1895 if (mp->mnt_flag & MNT_GETARGS) { 1896 return 0; 1897 } 1898 if (mp->mnt_flag & MNT_UPDATE) { 1899 if ((mp->mnt_iflag & IMNT_WANTRDONLY)) { 1900 /* Changing from read/write to read-only. */ 1901 flags = WRITECLOSE; 1902 if ((mp->mnt_flag & MNT_FORCE)) 1903 flags |= FORCECLOSE; 1904 error = vflush(mp, NULL, flags); 1905 if (error) 1906 return error; 1907 } 1908 return 0; 1909 } 1910 1911 error = set_statvfs_info(mntpath, UIO_USERSPACE, "rumpfs", UIO_SYSSPACE, 1912 mp->mnt_op->vfs_name, mp, curlwp); 1913 if (error) 1914 return error; 1915 1916 return rumpfs_mountfs(mp); 1917 } 1918 1919 int 1920 rumpfs_unmount(struct mount *mp, int mntflags) 1921 { 1922 struct rumpfs_mount *rfsmp = mp->mnt_data; 1923 int flags = 0, error; 1924 1925 if (panicstr || mntflags & MNT_FORCE) 1926 flags |= FORCECLOSE; 1927 1928 if (vrefcnt(rfsmp->rfsmp_rvp) > 1 && (flags & FORCECLOSE) == 0) 1929 return EBUSY; 1930 1931 if ((error = vflush(mp, rfsmp->rfsmp_rvp, flags)) != 0) 1932 return error; 1933 vgone(rfsmp->rfsmp_rvp); 1934 1935 kmem_free(rfsmp, sizeof(*rfsmp)); 1936 1937 return 0; 1938 } 1939 1940 int 1941 rumpfs_root(struct mount *mp, int lktype, struct vnode **vpp) 1942 { 1943 struct rumpfs_mount *rfsmp = mp->mnt_data; 1944 1945 vref(rfsmp->rfsmp_rvp); 1946 vn_lock(rfsmp->rfsmp_rvp, lktype | LK_RETRY); 1947 *vpp = rfsmp->rfsmp_rvp; 1948 return 0; 1949 } 1950 1951 int 1952 rumpfs_vget(struct mount *mp, ino_t ino, int lktype, struct vnode **vpp) 1953 { 1954 1955 return EOPNOTSUPP; 1956 } 1957 1958 int 1959 rumpfs_loadvnode(struct mount *mp, struct vnode *vp, 1960 const void *key, size_t key_len, const void **new_key) 1961 { 1962 struct rumpfs_node *rn; 1963 struct vattr *va; 1964 1965 KASSERT(!mutex_owned(&reclock)); 1966 1967 KASSERT(key_len == sizeof(rn)); 1968 memcpy(&rn, key, key_len); 1969 1970 va = &rn->rn_va; 1971 1972 vp->v_tag = VT_RUMP; 1973 vp->v_type = va->va_type; 1974 switch (vp->v_type) { 1975 case VCHR: 1976 case VBLK: 1977 vp->v_op = rump_specop_p; 1978 spec_node_init(vp, va->va_rdev); 1979 break; 1980 default: 1981 vp->v_op = rump_vnodeop_p; 1982 break; 1983 } 1984 vp->v_size = vp->v_writesize = va->va_size; 1985 vp->v_data = rn; 1986 1987 genfs_node_init(vp, &rumpfs_genfsops); 1988 mutex_enter(&reclock); 1989 rn->rn_vp = vp; 1990 mutex_exit(&reclock); 1991 1992 *new_key = &vp->v_data; 1993 1994 return 0; 1995 } 1996 1997 void 1998 rumpfs_init() 1999 { 2000 extern rump_etfs_register_withsize_fn rump__etfs_register; 2001 extern rump_etfs_remove_fn rump__etfs_remove; 2002 extern struct rump_boot_etfs *ebstart; 2003 struct rump_boot_etfs *eb; 2004 2005 CTASSERT(RUMP_ETFS_SIZE_ENDOFF == RUMPBLK_SIZENOTSET); 2006 2007 mutex_init(&reclock, MUTEX_DEFAULT, IPL_NONE); 2008 mutex_init(&etfs_lock, MUTEX_DEFAULT, IPL_NONE); 2009 2010 rump__etfs_register = etfsregister; 2011 rump__etfs_remove = etfsremove; 2012 2013 for (eb = ebstart; eb; eb = eb->_eb_next) { 2014 eb->eb_status = etfsregister(eb->eb_key, eb->eb_hostpath, 2015 eb->eb_type, eb->eb_begin, eb->eb_size); 2016 } 2017 } 2018 2019 void 2020 rumpfs_done() 2021 { 2022 2023 mutex_destroy(&reclock); 2024 mutex_destroy(&etfs_lock); 2025 } 2026 2027 int 2028 rumpfs_mountroot() 2029 { 2030 struct mount *mp; 2031 int error; 2032 2033 if ((error = vfs_rootmountalloc(MOUNT_RUMPFS, "rootdev", &mp)) != 0) { 2034 vrele(rootvp); 2035 return error; 2036 } 2037 2038 if ((error = rumpfs_mountfs(mp)) != 0) 2039 panic("mounting rootfs failed: %d", error); 2040 2041 mountlist_append(mp); 2042 2043 error = set_statvfs_info("/", UIO_SYSSPACE, "rumpfs", UIO_SYSSPACE, 2044 mp->mnt_op->vfs_name, mp, curlwp); 2045 if (error) 2046 panic("set_statvfs_info failed for rootfs: %d", error); 2047 2048 mp->mnt_flag &= ~MNT_RDONLY; 2049 vfs_unbusy(mp); 2050 2051 return 0; 2052 } 2053