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