1 /* $NetBSD: p2k.c,v 1.11 2009/04/02 09:30:41 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_destroy(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 213 strcpy(typebuf, "p2k|"); 214 if (strcmp(vfsname, "puffs") == 0) { /* XXX */ 215 struct puffs_kargs *args = arg; 216 strlcat(typebuf, args->pa_typename, sizeof(typebuf)); 217 dodaemon = false; 218 } else { 219 strlcat(typebuf, vfsname, sizeof(typebuf)); 220 } 221 222 pu = puffs_init(pops, devpath, typebuf, NULL, puffs_flags); 223 if (pu == NULL) 224 goto out; 225 226 if (dodaemon) 227 puffs_daemon(pu, 1, 1); 228 229 if (ukfs_init() == -1) 230 return -1; 231 ukfs = ukfs_mount(vfsname, devpath, mountpath, mntflags, arg, alen); 232 if (ukfs == NULL) 233 goto out; 234 235 rvp = ukfs_getrvp(ukfs); 236 pn_root = puffs_pn_new(pu, rvp); 237 puffs_setroot(pu, pn_root); 238 puffs_setfhsize(pu, 0, PUFFS_FHFLAG_PASSTHROUGH); 239 puffs_setstacksize(pu, PUFFS_STACKSIZE_MIN); 240 puffs_fakecc = 1; 241 242 puffs_set_prepost(pu, makelwp, clearlwp); 243 puffs_set_errnotify(pu, p2k_errcatcher); 244 245 puffs_setspecific(pu, ukfs_getmp(ukfs)); 246 if ((rv = puffs_mount(pu, mountpath, mntflags, rvp))== -1) 247 goto out; 248 rv = puffs_mainloop(pu); 249 puffs_exit(pu, 1); 250 pu = NULL; 251 252 out: 253 sverrno = errno; 254 if (ukfs) 255 ukfs_release(ukfs, UKFS_RELFLAG_NOUNMOUNT); 256 if (pu) 257 puffs_cancel(pu, sverrno); 258 if (rv) { 259 errno = sverrno; 260 rv = -1; 261 } 262 263 return rv; 264 } 265 266 /* XXX: vn_lock() */ 267 #define VLE(a) RUMP_VOP_LOCK(a, LK_EXCLUSIVE) 268 #define VLS(a) RUMP_VOP_LOCK(a, LK_SHARED) 269 #define VUL(a) RUMP_VOP_UNLOCK(a, 0); 270 #define AUL(a) assert(RUMP_VOP_ISLOCKED(a) == 0) 271 272 int 273 p2k_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp) 274 { 275 struct mount *mp = puffs_getspecific(pu); 276 277 return rump_vfs_statvfs(mp, sbp); 278 } 279 280 int 281 p2k_fs_unmount(struct puffs_usermount *pu, int flags) 282 { 283 struct mount *mp = puffs_getspecific(pu); 284 struct puffs_node *pn_root = puffs_getroot(pu); 285 struct vnode *rvp = pn_root->pn_data, *rvp2; 286 int rv; 287 288 /* 289 * We recycle the root node already here (god knows how 290 * many references it has due to lookup). This is good 291 * because VFS_UNMOUNT would do it anyway. But it is 292 * very bad if VFS_UNMOUNT fails for a reason or another 293 * (puffs guards against busy fs, but there might be other 294 * reasons). 295 * 296 * Theoretically we're going south, sinking fast & dying 297 * out here because the old vnode will be freed and we are 298 * unlikely to get a vnode at the same address. But try 299 * anyway. 300 * 301 * XXX: reallyfixmesomeday. either introduce VFS_ROOT to 302 * puffs (blah) or check the cookie in every routine 303 * against the root cookie, which might change (blah2). 304 */ 305 rump_vp_recycle_nokidding(rvp); 306 rv = rump_vfs_unmount(mp, flags); 307 if (rv) { 308 int rv2; 309 310 rv2 = rump_vfs_root(mp, &rvp2, 0); 311 assert(rv2 == 0 && rvp == rvp2); 312 } 313 return rv; 314 } 315 316 int 317 p2k_fs_sync(struct puffs_usermount *pu, int waitfor, 318 const struct puffs_cred *pcr) 319 { 320 struct mount *mp = puffs_getspecific(pu); 321 kauth_cred_t cred; 322 int rv; 323 324 cred = cred_create(pcr); 325 rv = rump_vfs_sync(mp, waitfor, (kauth_cred_t)cred); 326 cred_destroy(cred); 327 328 return rv; 329 } 330 331 /*ARGSUSED*/ 332 int 333 p2k_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, 334 struct puffs_newinfo *pni) 335 { 336 struct mount *mp = puffs_getspecific(pu); 337 struct vnode *vp; 338 enum vtype vtype; 339 voff_t vsize; 340 dev_t rdev; 341 int rv; 342 343 rv = rump_vfs_fhtovp(mp, fid, &vp); 344 if (rv) 345 return rv; 346 347 puffs_newinfo_setcookie(pni, vp); 348 rump_getvninfo(vp, &vtype, &vsize, &rdev); 349 puffs_newinfo_setvtype(pni, vtype); 350 puffs_newinfo_setsize(pni, vsize); 351 puffs_newinfo_setrdev(pni, rdev); 352 353 return 0; 354 } 355 356 /*ARGSUSED*/ 357 int 358 p2k_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie, void *fid, 359 size_t *fidsize) 360 { 361 struct vnode *vp = cookie; 362 363 return rump_vfs_vptofh(vp, fid, fidsize); 364 } 365 366 /*ARGSUSED*/ 367 int 368 p2k_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, 369 struct puffs_newinfo *pni, const struct puffs_cn *pcn) 370 { 371 struct componentname *cn; 372 struct vnode *vp; 373 enum vtype vtype; 374 voff_t vsize; 375 dev_t rdev; 376 int rv; 377 378 cn = makecn(pcn); 379 VLE(opc); 380 rv = RUMP_VOP_LOOKUP(opc, &vp, cn); 381 VUL(opc); 382 freecn(cn, RUMPCN_ISLOOKUP); 383 if (rv) { 384 if (rv == EJUSTRETURN) 385 rv = ENOENT; 386 return rv; 387 } 388 VUL(vp); 389 390 puffs_newinfo_setcookie(pni, vp); 391 rump_getvninfo(vp, &vtype, &vsize, &rdev); 392 puffs_newinfo_setvtype(pni, vtype); 393 puffs_newinfo_setsize(pni, vsize); 394 puffs_newinfo_setrdev(pni, rdev); 395 396 return 0; 397 } 398 399 /*ARGSUSED*/ 400 int 401 p2k_node_create(struct puffs_usermount *pu, puffs_cookie_t opc, 402 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 403 const struct vattr *vap) 404 { 405 struct componentname *cn; 406 struct vnode *vp; 407 int rv; 408 409 cn = makecn(pcn); 410 VLE(opc); 411 rump_vp_incref(opc); 412 rv = RUMP_VOP_CREATE(opc, &vp, cn, __UNCONST(vap)); 413 AUL(opc); 414 freecn(cn, 0); 415 if (rv == 0) { 416 VUL(vp); 417 puffs_newinfo_setcookie(pni, vp); 418 } 419 420 return rv; 421 } 422 423 /*ARGSUSED*/ 424 int 425 p2k_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc, 426 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 427 const struct vattr *vap) 428 { 429 struct componentname *cn; 430 struct vnode *vp; 431 int rv; 432 433 cn = makecn(pcn); 434 VLE(opc); 435 rump_vp_incref(opc); 436 rv = RUMP_VOP_MKNOD(opc, &vp, cn, __UNCONST(vap)); 437 AUL(opc); 438 freecn(cn, 0); 439 if (rv == 0) { 440 VUL(vp); 441 puffs_newinfo_setcookie(pni, vp); 442 } 443 444 return rv; 445 } 446 447 /*ARGSUSED*/ 448 int 449 p2k_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 450 const struct puffs_cred *pcr) 451 { 452 kauth_cred_t cred; 453 int rv; 454 455 cred = cred_create(pcr); 456 VLE(opc); 457 rv = RUMP_VOP_OPEN(opc, mode, cred); 458 VUL(opc); 459 cred_destroy(cred); 460 461 return rv; 462 } 463 464 /*ARGSUSED*/ 465 int 466 p2k_node_close(struct puffs_usermount *pu, puffs_cookie_t opc, int flags, 467 const struct puffs_cred *pcr) 468 { 469 kauth_cred_t cred; 470 471 cred = cred_create(pcr); 472 VLE(opc); 473 RUMP_VOP_CLOSE(opc, flags, cred); 474 VUL(opc); 475 cred_destroy(cred); 476 477 return 0; 478 } 479 480 /*ARGSUSED*/ 481 int 482 p2k_node_access(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 483 const struct puffs_cred *pcr) 484 { 485 kauth_cred_t cred; 486 int rv; 487 488 cred = cred_create(pcr); 489 VLE(opc); 490 rv = RUMP_VOP_ACCESS(opc, mode, cred); 491 VUL(opc); 492 cred_destroy(cred); 493 494 return rv; 495 } 496 497 /*ARGSUSED*/ 498 int 499 p2k_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 500 struct vattr *vap, const struct puffs_cred *pcr) 501 { 502 kauth_cred_t cred; 503 int rv; 504 505 cred = cred_create(pcr); 506 VLE(opc); 507 rv = RUMP_VOP_GETATTR(opc, vap, cred); 508 VUL(opc); 509 cred_destroy(cred); 510 511 return rv; 512 } 513 514 /*ARGSUSED*/ 515 int 516 p2k_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 517 const struct vattr *vap, const struct puffs_cred *pcr) 518 { 519 kauth_cred_t cred; 520 int rv; 521 522 cred = cred_create(pcr); 523 VLE(opc); 524 rv = RUMP_VOP_SETATTR(opc, __UNCONST(vap), cred); 525 VUL(opc); 526 cred_destroy(cred); 527 528 return rv; 529 } 530 531 /*ARGSUSED*/ 532 int 533 p2k_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc, 534 const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi) 535 { 536 kauth_cred_t cred; 537 int rv; 538 539 cred = cred_create(pcr); 540 VLE(opc); 541 rv = RUMP_VOP_FSYNC(opc, cred, flags, offlo, offhi); 542 VUL(opc); 543 cred_destroy(cred); 544 545 return rv; 546 } 547 548 /*ARGSUSED*/ 549 int 550 p2k_node_mmap(struct puffs_usermount *pu, puffs_cookie_t opc, vm_prot_t flags, 551 const struct puffs_cred *pcr) 552 { 553 kauth_cred_t cred; 554 int rv; 555 556 cred = cred_create(pcr); 557 rv = RUMP_VOP_MMAP(opc, flags, cred); 558 cred_destroy(cred); 559 560 return rv; 561 } 562 563 /*ARGSUSED*/ 564 int 565 p2k_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc, 566 off_t oldoff, off_t newoff, const struct puffs_cred *pcr) 567 { 568 kauth_cred_t cred; 569 int rv; 570 571 cred = cred_create(pcr); 572 VLE(opc); 573 rv = RUMP_VOP_SEEK(opc, oldoff, newoff, cred); 574 VUL(opc); 575 cred_destroy(cred); 576 577 return rv; 578 } 579 580 /*ARGSUSED*/ 581 int 582 p2k_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc, 583 puffs_cookie_t targ, const struct puffs_cn *pcn) 584 { 585 struct componentname *cn; 586 int rv; 587 588 cn = makecn(pcn); 589 VLE(opc); 590 rump_vp_incref(opc); 591 VLE(targ); 592 rump_vp_incref(targ); 593 rv = RUMP_VOP_REMOVE(opc, targ, cn); 594 AUL(opc); 595 AUL(targ); 596 freecn(cn, 0); 597 598 return rv; 599 } 600 601 /*ARGSUSED*/ 602 int 603 p2k_node_link(struct puffs_usermount *pu, puffs_cookie_t opc, 604 puffs_cookie_t targ, const struct puffs_cn *pcn) 605 { 606 struct componentname *cn; 607 int rv; 608 609 cn = makecn(pcn); 610 VLE(opc); 611 rump_vp_incref(opc); 612 rv = RUMP_VOP_LINK(opc, targ, cn); 613 freecn(cn, 0); 614 615 return rv; 616 } 617 618 /*ARGSUSED*/ 619 int 620 p2k_node_rename(struct puffs_usermount *pu, 621 puffs_cookie_t src_dir, puffs_cookie_t src, 622 const struct puffs_cn *pcn_src, 623 puffs_cookie_t targ_dir, puffs_cookie_t targ, 624 const struct puffs_cn *pcn_targ) 625 { 626 struct componentname *cn_src, *cn_targ; 627 int rv; 628 629 cn_src = makecn(pcn_src); 630 cn_targ = makecn(pcn_targ); 631 rump_vp_incref(src_dir); 632 rump_vp_incref(src); 633 VLE(targ_dir); 634 rump_vp_incref(targ_dir); 635 if (targ) { 636 VLE(targ); 637 rump_vp_incref(targ); 638 } 639 rv = RUMP_VOP_RENAME(src_dir, src, cn_src, targ_dir, targ, cn_targ); 640 AUL(targ_dir); 641 if (targ) 642 AUL(targ); 643 freecn(cn_src, 0); 644 freecn(cn_targ, 0); 645 646 return rv; 647 } 648 649 /*ARGSUSED*/ 650 int 651 p2k_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc, 652 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 653 const struct vattr *vap) 654 { 655 struct componentname *cn; 656 struct vnode *vp; 657 int rv; 658 659 cn = makecn(pcn); 660 VLE(opc); 661 rump_vp_incref(opc); 662 rv = RUMP_VOP_MKDIR(opc, &vp, cn, __UNCONST(vap)); 663 AUL(opc); 664 freecn(cn, 0); 665 if (rv == 0) { 666 VUL(vp); 667 puffs_newinfo_setcookie(pni, vp); 668 } 669 670 return rv; 671 } 672 673 /*ARGSUSED*/ 674 int 675 p2k_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc, 676 puffs_cookie_t targ, const struct puffs_cn *pcn) 677 { 678 struct componentname *cn; 679 int rv; 680 681 cn = makecn(pcn); 682 VLE(opc); 683 rump_vp_incref(opc); 684 VLE(targ); 685 rump_vp_incref(targ); 686 rv = RUMP_VOP_RMDIR(opc, targ, cn); 687 AUL(targ); 688 AUL(opc); 689 freecn(cn, 0); 690 691 return rv; 692 } 693 694 /*ARGSUSED*/ 695 int 696 p2k_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc, 697 struct puffs_newinfo *pni, const struct puffs_cn *pcn_src, 698 const struct vattr *vap, const char *link_target) 699 { 700 struct componentname *cn; 701 struct vnode *vp; 702 int rv; 703 704 cn = makecn(pcn_src); 705 VLE(opc); 706 rump_vp_incref(opc); 707 rv = RUMP_VOP_SYMLINK(opc, &vp, cn, 708 __UNCONST(vap), __UNCONST(link_target)); 709 AUL(opc); 710 freecn(cn, 0); 711 if (rv == 0) { 712 VUL(vp); 713 puffs_newinfo_setcookie(pni, vp); 714 } 715 716 return rv; 717 } 718 719 /*ARGSUSED*/ 720 int 721 p2k_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, 722 struct dirent *dent, off_t *readoff, size_t *reslen, 723 const struct puffs_cred *pcr, int *eofflag, 724 off_t *cookies, size_t *ncookies) 725 { 726 kauth_cred_t cred; 727 struct uio *uio; 728 off_t *vop_cookies; 729 int vop_ncookies; 730 int rv; 731 732 cred = cred_create(pcr); 733 uio = rump_uio_setup(dent, *reslen, *readoff, RUMPUIO_READ); 734 VLS(opc); 735 if (cookies) { 736 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, 737 &vop_cookies, &vop_ncookies); 738 memcpy(cookies, vop_cookies, vop_ncookies * sizeof(*cookies)); 739 *ncookies = vop_ncookies; 740 free(vop_cookies); 741 } else { 742 rv = RUMP_VOP_READDIR(opc, uio, cred, eofflag, NULL, NULL); 743 } 744 VUL(opc); 745 if (rv == 0) { 746 *reslen = rump_uio_getresid(uio); 747 *readoff = rump_uio_getoff(uio); 748 } 749 rump_uio_free(uio); 750 cred_destroy(cred); 751 752 return rv; 753 } 754 755 /*ARGSUSED*/ 756 int 757 p2k_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc, 758 const struct puffs_cred *pcr, char *linkname, size_t *linklen) 759 { 760 kauth_cred_t cred; 761 struct uio *uio; 762 int rv; 763 764 cred = cred_create(pcr); 765 uio = rump_uio_setup(linkname, *linklen, 0, RUMPUIO_READ); 766 VLE(opc); 767 rv = RUMP_VOP_READLINK(opc, uio, cred); 768 VUL(opc); 769 *linklen -= rump_uio_free(uio); 770 cred_destroy(cred); 771 772 return rv; 773 } 774 775 /*ARGSUSED*/ 776 int 777 p2k_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, 778 uint8_t *buf, off_t offset, size_t *resid, 779 const struct puffs_cred *pcr, int ioflag) 780 { 781 kauth_cred_t cred; 782 struct uio *uio; 783 int rv; 784 785 cred = cred_create(pcr); 786 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_READ); 787 VLS(opc); 788 rv = RUMP_VOP_READ(opc, uio, ioflag, cred); 789 VUL(opc); 790 *resid = rump_uio_free(uio); 791 cred_destroy(cred); 792 793 return rv; 794 } 795 796 /*ARGSUSED*/ 797 int 798 p2k_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, 799 uint8_t *buf, off_t offset, size_t *resid, 800 const struct puffs_cred *pcr, int ioflag) 801 { 802 kauth_cred_t cred; 803 struct uio *uio; 804 int rv; 805 806 cred = cred_create(pcr); 807 uio = rump_uio_setup(buf, *resid, offset, RUMPUIO_WRITE); 808 VLE(opc); 809 rv = RUMP_VOP_WRITE(opc, uio, ioflag, cred); 810 VUL(opc); 811 *resid = rump_uio_free(uio); 812 cred_destroy(cred); 813 814 return rv; 815 } 816 817 int 818 p2k_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 819 { 820 struct vnode *vp = opc; 821 bool recycle; 822 int rv; 823 824 rump_vp_interlock(vp); 825 (void) RUMP_VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES); 826 VLE(vp); 827 rv = RUMP_VOP_INACTIVE(vp, &recycle); 828 if (recycle) 829 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 830 831 return rv; 832 } 833 834 /*ARGSUSED*/ 835 int 836 p2k_node_reclaim(struct puffs_usermount *pu, puffs_croissant_t opc) 837 { 838 839 rump_vp_recycle_nokidding(opc); 840 return 0; 841 } 842