1 /* $NetBSD: p2k.c,v 1.13 2009/05/03 20:26:42 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 dev_t rdev; 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, &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 dev_t rdev; 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, &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 /*ARGSUSED*/ 409 int 410 p2k_node_create(struct puffs_usermount *pu, puffs_cookie_t opc, 411 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 412 const struct vattr *vap) 413 { 414 struct componentname *cn; 415 struct vnode *vp; 416 int rv; 417 418 cn = makecn(pcn); 419 VLE(opc); 420 rump_vp_incref(opc); 421 rv = RUMP_VOP_CREATE(opc, &vp, cn, __UNCONST(vap)); 422 AUL(opc); 423 freecn(cn, 0); 424 if (rv == 0) { 425 VUL(vp); 426 puffs_newinfo_setcookie(pni, vp); 427 } 428 429 return rv; 430 } 431 432 /*ARGSUSED*/ 433 int 434 p2k_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc, 435 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 436 const struct vattr *vap) 437 { 438 struct componentname *cn; 439 struct vnode *vp; 440 int rv; 441 442 cn = makecn(pcn); 443 VLE(opc); 444 rump_vp_incref(opc); 445 rv = RUMP_VOP_MKNOD(opc, &vp, cn, __UNCONST(vap)); 446 AUL(opc); 447 freecn(cn, 0); 448 if (rv == 0) { 449 VUL(vp); 450 puffs_newinfo_setcookie(pni, vp); 451 } 452 453 return rv; 454 } 455 456 /*ARGSUSED*/ 457 int 458 p2k_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 459 const struct puffs_cred *pcr) 460 { 461 kauth_cred_t cred; 462 int rv; 463 464 cred = cred_create(pcr); 465 VLE(opc); 466 rv = RUMP_VOP_OPEN(opc, mode, cred); 467 VUL(opc); 468 cred_destroy(cred); 469 470 return rv; 471 } 472 473 /*ARGSUSED*/ 474 int 475 p2k_node_close(struct puffs_usermount *pu, puffs_cookie_t opc, int flags, 476 const struct puffs_cred *pcr) 477 { 478 kauth_cred_t cred; 479 480 cred = cred_create(pcr); 481 VLE(opc); 482 RUMP_VOP_CLOSE(opc, flags, cred); 483 VUL(opc); 484 cred_destroy(cred); 485 486 return 0; 487 } 488 489 /*ARGSUSED*/ 490 int 491 p2k_node_access(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 492 const struct puffs_cred *pcr) 493 { 494 kauth_cred_t cred; 495 int rv; 496 497 cred = cred_create(pcr); 498 VLE(opc); 499 rv = RUMP_VOP_ACCESS(opc, mode, cred); 500 VUL(opc); 501 cred_destroy(cred); 502 503 return rv; 504 } 505 506 /*ARGSUSED*/ 507 int 508 p2k_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 509 struct vattr *vap, const struct puffs_cred *pcr) 510 { 511 kauth_cred_t cred; 512 int rv; 513 514 cred = cred_create(pcr); 515 VLE(opc); 516 rv = RUMP_VOP_GETATTR(opc, vap, cred); 517 VUL(opc); 518 cred_destroy(cred); 519 520 return rv; 521 } 522 523 /*ARGSUSED*/ 524 int 525 p2k_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 526 const struct vattr *vap, const struct puffs_cred *pcr) 527 { 528 kauth_cred_t cred; 529 int rv; 530 531 cred = cred_create(pcr); 532 VLE(opc); 533 rv = RUMP_VOP_SETATTR(opc, __UNCONST(vap), cred); 534 VUL(opc); 535 cred_destroy(cred); 536 537 return rv; 538 } 539 540 /*ARGSUSED*/ 541 int 542 p2k_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc, 543 const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi) 544 { 545 kauth_cred_t cred; 546 int rv; 547 548 cred = cred_create(pcr); 549 VLE(opc); 550 rv = RUMP_VOP_FSYNC(opc, cred, flags, offlo, offhi); 551 VUL(opc); 552 cred_destroy(cred); 553 554 return rv; 555 } 556 557 /*ARGSUSED*/ 558 int 559 p2k_node_mmap(struct puffs_usermount *pu, puffs_cookie_t opc, vm_prot_t flags, 560 const struct puffs_cred *pcr) 561 { 562 kauth_cred_t cred; 563 int rv; 564 565 cred = cred_create(pcr); 566 rv = RUMP_VOP_MMAP(opc, flags, cred); 567 cred_destroy(cred); 568 569 return rv; 570 } 571 572 /*ARGSUSED*/ 573 int 574 p2k_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc, 575 off_t oldoff, off_t newoff, const struct puffs_cred *pcr) 576 { 577 kauth_cred_t cred; 578 int rv; 579 580 cred = cred_create(pcr); 581 VLE(opc); 582 rv = RUMP_VOP_SEEK(opc, oldoff, newoff, cred); 583 VUL(opc); 584 cred_destroy(cred); 585 586 return rv; 587 } 588 589 /*ARGSUSED*/ 590 int 591 p2k_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc, 592 puffs_cookie_t targ, const struct puffs_cn *pcn) 593 { 594 struct componentname *cn; 595 int rv; 596 597 cn = makecn(pcn); 598 VLE(opc); 599 rump_vp_incref(opc); 600 VLE(targ); 601 rump_vp_incref(targ); 602 rv = RUMP_VOP_REMOVE(opc, targ, cn); 603 AUL(opc); 604 AUL(targ); 605 freecn(cn, 0); 606 607 return rv; 608 } 609 610 /*ARGSUSED*/ 611 int 612 p2k_node_link(struct puffs_usermount *pu, puffs_cookie_t opc, 613 puffs_cookie_t targ, const struct puffs_cn *pcn) 614 { 615 struct componentname *cn; 616 int rv; 617 618 cn = makecn(pcn); 619 VLE(opc); 620 rump_vp_incref(opc); 621 rv = RUMP_VOP_LINK(opc, targ, cn); 622 freecn(cn, 0); 623 624 return rv; 625 } 626 627 /*ARGSUSED*/ 628 int 629 p2k_node_rename(struct puffs_usermount *pu, 630 puffs_cookie_t src_dir, puffs_cookie_t src, 631 const struct puffs_cn *pcn_src, 632 puffs_cookie_t targ_dir, puffs_cookie_t targ, 633 const struct puffs_cn *pcn_targ) 634 { 635 struct componentname *cn_src, *cn_targ; 636 int rv; 637 638 cn_src = makecn(pcn_src); 639 cn_targ = makecn(pcn_targ); 640 rump_vp_incref(src_dir); 641 rump_vp_incref(src); 642 VLE(targ_dir); 643 rump_vp_incref(targ_dir); 644 if (targ) { 645 VLE(targ); 646 rump_vp_incref(targ); 647 } 648 rv = RUMP_VOP_RENAME(src_dir, src, cn_src, targ_dir, targ, cn_targ); 649 AUL(targ_dir); 650 if (targ) 651 AUL(targ); 652 freecn(cn_src, 0); 653 freecn(cn_targ, 0); 654 655 return rv; 656 } 657 658 /*ARGSUSED*/ 659 int 660 p2k_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc, 661 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 662 const struct vattr *vap) 663 { 664 struct componentname *cn; 665 struct vnode *vp; 666 int rv; 667 668 cn = makecn(pcn); 669 VLE(opc); 670 rump_vp_incref(opc); 671 rv = RUMP_VOP_MKDIR(opc, &vp, cn, __UNCONST(vap)); 672 AUL(opc); 673 freecn(cn, 0); 674 if (rv == 0) { 675 VUL(vp); 676 puffs_newinfo_setcookie(pni, vp); 677 } 678 679 return rv; 680 } 681 682 /*ARGSUSED*/ 683 int 684 p2k_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc, 685 puffs_cookie_t targ, const struct puffs_cn *pcn) 686 { 687 struct componentname *cn; 688 int rv; 689 690 cn = makecn(pcn); 691 VLE(opc); 692 rump_vp_incref(opc); 693 VLE(targ); 694 rump_vp_incref(targ); 695 rv = RUMP_VOP_RMDIR(opc, targ, cn); 696 AUL(targ); 697 AUL(opc); 698 freecn(cn, 0); 699 700 return rv; 701 } 702 703 /*ARGSUSED*/ 704 int 705 p2k_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc, 706 struct puffs_newinfo *pni, const struct puffs_cn *pcn_src, 707 const struct vattr *vap, const char *link_target) 708 { 709 struct componentname *cn; 710 struct vnode *vp; 711 int rv; 712 713 cn = makecn(pcn_src); 714 VLE(opc); 715 rump_vp_incref(opc); 716 rv = RUMP_VOP_SYMLINK(opc, &vp, cn, 717 __UNCONST(vap), __UNCONST(link_target)); 718 AUL(opc); 719 freecn(cn, 0); 720 if (rv == 0) { 721 VUL(vp); 722 puffs_newinfo_setcookie(pni, vp); 723 } 724 725 return rv; 726 } 727 728 /*ARGSUSED*/ 729 int 730 p2k_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, 731 struct dirent *dent, off_t *readoff, size_t *reslen, 732 const struct puffs_cred *pcr, int *eofflag, 733 off_t *cookies, size_t *ncookies) 734 { 735 kauth_cred_t cred; 736 struct uio *uio; 737 off_t *vop_cookies; 738 int vop_ncookies; 739 int rv; 740 741 cred = cred_create(pcr); 742 uio = rump_uio_setup(dent, *reslen, *readoff, RUMPUIO_READ); 743 VLS(opc); 744 if (cookies) { 745 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, 746 &vop_cookies, &vop_ncookies); 747 memcpy(cookies, vop_cookies, vop_ncookies * sizeof(*cookies)); 748 *ncookies = vop_ncookies; 749 free(vop_cookies); 750 } else { 751 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, NULL, NULL); 752 } 753 VUL(opc); 754 if (rv == 0) { 755 *reslen = rump_uio_getresid(uio); 756 *readoff = rump_uio_getoff(uio); 757 } 758 rump_uio_free(uio); 759 cred_destroy(cred); 760 761 return rv; 762 } 763 764 /*ARGSUSED*/ 765 int 766 p2k_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc, 767 const struct puffs_cred *pcr, char *linkname, size_t *linklen) 768 { 769 kauth_cred_t cred; 770 struct uio *uio; 771 int rv; 772 773 cred = cred_create(pcr); 774 uio = rump_uio_setup(linkname, *linklen, 0, RUMPUIO_READ); 775 VLE(opc); 776 rv = RUMP_VOP_READLINK(opc, uio, cred); 777 VUL(opc); 778 *linklen -= rump_uio_free(uio); 779 cred_destroy(cred); 780 781 return rv; 782 } 783 784 /*ARGSUSED*/ 785 int 786 p2k_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, 787 uint8_t *buf, off_t offset, size_t *resid, 788 const struct puffs_cred *pcr, int ioflag) 789 { 790 kauth_cred_t cred; 791 struct uio *uio; 792 int rv; 793 794 cred = cred_create(pcr); 795 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_READ); 796 VLS(opc); 797 rv = RUMP_VOP_READ(opc, uio, ioflag, cred); 798 VUL(opc); 799 *resid = rump_uio_free(uio); 800 cred_destroy(cred); 801 802 return rv; 803 } 804 805 /*ARGSUSED*/ 806 int 807 p2k_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, 808 uint8_t *buf, off_t offset, size_t *resid, 809 const struct puffs_cred *pcr, int ioflag) 810 { 811 kauth_cred_t cred; 812 struct uio *uio; 813 int rv; 814 815 cred = cred_create(pcr); 816 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_WRITE); 817 VLE(opc); 818 rv = RUMP_VOP_WRITE(opc, uio, ioflag, cred); 819 VUL(opc); 820 *resid = rump_uio_free(uio); 821 cred_destroy(cred); 822 823 return rv; 824 } 825 826 int 827 p2k_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 828 { 829 struct vnode *vp = opc; 830 bool recycle; 831 int rv; 832 833 rump_vp_interlock(vp); 834 (void) RUMP_VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES); 835 VLE(vp); 836 rv = RUMP_VOP_INACTIVE(vp, &recycle); 837 if (recycle) 838 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 839 840 return rv; 841 } 842 843 /*ARGSUSED*/ 844 int 845 p2k_node_reclaim(struct puffs_usermount *pu, puffs_croissant_t opc) 846 { 847 848 rump_vp_recycle_nokidding(opc); 849 return 0; 850 } 851