1 /* $NetBSD: dispatcher.c,v 1.34 2010/05/21 10:50:52 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.34 2010/05/21 10:50:52 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_EXTATTRCTL: 234 { 235 struct puffs_vfsmsg_extattrctl *auxt = auxbuf; 236 const char *attrname; 237 int flags; 238 239 if (pops->puffs_fs_extattrctl == NULL) { 240 error = EOPNOTSUPP; 241 break; 242 } 243 244 if (auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASATTRNAME) 245 attrname = auxt->pvfsr_attrname; 246 else 247 attrname = NULL; 248 249 flags = auxt->pvfsr_flags & PUFFS_EXTATTRCTL_HASNODE; 250 error = pops->puffs_fs_extattrctl(pu, auxt->pvfsr_cmd, 251 opcookie, flags, 252 auxt->pvfsr_attrnamespace, attrname); 253 break; 254 } 255 256 default: 257 /* 258 * I guess the kernel sees this one coming 259 */ 260 error = EINVAL; 261 break; 262 } 263 264 /* XXX: audit return values */ 265 /* XXX: sync with kernel */ 266 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) { 267 switch (preq->preq_optype) { 268 case PUFFS_VN_LOOKUP: 269 { 270 struct puffs_vnmsg_lookup *auxt = auxbuf; 271 struct puffs_newinfo pni; 272 struct puffs_cn pcn; 273 274 pcn.pcn_pkcnp = &auxt->pvnr_cn; 275 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 276 pni.pni_cookie = &auxt->pvnr_newnode; 277 pni.pni_vtype = &auxt->pvnr_vtype; 278 pni.pni_size = &auxt->pvnr_size; 279 pni.pni_rdev = &auxt->pvnr_rdev; 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 struct puffs_node *pn; 296 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 break; 311 } 312 313 case PUFFS_VN_CREATE: 314 { 315 struct puffs_vnmsg_create *auxt = auxbuf; 316 struct puffs_newinfo pni; 317 struct puffs_cn pcn; 318 319 if (pops->puffs_node_create == NULL) { 320 error = 0; 321 break; 322 } 323 324 pcn.pcn_pkcnp = &auxt->pvnr_cn; 325 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 326 327 memset(&pni, 0, sizeof(pni)); 328 pni.pni_cookie = &auxt->pvnr_newnode; 329 330 if (buildpath) { 331 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 332 if (error) 333 break; 334 } 335 336 error = pops->puffs_node_create(pu, 337 opcookie, &pni, &pcn, &auxt->pvnr_va); 338 339 if (buildpath) { 340 if (error) { 341 pu->pu_pathfree(pu, &pcn.pcn_po_full); 342 } else { 343 struct puffs_node *pn; 344 345 pn = PU_CMAP(pu, auxt->pvnr_newnode); 346 pn->pn_po = pcn.pcn_po_full; 347 } 348 } 349 350 break; 351 } 352 353 case PUFFS_VN_MKNOD: 354 { 355 struct puffs_vnmsg_mknod *auxt = auxbuf; 356 struct puffs_newinfo pni; 357 struct puffs_cn pcn; 358 359 if (pops->puffs_node_mknod == NULL) { 360 error = 0; 361 break; 362 } 363 364 pcn.pcn_pkcnp = &auxt->pvnr_cn; 365 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 366 367 memset(&pni, 0, sizeof(pni)); 368 pni.pni_cookie = &auxt->pvnr_newnode; 369 370 if (buildpath) { 371 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 372 if (error) 373 break; 374 } 375 376 error = pops->puffs_node_mknod(pu, 377 opcookie, &pni, &pcn, &auxt->pvnr_va); 378 379 if (buildpath) { 380 if (error) { 381 pu->pu_pathfree(pu, &pcn.pcn_po_full); 382 } else { 383 struct puffs_node *pn; 384 385 pn = PU_CMAP(pu, auxt->pvnr_newnode); 386 pn->pn_po = pcn.pcn_po_full; 387 } 388 } 389 390 break; 391 } 392 393 case PUFFS_VN_OPEN: 394 { 395 struct puffs_vnmsg_open *auxt = auxbuf; 396 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 397 398 if (pops->puffs_node_open == NULL) { 399 error = 0; 400 break; 401 } 402 403 error = pops->puffs_node_open(pu, 404 opcookie, auxt->pvnr_mode, pcr); 405 break; 406 } 407 408 case PUFFS_VN_CLOSE: 409 { 410 struct puffs_vnmsg_close *auxt = auxbuf; 411 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 412 413 if (pops->puffs_node_close == NULL) { 414 error = 0; 415 break; 416 } 417 418 error = pops->puffs_node_close(pu, 419 opcookie, auxt->pvnr_fflag, pcr); 420 break; 421 } 422 423 case PUFFS_VN_ACCESS: 424 { 425 struct puffs_vnmsg_access *auxt = auxbuf; 426 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 427 428 if (pops->puffs_node_access == NULL) { 429 error = 0; 430 break; 431 } 432 433 error = pops->puffs_node_access(pu, 434 opcookie, auxt->pvnr_mode, pcr); 435 break; 436 } 437 438 case PUFFS_VN_GETATTR: 439 { 440 struct puffs_vnmsg_getattr *auxt = auxbuf; 441 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 442 443 if (pops->puffs_node_getattr == NULL) { 444 error = EOPNOTSUPP; 445 break; 446 } 447 448 error = pops->puffs_node_getattr(pu, 449 opcookie, &auxt->pvnr_va, pcr); 450 break; 451 } 452 453 case PUFFS_VN_SETATTR: 454 { 455 struct puffs_vnmsg_setattr *auxt = auxbuf; 456 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 457 458 if (pops->puffs_node_setattr == NULL) { 459 error = EOPNOTSUPP; 460 break; 461 } 462 463 error = pops->puffs_node_setattr(pu, 464 opcookie, &auxt->pvnr_va, pcr); 465 break; 466 } 467 468 case PUFFS_VN_MMAP: 469 { 470 struct puffs_vnmsg_mmap *auxt = auxbuf; 471 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 472 473 if (pops->puffs_node_mmap == NULL) { 474 error = 0; 475 break; 476 } 477 478 error = pops->puffs_node_mmap(pu, 479 opcookie, auxt->pvnr_prot, pcr); 480 break; 481 } 482 483 case PUFFS_VN_FSYNC: 484 { 485 struct puffs_vnmsg_fsync *auxt = auxbuf; 486 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 487 488 if (pops->puffs_node_fsync == NULL) { 489 error = 0; 490 break; 491 } 492 493 error = pops->puffs_node_fsync(pu, opcookie, pcr, 494 auxt->pvnr_flags, auxt->pvnr_offlo, 495 auxt->pvnr_offhi); 496 break; 497 } 498 499 case PUFFS_VN_SEEK: 500 { 501 struct puffs_vnmsg_seek *auxt = auxbuf; 502 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 503 504 if (pops->puffs_node_seek == NULL) { 505 error = 0; 506 break; 507 } 508 509 error = pops->puffs_node_seek(pu, 510 opcookie, auxt->pvnr_oldoff, 511 auxt->pvnr_newoff, pcr); 512 break; 513 } 514 515 case PUFFS_VN_REMOVE: 516 { 517 struct puffs_vnmsg_remove *auxt = auxbuf; 518 struct puffs_cn pcn; 519 if (pops->puffs_node_remove == NULL) { 520 error = 0; 521 break; 522 } 523 524 pcn.pcn_pkcnp = &auxt->pvnr_cn; 525 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 526 527 error = pops->puffs_node_remove(pu, 528 opcookie, auxt->pvnr_cookie_targ, &pcn); 529 break; 530 } 531 532 case PUFFS_VN_LINK: 533 { 534 struct puffs_vnmsg_link *auxt = auxbuf; 535 struct puffs_cn pcn; 536 if (pops->puffs_node_link == NULL) { 537 error = 0; 538 break; 539 } 540 541 pcn.pcn_pkcnp = &auxt->pvnr_cn; 542 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 543 544 if (buildpath) { 545 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 546 if (error) 547 break; 548 } 549 550 error = pops->puffs_node_link(pu, 551 opcookie, auxt->pvnr_cookie_targ, &pcn); 552 if (buildpath) 553 pu->pu_pathfree(pu, &pcn.pcn_po_full); 554 555 break; 556 } 557 558 case PUFFS_VN_RENAME: 559 { 560 struct puffs_vnmsg_rename *auxt = auxbuf; 561 struct puffs_cn pcn_src, pcn_targ; 562 struct puffs_node *pn_src; 563 564 if (pops->puffs_node_rename == NULL) { 565 error = 0; 566 break; 567 } 568 569 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src; 570 PUFFS_KCREDTOCRED(pcn_src.pcn_cred, 571 &auxt->pvnr_cn_src_cred); 572 573 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ; 574 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred, 575 &auxt->pvnr_cn_targ_cred); 576 577 if (buildpath) { 578 pn_src = auxt->pvnr_cookie_src; 579 pcn_src.pcn_po_full = pn_src->pn_po; 580 581 error = puffs_path_pcnbuild(pu, &pcn_targ, 582 auxt->pvnr_cookie_targdir); 583 if (error) 584 break; 585 } 586 587 error = pops->puffs_node_rename(pu, 588 opcookie, auxt->pvnr_cookie_src, 589 &pcn_src, auxt->pvnr_cookie_targdir, 590 auxt->pvnr_cookie_targ, &pcn_targ); 591 592 if (buildpath) { 593 if (error) { 594 pu->pu_pathfree(pu, 595 &pcn_targ.pcn_po_full); 596 } else { 597 struct puffs_pathinfo pi; 598 struct puffs_pathobj po_old; 599 600 /* handle this node */ 601 po_old = pn_src->pn_po; 602 pn_src->pn_po = pcn_targ.pcn_po_full; 603 604 if (pn_src->pn_va.va_type != VDIR) { 605 pu->pu_pathfree(pu, &po_old); 606 break; 607 } 608 609 /* handle all child nodes for DIRs */ 610 pi.pi_old = &pcn_src.pcn_po_full; 611 pi.pi_new = &pcn_targ.pcn_po_full; 612 613 PU_LOCK(); 614 if (puffs_pn_nodewalk(pu, 615 puffs_path_prefixadj, &pi) != NULL) 616 error = ENOMEM; 617 PU_UNLOCK(); 618 pu->pu_pathfree(pu, &po_old); 619 } 620 } 621 break; 622 } 623 624 case PUFFS_VN_MKDIR: 625 { 626 struct puffs_vnmsg_mkdir *auxt = auxbuf; 627 struct puffs_newinfo pni; 628 struct puffs_cn pcn; 629 630 if (pops->puffs_node_mkdir == NULL) { 631 error = 0; 632 break; 633 } 634 635 pcn.pcn_pkcnp = &auxt->pvnr_cn; 636 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 637 638 memset(&pni, 0, sizeof(pni)); 639 pni.pni_cookie = &auxt->pvnr_newnode; 640 641 if (buildpath) { 642 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 643 if (error) 644 break; 645 } 646 647 error = pops->puffs_node_mkdir(pu, 648 opcookie, &pni, &pcn, &auxt->pvnr_va); 649 650 if (buildpath) { 651 if (error) { 652 pu->pu_pathfree(pu, &pcn.pcn_po_full); 653 } else { 654 struct puffs_node *pn; 655 656 pn = PU_CMAP(pu, auxt->pvnr_newnode); 657 pn->pn_po = pcn.pcn_po_full; 658 } 659 } 660 661 break; 662 } 663 664 case PUFFS_VN_RMDIR: 665 { 666 struct puffs_vnmsg_rmdir *auxt = auxbuf; 667 struct puffs_cn pcn; 668 if (pops->puffs_node_rmdir == NULL) { 669 error = 0; 670 break; 671 } 672 673 pcn.pcn_pkcnp = &auxt->pvnr_cn; 674 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 675 676 error = pops->puffs_node_rmdir(pu, 677 opcookie, auxt->pvnr_cookie_targ, &pcn); 678 break; 679 } 680 681 case PUFFS_VN_SYMLINK: 682 { 683 struct puffs_vnmsg_symlink *auxt = auxbuf; 684 struct puffs_newinfo pni; 685 struct puffs_cn pcn; 686 687 if (pops->puffs_node_symlink == NULL) { 688 error = 0; 689 break; 690 } 691 692 pcn.pcn_pkcnp = &auxt->pvnr_cn; 693 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 694 695 memset(&pni, 0, sizeof(pni)); 696 pni.pni_cookie = &auxt->pvnr_newnode; 697 698 if (buildpath) { 699 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 700 if (error) 701 break; 702 } 703 704 error = pops->puffs_node_symlink(pu, 705 opcookie, &pni, &pcn, 706 &auxt->pvnr_va, auxt->pvnr_link); 707 708 if (buildpath) { 709 if (error) { 710 pu->pu_pathfree(pu, &pcn.pcn_po_full); 711 } else { 712 struct puffs_node *pn; 713 714 pn = PU_CMAP(pu, auxt->pvnr_newnode); 715 pn->pn_po = pcn.pcn_po_full; 716 } 717 } 718 719 break; 720 } 721 722 case PUFFS_VN_READDIR: 723 { 724 struct puffs_vnmsg_readdir *auxt = auxbuf; 725 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 726 struct dirent *dent; 727 off_t *cookies; 728 size_t res, origcookies; 729 730 if (pops->puffs_node_readdir == NULL) { 731 error = 0; 732 break; 733 } 734 735 if (auxt->pvnr_ncookies) { 736 /* LINTED: pvnr_data is __aligned() */ 737 cookies = (off_t *)auxt->pvnr_data; 738 origcookies = auxt->pvnr_ncookies; 739 } else { 740 cookies = NULL; 741 origcookies = 0; 742 } 743 /* LINTED: dentoff is aligned in the kernel */ 744 dent = (struct dirent *) 745 (auxt->pvnr_data + auxt->pvnr_dentoff); 746 747 res = auxt->pvnr_resid; 748 error = pops->puffs_node_readdir(pu, 749 opcookie, dent, &auxt->pvnr_offset, 750 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag, 751 cookies, &auxt->pvnr_ncookies); 752 753 /* much easier to track non-working NFS */ 754 assert(auxt->pvnr_ncookies <= origcookies); 755 756 /* need to move a bit more */ 757 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir) 758 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid); 759 break; 760 } 761 762 case PUFFS_VN_READLINK: 763 { 764 struct puffs_vnmsg_readlink *auxt = auxbuf; 765 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 766 767 if (pops->puffs_node_readlink == NULL) { 768 error = EOPNOTSUPP; 769 break; 770 } 771 772 /*LINTED*/ 773 error = pops->puffs_node_readlink(pu, opcookie, pcr, 774 auxt->pvnr_link, &auxt->pvnr_linklen); 775 break; 776 } 777 778 case PUFFS_VN_RECLAIM: 779 { 780 781 if (pops->puffs_node_reclaim == NULL) { 782 error = 0; 783 break; 784 } 785 786 error = pops->puffs_node_reclaim(pu, opcookie); 787 break; 788 } 789 790 case PUFFS_VN_INACTIVE: 791 { 792 793 if (pops->puffs_node_inactive == NULL) { 794 error = EOPNOTSUPP; 795 break; 796 } 797 798 error = pops->puffs_node_inactive(pu, opcookie); 799 break; 800 } 801 802 case PUFFS_VN_PATHCONF: 803 { 804 struct puffs_vnmsg_pathconf *auxt = auxbuf; 805 if (pops->puffs_node_pathconf == NULL) { 806 error = 0; 807 break; 808 } 809 810 error = pops->puffs_node_pathconf(pu, 811 opcookie, auxt->pvnr_name, 812 &auxt->pvnr_retval); 813 break; 814 } 815 816 case PUFFS_VN_ADVLOCK: 817 { 818 struct puffs_vnmsg_advlock *auxt = auxbuf; 819 if (pops->puffs_node_advlock == NULL) { 820 error = 0; 821 break; 822 } 823 824 error = pops->puffs_node_advlock(pu, 825 opcookie, auxt->pvnr_id, auxt->pvnr_op, 826 &auxt->pvnr_fl, auxt->pvnr_flags); 827 break; 828 } 829 830 case PUFFS_VN_PRINT: 831 { 832 if (pops->puffs_node_print == NULL) { 833 error = 0; 834 break; 835 } 836 837 error = pops->puffs_node_print(pu, 838 opcookie); 839 break; 840 } 841 842 case PUFFS_VN_ABORTOP: 843 { 844 struct puffs_vnmsg_abortop *auxt = auxbuf; 845 struct puffs_cn pcn; 846 847 if (pops->puffs_node_abortop == NULL) { 848 error = 0; 849 break; 850 } 851 852 pcn.pcn_pkcnp = &auxt->pvnr_cn; 853 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 854 855 error = pops->puffs_node_abortop(pu, opcookie, &pcn); 856 857 break; 858 } 859 860 case PUFFS_VN_READ: 861 { 862 struct puffs_vnmsg_read *auxt = auxbuf; 863 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 864 size_t res; 865 866 if (pops->puffs_node_read == NULL) { 867 error = EIO; 868 break; 869 } 870 871 res = auxt->pvnr_resid; 872 error = pops->puffs_node_read(pu, 873 opcookie, auxt->pvnr_data, 874 auxt->pvnr_offset, &auxt->pvnr_resid, 875 pcr, auxt->pvnr_ioflag); 876 877 /* need to move a bit more */ 878 preq->preq_buflen = sizeof(struct puffs_vnmsg_read) 879 + (res - auxt->pvnr_resid); 880 break; 881 } 882 883 case PUFFS_VN_WRITE: 884 { 885 struct puffs_vnmsg_write *auxt = auxbuf; 886 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 887 888 if (pops->puffs_node_write == NULL) { 889 error = EIO; 890 break; 891 } 892 893 error = pops->puffs_node_write(pu, 894 opcookie, auxt->pvnr_data, 895 auxt->pvnr_offset, &auxt->pvnr_resid, 896 pcr, auxt->pvnr_ioflag); 897 898 /* don't need to move data back to the kernel */ 899 preq->preq_buflen = sizeof(struct puffs_vnmsg_write); 900 break; 901 } 902 903 case PUFFS_VN_POLL: 904 { 905 struct puffs_vnmsg_poll *auxt = auxbuf; 906 907 if (pops->puffs_node_poll == NULL) { 908 error = 0; 909 910 /* emulate genfs_poll() */ 911 auxt->pvnr_events &= (POLLIN | POLLOUT 912 | POLLRDNORM | POLLWRNORM); 913 914 break; 915 } 916 917 error = pops->puffs_node_poll(pu, 918 opcookie, &auxt->pvnr_events); 919 break; 920 } 921 922 case PUFFS_VN_GETEXTATTR: 923 { 924 struct puffs_vnmsg_getextattr *auxt = auxbuf; 925 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 926 size_t res, *resp, *sizep; 927 uint8_t *data; 928 929 if (pops->puffs_node_getextattr == NULL) { 930 error = EOPNOTSUPP; 931 break; 932 } 933 934 if (auxt->pvnr_datasize) 935 sizep = &auxt->pvnr_datasize; 936 else 937 sizep = NULL; 938 939 res = auxt->pvnr_resid; 940 if (res > 0) { 941 data = auxt->pvnr_data; 942 resp = &auxt->pvnr_resid; 943 } else { 944 data = NULL; 945 resp = NULL; 946 } 947 948 error = pops->puffs_node_getextattr(pu, 949 opcookie, auxt->pvnr_attrnamespace, 950 auxt->pvnr_attrname, sizep, data, resp, pcr); 951 952 /* need to move a bit more? */ 953 preq->preq_buflen = 954 sizeof(struct puffs_vnmsg_getextattr) 955 + (res - auxt->pvnr_resid); 956 break; 957 } 958 959 case PUFFS_VN_SETEXTATTR: 960 { 961 struct puffs_vnmsg_setextattr *auxt = auxbuf; 962 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 963 size_t *resp; 964 uint8_t *data; 965 966 if (pops->puffs_node_setextattr == NULL) { 967 error = EOPNOTSUPP; 968 break; 969 } 970 971 if (auxt->pvnr_resid > 0) { 972 data = auxt->pvnr_data; 973 resp = &auxt->pvnr_resid; 974 } else { 975 data = NULL; 976 resp = NULL; 977 } 978 979 error = pops->puffs_node_setextattr(pu, 980 opcookie, auxt->pvnr_attrnamespace, 981 auxt->pvnr_attrname, data, resp, pcr); 982 break; 983 } 984 985 case PUFFS_VN_LISTEXTATTR: 986 { 987 struct puffs_vnmsg_listextattr *auxt = auxbuf; 988 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 989 size_t res, *resp, *sizep; 990 uint8_t *data; 991 992 if (pops->puffs_node_listextattr == NULL) { 993 error = EOPNOTSUPP; 994 break; 995 } 996 997 if (auxt->pvnr_datasize) 998 sizep = &auxt->pvnr_datasize; 999 else 1000 sizep = NULL; 1001 1002 res = auxt->pvnr_resid; 1003 if (res > 0) { 1004 data = auxt->pvnr_data; 1005 resp = &auxt->pvnr_resid; 1006 } else { 1007 data = NULL; 1008 resp = NULL; 1009 } 1010 1011 res = auxt->pvnr_resid; 1012 error = pops->puffs_node_listextattr(pu, 1013 opcookie, auxt->pvnr_attrnamespace, 1014 sizep, data, resp, pcr); 1015 1016 /* need to move a bit more? */ 1017 preq->preq_buflen = 1018 sizeof(struct puffs_vnmsg_listextattr) 1019 + (res - auxt->pvnr_resid); 1020 break; 1021 } 1022 1023 case PUFFS_VN_DELETEEXTATTR: 1024 { 1025 struct puffs_vnmsg_deleteextattr *auxt = auxbuf; 1026 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 1027 1028 if (pops->puffs_node_deleteextattr == NULL) { 1029 error = EOPNOTSUPP; 1030 break; 1031 } 1032 1033 error = pops->puffs_node_deleteextattr(pu, 1034 opcookie, auxt->pvnr_attrnamespace, 1035 auxt->pvnr_attrname, pcr); 1036 break; 1037 } 1038 1039 default: 1040 printf("inval op %d\n", preq->preq_optype); 1041 error = EINVAL; 1042 break; 1043 } 1044 1045 #if 0 1046 /* not issued by kernel currently */ 1047 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) { 1048 struct puffs_cacheinfo *pci = (void *)preq; 1049 1050 if (pu->pu_ops.puffs_cache_write) { 1051 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie, 1052 pci->pcache_nruns, pci->pcache_runs); 1053 } 1054 error = 0; 1055 #endif 1056 1057 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) { 1058 struct puffs_error *perr = (void *)preq; 1059 1060 pu->pu_errnotify(pu, preq->preq_optype, 1061 perr->perr_error, perr->perr_str, preq->preq_cookie); 1062 error = 0; 1063 } else { 1064 /* 1065 * I guess the kernel sees this one coming also 1066 */ 1067 error = EINVAL; 1068 } 1069 1070 out: 1071 preq->preq_rv = error; 1072 1073 if (pu->pu_oppost) 1074 pu->pu_oppost(pu); 1075 1076 pcc->pcc_flags |= PCC_DONE; 1077 } 1078