1 /* $NetBSD: dispatcher.c,v 1.49 2021/03/08 17:34:10 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Ulla Tuominen Foundation, the Finnish Cultural Foundation and 8 * Research Foundation of Helsinki University of Technology. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #if !defined(lint) 34 __RCSID("$NetBSD: dispatcher.c,v 1.49 2021/03/08 17:34:10 christos Exp $"); 35 #endif /* !lint */ 36 37 #include <sys/types.h> 38 #include <sys/poll.h> 39 40 #include <assert.h> 41 #include <errno.h> 42 #include <pthread.h> 43 #include <puffs.h> 44 #include <puffsdump.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 49 #include "puffs_priv.h" 50 51 #define PUFFS_USE_FS_TTL(pu) (pu->pu_flags & PUFFS_KFLAG_CACHE_FS_TTL) 52 53 static void dispatch(struct puffs_cc *); 54 55 /* for our eyes only */ 56 void 57 puffs__ml_dispatch(struct puffs_usermount *pu, struct puffs_framebuf *pb) 58 { 59 struct puffs_cc *pcc = puffs_cc_getcc(pu); 60 struct puffs_req *preq; 61 62 pcc->pcc_pb = pb; 63 pcc->pcc_flags |= PCC_MLCONT; 64 dispatch(pcc); 65 66 /* Put result to kernel sendqueue if necessary */ 67 preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 68 if (PUFFSOP_WANTREPLY(preq->preq_opclass)) { 69 if (pu->pu_flags & PUFFS_FLAG_OPDUMP) 70 puffsdump_rv(preq); 71 72 puffs_framev_enqueue_justsend(pu, pu->pu_fd, 73 pcc->pcc_pb, 0, 0); 74 } else { 75 puffs_framebuf_destroy(pcc->pcc_pb); 76 } 77 78 /* who needs information when you're living on borrowed time? */ 79 if (pcc->pcc_flags & PCC_BORROWED) { 80 puffs_cc_yield(pcc); /* back to borrow source */ 81 } 82 pcc->pcc_flags = 0; 83 } 84 85 /* public, but not really tested and only semi-supported */ 86 int 87 puffs_dispatch_create(struct puffs_usermount *pu, struct puffs_framebuf *pb, 88 struct puffs_cc **pccp) 89 { 90 struct puffs_cc *pcc; 91 92 if (puffs__cc_create(pu, dispatch, &pcc) == -1) 93 return -1; 94 95 pcc->pcc_pb = pb; 96 *pccp = pcc; 97 98 return 0; 99 } 100 101 int 102 puffs_dispatch_exec(struct puffs_cc *pcc, struct puffs_framebuf **pbp) 103 { 104 int rv; 105 106 puffs_cc_continue(pcc); 107 108 if (pcc->pcc_flags & PCC_DONE) { 109 rv = 1; 110 *pbp = pcc->pcc_pb; 111 pcc->pcc_flags = 0; 112 puffs__cc_destroy(pcc, 0); 113 } else { 114 rv = 0; 115 } 116 117 return rv; 118 } 119 120 static void 121 dispatch(struct puffs_cc *pcc) 122 { 123 struct puffs_usermount *pu = pcc->pcc_pu; 124 struct puffs_ops *pops = &pu->pu_ops; 125 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 126 void *auxbuf; /* help with typecasting */ 127 puffs_cookie_t opcookie; 128 int error = 0, buildpath, pncookie; 129 130 /* XXX: smaller hammer, please */ 131 if ((PUFFSOP_OPCLASS(preq->preq_opclass == PUFFSOP_VFS && 132 preq->preq_optype == PUFFS_VFS_VPTOFH)) || 133 (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN && 134 (preq->preq_optype == PUFFS_VN_READDIR 135 || preq->preq_optype == PUFFS_VN_READ))) { 136 if (puffs_framebuf_reserve_space(pcc->pcc_pb, 137 PUFFS_MSG_MAXSIZE) == -1) 138 error = errno; 139 preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 140 } 141 142 auxbuf = preq; 143 opcookie = preq->preq_cookie; 144 145 assert((pcc->pcc_flags & PCC_DONE) == 0); 146 147 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH; 148 pncookie = pu->pu_flags & PUFFS_FLAG_PNCOOKIE; 149 assert(!buildpath || pncookie); 150 151 preq->preq_setbacks = 0; 152 153 if (pu->pu_flags & PUFFS_FLAG_OPDUMP) 154 puffsdump_req(preq); 155 156 puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid); 157 158 /* pre-operation */ 159 if (pu->pu_oppre) 160 pu->pu_oppre(pu); 161 162 if (error) 163 goto out; 164 165 /* Execute actual operation */ 166 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) { 167 switch ((enum puffs_vfs)preq->preq_optype) { 168 case PUFFS_VFS_UNMOUNT: 169 { 170 struct puffs_vfsmsg_unmount *auxt = auxbuf; 171 172 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING); 173 error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags); 174 if (!error) 175 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED); 176 else 177 PU_SETSTATE(pu, PUFFS_STATE_RUNNING); 178 break; 179 } 180 181 case PUFFS_VFS_STATVFS: 182 { 183 struct puffs_vfsmsg_statvfs *auxt = auxbuf; 184 185 error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb); 186 break; 187 } 188 189 case PUFFS_VFS_SYNC: 190 { 191 struct puffs_vfsmsg_sync *auxt = auxbuf; 192 PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred); 193 194 error = pops->puffs_fs_sync(pu, 195 auxt->pvfsr_waitfor, pcr); 196 break; 197 } 198 199 case PUFFS_VFS_FHTOVP: 200 { 201 struct puffs_vfsmsg_fhtonode *auxt = auxbuf; 202 struct puffs_newinfo pni; 203 204 pni.pni_cookie = &auxt->pvfsr_fhcookie; 205 pni.pni_vtype = &auxt->pvfsr_vtype; 206 pni.pni_size = &auxt->pvfsr_size; 207 pni.pni_rdev = &auxt->pvfsr_rdev; 208 pni.pni_va = NULL; 209 pni.pni_va_ttl = NULL; 210 pni.pni_cn_ttl = NULL; 211 212 error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data, 213 auxt->pvfsr_dsize, &pni); 214 215 break; 216 } 217 218 case PUFFS_VFS_VPTOFH: 219 { 220 struct puffs_vfsmsg_nodetofh *auxt = auxbuf; 221 222 error = pops->puffs_fs_nodetofh(pu, 223 auxt->pvfsr_fhcookie, auxt->pvfsr_data, 224 &auxt->pvfsr_dsize); 225 226 break; 227 } 228 229 case PUFFS_VFS_EXTATTRCTL: 230 { 231 struct puffs_vfsmsg_extattrctl *auxt = auxbuf; 232 const char *attrname; 233 int flags; 234 235 if (pops->puffs_fs_extattrctl == NULL) { 236 error = EOPNOTSUPP; 237 break; 238 } 239 240 if (auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASATTRNAME) 241 attrname = auxt->pvfsr_attrname; 242 else 243 attrname = NULL; 244 245 flags = auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASNODE; 246 error = pops->puffs_fs_extattrctl(pu, auxt->pvfsr_cmd, 247 opcookie, flags, 248 auxt->pvfsr_attrnamespace, attrname); 249 break; 250 } 251 252 default: 253 /* 254 * I guess the kernel sees this one coming 255 */ 256 error = EINVAL; 257 break; 258 } 259 260 /* XXX: audit return values */ 261 /* XXX: sync with kernel */ 262 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) { 263 switch ((enum puffs_vn)preq->preq_optype) { 264 case PUFFS_VN_LOOKUP: 265 { 266 struct puffs_vnmsg_lookup *auxt = auxbuf; 267 struct puffs_newinfo pni; 268 struct puffs_cn pcn; 269 struct puffs_node *pn = NULL; 270 271 pcn.pcn_pkcnp = &auxt->pvnr_cn; 272 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 273 pni.pni_cookie = &auxt->pvnr_newnode; 274 pni.pni_vtype = &auxt->pvnr_vtype; 275 pni.pni_size = &auxt->pvnr_size; 276 pni.pni_rdev = &auxt->pvnr_rdev; 277 pni.pni_va = &auxt->pvnr_va; 278 pni.pni_va_ttl = &auxt->pvnr_va_ttl; 279 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl; 280 281 if (buildpath) { 282 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 283 if (error) 284 break; 285 } 286 287 /* lookup *must* be present */ 288 error = pops->puffs_node_lookup(pu, opcookie, 289 &pni, &pcn); 290 291 if (buildpath) { 292 if (error) { 293 pu->pu_pathfree(pu, &pcn.pcn_po_full); 294 } else { 295 /* 296 * did we get a new node or a 297 * recycled node? 298 */ 299 pn = PU_CMAP(pu, auxt->pvnr_newnode); 300 if (pn->pn_po.po_path == NULL) 301 pn->pn_po = pcn.pcn_po_full; 302 else 303 pu->pu_pathfree(pu, 304 &pcn.pcn_po_full); 305 } 306 } 307 308 if (pncookie && !error) { 309 if (pn == NULL) 310 pn = PU_CMAP(pu, auxt->pvnr_newnode); 311 pn->pn_nlookup++; 312 } 313 break; 314 } 315 316 case PUFFS_VN_CREATE: 317 { 318 struct puffs_vnmsg_create *auxt = auxbuf; 319 struct puffs_newinfo pni; 320 struct puffs_cn pcn; 321 struct puffs_node *pn = NULL; 322 323 if (pops->puffs_node_create == NULL) { 324 error = 0; 325 break; 326 } 327 328 pcn.pcn_pkcnp = &auxt->pvnr_cn; 329 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 330 331 memset(&pni, 0, sizeof(pni)); 332 pni.pni_cookie = &auxt->pvnr_newnode; 333 pni.pni_va = &auxt->pvnr_va; 334 pni.pni_va_ttl = &auxt->pvnr_va_ttl; 335 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl; 336 337 if (buildpath) { 338 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 339 if (error) 340 break; 341 } 342 343 error = pops->puffs_node_create(pu, 344 opcookie, &pni, &pcn, &auxt->pvnr_va); 345 346 if (buildpath) { 347 if (error) { 348 pu->pu_pathfree(pu, &pcn.pcn_po_full); 349 } else { 350 pn = PU_CMAP(pu, auxt->pvnr_newnode); 351 pn->pn_po = pcn.pcn_po_full; 352 } 353 } 354 355 if (pncookie && !error) { 356 if (pn == NULL) 357 pn = PU_CMAP(pu, auxt->pvnr_newnode); 358 pn->pn_nlookup++; 359 } 360 break; 361 } 362 363 case PUFFS_VN_MKNOD: 364 { 365 struct puffs_vnmsg_mknod *auxt = auxbuf; 366 struct puffs_newinfo pni; 367 struct puffs_cn pcn; 368 struct puffs_node *pn = NULL; 369 370 if (pops->puffs_node_mknod == NULL) { 371 error = 0; 372 break; 373 } 374 375 pcn.pcn_pkcnp = &auxt->pvnr_cn; 376 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 377 378 memset(&pni, 0, sizeof(pni)); 379 pni.pni_cookie = &auxt->pvnr_newnode; 380 pni.pni_va = &auxt->pvnr_va; 381 pni.pni_va_ttl = &auxt->pvnr_va_ttl; 382 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl; 383 384 if (buildpath) { 385 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 386 if (error) 387 break; 388 } 389 390 error = pops->puffs_node_mknod(pu, 391 opcookie, &pni, &pcn, &auxt->pvnr_va); 392 393 if (buildpath) { 394 if (error) { 395 pu->pu_pathfree(pu, &pcn.pcn_po_full); 396 } else { 397 pn = PU_CMAP(pu, auxt->pvnr_newnode); 398 pn->pn_po = pcn.pcn_po_full; 399 } 400 } 401 402 if (pncookie && !error) { 403 if (pn == NULL) 404 pn = PU_CMAP(pu, auxt->pvnr_newnode); 405 pn->pn_nlookup++; 406 } 407 break; 408 } 409 410 case PUFFS_VN_OPEN: 411 { 412 struct puffs_vnmsg_open *auxt = auxbuf; 413 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 414 415 if (pops->puffs_node_open2 != NULL) { 416 error = pops->puffs_node_open2(pu, 417 opcookie, auxt->pvnr_mode, pcr, 418 &auxt->pvnr_oflags); 419 420 break; 421 } 422 423 if (pops->puffs_node_open == NULL) { 424 error = 0; 425 break; 426 } 427 428 error = pops->puffs_node_open(pu, 429 opcookie, auxt->pvnr_mode, pcr); 430 break; 431 } 432 433 case PUFFS_VN_CLOSE: 434 { 435 struct puffs_vnmsg_close *auxt = auxbuf; 436 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 437 438 if (pops->puffs_node_close == NULL) { 439 error = 0; 440 break; 441 } 442 443 error = pops->puffs_node_close(pu, 444 opcookie, auxt->pvnr_fflag, pcr); 445 break; 446 } 447 448 case PUFFS_VN_ACCESS: 449 { 450 struct puffs_vnmsg_access *auxt = auxbuf; 451 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 452 453 if (pops->puffs_node_access == NULL) { 454 error = 0; 455 break; 456 } 457 458 error = pops->puffs_node_access(pu, 459 opcookie, auxt->pvnr_mode, pcr); 460 break; 461 } 462 463 case PUFFS_VN_GETATTR: 464 { 465 struct puffs_vnmsg_getattr *auxt = auxbuf; 466 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 467 468 if (PUFFS_USE_FS_TTL(pu)) { 469 if (pops->puffs_node_getattr_ttl == NULL) { 470 error = EOPNOTSUPP; 471 break; 472 } 473 474 error = pops->puffs_node_getattr_ttl(pu, 475 opcookie, &auxt->pvnr_va, pcr, 476 &auxt->pvnr_va_ttl); 477 } else { 478 if (pops->puffs_node_getattr == NULL) { 479 error = EOPNOTSUPP; 480 break; 481 } 482 483 error = pops->puffs_node_getattr(pu, 484 opcookie, &auxt->pvnr_va, pcr); 485 } 486 break; 487 } 488 489 case PUFFS_VN_SETATTR: 490 { 491 struct puffs_vnmsg_setattr *auxt = auxbuf; 492 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 493 494 if (PUFFS_USE_FS_TTL(pu)) { 495 int xflag = 0; 496 497 if (pops->puffs_node_setattr_ttl == NULL) { 498 error = EOPNOTSUPP; 499 break; 500 } 501 502 if (!PUFFSOP_WANTREPLY(preq->preq_opclass)) 503 xflag |= PUFFS_SETATTR_FAF; 504 505 error = pops->puffs_node_setattr_ttl(pu, 506 opcookie, &auxt->pvnr_va, pcr, 507 &auxt->pvnr_va_ttl, xflag); 508 } else { 509 if (pops->puffs_node_setattr == NULL) { 510 error = EOPNOTSUPP; 511 break; 512 } 513 514 error = pops->puffs_node_setattr(pu, 515 opcookie, &auxt->pvnr_va, pcr); 516 } 517 break; 518 } 519 520 case PUFFS_VN_MMAP: 521 { 522 struct puffs_vnmsg_mmap *auxt = auxbuf; 523 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 524 525 if (pops->puffs_node_mmap == NULL) { 526 error = 0; 527 break; 528 } 529 530 error = pops->puffs_node_mmap(pu, 531 opcookie, auxt->pvnr_prot, pcr); 532 break; 533 } 534 535 case PUFFS_VN_FSYNC: 536 { 537 struct puffs_vnmsg_fsync *auxt = auxbuf; 538 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 539 540 if (pops->puffs_node_fsync == NULL) { 541 error = 0; 542 break; 543 } 544 545 error = pops->puffs_node_fsync(pu, opcookie, pcr, 546 auxt->pvnr_flags, auxt->pvnr_offlo, 547 auxt->pvnr_offhi); 548 break; 549 } 550 551 case PUFFS_VN_SEEK: 552 { 553 struct puffs_vnmsg_seek *auxt = auxbuf; 554 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 555 556 if (pops->puffs_node_seek == NULL) { 557 error = 0; 558 break; 559 } 560 561 error = pops->puffs_node_seek(pu, 562 opcookie, auxt->pvnr_oldoff, 563 auxt->pvnr_newoff, pcr); 564 break; 565 } 566 567 case PUFFS_VN_REMOVE: 568 { 569 struct puffs_vnmsg_remove *auxt = auxbuf; 570 struct puffs_cn pcn; 571 if (pops->puffs_node_remove == NULL) { 572 error = 0; 573 break; 574 } 575 576 pcn.pcn_pkcnp = &auxt->pvnr_cn; 577 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 578 579 error = pops->puffs_node_remove(pu, 580 opcookie, auxt->pvnr_cookie_targ, &pcn); 581 break; 582 } 583 584 case PUFFS_VN_LINK: 585 { 586 struct puffs_vnmsg_link *auxt = auxbuf; 587 struct puffs_cn pcn; 588 if (pops->puffs_node_link == NULL) { 589 error = 0; 590 break; 591 } 592 593 pcn.pcn_pkcnp = &auxt->pvnr_cn; 594 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 595 596 if (buildpath) { 597 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 598 if (error) 599 break; 600 } 601 602 error = pops->puffs_node_link(pu, 603 opcookie, auxt->pvnr_cookie_targ, &pcn); 604 if (buildpath) 605 pu->pu_pathfree(pu, &pcn.pcn_po_full); 606 607 break; 608 } 609 610 case PUFFS_VN_RENAME: 611 { 612 struct puffs_vnmsg_rename *auxt = auxbuf; 613 struct puffs_cn pcn_src, pcn_targ; 614 struct puffs_node *pn_src; 615 616 if (pops->puffs_node_rename == NULL) { 617 error = 0; 618 break; 619 } 620 621 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src; 622 PUFFS_KCREDTOCRED(pcn_src.pcn_cred, 623 &auxt->pvnr_cn_src_cred); 624 625 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ; 626 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred, 627 &auxt->pvnr_cn_targ_cred); 628 629 if (buildpath) { 630 pn_src = auxt->pvnr_cookie_src; 631 pcn_src.pcn_po_full = pn_src->pn_po; 632 633 error = puffs_path_pcnbuild(pu, &pcn_targ, 634 auxt->pvnr_cookie_targdir); 635 if (error) 636 break; 637 } 638 639 error = pops->puffs_node_rename(pu, 640 opcookie, auxt->pvnr_cookie_src, 641 &pcn_src, auxt->pvnr_cookie_targdir, 642 auxt->pvnr_cookie_targ, &pcn_targ); 643 644 if (buildpath) { 645 if (error) { 646 pu->pu_pathfree(pu, 647 &pcn_targ.pcn_po_full); 648 } else { 649 struct puffs_pathinfo pi; 650 struct puffs_pathobj po_old; 651 652 /* handle this node */ 653 po_old = pn_src->pn_po; 654 pn_src->pn_po = pcn_targ.pcn_po_full; 655 656 if (pn_src->pn_va.va_type != VDIR) { 657 pu->pu_pathfree(pu, &po_old); 658 break; 659 } 660 661 /* handle all child nodes for DIRs */ 662 pi.pi_old = &pcn_src.pcn_po_full; 663 pi.pi_new = &pcn_targ.pcn_po_full; 664 665 PU_LOCK(); 666 if (puffs_pn_nodewalk(pu, 667 puffs_path_prefixadj, &pi) != NULL) 668 error = ENOMEM; 669 PU_UNLOCK(); 670 pu->pu_pathfree(pu, &po_old); 671 } 672 } 673 break; 674 } 675 676 case PUFFS_VN_MKDIR: 677 { 678 struct puffs_vnmsg_mkdir *auxt = auxbuf; 679 struct puffs_newinfo pni; 680 struct puffs_cn pcn; 681 struct puffs_node *pn = NULL; 682 683 if (pops->puffs_node_mkdir == NULL) { 684 error = 0; 685 break; 686 } 687 688 pcn.pcn_pkcnp = &auxt->pvnr_cn; 689 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 690 691 memset(&pni, 0, sizeof(pni)); 692 pni.pni_cookie = &auxt->pvnr_newnode; 693 pni.pni_va = &auxt->pvnr_va; 694 pni.pni_va_ttl = &auxt->pvnr_va_ttl; 695 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl; 696 697 if (buildpath) { 698 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 699 if (error) 700 break; 701 } 702 703 error = pops->puffs_node_mkdir(pu, 704 opcookie, &pni, &pcn, &auxt->pvnr_va); 705 706 if (buildpath) { 707 if (error) { 708 pu->pu_pathfree(pu, &pcn.pcn_po_full); 709 } else { 710 pn = PU_CMAP(pu, auxt->pvnr_newnode); 711 pn->pn_po = pcn.pcn_po_full; 712 } 713 } 714 715 if (pncookie && !error) { 716 if (pn == NULL) 717 pn = PU_CMAP(pu, auxt->pvnr_newnode); 718 pn->pn_nlookup++; 719 } 720 break; 721 } 722 723 case PUFFS_VN_RMDIR: 724 { 725 struct puffs_vnmsg_rmdir *auxt = auxbuf; 726 struct puffs_cn pcn; 727 if (pops->puffs_node_rmdir == NULL) { 728 error = 0; 729 break; 730 } 731 732 pcn.pcn_pkcnp = &auxt->pvnr_cn; 733 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 734 735 error = pops->puffs_node_rmdir(pu, 736 opcookie, auxt->pvnr_cookie_targ, &pcn); 737 break; 738 } 739 740 case PUFFS_VN_SYMLINK: 741 { 742 struct puffs_vnmsg_symlink *auxt = auxbuf; 743 struct puffs_newinfo pni; 744 struct puffs_cn pcn; 745 struct puffs_node *pn = NULL; 746 747 if (pops->puffs_node_symlink == NULL) { 748 error = 0; 749 break; 750 } 751 752 pcn.pcn_pkcnp = &auxt->pvnr_cn; 753 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 754 755 memset(&pni, 0, sizeof(pni)); 756 pni.pni_cookie = &auxt->pvnr_newnode; 757 pni.pni_va = &auxt->pvnr_va; 758 pni.pni_va_ttl = &auxt->pvnr_va_ttl; 759 pni.pni_cn_ttl = &auxt->pvnr_cn_ttl; 760 761 if (buildpath) { 762 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 763 if (error) 764 break; 765 } 766 767 error = pops->puffs_node_symlink(pu, 768 opcookie, &pni, &pcn, 769 &auxt->pvnr_va, auxt->pvnr_link); 770 771 if (buildpath) { 772 if (error) { 773 pu->pu_pathfree(pu, &pcn.pcn_po_full); 774 } else { 775 pn = PU_CMAP(pu, auxt->pvnr_newnode); 776 pn->pn_po = pcn.pcn_po_full; 777 } 778 } 779 780 if (pncookie && !error) { 781 if (pn == NULL) 782 pn = PU_CMAP(pu, auxt->pvnr_newnode); 783 pn->pn_nlookup++; 784 } 785 break; 786 } 787 788 case PUFFS_VN_READDIR: 789 { 790 struct puffs_vnmsg_readdir *auxt = auxbuf; 791 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 792 struct dirent *dent; 793 off_t *cookies; 794 size_t res, origcookies; 795 796 if (pops->puffs_node_readdir == NULL) { 797 error = 0; 798 break; 799 } 800 801 if (auxt->pvnr_ncookies) { 802 /* LINTED: pvnr_data is __aligned() */ 803 cookies = (off_t *)auxt->pvnr_data; 804 origcookies = auxt->pvnr_ncookies; 805 } else { 806 cookies = NULL; 807 origcookies = 0; 808 } 809 /* LINTED: dentoff is aligned in the kernel */ 810 dent = (struct dirent *) 811 (auxt->pvnr_data + auxt->pvnr_dentoff); 812 813 res = auxt->pvnr_resid; 814 error = pops->puffs_node_readdir(pu, 815 opcookie, dent, &auxt->pvnr_offset, 816 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag, 817 cookies, &auxt->pvnr_ncookies); 818 819 /* much easier to track non-working NFS */ 820 assert(auxt->pvnr_ncookies <= origcookies); 821 822 /* need to move a bit more */ 823 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir) 824 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid); 825 break; 826 } 827 828 case PUFFS_VN_READLINK: 829 { 830 struct puffs_vnmsg_readlink *auxt = auxbuf; 831 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 832 833 if (pops->puffs_node_readlink == NULL) { 834 error = EOPNOTSUPP; 835 break; 836 } 837 838 /*LINTED*/ 839 error = pops->puffs_node_readlink(pu, opcookie, pcr, 840 auxt->pvnr_link, &auxt->pvnr_linklen); 841 break; 842 } 843 844 case PUFFS_VN_RECLAIM: 845 { 846 struct puffs_vnmsg_reclaim *auxt = auxbuf; 847 struct puffs_node *pn; 848 849 if (pops->puffs_node_reclaim2 != NULL) { 850 error = pops->puffs_node_reclaim2(pu, opcookie, 851 auxt->pvnr_nlookup); 852 break; 853 } 854 855 if (pops->puffs_node_reclaim == NULL) { 856 error = 0; 857 break; 858 } 859 860 /* 861 * This fixes a race condition, 862 * where a node in reclaimed by kernel 863 * after a lookup request is sent, 864 * but before the reply, leaving the kernel 865 * with a invalid vnode/cookie reference. 866 */ 867 if (pncookie) { 868 pn = PU_CMAP(pu, opcookie); 869 pn->pn_nlookup -= auxt->pvnr_nlookup; 870 if (pn->pn_nlookup >= 1) { 871 error = 0; 872 break; 873 } 874 } 875 876 error = pops->puffs_node_reclaim(pu, opcookie); 877 break; 878 } 879 880 case PUFFS_VN_INACTIVE: 881 { 882 883 if (pops->puffs_node_inactive == NULL) { 884 error = EOPNOTSUPP; 885 break; 886 } 887 888 error = pops->puffs_node_inactive(pu, opcookie); 889 break; 890 } 891 892 case PUFFS_VN_PATHCONF: 893 { 894 struct puffs_vnmsg_pathconf *auxt = auxbuf; 895 if (pops->puffs_node_pathconf == NULL) { 896 error = 0; 897 break; 898 } 899 900 error = pops->puffs_node_pathconf(pu, 901 opcookie, auxt->pvnr_name, 902 &auxt->pvnr_retval); 903 break; 904 } 905 906 case PUFFS_VN_ADVLOCK: 907 { 908 struct puffs_vnmsg_advlock *auxt = auxbuf; 909 if (pops->puffs_node_advlock == NULL) { 910 error = 0; 911 break; 912 } 913 914 error = pops->puffs_node_advlock(pu, 915 opcookie, auxt->pvnr_id, auxt->pvnr_op, 916 &auxt->pvnr_fl, auxt->pvnr_flags); 917 break; 918 } 919 920 case PUFFS_VN_PRINT: 921 { 922 if (pops->puffs_node_print == NULL) { 923 error = 0; 924 break; 925 } 926 927 error = pops->puffs_node_print(pu, 928 opcookie); 929 break; 930 } 931 932 case PUFFS_VN_ABORTOP: 933 { 934 struct puffs_vnmsg_abortop *auxt = auxbuf; 935 struct puffs_cn pcn; 936 937 if (pops->puffs_node_abortop == NULL) { 938 error = 0; 939 break; 940 } 941 942 pcn.pcn_pkcnp = &auxt->pvnr_cn; 943 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 944 945 error = pops->puffs_node_abortop(pu, opcookie, &pcn); 946 947 break; 948 } 949 950 case PUFFS_VN_READ: 951 { 952 struct puffs_vnmsg_read *auxt = auxbuf; 953 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 954 size_t res; 955 956 if (pops->puffs_node_read == NULL) { 957 error = EIO; 958 break; 959 } 960 961 res = auxt->pvnr_resid; 962 error = pops->puffs_node_read(pu, 963 opcookie, auxt->pvnr_data, 964 auxt->pvnr_offset, &auxt->pvnr_resid, 965 pcr, auxt->pvnr_ioflag); 966 967 /* need to move a bit more */ 968 preq->preq_buflen = sizeof(struct puffs_vnmsg_read) 969 + (res - auxt->pvnr_resid); 970 break; 971 } 972 973 case PUFFS_VN_WRITE: 974 { 975 struct puffs_vnmsg_write *auxt = auxbuf; 976 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 977 978 if (pops->puffs_node_write2 != NULL) { 979 int xflag = 0; 980 981 if (!PUFFSOP_WANTREPLY(preq->preq_opclass)) 982 xflag |= PUFFS_SETATTR_FAF; 983 984 error = pops->puffs_node_write2(pu, 985 opcookie, auxt->pvnr_data, 986 auxt->pvnr_offset, &auxt->pvnr_resid, 987 pcr, auxt->pvnr_ioflag, xflag); 988 989 } else if (pops->puffs_node_write != NULL) { 990 error = pops->puffs_node_write(pu, 991 opcookie, auxt->pvnr_data, 992 auxt->pvnr_offset, &auxt->pvnr_resid, 993 pcr, auxt->pvnr_ioflag); 994 } else { 995 error = EIO; 996 break; 997 } 998 999 1000 /* don't need to move data back to the kernel */ 1001 preq->preq_buflen = sizeof(struct puffs_vnmsg_write); 1002 break; 1003 } 1004 1005 case PUFFS_VN_POLL: 1006 { 1007 struct puffs_vnmsg_poll *auxt = auxbuf; 1008 1009 if (pops->puffs_node_poll == NULL) { 1010 error = 0; 1011 1012 /* emulate genfs_poll() */ 1013 auxt->pvnr_events &= (POLLIN | POLLOUT 1014 | POLLRDNORM | POLLWRNORM); 1015 1016 break; 1017 } 1018 1019 error = pops->puffs_node_poll(pu, 1020 opcookie, &auxt->pvnr_events); 1021 break; 1022 } 1023 1024 case PUFFS_VN_GETEXTATTR: 1025 { 1026 struct puffs_vnmsg_getextattr *auxt = auxbuf; 1027 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 1028 size_t res, *resp, *sizep; 1029 uint8_t *data; 1030 1031 if (pops->puffs_node_getextattr == NULL) { 1032 error = EOPNOTSUPP; 1033 break; 1034 } 1035 1036 if (auxt->pvnr_datasize) 1037 sizep = &auxt->pvnr_datasize; 1038 else 1039 sizep = NULL; 1040 1041 res = auxt->pvnr_resid; 1042 if (res > 0) { 1043 data = auxt->pvnr_data; 1044 resp = &auxt->pvnr_resid; 1045 } else { 1046 data = NULL; 1047 resp = NULL; 1048 } 1049 1050 error = pops->puffs_node_getextattr(pu, 1051 opcookie, auxt->pvnr_attrnamespace, 1052 auxt->pvnr_attrname, sizep, data, resp, pcr); 1053 1054 /* need to move a bit more? */ 1055 preq->preq_buflen = 1056 sizeof(struct puffs_vnmsg_getextattr) 1057 + (res - auxt->pvnr_resid); 1058 break; 1059 } 1060 1061 case PUFFS_VN_SETEXTATTR: 1062 { 1063 struct puffs_vnmsg_setextattr *auxt = auxbuf; 1064 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 1065 size_t *resp; 1066 uint8_t *data; 1067 1068 if (pops->puffs_node_setextattr == NULL) { 1069 error = EOPNOTSUPP; 1070 break; 1071 } 1072 1073 if (auxt->pvnr_resid > 0) { 1074 data = auxt->pvnr_data; 1075 resp = &auxt->pvnr_resid; 1076 } else { 1077 data = NULL; 1078 resp = NULL; 1079 } 1080 1081 error = pops->puffs_node_setextattr(pu, 1082 opcookie, auxt->pvnr_attrnamespace, 1083 auxt->pvnr_attrname, data, resp, pcr); 1084 break; 1085 } 1086 1087 case PUFFS_VN_LISTEXTATTR: 1088 { 1089 struct puffs_vnmsg_listextattr *auxt = auxbuf; 1090 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 1091 size_t res, *resp, *sizep; 1092 int flag; 1093 uint8_t *data; 1094 1095 if (pops->puffs_node_listextattr == NULL) { 1096 error = EOPNOTSUPP; 1097 break; 1098 } 1099 1100 if (auxt->pvnr_datasize) 1101 sizep = &auxt->pvnr_datasize; 1102 else 1103 sizep = NULL; 1104 1105 res = auxt->pvnr_resid; 1106 if (res > 0) { 1107 data = auxt->pvnr_data; 1108 resp = &auxt->pvnr_resid; 1109 } else { 1110 data = NULL; 1111 resp = NULL; 1112 } 1113 1114 res = auxt->pvnr_resid; 1115 flag = auxt->pvnr_flag; 1116 error = pops->puffs_node_listextattr(pu, 1117 opcookie, auxt->pvnr_attrnamespace, 1118 sizep, data, resp, flag, pcr); 1119 1120 /* need to move a bit more? */ 1121 preq->preq_buflen = 1122 sizeof(struct puffs_vnmsg_listextattr) 1123 + (res - auxt->pvnr_resid); 1124 break; 1125 } 1126 1127 case PUFFS_VN_DELETEEXTATTR: 1128 { 1129 struct puffs_vnmsg_deleteextattr *auxt = auxbuf; 1130 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 1131 1132 if (pops->puffs_node_deleteextattr == NULL) { 1133 error = EOPNOTSUPP; 1134 break; 1135 } 1136 1137 error = pops->puffs_node_deleteextattr(pu, 1138 opcookie, auxt->pvnr_attrnamespace, 1139 auxt->pvnr_attrname, pcr); 1140 break; 1141 } 1142 1143 case PUFFS_VN_FALLOCATE: 1144 { 1145 struct puffs_vnmsg_fallocate *auxt = auxbuf; 1146 1147 if (pops->puffs_node_fallocate == NULL) { 1148 error = EOPNOTSUPP; 1149 break; 1150 } 1151 1152 error = pops->puffs_node_fallocate(pu, 1153 opcookie, auxt->pvnr_off, auxt->pvnr_len); 1154 break; 1155 } 1156 1157 case PUFFS_VN_FDISCARD: 1158 { 1159 struct puffs_vnmsg_fdiscard *auxt = auxbuf; 1160 1161 if (pops->puffs_node_fdiscard == NULL) { 1162 error = EOPNOTSUPP; 1163 break; 1164 } 1165 1166 error = pops->puffs_node_fdiscard(pu, 1167 opcookie, auxt->pvnr_off, auxt->pvnr_len); 1168 break; 1169 } 1170 1171 default: 1172 printf("inval op %d\n", preq->preq_optype); 1173 error = EINVAL; 1174 break; 1175 } 1176 1177 #if 0 1178 /* not issued by kernel currently */ 1179 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) { 1180 struct puffs_cacheinfo *pci = (void *)preq; 1181 1182 if (pu->pu_ops.puffs_cache_write) { 1183 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie, 1184 pci->pcache_nruns, pci->pcache_runs); 1185 } 1186 error = 0; 1187 #endif 1188 1189 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) { 1190 struct puffs_error *perr = (void *)preq; 1191 1192 pu->pu_errnotify(pu, preq->preq_optype, 1193 perr->perr_error, perr->perr_str, preq->preq_cookie); 1194 error = 0; 1195 } else { 1196 /* 1197 * I guess the kernel sees this one coming also 1198 */ 1199 error = EINVAL; 1200 } 1201 1202 out: 1203 preq->preq_rv = error; 1204 1205 if (pu->pu_oppost) 1206 pu->pu_oppost(pu); 1207 1208 pcc->pcc_flags |= PCC_DONE; 1209 } 1210