1 /* $NetBSD: p2k.c,v 1.54 2011/01/07 16:02:32 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2007, 2008, 2009 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Finnish Cultural Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * puffs 2k, i.e. puffs 2 kernel. Converts the puffs protocol to 33 * the kernel vfs protocol and vice versa. 34 * 35 * A word about reference counting: puffs in the kernel is the king of 36 * reference counting. We must maintain a vnode alive and kicking 37 * until the kernel tells us to reclaim it. Therefore we make sure 38 * we never accidentally lose a vnode. Before calling operations which 39 * decrease the refcount we always bump the refcount up to compensate. 40 * Come inactive, if the file system thinks that the vnode should be 41 * put out of its misery, it will set the recycle flag. We use this 42 * to tell the kernel to reclaim the vnode. Only in reclaim do we 43 * really nuke the last reference. 44 */ 45 46 #include <sys/cdefs.h> 47 #include <sys/mount.h> 48 #include <sys/param.h> 49 #include <sys/vnode.h> 50 #include <sys/lock.h> 51 #include <sys/namei.h> 52 #include <sys/dirent.h> 53 #include <sys/hash.h> 54 55 #include <assert.h> 56 #include <errno.h> 57 #include <puffs.h> 58 #include <stdlib.h> 59 #include <stdio.h> 60 61 #include <rump/rump.h> 62 #include <rump/p2k.h> 63 #include <rump/ukfs.h> 64 65 /* NetBSD-5 compat */ 66 #ifndef MOUNT_RUMPFS 67 #define MOUNT_RUMPFS "rumpfs" 68 #endif 69 70 PUFFSOP_PROTOS(p2k) 71 72 LIST_HEAD(p2k_vp_hash, p2k_node); 73 #define NHASHBUCK (1<<16) 74 struct p2k_mount { 75 struct vnode *p2m_rvp; 76 struct puffs_usermount *p2m_pu; 77 struct ukfs *p2m_ukfs; 78 struct p2k_vp_hash p2m_vphash[NHASHBUCK]; 79 struct mount *p2m_mp; 80 int p2m_nvnodes; 81 int p2m_imtmpfsman; 82 bool p2m_hasdebug; 83 }; 84 85 struct p2k_node { 86 struct vnode *p2n_vp; 87 88 LIST_ENTRY(p2k_node) p2n_entries; 89 }; 90 91 #define OPC2VP(opc) (((struct p2k_node *)opc)->p2n_vp) 92 93 static int haswizard; 94 static uid_t wizarduid; 95 96 static struct kauth_cred * 97 cred_create(const struct puffs_cred *pcr) 98 { 99 gid_t groups[NGROUPS]; 100 uid_t uid; 101 gid_t gid; 102 short ngroups = __arraycount(groups); 103 104 if (haswizard) { 105 uid = wizarduid; 106 } else { 107 if (puffs_cred_getuid(pcr, &uid) == -1) 108 uid = 0; 109 } 110 if (puffs_cred_getgid(pcr, &gid) == -1) 111 gid = 0; 112 puffs_cred_getgroups(pcr, groups, &ngroups); 113 114 /* LINTED: ngroups is ok */ 115 return rump_pub_cred_create(uid, gid, ngroups, groups); 116 } 117 118 static __inline void 119 cred_destroy(struct kauth_cred *cred) 120 { 121 122 rump_pub_cred_put(cred); 123 } 124 125 static struct componentname * 126 makecn(const struct puffs_cn *pcn) 127 { 128 struct kauth_cred *cred; 129 130 cred = cred_create(pcn->pcn_cred); 131 /* LINTED: prehistoric types in first two args */ 132 return rump_pub_makecn(pcn->pcn_nameiop, pcn->pcn_flags, 133 pcn->pcn_name, pcn->pcn_namelen, cred, rump_pub_lwproc_curlwp()); 134 } 135 136 static __inline void 137 freecn(struct componentname *cnp) 138 { 139 140 rump_pub_freecn(cnp, RUMPCN_FREECRED); 141 } 142 143 static void 144 makelwp(struct puffs_usermount *pu) 145 { 146 pid_t pid; 147 lwpid_t lid; 148 149 puffs_cc_getcaller(puffs_cc_getcc(pu), &pid, &lid); 150 rump_pub_allbetsareoff_setid(pid, lid); 151 } 152 153 static volatile sig_atomic_t dodump; 154 static void 155 dumpmp(struct puffs_usermount *pu) 156 { 157 struct statvfs svfsb; 158 159 if (dodump && p2k_fs_statvfs(pu, &svfsb) == 0) { 160 rump_pub_vfs_mount_print(svfsb.f_mntonname, dodump-1); 161 } 162 163 dodump = 0; 164 } 165 166 static void 167 sighand(int sig) 168 { 169 170 if (sig == SIGINFO) 171 dodump = 1; 172 else if (sig == SIGUSR1) 173 dodump = 2; 174 } 175 176 static __inline struct p2k_vp_hash * 177 gethash(struct p2k_mount *p2m, struct vnode *vp) 178 { 179 uint32_t hash; 180 181 hash = hash32_buf(&vp, sizeof(vp), HASH32_BUF_INIT); 182 return &p2m->p2m_vphash[hash % NHASHBUCK]; 183 } 184 185 /* 186 * Find node based on hash of vnode pointer. If vnode is found, 187 * releases one reference to vnode based on the fact that we just 188 * performed a lookup for it. 189 * 190 * If the optinal p2n_storage parameter is passed, it is used instead 191 * of allocating more memory. This allows for easier error recovery. 192 */ 193 static struct p2k_node * 194 getp2n(struct p2k_mount *p2m, struct vnode *vp, bool initial, 195 struct p2k_node *p2n_storage) 196 { 197 struct p2k_vp_hash *hl; 198 struct p2k_node *p2n = NULL; 199 200 /* p2n_storage => initial */ 201 assert(!p2n_storage || initial); 202 203 hl = gethash(p2m, vp); 204 if (!initial) 205 LIST_FOREACH(p2n, hl, p2n_entries) 206 if (p2n->p2n_vp == vp) 207 break; 208 209 hl = gethash(p2m, vp); 210 if (p2n) { 211 rump_pub_vp_rele(vp); 212 } else { 213 if (p2n_storage) 214 p2n = p2n_storage; 215 else 216 p2n = malloc(sizeof(*p2n)); 217 if (!p2n) { 218 rump_pub_vp_rele(vp); 219 return NULL; 220 } 221 memset(p2n, 0, sizeof(*p2n)); 222 LIST_INSERT_HEAD(hl, p2n, p2n_entries); 223 p2n->p2n_vp = vp; 224 } 225 return p2n; 226 } 227 228 static void 229 freep2n(struct p2k_node *p2n) 230 { 231 232 assert(p2n->p2n_vp == NULL); 233 LIST_REMOVE(p2n, p2n_entries); 234 free(p2n); 235 } 236 237 /*ARGSUSED*/ 238 static void 239 p2k_errcatcher(struct puffs_usermount *pu, uint8_t type, int error, 240 const char *str, puffs_cookie_t cook) 241 { 242 243 fprintf(stderr, "type %d, error %d, cookie %p (%s)\n", 244 type, error, cook, str); 245 246 /* 247 * Trap all EINVAL responses to lookup. It most likely means 248 * that we supplied VNON/VBAD as the type. The real kernel 249 * doesn't panic from this either, but just handles it. 250 */ 251 if (type != PUFFS_VN_LOOKUP && error == EINVAL) 252 abort(); 253 } 254 255 /* just to avoid annoying loop when singlestepping */ 256 static struct p2k_mount * 257 allocp2m(void) 258 { 259 struct p2k_mount *p2m; 260 int i; 261 262 p2m = malloc(sizeof(*p2m)); 263 if (p2m == NULL) 264 return NULL; 265 memset(p2m, 0, sizeof(*p2m)); 266 267 for (i = 0; i < NHASHBUCK; i++) 268 LIST_INIT(&p2m->p2m_vphash[i]); 269 270 return p2m; 271 } 272 273 struct p2k_mount * 274 p2k_init(uint32_t puffs_flags) 275 { 276 struct puffs_ops *pops; 277 struct p2k_mount *p2m; 278 char *envbuf; 279 bool dodaemon; 280 bool hasdebug; 281 282 PUFFSOP_INIT(pops); 283 284 PUFFSOP_SET(pops, p2k, fs, statvfs); 285 PUFFSOP_SET(pops, p2k, fs, unmount); 286 PUFFSOP_SET(pops, p2k, fs, sync); 287 PUFFSOP_SET(pops, p2k, fs, fhtonode); 288 PUFFSOP_SET(pops, p2k, fs, nodetofh); 289 PUFFSOP_SET(pops, p2k, fs, extattrctl); 290 291 PUFFSOP_SET(pops, p2k, node, lookup); 292 PUFFSOP_SET(pops, p2k, node, create); 293 PUFFSOP_SET(pops, p2k, node, mknod); 294 PUFFSOP_SET(pops, p2k, node, open); 295 PUFFSOP_SET(pops, p2k, node, close); 296 PUFFSOP_SET(pops, p2k, node, access); 297 PUFFSOP_SET(pops, p2k, node, getattr); 298 PUFFSOP_SET(pops, p2k, node, setattr); 299 #if 0 300 PUFFSOP_SET(pops, p2k, node, poll); 301 #endif 302 PUFFSOP_SET(pops, p2k, node, mmap); 303 PUFFSOP_SET(pops, p2k, node, fsync); 304 PUFFSOP_SET(pops, p2k, node, seek); 305 PUFFSOP_SET(pops, p2k, node, remove); 306 PUFFSOP_SET(pops, p2k, node, link); 307 PUFFSOP_SET(pops, p2k, node, rename); 308 PUFFSOP_SET(pops, p2k, node, mkdir); 309 PUFFSOP_SET(pops, p2k, node, rmdir); 310 PUFFSOP_SET(pops, p2k, node, symlink); 311 PUFFSOP_SET(pops, p2k, node, readdir); 312 PUFFSOP_SET(pops, p2k, node, readlink); 313 PUFFSOP_SET(pops, p2k, node, read); 314 PUFFSOP_SET(pops, p2k, node, write); 315 316 PUFFSOP_SET(pops, p2k, node, pathconf); 317 318 PUFFSOP_SET(pops, p2k, node, inactive); 319 PUFFSOP_SET(pops, p2k, node, reclaim); 320 321 PUFFSOP_SET(pops, p2k, node, getextattr); 322 PUFFSOP_SET(pops, p2k, node, setextattr); 323 PUFFSOP_SET(pops, p2k, node, listextattr); 324 PUFFSOP_SET(pops, p2k, node, deleteextattr); 325 326 dodaemon = true; 327 hasdebug = false; 328 329 if (getenv("P2K_DEBUG") != NULL) { 330 puffs_flags |= PUFFS_FLAG_OPDUMP; 331 dodaemon = false; 332 hasdebug = true; 333 } 334 if (getenv("P2K_NODETACH") != NULL) { 335 dodaemon = false; 336 } 337 if (getenv("P2K_NOCACHE_PAGE") != NULL) { 338 puffs_flags |= PUFFS_KFLAG_NOCACHE_PAGE; 339 } 340 if (getenv("P2K_NOCACHE_NAME") != NULL) { 341 puffs_flags |= PUFFS_KFLAG_NOCACHE_NAME; 342 } 343 if (getenv("P2K_NOCACHE") != NULL) { 344 puffs_flags |= PUFFS_KFLAG_NOCACHE; 345 } 346 if ((envbuf = getenv("P2K_WIZARDUID")) != NULL) { 347 char *ep; 348 349 wizarduid = strtoul(envbuf, &ep, 10); 350 if (envbuf[0] == '\0' || *ep != '\0') { 351 printf("P2K_WIZARDUID: invalid uid %s\n", envbuf); 352 } else if (wizarduid > UID_MAX) { 353 printf("P2K_WIZARDUID: uid %s out-of-range\n", envbuf); 354 } else { 355 haswizard = 1; 356 printf("P2K WIZARD MODE: using uid %d\n", wizarduid); 357 } 358 } 359 360 p2m = allocp2m(); 361 if (p2m == NULL) 362 return NULL; 363 p2m->p2m_pu = puffs_init(pops, PUFFS_DEFER, PUFFS_DEFER, 364 PUFFS_DEFER, puffs_flags); 365 if (p2m->p2m_pu == NULL) { 366 int sverrno = errno; 367 free(p2m); 368 errno = sverrno; 369 return NULL; 370 } 371 p2m->p2m_hasdebug = hasdebug; 372 373 if (dodaemon) { 374 if (puffs_daemon(p2m->p2m_pu, 1, 1) == -1) { 375 int sverrno = errno; 376 p2k_cancel(p2m, sverrno); 377 errno = sverrno; 378 p2m = NULL; 379 } 380 } 381 if (p2m) 382 rump_init(); 383 384 rump_pub_lwproc_rfork(RUMP_RFCFDG); 385 386 return p2m; 387 } 388 389 void 390 p2k_cancel(struct p2k_mount *p2m, int error) 391 { 392 393 puffs_cancel(p2m->p2m_pu, error); 394 free(p2m); 395 } 396 397 static int 398 setupfs(struct p2k_mount *p2m, const char *vfsname, const char *devpath, 399 struct ukfs_part *part, const char *mountpath, int mntflags, 400 void *arg, size_t alen) 401 { 402 char partpath[UKFS_DEVICE_MAXPATHLEN]; 403 char partbuf[UKFS_DEVICE_MAXSTR]; 404 char typebuf[PUFFS_TYPELEN]; 405 struct puffs_usermount *pu = p2m->p2m_pu; 406 struct p2k_node *p2n_root; 407 struct ukfs *ukfs = NULL; 408 extern int puffs_fakecc; 409 int rv = -1, sverrno; 410 411 strcpy(typebuf, "p2k|"); 412 if (strcmp(vfsname, "puffs") == 0) { /* XXX */ 413 struct puffs_kargs *args = arg; 414 strlcat(typebuf, args->pa_typename, sizeof(typebuf)); 415 } else { 416 strlcat(typebuf, vfsname, sizeof(typebuf)); 417 } 418 419 strlcpy(partpath, devpath, sizeof(partpath)); 420 if (ukfs_part_tostring(part, partbuf, sizeof(partbuf))) { 421 strlcat(partpath, partbuf, sizeof(partpath)); 422 } 423 puffs_setmntinfo(pu, partpath, typebuf); 424 425 if (ukfs_init() == -1) 426 goto out; 427 428 /* 429 * If we're mounting rumpfs, actually do no mount and redirect 430 * requests to rump fs namespace root. Strictly speaking, this 431 * is not correct, but I don't think anyone will notice. 432 * After all, we're mostly interested in things which reside 433 * specifically on the rootfs, namely the contents of /dev 434 */ 435 if (strcmp(vfsname, MOUNT_RUMPFS) == 0) { 436 if ((rv = rump_pub_vfs_getmp("/", &p2m->p2m_mp)) != 0) { 437 errno = rv; 438 rv = -1; 439 goto out; 440 } 441 } else { 442 if (part != ukfs_part_na) 443 ukfs = ukfs_mount_disk(vfsname, devpath, part, 444 mountpath, mntflags, arg, alen); 445 else 446 ukfs = ukfs_mount(vfsname, devpath, mountpath, mntflags, 447 arg, alen); 448 if (ukfs == NULL) 449 goto out; 450 ukfs_setspecific(ukfs, p2m); 451 p2m->p2m_ukfs = ukfs; 452 p2m->p2m_mp = ukfs_getmp(ukfs); 453 } 454 if ((rv = rump_pub_vfs_root(p2m->p2m_mp, &p2m->p2m_rvp, 0)) != 0) { 455 errno = rv; 456 rv = -1; 457 goto out; 458 } 459 460 p2m->p2m_pu = pu; 461 462 /* 463 * Detect tmpfs. XXX: this is a kludge. See inactive(). 464 * 465 * In reality we'd want "does file system use anon objects 466 * for storage?". But since tmpfs hides the anon object from 467 * the public interface, we can't actually detect it sanely. 468 * Therefore, use this kludge. 469 */ 470 p2m->p2m_imtmpfsman = strcmp(vfsname, MOUNT_TMPFS) == 0; 471 472 p2n_root = getp2n(p2m, p2m->p2m_rvp, true, NULL); 473 puffs_setfhsize(pu, 0, PUFFS_FHFLAG_PASSTHROUGH); 474 puffs_setstacksize(pu, PUFFS_STACKSIZE_MIN); 475 puffs_fakecc = 1; 476 puffs_set_prepost(pu, makelwp, NULL); 477 478 if (p2m->p2m_hasdebug) { 479 struct timespec ts; 480 481 signal(SIGINFO, sighand); 482 signal(SIGUSR1, sighand); 483 484 ts.tv_sec = 0; 485 ts.tv_nsec = 1000*1000*10; /* 10ms */ 486 puffs_ml_setloopfn(pu, dumpmp); 487 puffs_ml_settimeout(pu, &ts); 488 } 489 puffs_set_errnotify(pu, p2k_errcatcher); 490 491 puffs_setspecific(pu, p2m); 492 rv = puffs_mount(pu, mountpath, mntflags, p2n_root); 493 494 out: 495 if (rv == -1) { 496 sverrno = errno; 497 puffs_cancel(pu, sverrno); 498 if (ukfs) 499 ukfs_release(p2m->p2m_ukfs, UKFS_RELFLAG_FORCE); 500 free(p2m); 501 errno = sverrno; 502 } 503 504 return rv; 505 } 506 507 int 508 p2k_mainloop(struct p2k_mount *p2m) 509 { 510 int rv, sverrno; 511 512 rv = puffs_mainloop(p2m->p2m_pu); 513 sverrno = errno; 514 puffs_exit(p2m->p2m_pu, 1); 515 if (p2m->p2m_ukfs) 516 ukfs_release(p2m->p2m_ukfs, UKFS_RELFLAG_FORCE); 517 free(p2m); 518 519 if (rv == -1) 520 errno = sverrno; 521 return rv; 522 } 523 524 int 525 p2k_run_fs(const char *vfsname, const char *devpath, const char *mountpath, 526 int mntflags, void *arg, size_t alen, uint32_t puffs_flags) 527 { 528 struct p2k_mount *p2m; 529 int rv; 530 531 p2m = p2k_init(puffs_flags); 532 if (p2m == NULL) 533 return -1; 534 rv = setupfs(p2m, vfsname, devpath, ukfs_part_na, mountpath, 535 mntflags, arg, alen); 536 if (rv == -1) 537 return rv; 538 return p2k_mainloop(p2m); 539 } 540 541 int 542 p2k_run_diskfs(const char *vfsname, const char *devpath, struct ukfs_part *part, 543 const char *mountpath, int mntflags, void *arg, size_t alen, 544 uint32_t puffs_flags) 545 { 546 struct p2k_mount *p2m; 547 int rv; 548 549 p2m = p2k_init(puffs_flags); 550 if (p2m == NULL) 551 return -1; 552 rv = setupfs(p2m, vfsname, devpath, part, mountpath, mntflags, 553 arg, alen); 554 if (rv == -1) 555 return rv; 556 return p2k_mainloop(p2m); 557 } 558 559 int 560 p2k_setup_fs(struct p2k_mount *p2m, const char *vfsname, const char *devpath, 561 const char *mountpath, int mntflags, void *arg, size_t alen) 562 { 563 564 return setupfs(p2m, vfsname, devpath, ukfs_part_na, mountpath, 565 mntflags, arg, alen); 566 } 567 568 int 569 p2k_setup_diskfs(struct p2k_mount *p2m, const char *vfsname, 570 const char *devpath, struct ukfs_part *part, const char *mountpath, 571 int mntflags, void *arg, size_t alen) 572 { 573 574 return setupfs(p2m, vfsname, devpath, part, mountpath, mntflags, 575 arg, alen); 576 } 577 578 int 579 p2k_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp) 580 { 581 struct p2k_mount *p2m = puffs_getspecific(pu); 582 struct mount *mp = p2m->p2m_mp; 583 584 return rump_pub_vfs_statvfs(mp, sbp); 585 } 586 587 /*ARGSUSED*/ 588 int 589 p2k_fs_unmount(struct puffs_usermount *pu, int flags) 590 { 591 struct p2k_mount *p2m = puffs_getspecific(pu); 592 struct ukfs *fs = p2m->p2m_ukfs; 593 int error = 0; 594 595 rump_pub_vp_rele(p2m->p2m_rvp); 596 597 if (fs) { 598 if (ukfs_release(fs, 0) != 0) { 599 struct statvfs svfsb; 600 601 if (p2m->p2m_hasdebug 602 && p2k_fs_statvfs(pu, &svfsb) == 0) { 603 printf("\nSOFT UNMOUNT FAILED, MP INFO DUMP\n"); 604 rump_pub_vfs_mount_print(svfsb.f_mntonname, 1); 605 } 606 ukfs_release(fs, UKFS_RELFLAG_FORCE); 607 error = 0; 608 } 609 } 610 p2m->p2m_ukfs = NULL; 611 612 if (p2m->p2m_hasdebug) { 613 printf("-- rump kernel event counters --\n"); 614 rump_printevcnts(); 615 printf("-- end of event counters --\n"); 616 } 617 618 return error; 619 } 620 621 int 622 p2k_fs_sync(struct puffs_usermount *pu, int waitfor, 623 const struct puffs_cred *pcr) 624 { 625 struct p2k_mount *p2m = puffs_getspecific(pu); 626 struct mount *mp = p2m->p2m_mp; 627 struct kauth_cred *cred; 628 int rv; 629 630 cred = cred_create(pcr); 631 rv = rump_pub_vfs_sync(mp, waitfor, cred); 632 cred_destroy(cred); 633 634 return rv; 635 } 636 637 /*ARGSUSED*/ 638 int 639 p2k_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, 640 struct puffs_newinfo *pni) 641 { 642 struct p2k_mount *p2m = puffs_getspecific(pu); 643 struct mount *mp = p2m->p2m_mp; 644 struct p2k_node *p2n; 645 struct vnode *vp; 646 enum vtype vtype; 647 voff_t vsize; 648 uint64_t rdev; /* XXX: allows running this on NetBSD 5.0 */ 649 int rv; 650 651 rv = rump_pub_vfs_fhtovp(mp, fid, &vp); 652 if (rv) 653 return rv; 654 RUMP_VOP_UNLOCK(vp); 655 656 p2n = getp2n(p2m, vp, false, NULL); 657 if (p2n == NULL) 658 return ENOMEM; 659 660 puffs_newinfo_setcookie(pni, p2n); 661 rump_pub_getvninfo(vp, &vtype, &vsize, (void *)&rdev); 662 puffs_newinfo_setvtype(pni, vtype); 663 puffs_newinfo_setsize(pni, vsize); 664 /* LINTED: yea, it'll lose accuracy, but that's life */ 665 puffs_newinfo_setrdev(pni, rdev); 666 667 return 0; 668 } 669 670 /*ARGSUSED*/ 671 int 672 p2k_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie, void *fid, 673 size_t *fidsize) 674 { 675 struct vnode *vp = OPC2VP(cookie); 676 677 return rump_pub_vfs_vptofh(vp, fid, fidsize); 678 } 679 680 int 681 p2k_fs_extattrctl(struct puffs_usermount *pu, int cmd, 682 puffs_cookie_t cookie, int flags, 683 int attrnamespace, const char *attrname) 684 { 685 struct p2k_mount *p2m = puffs_getspecific(pu); 686 struct mount *mp = p2m->p2m_mp; 687 struct vnode *vp; 688 689 if (flags & PUFFS_EXTATTRCTL_HASNODE) { 690 vp = OPC2VP(cookie); 691 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY); 692 } else { 693 vp = NULL; 694 } 695 696 /* vfsop unlocks (but doesn't release) vnode, so we're done here */ 697 return rump_pub_vfs_extattrctl(mp, cmd, vp, attrnamespace, attrname); 698 } 699 700 /*ARGSUSED*/ 701 int 702 p2k_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, 703 struct puffs_newinfo *pni, const struct puffs_cn *pcn) 704 { 705 struct p2k_mount *p2m = puffs_getspecific(pu); 706 struct p2k_node *p2n_dir = opc, *p2n; 707 struct componentname *cn; 708 struct vnode *dvp = p2n_dir->p2n_vp, *vp; 709 enum vtype vtype; 710 voff_t vsize; 711 uint64_t rdev; /* XXX: uint64_t because of stack overwrite in compat */ 712 int rv; 713 714 cn = makecn(pcn); 715 RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE); 716 rv = RUMP_VOP_LOOKUP(dvp, &vp, cn); 717 RUMP_VOP_UNLOCK(dvp); 718 freecn(cn); 719 720 if (rv) { 721 if (rv == EJUSTRETURN) { 722 rv = ENOENT; 723 } 724 return rv; 725 } 726 RUMP_VOP_UNLOCK(vp); 727 728 p2n = getp2n(p2m, vp, false, NULL); 729 if (p2n == NULL) { 730 return ENOMEM; 731 } 732 733 puffs_newinfo_setcookie(pni, p2n); 734 rump_pub_getvninfo(vp, &vtype, &vsize, (void *)&rdev); 735 puffs_newinfo_setvtype(pni, vtype); 736 puffs_newinfo_setsize(pni, vsize); 737 /* LINTED: yea, it'll lose accuracy, but that's life */ 738 puffs_newinfo_setrdev(pni, rdev); 739 740 return 0; 741 } 742 743 #define VERS_TIMECHANGE 599000700 744 static int 745 needcompat(void) 746 { 747 748 /*LINTED*/ 749 return __NetBSD_Version__ < VERS_TIMECHANGE 750 && rump_pub_getversion() >= VERS_TIMECHANGE; 751 } 752 753 #define DOCOMPAT(va, va_compat) \ 754 do { \ 755 if (needcompat()) { \ 756 va_compat = rump_pub_vattr_init(); \ 757 rump_pub_vattr50_to_vattr(va, va_compat); \ 758 } else { \ 759 va_compat = __UNCONST(va); \ 760 } \ 761 } while (/*CONSTCOND*/0) 762 763 #define UNDOCOMPAT(va_compat) \ 764 do { \ 765 if (needcompat()) \ 766 rump_pub_vattr_free(va_compat); \ 767 } while (/*CONSTCOND*/0) 768 769 static int 770 do_makenode(struct puffs_usermount *pu, struct p2k_node *p2n_dir, 771 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 772 const struct vattr *vap, char *link_target, 773 int (*makefn)(struct vnode *, struct vnode **, struct componentname *, 774 struct vattr *), 775 int (*symfn)(struct vnode *, struct vnode **, struct componentname *, 776 struct vattr *, char *)) 777 { 778 struct p2k_mount *p2m = puffs_getspecific(pu); 779 struct vnode *dvp = p2n_dir->p2n_vp; 780 struct p2k_node *p2n; 781 struct componentname *cn; 782 struct vattr *va_x; 783 struct vnode *vp; 784 int rv; 785 786 p2n = malloc(sizeof(*p2n)); 787 if (p2n == NULL) 788 return ENOMEM; 789 DOCOMPAT(vap, va_x); 790 791 cn = makecn(pcn); 792 RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE); 793 rump_pub_vp_incref(dvp); 794 if (makefn) { 795 rv = makefn(dvp, &vp, cn, va_x); 796 } else { 797 rv = symfn(dvp, &vp, cn, va_x, link_target); 798 } 799 assert(RUMP_VOP_ISLOCKED(dvp) == 0); 800 freecn(cn); 801 802 if (rv == 0) { 803 RUMP_VOP_UNLOCK(vp); 804 p2n = getp2n(p2m, vp, true, p2n); 805 puffs_newinfo_setcookie(pni, p2n); 806 } else { 807 free(p2n); 808 } 809 810 UNDOCOMPAT(va_x); 811 812 return rv; 813 814 } 815 816 /*ARGSUSED*/ 817 int 818 p2k_node_create(struct puffs_usermount *pu, puffs_cookie_t opc, 819 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 820 const struct vattr *vap) 821 { 822 823 return do_makenode(pu, opc, pni, pcn, vap, NULL, RUMP_VOP_CREATE, NULL); 824 } 825 826 /*ARGSUSED*/ 827 int 828 p2k_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc, 829 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 830 const struct vattr *vap) 831 { 832 833 return do_makenode(pu, opc, pni, pcn, vap, NULL, RUMP_VOP_MKNOD, NULL); 834 } 835 836 /*ARGSUSED*/ 837 int 838 p2k_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 839 const struct puffs_cred *pcr) 840 { 841 struct vnode *vp = OPC2VP(opc); 842 struct kauth_cred *cred; 843 int rv; 844 845 cred = cred_create(pcr); 846 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 847 rv = RUMP_VOP_OPEN(vp, mode, cred); 848 RUMP_VOP_UNLOCK(vp); 849 cred_destroy(cred); 850 851 return rv; 852 } 853 854 /*ARGSUSED*/ 855 int 856 p2k_node_close(struct puffs_usermount *pu, puffs_cookie_t opc, int flags, 857 const struct puffs_cred *pcr) 858 { 859 struct vnode *vp = OPC2VP(opc); 860 struct kauth_cred *cred; 861 862 cred = cred_create(pcr); 863 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 864 RUMP_VOP_CLOSE(vp, flags, cred); 865 RUMP_VOP_UNLOCK(vp); 866 cred_destroy(cred); 867 868 return 0; 869 } 870 871 /*ARGSUSED*/ 872 int 873 p2k_node_access(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 874 const struct puffs_cred *pcr) 875 { 876 struct vnode *vp = OPC2VP(opc); 877 struct kauth_cred *cred; 878 int rv; 879 880 cred = cred_create(pcr); 881 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 882 rv = RUMP_VOP_ACCESS(vp, mode, cred); 883 RUMP_VOP_UNLOCK(vp); 884 cred_destroy(cred); 885 886 return rv; 887 } 888 889 /*ARGSUSED*/ 890 int 891 p2k_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 892 struct vattr *vap, const struct puffs_cred *pcr) 893 { 894 struct vnode *vp = OPC2VP(opc); 895 struct kauth_cred *cred; 896 struct vattr *va_x; 897 int rv; 898 899 /* "deadfs" */ 900 if (!vp) 901 return 0; 902 903 if (needcompat()) { 904 va_x = rump_pub_vattr_init(); 905 } else { 906 va_x = vap; 907 } 908 909 cred = cred_create(pcr); 910 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 911 rv = RUMP_VOP_GETATTR(vp, va_x, cred); 912 RUMP_VOP_UNLOCK(vp); 913 cred_destroy(cred); 914 915 if (needcompat()) { 916 rump_pub_vattr_to_vattr50(va_x, vap); 917 rump_pub_vattr_free(va_x); 918 } 919 920 return rv; 921 } 922 923 /*ARGSUSED*/ 924 int 925 p2k_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 926 const struct vattr *vap, const struct puffs_cred *pcr) 927 { 928 struct vnode *vp = OPC2VP(opc); 929 struct kauth_cred *cred; 930 struct vattr *va_x; 931 int rv; 932 933 /* "deadfs" */ 934 if (!vp) 935 return 0; 936 937 DOCOMPAT(vap, va_x); 938 939 cred = cred_create(pcr); 940 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 941 rv = RUMP_VOP_SETATTR(vp, va_x, cred); 942 RUMP_VOP_UNLOCK(vp); 943 cred_destroy(cred); 944 945 UNDOCOMPAT(va_x); 946 947 return rv; 948 } 949 950 /*ARGSUSED*/ 951 int 952 p2k_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc, 953 const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi) 954 { 955 struct vnode *vp = OPC2VP(opc); 956 struct kauth_cred *cred; 957 int rv; 958 959 /* "deadfs" */ 960 if (!vp) 961 return 0; 962 963 cred = cred_create(pcr); 964 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 965 rv = RUMP_VOP_FSYNC(vp, cred, flags, offlo, offhi); 966 RUMP_VOP_UNLOCK(vp); 967 cred_destroy(cred); 968 969 return rv; 970 } 971 972 /*ARGSUSED*/ 973 int 974 p2k_node_mmap(struct puffs_usermount *pu, puffs_cookie_t opc, vm_prot_t flags, 975 const struct puffs_cred *pcr) 976 { 977 struct kauth_cred *cred; 978 int rv; 979 980 cred = cred_create(pcr); 981 rv = RUMP_VOP_MMAP(OPC2VP(opc), flags, cred); 982 cred_destroy(cred); 983 984 return rv; 985 } 986 987 /*ARGSUSED*/ 988 int 989 p2k_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc, 990 off_t oldoff, off_t newoff, const struct puffs_cred *pcr) 991 { 992 struct vnode *vp = OPC2VP(opc); 993 struct kauth_cred *cred; 994 int rv; 995 996 cred = cred_create(pcr); 997 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 998 rv = RUMP_VOP_SEEK(vp, oldoff, newoff, cred); 999 RUMP_VOP_UNLOCK(vp); 1000 cred_destroy(cred); 1001 1002 return rv; 1003 } 1004 1005 static int 1006 do_nukenode(struct p2k_node *p2n_dir, struct p2k_node *p2n, 1007 const struct puffs_cn *pcn, 1008 int (*nukefn)(struct vnode *, struct vnode *, struct componentname *)) 1009 { 1010 struct vnode *dvp = p2n_dir->p2n_vp, *vp = p2n->p2n_vp; 1011 struct componentname *cn; 1012 int rv; 1013 1014 cn = makecn(pcn); 1015 RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE); 1016 rump_pub_vp_incref(dvp); 1017 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 1018 rump_pub_vp_incref(vp); 1019 rv = nukefn(dvp, vp, cn); 1020 assert(RUMP_VOP_ISLOCKED(dvp) == 0); 1021 assert(RUMP_VOP_ISLOCKED(vp) == 0); 1022 freecn(cn); 1023 1024 return rv; 1025 1026 } 1027 1028 /*ARGSUSED*/ 1029 int 1030 p2k_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc, 1031 puffs_cookie_t targ, const struct puffs_cn *pcn) 1032 { 1033 1034 return do_nukenode(opc, targ, pcn, RUMP_VOP_REMOVE); 1035 } 1036 1037 /*ARGSUSED*/ 1038 int 1039 p2k_node_link(struct puffs_usermount *pu, puffs_cookie_t opc, 1040 puffs_cookie_t targ, const struct puffs_cn *pcn) 1041 { 1042 struct vnode *dvp = OPC2VP(opc); 1043 struct componentname *cn; 1044 int rv; 1045 1046 cn = makecn(pcn); 1047 RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE); 1048 rump_pub_vp_incref(dvp); 1049 rv = RUMP_VOP_LINK(dvp, OPC2VP(targ), cn); 1050 freecn(cn); 1051 1052 return rv; 1053 } 1054 1055 /*ARGSUSED*/ 1056 int 1057 p2k_node_rename(struct puffs_usermount *pu, 1058 puffs_cookie_t src_dir, puffs_cookie_t src, 1059 const struct puffs_cn *pcn_src, 1060 puffs_cookie_t targ_dir, puffs_cookie_t targ, 1061 const struct puffs_cn *pcn_targ) 1062 { 1063 struct vnode *dvp, *vp, *tdvp, *tvp = NULL; 1064 struct componentname *cn_src, *cn_targ; 1065 int rv; 1066 1067 cn_src = makecn(pcn_src); 1068 cn_targ = makecn(pcn_targ); 1069 1070 dvp = OPC2VP(src_dir); 1071 vp = OPC2VP(src); 1072 tdvp = OPC2VP(targ_dir); 1073 if (targ) { 1074 tvp = OPC2VP(targ); 1075 } 1076 1077 rump_pub_vp_incref(dvp); 1078 rump_pub_vp_incref(vp); 1079 RUMP_VOP_LOCK(tdvp, LK_EXCLUSIVE); 1080 rump_pub_vp_incref(tdvp); 1081 if (tvp) { 1082 RUMP_VOP_LOCK(tvp, LK_EXCLUSIVE); 1083 rump_pub_vp_incref(tvp); 1084 } 1085 rv = RUMP_VOP_RENAME(dvp, vp, cn_src, tdvp, tvp, cn_targ); 1086 assert(RUMP_VOP_ISLOCKED(tdvp) == 0); 1087 if (tvp) { 1088 assert(RUMP_VOP_ISLOCKED(tvp) == 0); 1089 } 1090 freecn(cn_src); 1091 freecn(cn_targ); 1092 1093 return rv; 1094 } 1095 1096 /*ARGSUSED*/ 1097 int 1098 p2k_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc, 1099 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 1100 const struct vattr *vap) 1101 { 1102 1103 return do_makenode(pu, opc, pni, pcn, vap, NULL, RUMP_VOP_MKDIR, NULL); 1104 } 1105 1106 /*ARGSUSED*/ 1107 int 1108 p2k_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc, 1109 puffs_cookie_t targ, const struct puffs_cn *pcn) 1110 { 1111 1112 return do_nukenode(opc, targ, pcn, RUMP_VOP_RMDIR); 1113 } 1114 1115 /*ARGSUSED*/ 1116 int 1117 p2k_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc, 1118 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 1119 const struct vattr *vap, const char *link_target) 1120 { 1121 1122 return do_makenode(pu, opc, pni, pcn, vap, 1123 __UNCONST(link_target), NULL, RUMP_VOP_SYMLINK); 1124 } 1125 1126 /*ARGSUSED*/ 1127 int 1128 p2k_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, 1129 struct dirent *dent, off_t *readoff, size_t *reslen, 1130 const struct puffs_cred *pcr, int *eofflag, 1131 off_t *cookies, size_t *ncookies) 1132 { 1133 struct vnode *vp = OPC2VP(opc); 1134 struct kauth_cred *cred; 1135 struct uio *uio; 1136 off_t *vop_cookies; 1137 int vop_ncookies; 1138 int rv; 1139 1140 cred = cred_create(pcr); 1141 uio = rump_pub_uio_setup(dent, *reslen, *readoff, RUMPUIO_READ); 1142 RUMP_VOP_LOCK(vp, LK_SHARED); 1143 if (cookies) { 1144 rv = RUMP_VOP_READDIR(vp, uio, cred, eofflag, 1145 &vop_cookies, &vop_ncookies); 1146 memcpy(cookies, vop_cookies, vop_ncookies * sizeof(*cookies)); 1147 *ncookies = vop_ncookies; 1148 free(vop_cookies); 1149 } else { 1150 rv = RUMP_VOP_READDIR(vp, uio, cred, eofflag, NULL, NULL); 1151 } 1152 RUMP_VOP_UNLOCK(vp); 1153 if (rv == 0) { 1154 *reslen = rump_pub_uio_getresid(uio); 1155 *readoff = rump_pub_uio_getoff(uio); 1156 } 1157 rump_pub_uio_free(uio); 1158 cred_destroy(cred); 1159 1160 return rv; 1161 } 1162 1163 /*ARGSUSED*/ 1164 int 1165 p2k_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc, 1166 const struct puffs_cred *pcr, char *linkname, size_t *linklen) 1167 { 1168 struct vnode *vp = OPC2VP(opc); 1169 struct kauth_cred *cred; 1170 struct uio *uio; 1171 int rv; 1172 1173 cred = cred_create(pcr); 1174 uio = rump_pub_uio_setup(linkname, *linklen, 0, RUMPUIO_READ); 1175 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 1176 rv = RUMP_VOP_READLINK(vp, uio, cred); 1177 RUMP_VOP_UNLOCK(vp); 1178 *linklen -= rump_pub_uio_free(uio); 1179 cred_destroy(cred); 1180 1181 return rv; 1182 } 1183 1184 /*ARGSUSED*/ 1185 int 1186 p2k_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, 1187 uint8_t *buf, off_t offset, size_t *resid, 1188 const struct puffs_cred *pcr, int ioflag) 1189 { 1190 struct vnode *vp = OPC2VP(opc); 1191 struct kauth_cred *cred; 1192 struct uio *uio; 1193 int rv; 1194 1195 cred = cred_create(pcr); 1196 uio = rump_pub_uio_setup(buf, *resid, offset, RUMPUIO_READ); 1197 RUMP_VOP_LOCK(vp, LK_SHARED); 1198 rv = RUMP_VOP_READ(vp, uio, ioflag, cred); 1199 RUMP_VOP_UNLOCK(vp); 1200 *resid = rump_pub_uio_free(uio); 1201 cred_destroy(cred); 1202 1203 return rv; 1204 } 1205 1206 /*ARGSUSED*/ 1207 int 1208 p2k_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, 1209 uint8_t *buf, off_t offset, size_t *resid, 1210 const struct puffs_cred *pcr, int ioflag) 1211 { 1212 struct vnode *vp = OPC2VP(opc); 1213 struct kauth_cred *cred; 1214 struct uio *uio; 1215 int rv; 1216 1217 /* "deadfs" */ 1218 if (!vp) 1219 return 0; 1220 1221 cred = cred_create(pcr); 1222 uio = rump_pub_uio_setup(buf, *resid, offset, RUMPUIO_WRITE); 1223 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 1224 rv = RUMP_VOP_WRITE(vp, uio, ioflag, cred); 1225 RUMP_VOP_UNLOCK(vp); 1226 *resid = rump_pub_uio_free(uio); 1227 cred_destroy(cred); 1228 1229 return rv; 1230 } 1231 1232 /*ARGSUSED*/ 1233 int 1234 p2k_node_pathconf(struct puffs_usermount *pu, puffs_cookie_t opc, 1235 int name, register_t *retval) 1236 { 1237 struct vnode *vp = OPC2VP(opc); 1238 int rv; 1239 1240 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 1241 rv = RUMP_VOP_PATHCONF(vp, name, retval); 1242 RUMP_VOP_UNLOCK(vp); 1243 1244 return rv; 1245 } 1246 1247 /*ARGSUSED*/ 1248 int 1249 p2k_node_getextattr(struct puffs_usermount *pu, puffs_cookie_t opc, 1250 int attrnamespace, const char *attrname, size_t *attrsize, 1251 uint8_t *attr, size_t *resid, const struct puffs_cred *pcr) 1252 { 1253 struct vnode *vp = OPC2VP(opc); 1254 struct kauth_cred *cred; 1255 struct uio *uio; 1256 int rv; 1257 1258 if (attr) 1259 uio = rump_pub_uio_setup(attr, *resid, 0, RUMPUIO_READ); 1260 else 1261 uio = NULL; 1262 1263 cred = cred_create(pcr); 1264 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 1265 rv = RUMP_VOP_GETEXTATTR(vp, attrnamespace, attrname, uio, 1266 attrsize, cred); 1267 RUMP_VOP_UNLOCK(vp); 1268 cred_destroy(cred); 1269 1270 if (uio) 1271 *resid = rump_pub_uio_free(uio); 1272 1273 return rv; 1274 } 1275 1276 /*ARGSUSED*/ 1277 int 1278 p2k_node_setextattr(struct puffs_usermount *pu, puffs_cookie_t opc, 1279 int attrnamespace, const char *attrname, 1280 uint8_t *attr, size_t *resid, const struct puffs_cred *pcr) 1281 { 1282 struct vnode *vp = OPC2VP(opc); 1283 struct kauth_cred *cred; 1284 struct uio *uio; 1285 int rv; 1286 1287 if (attr) 1288 uio = rump_pub_uio_setup(attr, *resid, 0, RUMPUIO_READ); 1289 else 1290 uio = NULL; 1291 1292 cred = cred_create(pcr); 1293 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 1294 rv = RUMP_VOP_SETEXTATTR(vp, attrnamespace, attrname, uio, cred); 1295 RUMP_VOP_UNLOCK(vp); 1296 cred_destroy(cred); 1297 1298 if (uio) 1299 *resid = rump_pub_uio_free(uio); 1300 1301 return rv; 1302 } 1303 1304 /*ARGSUSED*/ 1305 int 1306 p2k_node_listextattr(struct puffs_usermount *pu, puffs_cookie_t opc, 1307 int attrnamespace, size_t *attrsize, 1308 uint8_t *attrs, size_t *resid, const struct puffs_cred *pcr) 1309 { 1310 struct vnode *vp = OPC2VP(opc); 1311 struct kauth_cred *cred; 1312 struct uio *uio; 1313 int rv; 1314 1315 if (attrs) 1316 uio = rump_pub_uio_setup(attrs, *resid, 0, RUMPUIO_READ); 1317 else 1318 uio = NULL; 1319 1320 cred = cred_create(pcr); 1321 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 1322 rv = RUMP_VOP_LISTEXTATTR(vp, attrnamespace, uio, attrsize, cred); 1323 RUMP_VOP_UNLOCK(vp); 1324 cred_destroy(cred); 1325 1326 if (uio) 1327 *resid = rump_pub_uio_free(uio); 1328 1329 return rv; 1330 } 1331 1332 /*ARGSUSED*/ 1333 int 1334 p2k_node_deleteextattr(struct puffs_usermount *pu, puffs_cookie_t opc, 1335 int attrnamespace, const char *attrname, const struct puffs_cred *pcr) 1336 { 1337 struct vnode *vp = OPC2VP(opc); 1338 struct kauth_cred *cred; 1339 int rv; 1340 1341 cred = cred_create(pcr); 1342 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 1343 rv = RUMP_VOP_DELETEEXTATTR(vp, attrnamespace, attrname, cred); 1344 RUMP_VOP_UNLOCK(vp); 1345 cred_destroy(cred); 1346 1347 return rv; 1348 } 1349 1350 /* the kernel releases its last reference here */ 1351 int 1352 p2k_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 1353 { 1354 struct p2k_mount *p2m = puffs_getspecific(pu); 1355 struct p2k_node *p2n = opc; 1356 struct vnode *vp = OPC2VP(opc); 1357 bool recycle = false; 1358 int rv; 1359 1360 /* deadfs */ 1361 if (!vp) 1362 return 0; 1363 1364 /* 1365 * Flush all cached vnode pages from the rump kernel -- they 1366 * are kept in puffs for all things that matter. However, 1367 * don't do this for tmpfs (vnodes are backed by an aobj), since that 1368 * would cause us to clear the backing storage leaving us without 1369 * a way to regain the data from "stable storage". 1370 */ 1371 if (!p2m->p2m_imtmpfsman) { 1372 rump_pub_vp_interlock(vp); 1373 RUMP_VOP_PUTPAGES(vp, 0, 0, 1374 PGO_ALLPAGES|PGO_CLEANIT|PGO_FREE); 1375 } 1376 1377 /* 1378 * Ok, this is where we get nasty. We pretend the vnode is 1379 * inactive and already tell the file system that. However, 1380 * we are allowed to pretend it also grows a reference immediately 1381 * after per vget(), so this does not do harm. Cheap trick, but ... 1382 * 1383 * If the file system thinks the inode is done for, we release 1384 * our reference and clear all knowledge of the vnode. If, 1385 * however, the inode is still active, we retain our reference 1386 * until reclaim, since puffs might be flushing out some data 1387 * later. 1388 */ 1389 RUMP_VOP_LOCK(vp, LK_EXCLUSIVE); 1390 rv = RUMP_VOP_INACTIVE(vp, &recycle); 1391 if (recycle) { 1392 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 1393 rump_pub_vp_rele(p2n->p2n_vp); 1394 p2n->p2n_vp = NULL; 1395 } 1396 1397 return rv; 1398 } 1399 1400 /*ARGSUSED*/ 1401 int 1402 p2k_node_reclaim(struct puffs_usermount *pu, puffs_croissant_t opc) 1403 { 1404 struct p2k_node *p2n = opc; 1405 1406 if (p2n->p2n_vp) { 1407 rump_pub_vp_rele(p2n->p2n_vp); 1408 p2n->p2n_vp = NULL; 1409 } 1410 1411 freep2n(p2n); 1412 return 0; 1413 } 1414