1 /* $NetBSD: p2k.c,v 1.16 2009/08/04 13:39:18 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: For unmount we release this already in the operation. 125 */ 126 if (__predict_false(puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED)) 127 rump_clear_curlwp(); 128 } 129 130 /*ARGSUSED*/ 131 static void 132 p2k_errcatcher(struct puffs_usermount *pu, uint8_t type, int error, 133 const char *str, puffs_cookie_t cook) 134 { 135 136 fprintf(stderr, "type %d, error %d, cookie %p (%s)\n", 137 type, error, cook, str); 138 139 /* 140 * Trap all EINVAL responses to lookup. It most likely means 141 * that we supplied VNON/VBAD as the type. The real kernel 142 * doesn't panic from this either, but just handles it. 143 */ 144 if (type != PUFFS_VN_LOOKUP && error == EINVAL) 145 abort(); 146 } 147 148 int 149 p2k_run_fs(const char *vfsname, const char *devpath, const char *mountpath, 150 int mntflags, void *arg, size_t alen, uint32_t puffs_flags) 151 { 152 char typebuf[PUFFS_TYPELEN]; 153 struct puffs_ops *pops; 154 struct puffs_usermount *pu = NULL; 155 struct puffs_node *pn_root; 156 struct vnode *rvp; 157 struct ukfs *ukfs = NULL; 158 extern int puffs_fakecc; 159 int rv = -1, sverrno; 160 bool dodaemon; 161 162 PUFFSOP_INIT(pops); 163 164 PUFFSOP_SET(pops, p2k, fs, statvfs); 165 PUFFSOP_SET(pops, p2k, fs, unmount); 166 PUFFSOP_SET(pops, p2k, fs, sync); 167 PUFFSOP_SET(pops, p2k, fs, fhtonode); 168 PUFFSOP_SET(pops, p2k, fs, nodetofh); 169 170 PUFFSOP_SET(pops, p2k, node, lookup); 171 PUFFSOP_SET(pops, p2k, node, create); 172 PUFFSOP_SET(pops, p2k, node, mknod); 173 PUFFSOP_SET(pops, p2k, node, open); 174 PUFFSOP_SET(pops, p2k, node, close); 175 PUFFSOP_SET(pops, p2k, node, access); 176 PUFFSOP_SET(pops, p2k, node, getattr); 177 PUFFSOP_SET(pops, p2k, node, setattr); 178 #if 0 179 PUFFSOP_SET(pops, p2k, node, poll); 180 #endif 181 PUFFSOP_SET(pops, p2k, node, mmap); 182 PUFFSOP_SET(pops, p2k, node, fsync); 183 PUFFSOP_SET(pops, p2k, node, seek); 184 PUFFSOP_SET(pops, p2k, node, remove); 185 PUFFSOP_SET(pops, p2k, node, link); 186 PUFFSOP_SET(pops, p2k, node, rename); 187 PUFFSOP_SET(pops, p2k, node, mkdir); 188 PUFFSOP_SET(pops, p2k, node, rmdir); 189 PUFFSOP_SET(pops, p2k, node, symlink); 190 PUFFSOP_SET(pops, p2k, node, readdir); 191 PUFFSOP_SET(pops, p2k, node, readlink); 192 PUFFSOP_SET(pops, p2k, node, read); 193 PUFFSOP_SET(pops, p2k, node, write); 194 195 PUFFSOP_SET(pops, p2k, node, inactive); 196 PUFFSOP_SET(pops, p2k, node, reclaim); 197 198 dodaemon = true; 199 if (getenv("P2K_DEBUG") != NULL) { 200 puffs_flags |= PUFFS_FLAG_OPDUMP; 201 dodaemon = false; 202 } 203 if (getenv("P2K_NODETACH") != NULL) { 204 dodaemon = false; 205 } 206 if (getenv("P2K_NOCACHE_PAGE") != NULL) { 207 puffs_flags |= PUFFS_KFLAG_NOCACHE_PAGE; 208 } 209 if (getenv("P2K_NOCACHE_NAME") != NULL) { 210 puffs_flags |= PUFFS_KFLAG_NOCACHE_NAME; 211 } 212 if (getenv("P2K_NOCACHE") != NULL) { 213 puffs_flags |= PUFFS_KFLAG_NOCACHE; 214 } 215 216 strcpy(typebuf, "p2k|"); 217 if (strcmp(vfsname, "puffs") == 0) { /* XXX */ 218 struct puffs_kargs *args = arg; 219 strlcat(typebuf, args->pa_typename, sizeof(typebuf)); 220 dodaemon = false; 221 } else { 222 strlcat(typebuf, vfsname, sizeof(typebuf)); 223 } 224 225 pu = puffs_init(pops, devpath, typebuf, NULL, puffs_flags); 226 if (pu == NULL) 227 goto out; 228 229 if (dodaemon) 230 puffs_daemon(pu, 1, 1); 231 232 if (ukfs_init() == -1) 233 return -1; 234 ukfs = ukfs_mount(vfsname, devpath, mountpath, mntflags, arg, alen); 235 if (ukfs == NULL) 236 goto out; 237 238 rvp = ukfs_getrvp(ukfs); 239 pn_root = puffs_pn_new(pu, rvp); 240 puffs_setroot(pu, pn_root); 241 puffs_setfhsize(pu, 0, PUFFS_FHFLAG_PASSTHROUGH); 242 puffs_setstacksize(pu, PUFFS_STACKSIZE_MIN); 243 puffs_fakecc = 1; 244 245 puffs_set_prepost(pu, makelwp, clearlwp); 246 puffs_set_errnotify(pu, p2k_errcatcher); 247 248 puffs_setspecific(pu, ukfs); 249 if ((rv = puffs_mount(pu, mountpath, mntflags, rvp))== -1) 250 goto out; 251 rv = puffs_mainloop(pu); 252 puffs_exit(pu, 1); 253 pu = NULL; 254 ukfs = NULL; 255 256 out: 257 sverrno = errno; 258 if (ukfs) 259 ukfs_release(ukfs, UKFS_RELFLAG_FORCE); 260 if (pu) 261 puffs_cancel(pu, sverrno); 262 if (rv) { 263 errno = sverrno; 264 rv = -1; 265 } 266 267 return rv; 268 } 269 270 /* XXX: vn_lock() */ 271 #define VLE(a) RUMP_VOP_LOCK(a, LK_EXCLUSIVE) 272 #define VLS(a) RUMP_VOP_LOCK(a, LK_SHARED) 273 #define VUL(a) RUMP_VOP_UNLOCK(a, 0); 274 #define AUL(a) assert(RUMP_VOP_ISLOCKED(a) == 0) 275 276 int 277 p2k_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp) 278 { 279 struct mount *mp = ukfs_getmp(puffs_getspecific(pu)); 280 281 return rump_vfs_statvfs(mp, sbp); 282 } 283 284 /*ARGSUSED*/ 285 int 286 p2k_fs_unmount(struct puffs_usermount *pu, int flags) 287 { 288 struct ukfs *fs = puffs_getspecific(pu); 289 290 rump_clear_curlwp(); /* XXX: ukfs uses curlwp */ 291 ukfs_release(fs, UKFS_RELFLAG_FORCE); 292 293 return 0; 294 } 295 296 int 297 p2k_fs_sync(struct puffs_usermount *pu, int waitfor, 298 const struct puffs_cred *pcr) 299 { 300 struct mount *mp = ukfs_getmp(puffs_getspecific(pu)); 301 kauth_cred_t cred; 302 int rv; 303 304 cred = cred_create(pcr); 305 rv = rump_vfs_sync(mp, waitfor, (kauth_cred_t)cred); 306 cred_destroy(cred); 307 308 return rv; 309 } 310 311 /*ARGSUSED*/ 312 int 313 p2k_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, 314 struct puffs_newinfo *pni) 315 { 316 struct mount *mp = ukfs_getmp(puffs_getspecific(pu)); 317 struct vnode *vp; 318 enum vtype vtype; 319 voff_t vsize; 320 uint64_t rdev; /* XXX: uint64_t because of stack overwrite in compat */ 321 int rv; 322 323 rv = rump_vfs_fhtovp(mp, fid, &vp); 324 if (rv) 325 return rv; 326 327 puffs_newinfo_setcookie(pni, vp); 328 rump_getvninfo(vp, &vtype, &vsize, (void *)&rdev); 329 puffs_newinfo_setvtype(pni, vtype); 330 puffs_newinfo_setsize(pni, vsize); 331 puffs_newinfo_setrdev(pni, rdev); 332 333 return 0; 334 } 335 336 /*ARGSUSED*/ 337 int 338 p2k_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie, void *fid, 339 size_t *fidsize) 340 { 341 struct vnode *vp = cookie; 342 343 return rump_vfs_vptofh(vp, fid, fidsize); 344 } 345 346 /*ARGSUSED*/ 347 int 348 p2k_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, 349 struct puffs_newinfo *pni, const struct puffs_cn *pcn) 350 { 351 struct componentname *cn; 352 struct vnode *vp; 353 enum vtype vtype; 354 voff_t vsize; 355 uint64_t rdev; /* XXX: uint64_t because of stack overwrite in compat */ 356 int rv; 357 358 cn = makecn(pcn); 359 VLE(opc); 360 rv = RUMP_VOP_LOOKUP(opc, &vp, cn); 361 VUL(opc); 362 freecn(cn, RUMPCN_ISLOOKUP); 363 if (rv) { 364 if (rv == EJUSTRETURN) 365 rv = ENOENT; 366 return rv; 367 } 368 VUL(vp); 369 370 puffs_newinfo_setcookie(pni, vp); 371 rump_getvninfo(vp, &vtype, &vsize, (void *)&rdev); 372 puffs_newinfo_setvtype(pni, vtype); 373 puffs_newinfo_setsize(pni, vsize); 374 puffs_newinfo_setrdev(pni, rdev); 375 376 return 0; 377 } 378 379 #define VERS_TIMECHANGE 599000700 380 static int 381 needcompat(void) 382 { 383 384 /*LINTED*/ 385 return __NetBSD_Version__ < VERS_TIMECHANGE 386 && rump_getversion() >= VERS_TIMECHANGE; 387 } 388 389 #define DOCOMPAT(va, va_compat) \ 390 do { \ 391 if (needcompat()) { \ 392 va_compat = rump_vattr_init(); \ 393 rump_vattr50_to_vattr(va, va_compat); \ 394 } else { \ 395 va_compat = __UNCONST(va); \ 396 } \ 397 } while (/*CONSTCOND*/0) 398 399 #define UNDOCOMPAT(va_compat) \ 400 do { \ 401 if (needcompat()) \ 402 rump_vattr_free(va_compat); \ 403 } while (/*CONSTCOND*/0) 404 405 /*ARGSUSED*/ 406 int 407 p2k_node_create(struct puffs_usermount *pu, puffs_cookie_t opc, 408 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 409 const struct vattr *vap) 410 { 411 struct componentname *cn; 412 struct vattr *va_x; 413 struct vnode *vp; 414 int rv; 415 416 DOCOMPAT(vap, va_x); 417 418 cn = makecn(pcn); 419 VLE(opc); 420 rump_vp_incref(opc); 421 rv = RUMP_VOP_CREATE(opc, &vp, cn, va_x); 422 AUL(opc); 423 freecn(cn, 0); 424 if (rv == 0) { 425 VUL(vp); 426 puffs_newinfo_setcookie(pni, vp); 427 } 428 429 UNDOCOMPAT(va_x); 430 431 return rv; 432 } 433 434 /*ARGSUSED*/ 435 int 436 p2k_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc, 437 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 438 const struct vattr *vap) 439 { 440 struct componentname *cn; 441 struct vattr *va_x; 442 struct vnode *vp; 443 int rv; 444 445 DOCOMPAT(vap, va_x); 446 447 cn = makecn(pcn); 448 VLE(opc); 449 rump_vp_incref(opc); 450 rv = RUMP_VOP_MKNOD(opc, &vp, cn, va_x); 451 AUL(opc); 452 freecn(cn, 0); 453 if (rv == 0) { 454 VUL(vp); 455 puffs_newinfo_setcookie(pni, vp); 456 } 457 458 UNDOCOMPAT(va_x); 459 460 return rv; 461 } 462 463 /*ARGSUSED*/ 464 int 465 p2k_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 466 const struct puffs_cred *pcr) 467 { 468 kauth_cred_t cred; 469 int rv; 470 471 cred = cred_create(pcr); 472 VLE(opc); 473 rv = RUMP_VOP_OPEN(opc, mode, cred); 474 VUL(opc); 475 cred_destroy(cred); 476 477 return rv; 478 } 479 480 /*ARGSUSED*/ 481 int 482 p2k_node_close(struct puffs_usermount *pu, puffs_cookie_t opc, int flags, 483 const struct puffs_cred *pcr) 484 { 485 kauth_cred_t cred; 486 487 cred = cred_create(pcr); 488 VLE(opc); 489 RUMP_VOP_CLOSE(opc, flags, cred); 490 VUL(opc); 491 cred_destroy(cred); 492 493 return 0; 494 } 495 496 /*ARGSUSED*/ 497 int 498 p2k_node_access(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 499 const struct puffs_cred *pcr) 500 { 501 kauth_cred_t cred; 502 int rv; 503 504 cred = cred_create(pcr); 505 VLE(opc); 506 rv = RUMP_VOP_ACCESS(opc, mode, cred); 507 VUL(opc); 508 cred_destroy(cred); 509 510 return rv; 511 } 512 513 /*ARGSUSED*/ 514 int 515 p2k_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 516 struct vattr *vap, const struct puffs_cred *pcr) 517 { 518 kauth_cred_t cred; 519 struct vattr *va_x; 520 int rv; 521 522 if (needcompat()) { 523 va_x = rump_vattr_init(); 524 } else { 525 va_x = vap; 526 } 527 528 cred = cred_create(pcr); 529 VLE(opc); 530 rv = RUMP_VOP_GETATTR(opc, va_x, cred); 531 VUL(opc); 532 cred_destroy(cred); 533 534 if (needcompat()) { 535 rump_vattr_to_vattr50(va_x, vap); 536 rump_vattr_free(va_x); 537 } 538 539 return rv; 540 } 541 542 /*ARGSUSED*/ 543 int 544 p2k_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 545 const struct vattr *vap, const struct puffs_cred *pcr) 546 { 547 kauth_cred_t cred; 548 struct vattr *va_x; 549 int rv; 550 551 DOCOMPAT(vap, va_x); 552 553 cred = cred_create(pcr); 554 VLE(opc); 555 rv = RUMP_VOP_SETATTR(opc, va_x, cred); 556 VUL(opc); 557 cred_destroy(cred); 558 559 UNDOCOMPAT(va_x); 560 561 return rv; 562 } 563 564 /*ARGSUSED*/ 565 int 566 p2k_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc, 567 const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi) 568 { 569 kauth_cred_t cred; 570 int rv; 571 572 cred = cred_create(pcr); 573 VLE(opc); 574 rv = RUMP_VOP_FSYNC(opc, cred, flags, offlo, offhi); 575 VUL(opc); 576 cred_destroy(cred); 577 578 return rv; 579 } 580 581 /*ARGSUSED*/ 582 int 583 p2k_node_mmap(struct puffs_usermount *pu, puffs_cookie_t opc, vm_prot_t flags, 584 const struct puffs_cred *pcr) 585 { 586 kauth_cred_t cred; 587 int rv; 588 589 cred = cred_create(pcr); 590 rv = RUMP_VOP_MMAP(opc, flags, cred); 591 cred_destroy(cred); 592 593 return rv; 594 } 595 596 /*ARGSUSED*/ 597 int 598 p2k_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc, 599 off_t oldoff, off_t newoff, const struct puffs_cred *pcr) 600 { 601 kauth_cred_t cred; 602 int rv; 603 604 cred = cred_create(pcr); 605 VLE(opc); 606 rv = RUMP_VOP_SEEK(opc, oldoff, newoff, cred); 607 VUL(opc); 608 cred_destroy(cred); 609 610 return rv; 611 } 612 613 /*ARGSUSED*/ 614 int 615 p2k_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc, 616 puffs_cookie_t targ, const struct puffs_cn *pcn) 617 { 618 struct componentname *cn; 619 int rv; 620 621 cn = makecn(pcn); 622 VLE(opc); 623 rump_vp_incref(opc); 624 VLE(targ); 625 rump_vp_incref(targ); 626 rv = RUMP_VOP_REMOVE(opc, targ, cn); 627 AUL(opc); 628 AUL(targ); 629 freecn(cn, 0); 630 631 return rv; 632 } 633 634 /*ARGSUSED*/ 635 int 636 p2k_node_link(struct puffs_usermount *pu, puffs_cookie_t opc, 637 puffs_cookie_t targ, const struct puffs_cn *pcn) 638 { 639 struct componentname *cn; 640 int rv; 641 642 cn = makecn(pcn); 643 VLE(opc); 644 rump_vp_incref(opc); 645 rv = RUMP_VOP_LINK(opc, targ, cn); 646 freecn(cn, 0); 647 648 return rv; 649 } 650 651 /*ARGSUSED*/ 652 int 653 p2k_node_rename(struct puffs_usermount *pu, 654 puffs_cookie_t src_dir, puffs_cookie_t src, 655 const struct puffs_cn *pcn_src, 656 puffs_cookie_t targ_dir, puffs_cookie_t targ, 657 const struct puffs_cn *pcn_targ) 658 { 659 struct componentname *cn_src, *cn_targ; 660 int rv; 661 662 cn_src = makecn(pcn_src); 663 cn_targ = makecn(pcn_targ); 664 rump_vp_incref(src_dir); 665 rump_vp_incref(src); 666 VLE(targ_dir); 667 rump_vp_incref(targ_dir); 668 if (targ) { 669 VLE(targ); 670 rump_vp_incref(targ); 671 } 672 rv = RUMP_VOP_RENAME(src_dir, src, cn_src, targ_dir, targ, cn_targ); 673 AUL(targ_dir); 674 if (targ) 675 AUL(targ); 676 freecn(cn_src, 0); 677 freecn(cn_targ, 0); 678 679 return rv; 680 } 681 682 /*ARGSUSED*/ 683 int 684 p2k_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc, 685 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 686 const struct vattr *vap) 687 { 688 struct componentname *cn; 689 struct vattr *va_x; 690 struct vnode *vp; 691 int rv; 692 693 DOCOMPAT(vap, va_x); 694 695 cn = makecn(pcn); 696 VLE(opc); 697 rump_vp_incref(opc); 698 rv = RUMP_VOP_MKDIR(opc, &vp, cn, va_x); 699 AUL(opc); 700 freecn(cn, 0); 701 if (rv == 0) { 702 VUL(vp); 703 puffs_newinfo_setcookie(pni, vp); 704 } 705 706 UNDOCOMPAT(va_x); 707 708 return rv; 709 } 710 711 /*ARGSUSED*/ 712 int 713 p2k_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc, 714 puffs_cookie_t targ, const struct puffs_cn *pcn) 715 { 716 struct componentname *cn; 717 int rv; 718 719 cn = makecn(pcn); 720 VLE(opc); 721 rump_vp_incref(opc); 722 VLE(targ); 723 rump_vp_incref(targ); 724 rv = RUMP_VOP_RMDIR(opc, targ, cn); 725 AUL(targ); 726 AUL(opc); 727 freecn(cn, 0); 728 729 return rv; 730 } 731 732 /*ARGSUSED*/ 733 int 734 p2k_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc, 735 struct puffs_newinfo *pni, const struct puffs_cn *pcn_src, 736 const struct vattr *vap, const char *link_target) 737 { 738 struct componentname *cn; 739 struct vattr *va_x; 740 struct vnode *vp; 741 int rv; 742 743 DOCOMPAT(vap, va_x); 744 745 cn = makecn(pcn_src); 746 VLE(opc); 747 rump_vp_incref(opc); 748 rv = RUMP_VOP_SYMLINK(opc, &vp, cn, va_x, __UNCONST(link_target)); 749 AUL(opc); 750 freecn(cn, 0); 751 if (rv == 0) { 752 VUL(vp); 753 puffs_newinfo_setcookie(pni, vp); 754 } 755 756 UNDOCOMPAT(va_x); 757 758 return rv; 759 } 760 761 /*ARGSUSED*/ 762 int 763 p2k_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, 764 struct dirent *dent, off_t *readoff, size_t *reslen, 765 const struct puffs_cred *pcr, int *eofflag, 766 off_t *cookies, size_t *ncookies) 767 { 768 kauth_cred_t cred; 769 struct uio *uio; 770 off_t *vop_cookies; 771 int vop_ncookies; 772 int rv; 773 774 cred = cred_create(pcr); 775 uio = rump_uio_setup(dent, *reslen, *readoff, RUMPUIO_READ); 776 VLS(opc); 777 if (cookies) { 778 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, 779 &vop_cookies, &vop_ncookies); 780 memcpy(cookies, vop_cookies, vop_ncookies * sizeof(*cookies)); 781 *ncookies = vop_ncookies; 782 free(vop_cookies); 783 } else { 784 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, NULL, NULL); 785 } 786 VUL(opc); 787 if (rv == 0) { 788 *reslen = rump_uio_getresid(uio); 789 *readoff = rump_uio_getoff(uio); 790 } 791 rump_uio_free(uio); 792 cred_destroy(cred); 793 794 return rv; 795 } 796 797 /*ARGSUSED*/ 798 int 799 p2k_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc, 800 const struct puffs_cred *pcr, char *linkname, size_t *linklen) 801 { 802 kauth_cred_t cred; 803 struct uio *uio; 804 int rv; 805 806 cred = cred_create(pcr); 807 uio = rump_uio_setup(linkname, *linklen, 0, RUMPUIO_READ); 808 VLE(opc); 809 rv = RUMP_VOP_READLINK(opc, uio, cred); 810 VUL(opc); 811 *linklen -= rump_uio_free(uio); 812 cred_destroy(cred); 813 814 return rv; 815 } 816 817 /*ARGSUSED*/ 818 int 819 p2k_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, 820 uint8_t *buf, off_t offset, size_t *resid, 821 const struct puffs_cred *pcr, int ioflag) 822 { 823 kauth_cred_t cred; 824 struct uio *uio; 825 int rv; 826 827 cred = cred_create(pcr); 828 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_READ); 829 VLS(opc); 830 rv = RUMP_VOP_READ(opc, uio, ioflag, cred); 831 VUL(opc); 832 *resid = rump_uio_free(uio); 833 cred_destroy(cred); 834 835 return rv; 836 } 837 838 /*ARGSUSED*/ 839 int 840 p2k_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, 841 uint8_t *buf, off_t offset, size_t *resid, 842 const struct puffs_cred *pcr, int ioflag) 843 { 844 kauth_cred_t cred; 845 struct uio *uio; 846 int rv; 847 848 cred = cred_create(pcr); 849 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_WRITE); 850 VLE(opc); 851 rv = RUMP_VOP_WRITE(opc, uio, ioflag, cred); 852 VUL(opc); 853 *resid = rump_uio_free(uio); 854 cred_destroy(cred); 855 856 return rv; 857 } 858 859 int 860 p2k_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 861 { 862 struct vnode *vp = opc; 863 bool recycle; 864 int rv; 865 866 rump_vp_interlock(vp); 867 (void) RUMP_VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES|PGO_CLEANIT|PGO_FREE); 868 VLE(vp); 869 rv = RUMP_VOP_INACTIVE(vp, &recycle); 870 if (recycle) 871 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 872 873 return rv; 874 } 875 876 /*ARGSUSED*/ 877 int 878 p2k_node_reclaim(struct puffs_usermount *pu, puffs_croissant_t opc) 879 { 880 881 rump_vp_recycle_nokidding(opc); 882 return 0; 883 } 884