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