1 /* $NetBSD: dispatcher.c,v 1.32 2008/08/12 19:44:39 pooka 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.32 2008/08/12 19:44:39 pooka 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 #ifdef PUFFS_WITH_THREADS 43 #include <pthread.h> 44 #endif 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 #if 0 /* me not worka now */ 54 /* 55 * Set the following to 1 to handle each request in a separate pthread. 56 * This is not exported as it should not be used yet unless having a 57 * very good knowledge of what you're signing up for (libpuffs is not 58 * threadsafe). 59 */ 60 int puffs_usethreads; 61 #endif 62 63 static void dispatch(struct puffs_cc *); 64 65 /* for our eyes only */ 66 void 67 puffs__ml_dispatch(struct puffs_usermount *pu, struct puffs_framebuf *pb) 68 { 69 struct puffs_cc *pcc = puffs_cc_getcc(pu); 70 struct puffs_req *preq; 71 72 pcc->pcc_pb = pb; 73 pcc->pcc_flags |= PCC_MLCONT; 74 dispatch(pcc); 75 76 /* Put result to kernel sendqueue if necessary */ 77 preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 78 if (PUFFSOP_WANTREPLY(preq->preq_opclass)) { 79 if (pu->pu_flags & PUFFS_FLAG_OPDUMP) 80 puffsdump_rv(preq); 81 82 puffs_framev_enqueue_justsend(pu, pu->pu_fd, 83 pcc->pcc_pb, 0, 0); 84 } else { 85 puffs_framebuf_destroy(pcc->pcc_pb); 86 } 87 88 /* who needs information when you're living on borrowed time? */ 89 if (pcc->pcc_flags & PCC_BORROWED) { 90 puffs_cc_yield(pcc); /* back to borrow source */ 91 } 92 pcc->pcc_flags = 0; 93 } 94 95 /* public, but not really tested and only semi-supported */ 96 int 97 puffs_dispatch_create(struct puffs_usermount *pu, struct puffs_framebuf *pb, 98 struct puffs_cc **pccp) 99 { 100 struct puffs_cc *pcc; 101 102 if (puffs__cc_create(pu, dispatch, &pcc) == -1) 103 return -1; 104 105 pcc->pcc_pb = pb; 106 *pccp = pcc; 107 108 return 0; 109 } 110 111 int 112 puffs_dispatch_exec(struct puffs_cc *pcc, struct puffs_framebuf **pbp) 113 { 114 int rv; 115 116 puffs_cc_continue(pcc); 117 118 if (pcc->pcc_flags & PCC_DONE) { 119 rv = 1; 120 *pbp = pcc->pcc_pb; 121 pcc->pcc_flags = 0; 122 puffs__cc_destroy(pcc, 0); 123 } else { 124 rv = 0; 125 } 126 127 return rv; 128 } 129 130 static void 131 dispatch(struct puffs_cc *pcc) 132 { 133 struct puffs_usermount *pu = pcc->pcc_pu; 134 struct puffs_ops *pops = &pu->pu_ops; 135 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 136 void *auxbuf; /* help with typecasting */ 137 puffs_cookie_t opcookie; 138 int error = 0, buildpath; 139 140 /* XXX: smaller hammer, please */ 141 if ((PUFFSOP_OPCLASS(preq->preq_opclass == PUFFSOP_VFS && 142 preq->preq_optype == PUFFS_VFS_VPTOFH)) || 143 (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN && 144 (preq->preq_optype == PUFFS_VN_READDIR 145 || preq->preq_optype == PUFFS_VN_READ))) { 146 if (puffs_framebuf_reserve_space(pcc->pcc_pb, 147 PUFFS_MSG_MAXSIZE) == -1) 148 error = errno; 149 preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 150 } 151 152 auxbuf = preq; 153 opcookie = preq->preq_cookie; 154 155 assert((pcc->pcc_flags & PCC_DONE) == 0); 156 157 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH; 158 preq->preq_setbacks = 0; 159 160 if (pu->pu_flags & PUFFS_FLAG_OPDUMP) 161 puffsdump_req(preq); 162 163 puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid); 164 165 /* pre-operation */ 166 if (pu->pu_oppre) 167 pu->pu_oppre(pu); 168 169 if (error) 170 goto out; 171 172 /* Execute actual operation */ 173 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) { 174 switch (preq->preq_optype) { 175 case PUFFS_VFS_UNMOUNT: 176 { 177 struct puffs_vfsmsg_unmount *auxt = auxbuf; 178 179 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING); 180 error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags); 181 if (!error) 182 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED); 183 else 184 PU_SETSTATE(pu, PUFFS_STATE_RUNNING); 185 break; 186 } 187 188 case PUFFS_VFS_STATVFS: 189 { 190 struct puffs_vfsmsg_statvfs *auxt = auxbuf; 191 192 error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb); 193 break; 194 } 195 196 case PUFFS_VFS_SYNC: 197 { 198 struct puffs_vfsmsg_sync *auxt = auxbuf; 199 PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred); 200 201 error = pops->puffs_fs_sync(pu, 202 auxt->pvfsr_waitfor, pcr); 203 break; 204 } 205 206 case PUFFS_VFS_FHTOVP: 207 { 208 struct puffs_vfsmsg_fhtonode *auxt = auxbuf; 209 struct puffs_newinfo pni; 210 211 pni.pni_cookie = &auxt->pvfsr_fhcookie; 212 pni.pni_vtype = &auxt->pvfsr_vtype; 213 pni.pni_size = &auxt->pvfsr_size; 214 pni.pni_rdev = &auxt->pvfsr_rdev; 215 216 error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data, 217 auxt->pvfsr_dsize, &pni); 218 219 break; 220 } 221 222 case PUFFS_VFS_VPTOFH: 223 { 224 struct puffs_vfsmsg_nodetofh *auxt = auxbuf; 225 226 error = pops->puffs_fs_nodetofh(pu, 227 auxt->pvfsr_fhcookie, auxt->pvfsr_data, 228 &auxt->pvfsr_dsize); 229 230 break; 231 } 232 233 case PUFFS_VFS_SUSPEND: 234 { 235 struct puffs_vfsmsg_suspend *auxt = auxbuf; 236 237 error = 0; 238 if (pops->puffs_fs_suspend == NULL) 239 break; 240 241 pops->puffs_fs_suspend(pu, auxt->pvfsr_status); 242 break; 243 } 244 245 default: 246 /* 247 * I guess the kernel sees this one coming 248 */ 249 error = EINVAL; 250 break; 251 } 252 253 /* XXX: audit return values */ 254 /* XXX: sync with kernel */ 255 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) { 256 switch (preq->preq_optype) { 257 case PUFFS_VN_LOOKUP: 258 { 259 struct puffs_vnmsg_lookup *auxt = auxbuf; 260 struct puffs_newinfo pni; 261 struct puffs_cn pcn; 262 263 pcn.pcn_pkcnp = &auxt->pvnr_cn; 264 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 265 pni.pni_cookie = &auxt->pvnr_newnode; 266 pni.pni_vtype = &auxt->pvnr_vtype; 267 pni.pni_size = &auxt->pvnr_size; 268 pni.pni_rdev = &auxt->pvnr_rdev; 269 270 if (buildpath) { 271 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 272 if (error) 273 break; 274 } 275 276 /* lookup *must* be present */ 277 error = pops->puffs_node_lookup(pu, opcookie, 278 &pni, &pcn); 279 280 if (buildpath) { 281 if (error) { 282 pu->pu_pathfree(pu, &pcn.pcn_po_full); 283 } else { 284 struct puffs_node *pn; 285 286 /* 287 * did we get a new node or a 288 * recycled node? 289 */ 290 pn = PU_CMAP(pu, auxt->pvnr_newnode); 291 if (pn->pn_po.po_path == NULL) 292 pn->pn_po = pcn.pcn_po_full; 293 else 294 pu->pu_pathfree(pu, 295 &pcn.pcn_po_full); 296 } 297 } 298 299 break; 300 } 301 302 case PUFFS_VN_CREATE: 303 { 304 struct puffs_vnmsg_create *auxt = auxbuf; 305 struct puffs_newinfo pni; 306 struct puffs_cn pcn; 307 308 if (pops->puffs_node_create == NULL) { 309 error = 0; 310 break; 311 } 312 313 pcn.pcn_pkcnp = &auxt->pvnr_cn; 314 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 315 316 memset(&pni, 0, sizeof(pni)); 317 pni.pni_cookie = &auxt->pvnr_newnode; 318 319 if (buildpath) { 320 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 321 if (error) 322 break; 323 } 324 325 error = pops->puffs_node_create(pu, 326 opcookie, &pni, &pcn, &auxt->pvnr_va); 327 328 if (buildpath) { 329 if (error) { 330 pu->pu_pathfree(pu, &pcn.pcn_po_full); 331 } else { 332 struct puffs_node *pn; 333 334 pn = PU_CMAP(pu, auxt->pvnr_newnode); 335 pn->pn_po = pcn.pcn_po_full; 336 } 337 } 338 339 break; 340 } 341 342 case PUFFS_VN_MKNOD: 343 { 344 struct puffs_vnmsg_mknod *auxt = auxbuf; 345 struct puffs_newinfo pni; 346 struct puffs_cn pcn; 347 348 if (pops->puffs_node_mknod == NULL) { 349 error = 0; 350 break; 351 } 352 353 pcn.pcn_pkcnp = &auxt->pvnr_cn; 354 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 355 356 memset(&pni, 0, sizeof(pni)); 357 pni.pni_cookie = &auxt->pvnr_newnode; 358 359 if (buildpath) { 360 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 361 if (error) 362 break; 363 } 364 365 error = pops->puffs_node_mknod(pu, 366 opcookie, &pni, &pcn, &auxt->pvnr_va); 367 368 if (buildpath) { 369 if (error) { 370 pu->pu_pathfree(pu, &pcn.pcn_po_full); 371 } else { 372 struct puffs_node *pn; 373 374 pn = PU_CMAP(pu, auxt->pvnr_newnode); 375 pn->pn_po = pcn.pcn_po_full; 376 } 377 } 378 379 break; 380 } 381 382 case PUFFS_VN_OPEN: 383 { 384 struct puffs_vnmsg_open *auxt = auxbuf; 385 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 386 387 if (pops->puffs_node_open == NULL) { 388 error = 0; 389 break; 390 } 391 392 error = pops->puffs_node_open(pu, 393 opcookie, auxt->pvnr_mode, pcr); 394 break; 395 } 396 397 case PUFFS_VN_CLOSE: 398 { 399 struct puffs_vnmsg_close *auxt = auxbuf; 400 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 401 402 if (pops->puffs_node_close == NULL) { 403 error = 0; 404 break; 405 } 406 407 error = pops->puffs_node_close(pu, 408 opcookie, auxt->pvnr_fflag, pcr); 409 break; 410 } 411 412 case PUFFS_VN_ACCESS: 413 { 414 struct puffs_vnmsg_access *auxt = auxbuf; 415 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 416 417 if (pops->puffs_node_access == NULL) { 418 error = 0; 419 break; 420 } 421 422 error = pops->puffs_node_access(pu, 423 opcookie, auxt->pvnr_mode, pcr); 424 break; 425 } 426 427 case PUFFS_VN_GETATTR: 428 { 429 struct puffs_vnmsg_getattr *auxt = auxbuf; 430 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 431 432 if (pops->puffs_node_getattr == NULL) { 433 error = EOPNOTSUPP; 434 break; 435 } 436 437 error = pops->puffs_node_getattr(pu, 438 opcookie, &auxt->pvnr_va, pcr); 439 break; 440 } 441 442 case PUFFS_VN_SETATTR: 443 { 444 struct puffs_vnmsg_setattr *auxt = auxbuf; 445 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 446 447 if (pops->puffs_node_setattr == NULL) { 448 error = EOPNOTSUPP; 449 break; 450 } 451 452 error = pops->puffs_node_setattr(pu, 453 opcookie, &auxt->pvnr_va, pcr); 454 break; 455 } 456 457 case PUFFS_VN_MMAP: 458 { 459 struct puffs_vnmsg_mmap *auxt = auxbuf; 460 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 461 462 if (pops->puffs_node_mmap == NULL) { 463 error = 0; 464 break; 465 } 466 467 error = pops->puffs_node_mmap(pu, 468 opcookie, auxt->pvnr_prot, pcr); 469 break; 470 } 471 472 case PUFFS_VN_FSYNC: 473 { 474 struct puffs_vnmsg_fsync *auxt = auxbuf; 475 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 476 477 if (pops->puffs_node_fsync == NULL) { 478 error = 0; 479 break; 480 } 481 482 error = pops->puffs_node_fsync(pu, opcookie, pcr, 483 auxt->pvnr_flags, auxt->pvnr_offlo, 484 auxt->pvnr_offhi); 485 break; 486 } 487 488 case PUFFS_VN_SEEK: 489 { 490 struct puffs_vnmsg_seek *auxt = auxbuf; 491 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 492 493 if (pops->puffs_node_seek == NULL) { 494 error = 0; 495 break; 496 } 497 498 error = pops->puffs_node_seek(pu, 499 opcookie, auxt->pvnr_oldoff, 500 auxt->pvnr_newoff, pcr); 501 break; 502 } 503 504 case PUFFS_VN_REMOVE: 505 { 506 struct puffs_vnmsg_remove *auxt = auxbuf; 507 struct puffs_cn pcn; 508 if (pops->puffs_node_remove == NULL) { 509 error = 0; 510 break; 511 } 512 513 pcn.pcn_pkcnp = &auxt->pvnr_cn; 514 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 515 516 error = pops->puffs_node_remove(pu, 517 opcookie, auxt->pvnr_cookie_targ, &pcn); 518 break; 519 } 520 521 case PUFFS_VN_LINK: 522 { 523 struct puffs_vnmsg_link *auxt = auxbuf; 524 struct puffs_cn pcn; 525 if (pops->puffs_node_link == NULL) { 526 error = 0; 527 break; 528 } 529 530 pcn.pcn_pkcnp = &auxt->pvnr_cn; 531 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 532 533 if (buildpath) { 534 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 535 if (error) 536 break; 537 } 538 539 error = pops->puffs_node_link(pu, 540 opcookie, auxt->pvnr_cookie_targ, &pcn); 541 if (buildpath) 542 pu->pu_pathfree(pu, &pcn.pcn_po_full); 543 544 break; 545 } 546 547 case PUFFS_VN_RENAME: 548 { 549 struct puffs_vnmsg_rename *auxt = auxbuf; 550 struct puffs_cn pcn_src, pcn_targ; 551 struct puffs_node *pn_src; 552 553 if (pops->puffs_node_rename == NULL) { 554 error = 0; 555 break; 556 } 557 558 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src; 559 PUFFS_KCREDTOCRED(pcn_src.pcn_cred, 560 &auxt->pvnr_cn_src_cred); 561 562 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ; 563 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred, 564 &auxt->pvnr_cn_targ_cred); 565 566 if (buildpath) { 567 pn_src = auxt->pvnr_cookie_src; 568 pcn_src.pcn_po_full = pn_src->pn_po; 569 570 error = puffs_path_pcnbuild(pu, &pcn_targ, 571 auxt->pvnr_cookie_targdir); 572 if (error) 573 break; 574 } 575 576 error = pops->puffs_node_rename(pu, 577 opcookie, auxt->pvnr_cookie_src, 578 &pcn_src, auxt->pvnr_cookie_targdir, 579 auxt->pvnr_cookie_targ, &pcn_targ); 580 581 if (buildpath) { 582 if (error) { 583 pu->pu_pathfree(pu, 584 &pcn_targ.pcn_po_full); 585 } else { 586 struct puffs_pathinfo pi; 587 struct puffs_pathobj po_old; 588 589 /* handle this node */ 590 po_old = pn_src->pn_po; 591 pn_src->pn_po = pcn_targ.pcn_po_full; 592 593 if (pn_src->pn_va.va_type != VDIR) { 594 pu->pu_pathfree(pu, &po_old); 595 break; 596 } 597 598 /* handle all child nodes for DIRs */ 599 pi.pi_old = &pcn_src.pcn_po_full; 600 pi.pi_new = &pcn_targ.pcn_po_full; 601 602 PU_LOCK(); 603 if (puffs_pn_nodewalk(pu, 604 puffs_path_prefixadj, &pi) != NULL) 605 error = ENOMEM; 606 PU_UNLOCK(); 607 pu->pu_pathfree(pu, &po_old); 608 } 609 } 610 break; 611 } 612 613 case PUFFS_VN_MKDIR: 614 { 615 struct puffs_vnmsg_mkdir *auxt = auxbuf; 616 struct puffs_newinfo pni; 617 struct puffs_cn pcn; 618 619 if (pops->puffs_node_mkdir == NULL) { 620 error = 0; 621 break; 622 } 623 624 pcn.pcn_pkcnp = &auxt->pvnr_cn; 625 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 626 627 memset(&pni, 0, sizeof(pni)); 628 pni.pni_cookie = &auxt->pvnr_newnode; 629 630 if (buildpath) { 631 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 632 if (error) 633 break; 634 } 635 636 error = pops->puffs_node_mkdir(pu, 637 opcookie, &pni, &pcn, &auxt->pvnr_va); 638 639 if (buildpath) { 640 if (error) { 641 pu->pu_pathfree(pu, &pcn.pcn_po_full); 642 } else { 643 struct puffs_node *pn; 644 645 pn = PU_CMAP(pu, auxt->pvnr_newnode); 646 pn->pn_po = pcn.pcn_po_full; 647 } 648 } 649 650 break; 651 } 652 653 case PUFFS_VN_RMDIR: 654 { 655 struct puffs_vnmsg_rmdir *auxt = auxbuf; 656 struct puffs_cn pcn; 657 if (pops->puffs_node_rmdir == NULL) { 658 error = 0; 659 break; 660 } 661 662 pcn.pcn_pkcnp = &auxt->pvnr_cn; 663 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 664 665 error = pops->puffs_node_rmdir(pu, 666 opcookie, auxt->pvnr_cookie_targ, &pcn); 667 break; 668 } 669 670 case PUFFS_VN_SYMLINK: 671 { 672 struct puffs_vnmsg_symlink *auxt = auxbuf; 673 struct puffs_newinfo pni; 674 struct puffs_cn pcn; 675 676 if (pops->puffs_node_symlink == NULL) { 677 error = 0; 678 break; 679 } 680 681 pcn.pcn_pkcnp = &auxt->pvnr_cn; 682 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 683 684 memset(&pni, 0, sizeof(pni)); 685 pni.pni_cookie = &auxt->pvnr_newnode; 686 687 if (buildpath) { 688 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 689 if (error) 690 break; 691 } 692 693 error = pops->puffs_node_symlink(pu, 694 opcookie, &pni, &pcn, 695 &auxt->pvnr_va, auxt->pvnr_link); 696 697 if (buildpath) { 698 if (error) { 699 pu->pu_pathfree(pu, &pcn.pcn_po_full); 700 } else { 701 struct puffs_node *pn; 702 703 pn = PU_CMAP(pu, auxt->pvnr_newnode); 704 pn->pn_po = pcn.pcn_po_full; 705 } 706 } 707 708 break; 709 } 710 711 case PUFFS_VN_READDIR: 712 { 713 struct puffs_vnmsg_readdir *auxt = auxbuf; 714 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 715 struct dirent *dent; 716 off_t *cookies; 717 size_t res, origcookies; 718 719 if (pops->puffs_node_readdir == NULL) { 720 error = 0; 721 break; 722 } 723 724 if (auxt->pvnr_ncookies) { 725 /* LINTED: pvnr_data is __aligned() */ 726 cookies = (off_t *)auxt->pvnr_data; 727 origcookies = auxt->pvnr_ncookies; 728 } else { 729 cookies = NULL; 730 origcookies = 0; 731 } 732 /* LINTED: dentoff is aligned in the kernel */ 733 dent = (struct dirent *) 734 (auxt->pvnr_data + auxt->pvnr_dentoff); 735 736 res = auxt->pvnr_resid; 737 error = pops->puffs_node_readdir(pu, 738 opcookie, dent, &auxt->pvnr_offset, 739 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag, 740 cookies, &auxt->pvnr_ncookies); 741 742 /* much easier to track non-working NFS */ 743 assert(auxt->pvnr_ncookies <= origcookies); 744 745 /* need to move a bit more */ 746 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir) 747 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid); 748 break; 749 } 750 751 case PUFFS_VN_READLINK: 752 { 753 struct puffs_vnmsg_readlink *auxt = auxbuf; 754 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 755 756 if (pops->puffs_node_readlink == NULL) { 757 error = EOPNOTSUPP; 758 break; 759 } 760 761 /*LINTED*/ 762 error = pops->puffs_node_readlink(pu, opcookie, pcr, 763 auxt->pvnr_link, &auxt->pvnr_linklen); 764 break; 765 } 766 767 case PUFFS_VN_RECLAIM: 768 { 769 770 if (pops->puffs_node_reclaim == NULL) { 771 error = 0; 772 break; 773 } 774 775 error = pops->puffs_node_reclaim(pu, opcookie); 776 break; 777 } 778 779 case PUFFS_VN_INACTIVE: 780 { 781 782 if (pops->puffs_node_inactive == NULL) { 783 error = EOPNOTSUPP; 784 break; 785 } 786 787 error = pops->puffs_node_inactive(pu, opcookie); 788 break; 789 } 790 791 case PUFFS_VN_PATHCONF: 792 { 793 struct puffs_vnmsg_pathconf *auxt = auxbuf; 794 if (pops->puffs_node_pathconf == NULL) { 795 error = 0; 796 break; 797 } 798 799 error = pops->puffs_node_pathconf(pu, 800 opcookie, auxt->pvnr_name, 801 &auxt->pvnr_retval); 802 break; 803 } 804 805 case PUFFS_VN_ADVLOCK: 806 { 807 struct puffs_vnmsg_advlock *auxt = auxbuf; 808 if (pops->puffs_node_advlock == NULL) { 809 error = 0; 810 break; 811 } 812 813 error = pops->puffs_node_advlock(pu, 814 opcookie, auxt->pvnr_id, auxt->pvnr_op, 815 &auxt->pvnr_fl, auxt->pvnr_flags); 816 break; 817 } 818 819 case PUFFS_VN_PRINT: 820 { 821 if (pops->puffs_node_print == NULL) { 822 error = 0; 823 break; 824 } 825 826 error = pops->puffs_node_print(pu, 827 opcookie); 828 break; 829 } 830 831 case PUFFS_VN_READ: 832 { 833 struct puffs_vnmsg_read *auxt = auxbuf; 834 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 835 size_t res; 836 837 if (pops->puffs_node_read == NULL) { 838 error = EIO; 839 break; 840 } 841 842 res = auxt->pvnr_resid; 843 error = pops->puffs_node_read(pu, 844 opcookie, auxt->pvnr_data, 845 auxt->pvnr_offset, &auxt->pvnr_resid, 846 pcr, auxt->pvnr_ioflag); 847 848 /* need to move a bit more */ 849 preq->preq_buflen = sizeof(struct puffs_vnmsg_read) 850 + (res - auxt->pvnr_resid); 851 break; 852 } 853 854 case PUFFS_VN_WRITE: 855 { 856 struct puffs_vnmsg_write *auxt = auxbuf; 857 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 858 859 if (pops->puffs_node_write == NULL) { 860 error = EIO; 861 break; 862 } 863 864 error = pops->puffs_node_write(pu, 865 opcookie, auxt->pvnr_data, 866 auxt->pvnr_offset, &auxt->pvnr_resid, 867 pcr, auxt->pvnr_ioflag); 868 869 /* don't need to move data back to the kernel */ 870 preq->preq_buflen = sizeof(struct puffs_vnmsg_write); 871 break; 872 } 873 874 case PUFFS_VN_POLL: 875 { 876 struct puffs_vnmsg_poll *auxt = auxbuf; 877 878 if (pops->puffs_node_poll == NULL) { 879 error = 0; 880 881 /* emulate genfs_poll() */ 882 auxt->pvnr_events &= (POLLIN | POLLOUT 883 | POLLRDNORM | POLLWRNORM); 884 885 break; 886 } 887 888 error = pops->puffs_node_poll(pu, 889 opcookie, &auxt->pvnr_events); 890 break; 891 } 892 893 default: 894 printf("inval op %d\n", preq->preq_optype); 895 error = EINVAL; 896 break; 897 } 898 899 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) { 900 struct puffs_cacheinfo *pci = (void *)preq; 901 902 if (pu->pu_ops.puffs_cache_write) { 903 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie, 904 pci->pcache_nruns, pci->pcache_runs); 905 } 906 error = 0; 907 908 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) { 909 struct puffs_error *perr = (void *)preq; 910 911 pu->pu_errnotify(pu, preq->preq_optype, 912 perr->perr_error, perr->perr_str, preq->preq_cookie); 913 error = 0; 914 } else { 915 /* 916 * I guess the kernel sees this one coming also 917 */ 918 error = EINVAL; 919 } 920 921 out: 922 preq->preq_rv = error; 923 924 if (pu->pu_oppost) 925 pu->pu_oppost(pu); 926 927 pcc->pcc_flags |= PCC_DONE; 928 } 929