1 /* $NetBSD: p2k.c,v 1.9 2009/02/22 20:28:05 ad 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 58 #include <rump/rump.h> 59 #include <rump/p2k.h> 60 #include <rump/ukfs.h> 61 62 PUFFSOP_PROTOS(p2k) 63 64 static kauth_cred_t 65 cred_create(const struct puffs_cred *pcr) 66 { 67 gid_t groups[NGROUPS]; 68 uid_t uid; 69 gid_t gid; 70 short ngroups = 0; 71 72 if (puffs_cred_getuid(pcr, &uid) == -1) 73 uid = 0; 74 if (puffs_cred_getgid(pcr, &gid) == -1) 75 gid = 0; 76 puffs_cred_getgroups(pcr, groups, &ngroups); 77 78 /* LINTED: ngroups is ok */ 79 return rump_cred_create(uid, gid, ngroups, groups); 80 } 81 82 static __inline void 83 cred_destroy(kauth_cred_t cred) 84 { 85 86 rump_cred_destroy(cred); 87 } 88 89 static struct componentname * 90 makecn(const struct puffs_cn *pcn) 91 { 92 kauth_cred_t cred; 93 94 cred = cred_create(pcn->pcn_cred); 95 /* LINTED: prehistoric types in first two args */ 96 return rump_makecn(pcn->pcn_nameiop, pcn->pcn_flags, pcn->pcn_name, 97 pcn->pcn_namelen, cred, curlwp); 98 } 99 100 static __inline void 101 freecn(struct componentname *cnp, int flags) 102 { 103 104 rump_freecn(cnp, flags | RUMPCN_FREECRED); 105 } 106 107 static void 108 makelwp(struct puffs_usermount *pu) 109 { 110 pid_t pid; 111 lwpid_t lid; 112 113 puffs_cc_getcaller(puffs_cc_getcc(pu), &pid, &lid); 114 rump_setup_curlwp(pid, lid, 1); 115 } 116 117 /*ARGSUSED*/ 118 static void 119 clearlwp(struct puffs_usermount *pu) 120 { 121 122 /* 123 * XXX: because of the vnode reference counting lossage, we 124 * can't clear the curlwp if we unmounted succesfully. 125 * Therefore, don't do it to avoid a diagnostic panic. 126 * So this currently leaks a process structure in that case, 127 * but since p2k is rarely used multiple times in a single 128 * process, it's more like a feature than a bug (yea, I'm 129 * good at lying to myself). 130 */ 131 if (__predict_false(puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED)) 132 rump_clear_curlwp(); 133 } 134 135 int 136 p2k_run_fs(const char *vfsname, const char *devpath, const char *mountpath, 137 int mntflags, void *arg, size_t alen, uint32_t puffs_flags) 138 { 139 char typebuf[PUFFS_TYPELEN]; 140 struct puffs_ops *pops; 141 struct puffs_usermount *pu = NULL; 142 struct puffs_node *pn_root; 143 struct vnode *rvp; 144 struct ukfs *ukfs = NULL; 145 extern int puffs_fakecc; 146 int rv = -1, sverrno; 147 bool dodaemon; 148 149 PUFFSOP_INIT(pops); 150 151 PUFFSOP_SET(pops, p2k, fs, statvfs); 152 PUFFSOP_SET(pops, p2k, fs, unmount); 153 PUFFSOP_SET(pops, p2k, fs, sync); 154 PUFFSOP_SET(pops, p2k, fs, fhtonode); 155 PUFFSOP_SET(pops, p2k, fs, nodetofh); 156 157 PUFFSOP_SET(pops, p2k, node, lookup); 158 PUFFSOP_SET(pops, p2k, node, create); 159 PUFFSOP_SET(pops, p2k, node, mknod); 160 PUFFSOP_SET(pops, p2k, node, open); 161 PUFFSOP_SET(pops, p2k, node, close); 162 PUFFSOP_SET(pops, p2k, node, access); 163 PUFFSOP_SET(pops, p2k, node, getattr); 164 PUFFSOP_SET(pops, p2k, node, setattr); 165 #if 0 166 PUFFSOP_SET(pops, p2k, node, poll); 167 #endif 168 PUFFSOP_SET(pops, p2k, node, mmap); 169 PUFFSOP_SET(pops, p2k, node, fsync); 170 PUFFSOP_SET(pops, p2k, node, seek); 171 PUFFSOP_SET(pops, p2k, node, remove); 172 PUFFSOP_SET(pops, p2k, node, link); 173 PUFFSOP_SET(pops, p2k, node, rename); 174 PUFFSOP_SET(pops, p2k, node, mkdir); 175 PUFFSOP_SET(pops, p2k, node, rmdir); 176 PUFFSOP_SET(pops, p2k, node, symlink); 177 PUFFSOP_SET(pops, p2k, node, readdir); 178 PUFFSOP_SET(pops, p2k, node, readlink); 179 PUFFSOP_SET(pops, p2k, node, read); 180 PUFFSOP_SET(pops, p2k, node, write); 181 182 PUFFSOP_SET(pops, p2k, node, inactive); 183 PUFFSOP_SET(pops, p2k, node, reclaim); 184 185 dodaemon = true; 186 if (getenv("P2K_DEBUG") != NULL) { 187 puffs_flags |= PUFFS_FLAG_OPDUMP; 188 dodaemon = false; 189 } 190 if (getenv("P2K_NODETACH") != NULL) { 191 dodaemon = false; 192 } 193 194 strcpy(typebuf, "p2k|"); 195 if (strcmp(vfsname, "puffs") == 0) { /* XXX */ 196 struct puffs_kargs *args = arg; 197 strlcat(typebuf, args->pa_typename, sizeof(typebuf)); 198 dodaemon = false; 199 } else { 200 strlcat(typebuf, vfsname, sizeof(typebuf)); 201 } 202 203 pu = puffs_init(pops, devpath, typebuf, NULL, puffs_flags); 204 if (pu == NULL) 205 goto out; 206 207 if (dodaemon) 208 puffs_daemon(pu, 1, 1); 209 210 if (ukfs_init() == -1) 211 return -1; 212 ukfs = ukfs_mount(vfsname, devpath, mountpath, mntflags, arg, alen); 213 if (ukfs == NULL) 214 goto out; 215 216 rvp = ukfs_getrvp(ukfs); 217 pn_root = puffs_pn_new(pu, rvp); 218 puffs_setroot(pu, pn_root); 219 puffs_setfhsize(pu, 0, PUFFS_FHFLAG_PASSTHROUGH); 220 puffs_setstacksize(pu, PUFFS_STACKSIZE_MIN); 221 puffs_fakecc = 1; 222 223 puffs_set_prepost(pu, makelwp, clearlwp); 224 225 puffs_setspecific(pu, ukfs_getmp(ukfs)); 226 if ((rv = puffs_mount(pu, mountpath, mntflags, rvp))== -1) 227 goto out; 228 rv = puffs_mainloop(pu); 229 puffs_exit(pu, 1); 230 pu = NULL; 231 232 out: 233 sverrno = errno; 234 if (ukfs) 235 ukfs_release(ukfs, UKFS_RELFLAG_NOUNMOUNT); 236 if (pu) 237 puffs_cancel(pu, sverrno); 238 if (rv) { 239 errno = sverrno; 240 rv = -1; 241 } 242 243 return rv; 244 } 245 246 /* XXX: vn_lock() */ 247 #define VLE(a) RUMP_VOP_LOCK(a, LK_EXCLUSIVE) 248 #define VLS(a) RUMP_VOP_LOCK(a, LK_SHARED) 249 #define VUL(a) RUMP_VOP_UNLOCK(a, 0); 250 #define AUL(a) assert(RUMP_VOP_ISLOCKED(a) == 0) 251 252 int 253 p2k_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp) 254 { 255 struct mount *mp = puffs_getspecific(pu); 256 257 return rump_vfs_statvfs(mp, sbp); 258 } 259 260 int 261 p2k_fs_unmount(struct puffs_usermount *pu, int flags) 262 { 263 struct mount *mp = puffs_getspecific(pu); 264 struct puffs_node *pn_root = puffs_getroot(pu); 265 struct vnode *rvp = pn_root->pn_data, *rvp2; 266 int rv; 267 268 /* 269 * We recycle the root node already here (god knows how 270 * many references it has due to lookup). This is good 271 * because VFS_UNMOUNT would do it anyway. But it is 272 * very bad if VFS_UNMOUNT fails for a reason or another 273 * (puffs guards against busy fs, but there might be other 274 * reasons). 275 * 276 * Theoretically we're going south, sinking fast & dying 277 * out here because the old vnode will be freed and we are 278 * unlikely to get a vnode at the same address. But try 279 * anyway. 280 * 281 * XXX: reallyfixmesomeday. either introduce VFS_ROOT to 282 * puffs (blah) or check the cookie in every routine 283 * against the root cookie, which might change (blah2). 284 */ 285 rump_vp_recycle_nokidding(rvp); 286 rv = rump_vfs_unmount(mp, flags); 287 if (rv) { 288 int rv2; 289 290 rv2 = rump_vfs_root(mp, &rvp2, 0); 291 assert(rv2 == 0 && rvp == rvp2); 292 } 293 return rv; 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 = 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 = puffs_getspecific(pu); 317 struct vnode *vp; 318 enum vtype vtype; 319 voff_t vsize; 320 dev_t rdev; 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, &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 dev_t rdev; 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, &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 /*ARGSUSED*/ 380 int 381 p2k_node_create(struct puffs_usermount *pu, puffs_cookie_t opc, 382 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 383 const struct vattr *vap) 384 { 385 struct componentname *cn; 386 struct vnode *vp; 387 int rv; 388 389 cn = makecn(pcn); 390 VLE(opc); 391 rump_vp_incref(opc); 392 rv = RUMP_VOP_CREATE(opc, &vp, cn, __UNCONST(vap)); 393 AUL(opc); 394 freecn(cn, 0); 395 if (rv == 0) { 396 VUL(vp); 397 puffs_newinfo_setcookie(pni, vp); 398 } 399 400 return rv; 401 } 402 403 /*ARGSUSED*/ 404 int 405 p2k_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc, 406 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 407 const struct vattr *vap) 408 { 409 struct componentname *cn; 410 struct vnode *vp; 411 int rv; 412 413 cn = makecn(pcn); 414 VLE(opc); 415 rump_vp_incref(opc); 416 rv = RUMP_VOP_MKNOD(opc, &vp, cn, __UNCONST(vap)); 417 AUL(opc); 418 freecn(cn, 0); 419 if (rv == 0) { 420 VUL(vp); 421 puffs_newinfo_setcookie(pni, vp); 422 } 423 424 return rv; 425 } 426 427 /*ARGSUSED*/ 428 int 429 p2k_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 430 const struct puffs_cred *pcr) 431 { 432 kauth_cred_t cred; 433 int rv; 434 435 cred = cred_create(pcr); 436 VLE(opc); 437 rv = RUMP_VOP_OPEN(opc, mode, cred); 438 VUL(opc); 439 cred_destroy(cred); 440 441 return rv; 442 } 443 444 /*ARGSUSED*/ 445 int 446 p2k_node_close(struct puffs_usermount *pu, puffs_cookie_t opc, int flags, 447 const struct puffs_cred *pcr) 448 { 449 kauth_cred_t cred; 450 451 cred = cred_create(pcr); 452 VLE(opc); 453 RUMP_VOP_CLOSE(opc, flags, cred); 454 VUL(opc); 455 cred_destroy(cred); 456 457 return 0; 458 } 459 460 /*ARGSUSED*/ 461 int 462 p2k_node_access(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 463 const struct puffs_cred *pcr) 464 { 465 kauth_cred_t cred; 466 int rv; 467 468 cred = cred_create(pcr); 469 VLE(opc); 470 rv = RUMP_VOP_ACCESS(opc, mode, cred); 471 VUL(opc); 472 cred_destroy(cred); 473 474 return rv; 475 } 476 477 /*ARGSUSED*/ 478 int 479 p2k_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 480 struct vattr *vap, const struct puffs_cred *pcr) 481 { 482 kauth_cred_t cred; 483 int rv; 484 485 cred = cred_create(pcr); 486 VLE(opc); 487 rv = RUMP_VOP_GETATTR(opc, vap, cred); 488 VUL(opc); 489 cred_destroy(cred); 490 491 return rv; 492 } 493 494 /*ARGSUSED*/ 495 int 496 p2k_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 497 const struct vattr *vap, const struct puffs_cred *pcr) 498 { 499 kauth_cred_t cred; 500 int rv; 501 502 cred = cred_create(pcr); 503 VLE(opc); 504 rv = RUMP_VOP_SETATTR(opc, __UNCONST(vap), cred); 505 VUL(opc); 506 cred_destroy(cred); 507 508 return rv; 509 } 510 511 /*ARGSUSED*/ 512 int 513 p2k_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc, 514 const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi) 515 { 516 kauth_cred_t cred; 517 int rv; 518 519 cred = cred_create(pcr); 520 VLE(opc); 521 rv = RUMP_VOP_FSYNC(opc, cred, flags, offlo, offhi); 522 VUL(opc); 523 cred_destroy(cred); 524 525 return rv; 526 } 527 528 /*ARGSUSED*/ 529 int 530 p2k_node_mmap(struct puffs_usermount *pu, puffs_cookie_t opc, vm_prot_t flags, 531 const struct puffs_cred *pcr) 532 { 533 kauth_cred_t cred; 534 int rv; 535 536 cred = cred_create(pcr); 537 rv = RUMP_VOP_MMAP(opc, flags, cred); 538 cred_destroy(cred); 539 540 return rv; 541 } 542 543 /*ARGSUSED*/ 544 int 545 p2k_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc, 546 off_t oldoff, off_t newoff, const struct puffs_cred *pcr) 547 { 548 kauth_cred_t cred; 549 int rv; 550 551 cred = cred_create(pcr); 552 VLE(opc); 553 rv = RUMP_VOP_SEEK(opc, oldoff, newoff, cred); 554 VUL(opc); 555 cred_destroy(cred); 556 557 return rv; 558 } 559 560 /*ARGSUSED*/ 561 int 562 p2k_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc, 563 puffs_cookie_t targ, const struct puffs_cn *pcn) 564 { 565 struct componentname *cn; 566 int rv; 567 568 cn = makecn(pcn); 569 VLE(opc); 570 rump_vp_incref(opc); 571 VLE(targ); 572 rump_vp_incref(targ); 573 rv = RUMP_VOP_REMOVE(opc, targ, cn); 574 AUL(opc); 575 AUL(targ); 576 freecn(cn, 0); 577 578 return rv; 579 } 580 581 /*ARGSUSED*/ 582 int 583 p2k_node_link(struct puffs_usermount *pu, puffs_cookie_t opc, 584 puffs_cookie_t targ, const struct puffs_cn *pcn) 585 { 586 struct componentname *cn; 587 int rv; 588 589 cn = makecn(pcn); 590 VLE(opc); 591 rump_vp_incref(opc); 592 rv = RUMP_VOP_LINK(opc, targ, cn); 593 freecn(cn, 0); 594 595 return rv; 596 } 597 598 /*ARGSUSED*/ 599 int 600 p2k_node_rename(struct puffs_usermount *pu, 601 puffs_cookie_t src_dir, puffs_cookie_t src, 602 const struct puffs_cn *pcn_src, 603 puffs_cookie_t targ_dir, puffs_cookie_t targ, 604 const struct puffs_cn *pcn_targ) 605 { 606 struct componentname *cn_src, *cn_targ; 607 int rv; 608 609 cn_src = makecn(pcn_src); 610 cn_targ = makecn(pcn_targ); 611 rump_vp_incref(src_dir); 612 rump_vp_incref(src); 613 VLE(targ_dir); 614 rump_vp_incref(targ_dir); 615 if (targ) { 616 VLE(targ); 617 rump_vp_incref(targ); 618 } 619 rv = RUMP_VOP_RENAME(src_dir, src, cn_src, targ_dir, targ, cn_targ); 620 AUL(targ_dir); 621 if (targ) 622 AUL(targ); 623 freecn(cn_src, 0); 624 freecn(cn_targ, 0); 625 626 return rv; 627 } 628 629 /*ARGSUSED*/ 630 int 631 p2k_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc, 632 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 633 const struct vattr *vap) 634 { 635 struct componentname *cn; 636 struct vnode *vp; 637 int rv; 638 639 cn = makecn(pcn); 640 VLE(opc); 641 rump_vp_incref(opc); 642 rv = RUMP_VOP_MKDIR(opc, &vp, cn, __UNCONST(vap)); 643 AUL(opc); 644 freecn(cn, 0); 645 if (rv == 0) { 646 VUL(vp); 647 puffs_newinfo_setcookie(pni, vp); 648 } 649 650 return rv; 651 } 652 653 /*ARGSUSED*/ 654 int 655 p2k_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc, 656 puffs_cookie_t targ, const struct puffs_cn *pcn) 657 { 658 struct componentname *cn; 659 int rv; 660 661 cn = makecn(pcn); 662 VLE(opc); 663 rump_vp_incref(opc); 664 VLE(targ); 665 rump_vp_incref(targ); 666 rv = RUMP_VOP_RMDIR(opc, targ, cn); 667 AUL(targ); 668 AUL(opc); 669 freecn(cn, 0); 670 671 return rv; 672 } 673 674 /*ARGSUSED*/ 675 int 676 p2k_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc, 677 struct puffs_newinfo *pni, const struct puffs_cn *pcn_src, 678 const struct vattr *vap, const char *link_target) 679 { 680 struct componentname *cn; 681 struct vnode *vp; 682 int rv; 683 684 cn = makecn(pcn_src); 685 VLE(opc); 686 rump_vp_incref(opc); 687 rv = RUMP_VOP_SYMLINK(opc, &vp, cn, 688 __UNCONST(vap), __UNCONST(link_target)); 689 AUL(opc); 690 freecn(cn, 0); 691 if (rv == 0) { 692 VUL(vp); 693 puffs_newinfo_setcookie(pni, vp); 694 } 695 696 return rv; 697 } 698 699 /*ARGSUSED*/ 700 int 701 p2k_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, 702 struct dirent *dent, off_t *readoff, size_t *reslen, 703 const struct puffs_cred *pcr, int *eofflag, 704 off_t *cookies, size_t *ncookies) 705 { 706 kauth_cred_t cred; 707 struct uio *uio; 708 off_t *vop_cookies; 709 int vop_ncookies; 710 int rv; 711 712 cred = cred_create(pcr); 713 uio = rump_uio_setup(dent, *reslen, *readoff, RUMPUIO_READ); 714 VLS(opc); 715 if (cookies) { 716 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, 717 &vop_cookies, &vop_ncookies); 718 memcpy(cookies, vop_cookies, vop_ncookies * sizeof(*cookies)); 719 *ncookies = vop_ncookies; 720 free(vop_cookies); 721 } else { 722 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, NULL, NULL); 723 } 724 VUL(opc); 725 if (rv == 0) { 726 *reslen = rump_uio_getresid(uio); 727 *readoff = rump_uio_getoff(uio); 728 } 729 rump_uio_free(uio); 730 cred_destroy(cred); 731 732 return rv; 733 } 734 735 /*ARGSUSED*/ 736 int 737 p2k_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc, 738 const struct puffs_cred *pcr, char *linkname, size_t *linklen) 739 { 740 kauth_cred_t cred; 741 struct uio *uio; 742 int rv; 743 744 cred = cred_create(pcr); 745 uio = rump_uio_setup(linkname, *linklen, 0, RUMPUIO_READ); 746 VLE(opc); 747 rv = RUMP_VOP_READLINK(opc, uio, cred); 748 VUL(opc); 749 *linklen -= rump_uio_free(uio); 750 cred_destroy(cred); 751 752 return rv; 753 } 754 755 /*ARGSUSED*/ 756 int 757 p2k_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, 758 uint8_t *buf, off_t offset, size_t *resid, 759 const struct puffs_cred *pcr, int ioflag) 760 { 761 kauth_cred_t cred; 762 struct uio *uio; 763 int rv; 764 765 cred = cred_create(pcr); 766 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_READ); 767 VLS(opc); 768 rv = RUMP_VOP_READ(opc, uio, ioflag, cred); 769 VUL(opc); 770 *resid = rump_uio_free(uio); 771 cred_destroy(cred); 772 773 return rv; 774 } 775 776 /*ARGSUSED*/ 777 int 778 p2k_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, 779 uint8_t *buf, off_t offset, size_t *resid, 780 const struct puffs_cred *pcr, int ioflag) 781 { 782 kauth_cred_t cred; 783 struct uio *uio; 784 int rv; 785 786 cred = cred_create(pcr); 787 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_WRITE); 788 VLE(opc); 789 rv = RUMP_VOP_WRITE(opc, uio, ioflag, cred); 790 VUL(opc); 791 *resid = rump_uio_free(uio); 792 cred_destroy(cred); 793 794 return rv; 795 } 796 797 int 798 p2k_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 799 { 800 struct vnode *vp = opc; 801 bool recycle; 802 int rv; 803 804 rump_vp_interlock(vp); 805 (void) RUMP_VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES); 806 VLE(vp); 807 rv = RUMP_VOP_INACTIVE(vp, &recycle); 808 if (recycle) 809 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 810 811 return rv; 812 } 813 814 /*ARGSUSED*/ 815 int 816 p2k_node_reclaim(struct puffs_usermount *pu, puffs_croissant_t opc) 817 { 818 819 rump_vp_recycle_nokidding(opc); 820 return 0; 821 } 822