1 /* $NetBSD: p2k.c,v 1.14 2009/05/22 10:53:59 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by Google Summer of Code. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * puffs 2k, i.e. puffs 2 kernel. Converts the puffs protocol to 32 * the kernel vfs protocol and vice versa. 33 * 34 * A word about reference counting: puffs in the kernel is the king of 35 * reference counting. We must maintain a vnode alive and kicking 36 * until the kernel tells us to reclaim it. Therefore we make sure 37 * we never accidentally lose a vnode. Before calling operations which 38 * decrease the refcount we always bump the refcount up to compensate. 39 * Come inactive, if the file system thinks that the vnode should be 40 * put out of its misery, it will set the recycle flag. We use this 41 * to tell the kernel to reclaim the vnode. Only in reclaim do we 42 * really nuke the last reference. 43 */ 44 45 #include <sys/cdefs.h> 46 #include <sys/mount.h> 47 #include <sys/param.h> 48 #include <sys/vnode.h> 49 #include <sys/lock.h> 50 #include <sys/namei.h> 51 #include <sys/dirent.h> 52 53 #include <assert.h> 54 #include <errno.h> 55 #include <puffs.h> 56 #include <stdlib.h> 57 #include <stdio.h> 58 59 #include <rump/rump.h> 60 #include <rump/p2k.h> 61 #include <rump/ukfs.h> 62 63 PUFFSOP_PROTOS(p2k) 64 65 static kauth_cred_t 66 cred_create(const struct puffs_cred *pcr) 67 { 68 gid_t groups[NGROUPS]; 69 uid_t uid; 70 gid_t gid; 71 short ngroups = 0; 72 73 if (puffs_cred_getuid(pcr, &uid) == -1) 74 uid = 0; 75 if (puffs_cred_getgid(pcr, &gid) == -1) 76 gid = 0; 77 puffs_cred_getgroups(pcr, groups, &ngroups); 78 79 /* LINTED: ngroups is ok */ 80 return rump_cred_create(uid, gid, ngroups, groups); 81 } 82 83 static __inline void 84 cred_destroy(kauth_cred_t cred) 85 { 86 87 rump_cred_put(cred); 88 } 89 90 static struct componentname * 91 makecn(const struct puffs_cn *pcn) 92 { 93 kauth_cred_t cred; 94 95 cred = cred_create(pcn->pcn_cred); 96 /* LINTED: prehistoric types in first two args */ 97 return rump_makecn(pcn->pcn_nameiop, pcn->pcn_flags, pcn->pcn_name, 98 pcn->pcn_namelen, cred, curlwp); 99 } 100 101 static __inline void 102 freecn(struct componentname *cnp, int flags) 103 { 104 105 rump_freecn(cnp, flags | RUMPCN_FREECRED); 106 } 107 108 static void 109 makelwp(struct puffs_usermount *pu) 110 { 111 pid_t pid; 112 lwpid_t lid; 113 114 puffs_cc_getcaller(puffs_cc_getcc(pu), &pid, &lid); 115 rump_setup_curlwp(pid, lid, 1); 116 } 117 118 /*ARGSUSED*/ 119 static void 120 clearlwp(struct puffs_usermount *pu) 121 { 122 123 /* 124 * XXX: because of the vnode reference counting lossage, we 125 * can't clear the curlwp if we unmounted succesfully. 126 * Therefore, don't do it to avoid a diagnostic panic. 127 * So this currently leaks a process structure in that case, 128 * but since p2k is rarely used multiple times in a single 129 * process, it's more like a feature than a bug (yea, I'm 130 * good at lying to myself). 131 */ 132 if (__predict_false(puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED)) 133 rump_clear_curlwp(); 134 } 135 136 /*ARGSUSED*/ 137 static void 138 p2k_errcatcher(struct puffs_usermount *pu, uint8_t type, int error, 139 const char *str, puffs_cookie_t cook) 140 { 141 142 fprintf(stderr, "type %d, error %d, cookie %p (%s)\n", 143 type, error, cook, str); 144 145 /* 146 * Trap all EINVAL responses to lookup. It most likely means 147 * that we supplied VNON/VBAD as the type. The real kernel 148 * doesn't panic from this either, but just handles it. 149 */ 150 if (type != PUFFS_VN_LOOKUP && error == EINVAL) 151 abort(); 152 } 153 154 int 155 p2k_run_fs(const char *vfsname, const char *devpath, const char *mountpath, 156 int mntflags, void *arg, size_t alen, uint32_t puffs_flags) 157 { 158 char typebuf[PUFFS_TYPELEN]; 159 struct puffs_ops *pops; 160 struct puffs_usermount *pu = NULL; 161 struct puffs_node *pn_root; 162 struct vnode *rvp; 163 struct ukfs *ukfs = NULL; 164 extern int puffs_fakecc; 165 int rv = -1, sverrno; 166 bool dodaemon; 167 168 PUFFSOP_INIT(pops); 169 170 PUFFSOP_SET(pops, p2k, fs, statvfs); 171 PUFFSOP_SET(pops, p2k, fs, unmount); 172 PUFFSOP_SET(pops, p2k, fs, sync); 173 PUFFSOP_SET(pops, p2k, fs, fhtonode); 174 PUFFSOP_SET(pops, p2k, fs, nodetofh); 175 176 PUFFSOP_SET(pops, p2k, node, lookup); 177 PUFFSOP_SET(pops, p2k, node, create); 178 PUFFSOP_SET(pops, p2k, node, mknod); 179 PUFFSOP_SET(pops, p2k, node, open); 180 PUFFSOP_SET(pops, p2k, node, close); 181 PUFFSOP_SET(pops, p2k, node, access); 182 PUFFSOP_SET(pops, p2k, node, getattr); 183 PUFFSOP_SET(pops, p2k, node, setattr); 184 #if 0 185 PUFFSOP_SET(pops, p2k, node, poll); 186 #endif 187 PUFFSOP_SET(pops, p2k, node, mmap); 188 PUFFSOP_SET(pops, p2k, node, fsync); 189 PUFFSOP_SET(pops, p2k, node, seek); 190 PUFFSOP_SET(pops, p2k, node, remove); 191 PUFFSOP_SET(pops, p2k, node, link); 192 PUFFSOP_SET(pops, p2k, node, rename); 193 PUFFSOP_SET(pops, p2k, node, mkdir); 194 PUFFSOP_SET(pops, p2k, node, rmdir); 195 PUFFSOP_SET(pops, p2k, node, symlink); 196 PUFFSOP_SET(pops, p2k, node, readdir); 197 PUFFSOP_SET(pops, p2k, node, readlink); 198 PUFFSOP_SET(pops, p2k, node, read); 199 PUFFSOP_SET(pops, p2k, node, write); 200 201 PUFFSOP_SET(pops, p2k, node, inactive); 202 PUFFSOP_SET(pops, p2k, node, reclaim); 203 204 dodaemon = true; 205 if (getenv("P2K_DEBUG") != NULL) { 206 puffs_flags |= PUFFS_FLAG_OPDUMP; 207 dodaemon = false; 208 } 209 if (getenv("P2K_NODETACH") != NULL) { 210 dodaemon = false; 211 } 212 if (getenv("P2K_NOCACHE_PAGE") != NULL) { 213 puffs_flags |= PUFFS_KFLAG_NOCACHE_PAGE; 214 } 215 if (getenv("P2K_NOCACHE_NAME") != NULL) { 216 puffs_flags |= PUFFS_KFLAG_NOCACHE_NAME; 217 } 218 if (getenv("P2K_NOCACHE") != NULL) { 219 puffs_flags |= PUFFS_KFLAG_NOCACHE; 220 } 221 222 strcpy(typebuf, "p2k|"); 223 if (strcmp(vfsname, "puffs") == 0) { /* XXX */ 224 struct puffs_kargs *args = arg; 225 strlcat(typebuf, args->pa_typename, sizeof(typebuf)); 226 dodaemon = false; 227 } else { 228 strlcat(typebuf, vfsname, sizeof(typebuf)); 229 } 230 231 pu = puffs_init(pops, devpath, typebuf, NULL, puffs_flags); 232 if (pu == NULL) 233 goto out; 234 235 if (dodaemon) 236 puffs_daemon(pu, 1, 1); 237 238 if (ukfs_init() == -1) 239 return -1; 240 ukfs = ukfs_mount(vfsname, devpath, mountpath, mntflags, arg, alen); 241 if (ukfs == NULL) 242 goto out; 243 244 rvp = ukfs_getrvp(ukfs); 245 pn_root = puffs_pn_new(pu, rvp); 246 puffs_setroot(pu, pn_root); 247 puffs_setfhsize(pu, 0, PUFFS_FHFLAG_PASSTHROUGH); 248 puffs_setstacksize(pu, PUFFS_STACKSIZE_MIN); 249 puffs_fakecc = 1; 250 251 puffs_set_prepost(pu, makelwp, clearlwp); 252 puffs_set_errnotify(pu, p2k_errcatcher); 253 254 puffs_setspecific(pu, ukfs_getmp(ukfs)); 255 if ((rv = puffs_mount(pu, mountpath, mntflags, rvp))== -1) 256 goto out; 257 rv = puffs_mainloop(pu); 258 puffs_exit(pu, 1); 259 pu = NULL; 260 261 out: 262 sverrno = errno; 263 if (ukfs) 264 ukfs_release(ukfs, UKFS_RELFLAG_NOUNMOUNT); 265 if (pu) 266 puffs_cancel(pu, sverrno); 267 if (rv) { 268 errno = sverrno; 269 rv = -1; 270 } 271 272 return rv; 273 } 274 275 /* XXX: vn_lock() */ 276 #define VLE(a) RUMP_VOP_LOCK(a, LK_EXCLUSIVE) 277 #define VLS(a) RUMP_VOP_LOCK(a, LK_SHARED) 278 #define VUL(a) RUMP_VOP_UNLOCK(a, 0); 279 #define AUL(a) assert(RUMP_VOP_ISLOCKED(a) == 0) 280 281 int 282 p2k_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp) 283 { 284 struct mount *mp = puffs_getspecific(pu); 285 286 return rump_vfs_statvfs(mp, sbp); 287 } 288 289 int 290 p2k_fs_unmount(struct puffs_usermount *pu, int flags) 291 { 292 struct mount *mp = puffs_getspecific(pu); 293 struct puffs_node *pn_root = puffs_getroot(pu); 294 struct vnode *rvp = pn_root->pn_data, *rvp2; 295 int rv; 296 297 /* 298 * We recycle the root node already here (god knows how 299 * many references it has due to lookup). This is good 300 * because VFS_UNMOUNT would do it anyway. But it is 301 * very bad if VFS_UNMOUNT fails for a reason or another 302 * (puffs guards against busy fs, but there might be other 303 * reasons). 304 * 305 * Theoretically we're going south, sinking fast & dying 306 * out here because the old vnode will be freed and we are 307 * unlikely to get a vnode at the same address. But try 308 * anyway. 309 * 310 * XXX: reallyfixmesomeday. either introduce VFS_ROOT to 311 * puffs (blah) or check the cookie in every routine 312 * against the root cookie, which might change (blah2). 313 */ 314 rump_vp_recycle_nokidding(rvp); 315 rv = rump_vfs_unmount(mp, flags); 316 if (rv) { 317 int rv2; 318 319 rv2 = rump_vfs_root(mp, &rvp2, 0); 320 assert(rv2 == 0 && rvp == rvp2); 321 } 322 return rv; 323 } 324 325 int 326 p2k_fs_sync(struct puffs_usermount *pu, int waitfor, 327 const struct puffs_cred *pcr) 328 { 329 struct mount *mp = puffs_getspecific(pu); 330 kauth_cred_t cred; 331 int rv; 332 333 cred = cred_create(pcr); 334 rv = rump_vfs_sync(mp, waitfor, (kauth_cred_t)cred); 335 cred_destroy(cred); 336 337 return rv; 338 } 339 340 /*ARGSUSED*/ 341 int 342 p2k_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, 343 struct puffs_newinfo *pni) 344 { 345 struct mount *mp = puffs_getspecific(pu); 346 struct vnode *vp; 347 enum vtype vtype; 348 voff_t vsize; 349 uint64_t rdev; /* XXX: uint64_t because of stack overwrite in compat */ 350 int rv; 351 352 rv = rump_vfs_fhtovp(mp, fid, &vp); 353 if (rv) 354 return rv; 355 356 puffs_newinfo_setcookie(pni, vp); 357 rump_getvninfo(vp, &vtype, &vsize, (void *)&rdev); 358 puffs_newinfo_setvtype(pni, vtype); 359 puffs_newinfo_setsize(pni, vsize); 360 puffs_newinfo_setrdev(pni, rdev); 361 362 return 0; 363 } 364 365 /*ARGSUSED*/ 366 int 367 p2k_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie, void *fid, 368 size_t *fidsize) 369 { 370 struct vnode *vp = cookie; 371 372 return rump_vfs_vptofh(vp, fid, fidsize); 373 } 374 375 /*ARGSUSED*/ 376 int 377 p2k_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, 378 struct puffs_newinfo *pni, const struct puffs_cn *pcn) 379 { 380 struct componentname *cn; 381 struct vnode *vp; 382 enum vtype vtype; 383 voff_t vsize; 384 uint64_t rdev; /* XXX: uint64_t because of stack overwrite in compat */ 385 int rv; 386 387 cn = makecn(pcn); 388 VLE(opc); 389 rv = RUMP_VOP_LOOKUP(opc, &vp, cn); 390 VUL(opc); 391 freecn(cn, RUMPCN_ISLOOKUP); 392 if (rv) { 393 if (rv == EJUSTRETURN) 394 rv = ENOENT; 395 return rv; 396 } 397 VUL(vp); 398 399 puffs_newinfo_setcookie(pni, vp); 400 rump_getvninfo(vp, &vtype, &vsize, (void *)&rdev); 401 puffs_newinfo_setvtype(pni, vtype); 402 puffs_newinfo_setsize(pni, vsize); 403 puffs_newinfo_setrdev(pni, rdev); 404 405 return 0; 406 } 407 408 #define VERS_TIMECHANGE 599000700 409 static int 410 needcompat(void) 411 { 412 413 return __NetBSD_Version__ < VERS_TIMECHANGE 414 && rump_getversion() >= VERS_TIMECHANGE; 415 } 416 417 #define DOCOMPAT(va, va_compat) \ 418 do { \ 419 if (needcompat()) { \ 420 va_compat = rump_vattr_init(); \ 421 rump_vattr50_to_vattr(va, va_compat); \ 422 } else { \ 423 va_compat = __UNCONST(va); \ 424 } \ 425 } while (/*CONSTCOND*/0) 426 427 #define UNDOCOMPAT(va_compat) \ 428 do { \ 429 if (needcompat()) \ 430 rump_vattr_free(va_compat); \ 431 } while (/*CONSTCOND*/0) 432 433 /*ARGSUSED*/ 434 int 435 p2k_node_create(struct puffs_usermount *pu, puffs_cookie_t opc, 436 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 437 const struct vattr *vap) 438 { 439 struct componentname *cn; 440 struct vattr *va_x; 441 struct vnode *vp; 442 int rv; 443 444 DOCOMPAT(vap, va_x); 445 446 cn = makecn(pcn); 447 VLE(opc); 448 rump_vp_incref(opc); 449 rv = RUMP_VOP_CREATE(opc, &vp, cn, va_x); 450 AUL(opc); 451 freecn(cn, 0); 452 if (rv == 0) { 453 VUL(vp); 454 puffs_newinfo_setcookie(pni, vp); 455 } 456 457 UNDOCOMPAT(va_x); 458 459 return rv; 460 } 461 462 /*ARGSUSED*/ 463 int 464 p2k_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc, 465 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 466 const struct vattr *vap) 467 { 468 struct componentname *cn; 469 struct vattr *va_x; 470 struct vnode *vp; 471 int rv; 472 473 DOCOMPAT(vap, va_x); 474 475 cn = makecn(pcn); 476 VLE(opc); 477 rump_vp_incref(opc); 478 rv = RUMP_VOP_MKNOD(opc, &vp, cn, va_x); 479 AUL(opc); 480 freecn(cn, 0); 481 if (rv == 0) { 482 VUL(vp); 483 puffs_newinfo_setcookie(pni, vp); 484 } 485 486 UNDOCOMPAT(va_x); 487 488 return rv; 489 } 490 491 /*ARGSUSED*/ 492 int 493 p2k_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 494 const struct puffs_cred *pcr) 495 { 496 kauth_cred_t cred; 497 int rv; 498 499 cred = cred_create(pcr); 500 VLE(opc); 501 rv = RUMP_VOP_OPEN(opc, mode, cred); 502 VUL(opc); 503 cred_destroy(cred); 504 505 return rv; 506 } 507 508 /*ARGSUSED*/ 509 int 510 p2k_node_close(struct puffs_usermount *pu, puffs_cookie_t opc, int flags, 511 const struct puffs_cred *pcr) 512 { 513 kauth_cred_t cred; 514 515 cred = cred_create(pcr); 516 VLE(opc); 517 RUMP_VOP_CLOSE(opc, flags, cred); 518 VUL(opc); 519 cred_destroy(cred); 520 521 return 0; 522 } 523 524 /*ARGSUSED*/ 525 int 526 p2k_node_access(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 527 const struct puffs_cred *pcr) 528 { 529 kauth_cred_t cred; 530 int rv; 531 532 cred = cred_create(pcr); 533 VLE(opc); 534 rv = RUMP_VOP_ACCESS(opc, mode, cred); 535 VUL(opc); 536 cred_destroy(cred); 537 538 return rv; 539 } 540 541 /*ARGSUSED*/ 542 int 543 p2k_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 544 struct vattr *vap, const struct puffs_cred *pcr) 545 { 546 kauth_cred_t cred; 547 struct vattr *va_x; 548 int rv; 549 550 if (needcompat()) { 551 va_x = rump_vattr_init(); 552 } else { 553 va_x = vap; 554 } 555 556 cred = cred_create(pcr); 557 VLE(opc); 558 rv = RUMP_VOP_GETATTR(opc, va_x, cred); 559 VUL(opc); 560 cred_destroy(cred); 561 562 if (needcompat()) { 563 rump_vattr_to_vattr50(va_x, vap); 564 rump_vattr_free(va_x); 565 } 566 567 return rv; 568 } 569 570 /*ARGSUSED*/ 571 int 572 p2k_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 573 const struct vattr *vap, const struct puffs_cred *pcr) 574 { 575 kauth_cred_t cred; 576 struct vattr *va_x; 577 int rv; 578 579 DOCOMPAT(vap, va_x); 580 581 cred = cred_create(pcr); 582 VLE(opc); 583 rv = RUMP_VOP_SETATTR(opc, va_x, cred); 584 VUL(opc); 585 cred_destroy(cred); 586 587 UNDOCOMPAT(va_x); 588 589 return rv; 590 } 591 592 /*ARGSUSED*/ 593 int 594 p2k_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc, 595 const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi) 596 { 597 kauth_cred_t cred; 598 int rv; 599 600 cred = cred_create(pcr); 601 VLE(opc); 602 rv = RUMP_VOP_FSYNC(opc, cred, flags, offlo, offhi); 603 VUL(opc); 604 cred_destroy(cred); 605 606 return rv; 607 } 608 609 /*ARGSUSED*/ 610 int 611 p2k_node_mmap(struct puffs_usermount *pu, puffs_cookie_t opc, vm_prot_t flags, 612 const struct puffs_cred *pcr) 613 { 614 kauth_cred_t cred; 615 int rv; 616 617 cred = cred_create(pcr); 618 rv = RUMP_VOP_MMAP(opc, flags, cred); 619 cred_destroy(cred); 620 621 return rv; 622 } 623 624 /*ARGSUSED*/ 625 int 626 p2k_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc, 627 off_t oldoff, off_t newoff, const struct puffs_cred *pcr) 628 { 629 kauth_cred_t cred; 630 int rv; 631 632 cred = cred_create(pcr); 633 VLE(opc); 634 rv = RUMP_VOP_SEEK(opc, oldoff, newoff, cred); 635 VUL(opc); 636 cred_destroy(cred); 637 638 return rv; 639 } 640 641 /*ARGSUSED*/ 642 int 643 p2k_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc, 644 puffs_cookie_t targ, const struct puffs_cn *pcn) 645 { 646 struct componentname *cn; 647 int rv; 648 649 cn = makecn(pcn); 650 VLE(opc); 651 rump_vp_incref(opc); 652 VLE(targ); 653 rump_vp_incref(targ); 654 rv = RUMP_VOP_REMOVE(opc, targ, cn); 655 AUL(opc); 656 AUL(targ); 657 freecn(cn, 0); 658 659 return rv; 660 } 661 662 /*ARGSUSED*/ 663 int 664 p2k_node_link(struct puffs_usermount *pu, puffs_cookie_t opc, 665 puffs_cookie_t targ, const struct puffs_cn *pcn) 666 { 667 struct componentname *cn; 668 int rv; 669 670 cn = makecn(pcn); 671 VLE(opc); 672 rump_vp_incref(opc); 673 rv = RUMP_VOP_LINK(opc, targ, cn); 674 freecn(cn, 0); 675 676 return rv; 677 } 678 679 /*ARGSUSED*/ 680 int 681 p2k_node_rename(struct puffs_usermount *pu, 682 puffs_cookie_t src_dir, puffs_cookie_t src, 683 const struct puffs_cn *pcn_src, 684 puffs_cookie_t targ_dir, puffs_cookie_t targ, 685 const struct puffs_cn *pcn_targ) 686 { 687 struct componentname *cn_src, *cn_targ; 688 int rv; 689 690 cn_src = makecn(pcn_src); 691 cn_targ = makecn(pcn_targ); 692 rump_vp_incref(src_dir); 693 rump_vp_incref(src); 694 VLE(targ_dir); 695 rump_vp_incref(targ_dir); 696 if (targ) { 697 VLE(targ); 698 rump_vp_incref(targ); 699 } 700 rv = RUMP_VOP_RENAME(src_dir, src, cn_src, targ_dir, targ, cn_targ); 701 AUL(targ_dir); 702 if (targ) 703 AUL(targ); 704 freecn(cn_src, 0); 705 freecn(cn_targ, 0); 706 707 return rv; 708 } 709 710 /*ARGSUSED*/ 711 int 712 p2k_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc, 713 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 714 const struct vattr *vap) 715 { 716 struct componentname *cn; 717 struct vattr *va_x; 718 struct vnode *vp; 719 int rv; 720 721 DOCOMPAT(vap, va_x); 722 723 cn = makecn(pcn); 724 VLE(opc); 725 rump_vp_incref(opc); 726 rv = RUMP_VOP_MKDIR(opc, &vp, cn, va_x); 727 AUL(opc); 728 freecn(cn, 0); 729 if (rv == 0) { 730 VUL(vp); 731 puffs_newinfo_setcookie(pni, vp); 732 } 733 734 UNDOCOMPAT(va_x); 735 736 return rv; 737 } 738 739 /*ARGSUSED*/ 740 int 741 p2k_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc, 742 puffs_cookie_t targ, const struct puffs_cn *pcn) 743 { 744 struct componentname *cn; 745 int rv; 746 747 cn = makecn(pcn); 748 VLE(opc); 749 rump_vp_incref(opc); 750 VLE(targ); 751 rump_vp_incref(targ); 752 rv = RUMP_VOP_RMDIR(opc, targ, cn); 753 AUL(targ); 754 AUL(opc); 755 freecn(cn, 0); 756 757 return rv; 758 } 759 760 /*ARGSUSED*/ 761 int 762 p2k_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc, 763 struct puffs_newinfo *pni, const struct puffs_cn *pcn_src, 764 const struct vattr *vap, const char *link_target) 765 { 766 struct componentname *cn; 767 struct vattr *va_x; 768 struct vnode *vp; 769 int rv; 770 771 DOCOMPAT(vap, va_x); 772 773 cn = makecn(pcn_src); 774 VLE(opc); 775 rump_vp_incref(opc); 776 rv = RUMP_VOP_SYMLINK(opc, &vp, cn, va_x, __UNCONST(link_target)); 777 AUL(opc); 778 freecn(cn, 0); 779 if (rv == 0) { 780 VUL(vp); 781 puffs_newinfo_setcookie(pni, vp); 782 } 783 784 UNDOCOMPAT(va_x); 785 786 return rv; 787 } 788 789 /*ARGSUSED*/ 790 int 791 p2k_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, 792 struct dirent *dent, off_t *readoff, size_t *reslen, 793 const struct puffs_cred *pcr, int *eofflag, 794 off_t *cookies, size_t *ncookies) 795 { 796 kauth_cred_t cred; 797 struct uio *uio; 798 off_t *vop_cookies; 799 int vop_ncookies; 800 int rv; 801 802 cred = cred_create(pcr); 803 uio = rump_uio_setup(dent, *reslen, *readoff, RUMPUIO_READ); 804 VLS(opc); 805 if (cookies) { 806 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, 807 &vop_cookies, &vop_ncookies); 808 memcpy(cookies, vop_cookies, vop_ncookies * sizeof(*cookies)); 809 *ncookies = vop_ncookies; 810 free(vop_cookies); 811 } else { 812 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, NULL, NULL); 813 } 814 VUL(opc); 815 if (rv == 0) { 816 *reslen = rump_uio_getresid(uio); 817 *readoff = rump_uio_getoff(uio); 818 } 819 rump_uio_free(uio); 820 cred_destroy(cred); 821 822 return rv; 823 } 824 825 /*ARGSUSED*/ 826 int 827 p2k_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc, 828 const struct puffs_cred *pcr, char *linkname, size_t *linklen) 829 { 830 kauth_cred_t cred; 831 struct uio *uio; 832 int rv; 833 834 cred = cred_create(pcr); 835 uio = rump_uio_setup(linkname, *linklen, 0, RUMPUIO_READ); 836 VLE(opc); 837 rv = RUMP_VOP_READLINK(opc, uio, cred); 838 VUL(opc); 839 *linklen -= rump_uio_free(uio); 840 cred_destroy(cred); 841 842 return rv; 843 } 844 845 /*ARGSUSED*/ 846 int 847 p2k_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, 848 uint8_t *buf, off_t offset, size_t *resid, 849 const struct puffs_cred *pcr, int ioflag) 850 { 851 kauth_cred_t cred; 852 struct uio *uio; 853 int rv; 854 855 cred = cred_create(pcr); 856 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_READ); 857 VLS(opc); 858 rv = RUMP_VOP_READ(opc, uio, ioflag, cred); 859 VUL(opc); 860 *resid = rump_uio_free(uio); 861 cred_destroy(cred); 862 863 return rv; 864 } 865 866 /*ARGSUSED*/ 867 int 868 p2k_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, 869 uint8_t *buf, off_t offset, size_t *resid, 870 const struct puffs_cred *pcr, int ioflag) 871 { 872 kauth_cred_t cred; 873 struct uio *uio; 874 int rv; 875 876 cred = cred_create(pcr); 877 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_WRITE); 878 VLE(opc); 879 rv = RUMP_VOP_WRITE(opc, uio, ioflag, cred); 880 VUL(opc); 881 *resid = rump_uio_free(uio); 882 cred_destroy(cred); 883 884 return rv; 885 } 886 887 int 888 p2k_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 889 { 890 struct vnode *vp = opc; 891 bool recycle; 892 int rv; 893 894 rump_vp_interlock(vp); 895 (void) RUMP_VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES); 896 VLE(vp); 897 rv = RUMP_VOP_INACTIVE(vp, &recycle); 898 if (recycle) 899 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 900 901 return rv; 902 } 903 904 /*ARGSUSED*/ 905 int 906 p2k_node_reclaim(struct puffs_usermount *pu, puffs_croissant_t opc) 907 { 908 909 rump_vp_recycle_nokidding(opc); 910 return 0; 911 } 912