1 /* $NetBSD: dispatcher.c,v 1.26 2007/12/08 19:57:03 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Ulla Tuominen Foundation and the Finnish Cultural Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 #if !defined(lint) 33 __RCSID("$NetBSD: dispatcher.c,v 1.26 2007/12/08 19:57:03 pooka Exp $"); 34 #endif /* !lint */ 35 36 #include <sys/types.h> 37 #include <sys/poll.h> 38 39 #include <assert.h> 40 #include <errno.h> 41 #ifdef PUFFS_WITH_THREADS 42 #include <pthread.h> 43 #endif 44 #include <puffs.h> 45 #include <puffsdump.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <unistd.h> 49 50 #include "puffs_priv.h" 51 52 static void processresult(struct puffs_cc *, int); 53 54 /* 55 * Set the following to 1 to not handle each request on a separate 56 * stack. This is highly volatile kludge, therefore no external 57 * interface. 58 */ 59 int puffs_fakecc; 60 61 /* 62 * Set the following to 1 to handle each request in a separate pthread. 63 * This is not exported as it should not be used yet unless having a 64 * very good knowledge of what you're signing up for (libpuffs is not 65 * threadsafe). 66 */ 67 int puffs_usethreads; 68 69 static int 70 dopufbuf2(struct puffs_usermount *pu, struct puffs_framebuf *pb) 71 { 72 struct puffs_req *preq = puffs__framebuf_getdataptr(pb); 73 struct puffs_cc *pcc; 74 int type; 75 76 if (puffs_fakecc) { 77 type = PCC_FAKECC; 78 } else if (puffs_usethreads) { 79 type = PCC_THREADED; 80 #ifndef PUFFS_WITH_THREADS 81 type = PCC_FAKECC; 82 #endif 83 } else { 84 type = PCC_REALCC; 85 } 86 87 if (puffs_cc_create(pu, pb, type, &pcc) == -1) 88 return errno; 89 90 puffs_cc_setcaller(pcc, preq->preq_pid, preq->preq_lid); 91 92 #ifdef PUFFS_WITH_THREADS 93 if (puffs_usethreads) { 94 pthread_attr_t pattr; 95 pthread_t ptid; 96 int rv; 97 98 pthread_attr_init(&pattr); 99 pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED); 100 pthread_attr_destroy(&pattr); 101 102 ap->pwa_pcc = pcc; 103 104 rv = pthread_create(&ptid, &pattr, puffs_docc, pcc); 105 106 return rv; 107 } 108 #endif 109 puffs_docc(pcc); 110 return 0; 111 } 112 113 /* 114 * User-visible point to handle a request from. 115 * 116 * <insert text here> 117 */ 118 int 119 puffs_dopufbuf(struct puffs_usermount *pu, struct puffs_framebuf *pb) 120 { 121 struct puffs_req *preq = puffs__framebuf_getdataptr(pb); 122 struct puffs_executor *pex; 123 124 /* 125 * XXX: the structure is currently a mess. anyway, trap 126 * the cacheops here already, since they don't need a cc. 127 * I really should get around to revamping the operation 128 * dispatching code one of these days. 129 * 130 * Do the same for error notifications. 131 */ 132 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) { 133 struct puffs_cacheinfo *pci = (void *)preq; 134 135 if (pu->pu_ops.puffs_cache_write == NULL) 136 return 0; 137 138 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie, 139 pci->pcache_nruns, pci->pcache_runs); 140 return 0; 141 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) { 142 struct puffs_error *perr = (void *)preq; 143 144 pu->pu_errnotify(pu, preq->preq_optype, 145 perr->perr_error, perr->perr_str, preq->preq_cookie); 146 return 0; 147 } 148 149 if (pu->pu_flags & PUFFS_FLAG_OPDUMP) 150 puffsdump_req(preq); 151 152 /* 153 * Check if we are already processing an operation from the same 154 * caller. If so, queue this operation until the previous one 155 * finishes. This prevents us from executing certain operations 156 * out-of-order (e.g. fsync and reclaim). 157 * 158 * Each preq will only remove its own pex from the tailq. 159 * See puffs_docc() for the details on other-end removal 160 * and dispatching. 161 */ 162 pex = malloc(sizeof(struct puffs_executor)); 163 pex->pex_pufbuf = pb; 164 PU_LOCK(); 165 TAILQ_INSERT_TAIL(&pu->pu_exq, pex, pex_entries); 166 TAILQ_FOREACH(pex, &pu->pu_exq, pex_entries) { 167 struct puffs_req *pb_preq; 168 169 pb_preq = puffs__framebuf_getdataptr(pex->pex_pufbuf); 170 if (pb_preq->preq_pid == preq->preq_pid 171 && pb_preq->preq_lid == preq->preq_lid) { 172 if (pb_preq != preq) { 173 PU_UNLOCK(); 174 return 0; 175 } 176 } 177 } 178 PU_UNLOCK(); 179 180 return dopufbuf2(pu, pb); 181 } 182 183 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN}; 184 185 void * 186 puffs_docc(void *arg) 187 { 188 struct puffs_cc *pcc = arg; 189 struct puffs_usermount *pu = pcc->pcc_pu; 190 struct puffs_req *preq; 191 struct puffs_cc *pcc_iter; 192 struct puffs_executor *pex, *pex_n; 193 int found; 194 195 assert((pcc->pcc_flags & PCC_DONE) == 0); 196 197 if (pcc->pcc_flags & PCC_REALCC) 198 puffs_cc_continue(pcc); 199 else 200 puffs_calldispatcher(pcc); 201 202 if ((pcc->pcc_flags & PCC_DONE) == 0) { 203 assert(pcc->pcc_flags & PCC_REALCC); 204 return NULL; 205 } 206 207 /* check if we need to schedule FAFs which were stalled */ 208 found = 0; 209 preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 210 PU_LOCK(); 211 for (pex = TAILQ_FIRST(&pu->pu_exq); pex; pex = pex_n) { 212 struct puffs_req *pb_preq; 213 214 pb_preq = puffs__framebuf_getdataptr(pex->pex_pufbuf); 215 pex_n = TAILQ_NEXT(pex, pex_entries); 216 if (pb_preq->preq_pid == preq->preq_pid 217 && pb_preq->preq_lid == preq->preq_lid) { 218 if (found == 0) { 219 /* this is us */ 220 assert(pb_preq == preq); 221 TAILQ_REMOVE(&pu->pu_exq, pex, pex_entries); 222 free(pex); 223 found = 1; 224 } else { 225 /* down at the mardi gras */ 226 PU_UNLOCK(); 227 dopufbuf2(pu, pex->pex_pufbuf); 228 PU_LOCK(); 229 break; 230 } 231 } 232 } 233 234 if (!PUFFSOP_WANTREPLY(preq->preq_opclass)) 235 puffs_framebuf_destroy(pcc->pcc_pb); 236 237 /* can't do this above due to PCC_BORROWED */ 238 while ((pcc_iter = LIST_FIRST(&pu->pu_ccnukelst)) != NULL) { 239 LIST_REMOVE(pcc_iter, nlst_entries); 240 puffs_cc_destroy(pcc_iter); 241 } 242 PU_UNLOCK(); 243 244 return NULL; 245 } 246 247 /* library private, but linked from callcontext.c */ 248 249 void 250 puffs_calldispatcher(struct puffs_cc *pcc) 251 { 252 struct puffs_usermount *pu = pcc->pcc_pu; 253 struct puffs_ops *pops = &pu->pu_ops; 254 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 255 void *auxbuf = preq; /* help with typecasting */ 256 void *opcookie = preq->preq_cookie; 257 int error, rv, buildpath; 258 259 assert(pcc->pcc_flags & (PCC_FAKECC | PCC_REALCC | PCC_THREADED)); 260 assert(pcc == puffs_cc_getcc(pu)); /* remove me soon */ 261 262 if (PUFFSOP_WANTREPLY(preq->preq_opclass)) 263 rv = PUFFCALL_ANSWER; 264 else 265 rv = PUFFCALL_IGNORE; 266 267 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH; 268 preq->preq_setbacks = 0; 269 270 if (pu->pu_oppre) 271 pu->pu_oppre(pu); 272 273 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) { 274 switch (preq->preq_optype) { 275 case PUFFS_VFS_UNMOUNT: 276 { 277 struct puffs_vfsmsg_unmount *auxt = auxbuf; 278 279 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTING); 280 error = pops->puffs_fs_unmount(pu, auxt->pvfsr_flags); 281 if (!error) 282 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED); 283 else 284 PU_SETSTATE(pu, PUFFS_STATE_RUNNING); 285 break; 286 } 287 288 case PUFFS_VFS_STATVFS: 289 { 290 struct puffs_vfsmsg_statvfs *auxt = auxbuf; 291 292 error = pops->puffs_fs_statvfs(pu, &auxt->pvfsr_sb); 293 break; 294 } 295 296 case PUFFS_VFS_SYNC: 297 { 298 struct puffs_vfsmsg_sync *auxt = auxbuf; 299 PUFFS_MAKECRED(pcr, &auxt->pvfsr_cred); 300 301 error = pops->puffs_fs_sync(pu, 302 auxt->pvfsr_waitfor, pcr); 303 break; 304 } 305 306 case PUFFS_VFS_FHTOVP: 307 { 308 struct puffs_vfsmsg_fhtonode *auxt = auxbuf; 309 struct puffs_newinfo pni; 310 311 pni.pni_cookie = &auxt->pvfsr_fhcookie; 312 pni.pni_vtype = &auxt->pvfsr_vtype; 313 pni.pni_size = &auxt->pvfsr_size; 314 pni.pni_rdev = &auxt->pvfsr_rdev; 315 316 error = pops->puffs_fs_fhtonode(pu, auxt->pvfsr_data, 317 auxt->pvfsr_dsize, &pni); 318 319 break; 320 } 321 322 case PUFFS_VFS_VPTOFH: 323 { 324 struct puffs_vfsmsg_nodetofh *auxt = auxbuf; 325 326 error = pops->puffs_fs_nodetofh(pu, 327 auxt->pvfsr_fhcookie, auxt->pvfsr_data, 328 &auxt->pvfsr_dsize); 329 330 break; 331 } 332 333 case PUFFS_VFS_SUSPEND: 334 { 335 struct puffs_vfsmsg_suspend *auxt = auxbuf; 336 337 error = 0; 338 if (pops->puffs_fs_suspend == NULL) 339 break; 340 341 pops->puffs_fs_suspend(pu, auxt->pvfsr_status); 342 break; 343 } 344 345 default: 346 /* 347 * I guess the kernel sees this one coming 348 */ 349 error = EINVAL; 350 break; 351 } 352 353 /* XXX: audit return values */ 354 /* XXX: sync with kernel */ 355 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) { 356 switch (preq->preq_optype) { 357 case PUFFS_VN_LOOKUP: 358 { 359 struct puffs_vnmsg_lookup *auxt = auxbuf; 360 struct puffs_newinfo pni; 361 struct puffs_cn pcn; 362 363 pcn.pcn_pkcnp = &auxt->pvnr_cn; 364 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 365 pni.pni_cookie = &auxt->pvnr_newnode; 366 pni.pni_vtype = &auxt->pvnr_vtype; 367 pni.pni_size = &auxt->pvnr_size; 368 pni.pni_rdev = &auxt->pvnr_rdev; 369 370 if (buildpath) { 371 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 372 if (error) 373 break; 374 } 375 376 /* lookup *must* be present */ 377 error = pops->puffs_node_lookup(pu, opcookie, 378 &pni, &pcn); 379 380 if (buildpath) { 381 if (error) { 382 pu->pu_pathfree(pu, &pcn.pcn_po_full); 383 } else { 384 struct puffs_node *pn; 385 386 /* 387 * did we get a new node or a 388 * recycled node? 389 */ 390 pn = PU_CMAP(pu, auxt->pvnr_newnode); 391 if (pn->pn_po.po_path == NULL) 392 pn->pn_po = pcn.pcn_po_full; 393 else 394 pu->pu_pathfree(pu, 395 &pcn.pcn_po_full); 396 } 397 } 398 399 break; 400 } 401 402 case PUFFS_VN_CREATE: 403 { 404 struct puffs_vnmsg_create *auxt = auxbuf; 405 struct puffs_newinfo pni; 406 struct puffs_cn pcn; 407 408 if (pops->puffs_node_create == NULL) { 409 error = 0; 410 break; 411 } 412 413 pcn.pcn_pkcnp = &auxt->pvnr_cn; 414 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 415 416 memset(&pni, 0, sizeof(pni)); 417 pni.pni_cookie = &auxt->pvnr_newnode; 418 419 if (buildpath) { 420 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 421 if (error) 422 break; 423 } 424 425 error = pops->puffs_node_create(pu, 426 opcookie, &pni, &pcn, &auxt->pvnr_va); 427 428 if (buildpath) { 429 if (error) { 430 pu->pu_pathfree(pu, &pcn.pcn_po_full); 431 } else { 432 struct puffs_node *pn; 433 434 pn = PU_CMAP(pu, auxt->pvnr_newnode); 435 pn->pn_po = pcn.pcn_po_full; 436 } 437 } 438 439 break; 440 } 441 442 case PUFFS_VN_MKNOD: 443 { 444 struct puffs_vnmsg_mknod *auxt = auxbuf; 445 struct puffs_newinfo pni; 446 struct puffs_cn pcn; 447 448 if (pops->puffs_node_mknod == NULL) { 449 error = 0; 450 break; 451 } 452 453 pcn.pcn_pkcnp = &auxt->pvnr_cn; 454 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 455 456 memset(&pni, 0, sizeof(pni)); 457 pni.pni_cookie = &auxt->pvnr_newnode; 458 459 if (buildpath) { 460 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 461 if (error) 462 break; 463 } 464 465 error = pops->puffs_node_mknod(pu, 466 opcookie, &pni, &pcn, &auxt->pvnr_va); 467 468 if (buildpath) { 469 if (error) { 470 pu->pu_pathfree(pu, &pcn.pcn_po_full); 471 } else { 472 struct puffs_node *pn; 473 474 pn = PU_CMAP(pu, auxt->pvnr_newnode); 475 pn->pn_po = pcn.pcn_po_full; 476 } 477 } 478 479 break; 480 } 481 482 case PUFFS_VN_OPEN: 483 { 484 struct puffs_vnmsg_open *auxt = auxbuf; 485 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 486 487 if (pops->puffs_node_open == NULL) { 488 error = 0; 489 break; 490 } 491 492 error = pops->puffs_node_open(pu, 493 opcookie, auxt->pvnr_mode, pcr); 494 break; 495 } 496 497 case PUFFS_VN_CLOSE: 498 { 499 struct puffs_vnmsg_close *auxt = auxbuf; 500 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 501 502 if (pops->puffs_node_close == NULL) { 503 error = 0; 504 break; 505 } 506 507 error = pops->puffs_node_close(pu, 508 opcookie, auxt->pvnr_fflag, pcr); 509 break; 510 } 511 512 case PUFFS_VN_ACCESS: 513 { 514 struct puffs_vnmsg_access *auxt = auxbuf; 515 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 516 517 if (pops->puffs_node_access == NULL) { 518 error = 0; 519 break; 520 } 521 522 error = pops->puffs_node_access(pu, 523 opcookie, auxt->pvnr_mode, pcr); 524 break; 525 } 526 527 case PUFFS_VN_GETATTR: 528 { 529 struct puffs_vnmsg_getattr *auxt = auxbuf; 530 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 531 532 if (pops->puffs_node_getattr == NULL) { 533 error = EOPNOTSUPP; 534 break; 535 } 536 537 error = pops->puffs_node_getattr(pu, 538 opcookie, &auxt->pvnr_va, pcr); 539 break; 540 } 541 542 case PUFFS_VN_SETATTR: 543 { 544 struct puffs_vnmsg_setattr *auxt = auxbuf; 545 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 546 547 if (pops->puffs_node_setattr == NULL) { 548 error = EOPNOTSUPP; 549 break; 550 } 551 552 error = pops->puffs_node_setattr(pu, 553 opcookie, &auxt->pvnr_va, pcr); 554 break; 555 } 556 557 case PUFFS_VN_MMAP: 558 { 559 struct puffs_vnmsg_mmap *auxt = auxbuf; 560 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 561 562 if (pops->puffs_node_mmap == NULL) { 563 error = 0; 564 break; 565 } 566 567 error = pops->puffs_node_mmap(pu, 568 opcookie, auxt->pvnr_prot, pcr); 569 break; 570 } 571 572 case PUFFS_VN_FSYNC: 573 { 574 struct puffs_vnmsg_fsync *auxt = auxbuf; 575 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 576 577 if (pops->puffs_node_fsync == NULL) { 578 error = 0; 579 break; 580 } 581 582 error = pops->puffs_node_fsync(pu, opcookie, pcr, 583 auxt->pvnr_flags, auxt->pvnr_offlo, 584 auxt->pvnr_offhi); 585 break; 586 } 587 588 case PUFFS_VN_SEEK: 589 { 590 struct puffs_vnmsg_seek *auxt = auxbuf; 591 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 592 593 if (pops->puffs_node_seek == NULL) { 594 error = 0; 595 break; 596 } 597 598 error = pops->puffs_node_seek(pu, 599 opcookie, auxt->pvnr_oldoff, 600 auxt->pvnr_newoff, pcr); 601 break; 602 } 603 604 case PUFFS_VN_REMOVE: 605 { 606 struct puffs_vnmsg_remove *auxt = auxbuf; 607 struct puffs_cn pcn; 608 if (pops->puffs_node_remove == NULL) { 609 error = 0; 610 break; 611 } 612 613 pcn.pcn_pkcnp = &auxt->pvnr_cn; 614 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 615 616 error = pops->puffs_node_remove(pu, 617 opcookie, auxt->pvnr_cookie_targ, &pcn); 618 break; 619 } 620 621 case PUFFS_VN_LINK: 622 { 623 struct puffs_vnmsg_link *auxt = auxbuf; 624 struct puffs_cn pcn; 625 if (pops->puffs_node_link == NULL) { 626 error = 0; 627 break; 628 } 629 630 pcn.pcn_pkcnp = &auxt->pvnr_cn; 631 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 632 633 if (buildpath) { 634 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 635 if (error) 636 break; 637 } 638 639 error = pops->puffs_node_link(pu, 640 opcookie, auxt->pvnr_cookie_targ, &pcn); 641 if (buildpath) 642 pu->pu_pathfree(pu, &pcn.pcn_po_full); 643 644 break; 645 } 646 647 case PUFFS_VN_RENAME: 648 { 649 struct puffs_vnmsg_rename *auxt = auxbuf; 650 struct puffs_cn pcn_src, pcn_targ; 651 struct puffs_node *pn_src; 652 653 if (pops->puffs_node_rename == NULL) { 654 error = 0; 655 break; 656 } 657 658 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src; 659 PUFFS_KCREDTOCRED(pcn_src.pcn_cred, 660 &auxt->pvnr_cn_src_cred); 661 662 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ; 663 PUFFS_KCREDTOCRED(pcn_targ.pcn_cred, 664 &auxt->pvnr_cn_targ_cred); 665 666 if (buildpath) { 667 pn_src = auxt->pvnr_cookie_src; 668 pcn_src.pcn_po_full = pn_src->pn_po; 669 670 error = puffs_path_pcnbuild(pu, &pcn_targ, 671 auxt->pvnr_cookie_targdir); 672 if (error) 673 break; 674 } 675 676 error = pops->puffs_node_rename(pu, 677 opcookie, auxt->pvnr_cookie_src, 678 &pcn_src, auxt->pvnr_cookie_targdir, 679 auxt->pvnr_cookie_targ, &pcn_targ); 680 681 if (buildpath) { 682 if (error) { 683 pu->pu_pathfree(pu, 684 &pcn_targ.pcn_po_full); 685 } else { 686 struct puffs_pathinfo pi; 687 struct puffs_pathobj po_old; 688 689 /* handle this node */ 690 po_old = pn_src->pn_po; 691 pn_src->pn_po = pcn_targ.pcn_po_full; 692 693 if (pn_src->pn_va.va_type != VDIR) { 694 pu->pu_pathfree(pu, &po_old); 695 break; 696 } 697 698 /* handle all child nodes for DIRs */ 699 pi.pi_old = &pcn_src.pcn_po_full; 700 pi.pi_new = &pcn_targ.pcn_po_full; 701 702 PU_LOCK(); 703 if (puffs_pn_nodewalk(pu, 704 puffs_path_prefixadj, &pi) != NULL) 705 error = ENOMEM; 706 PU_UNLOCK(); 707 pu->pu_pathfree(pu, &po_old); 708 } 709 } 710 break; 711 } 712 713 case PUFFS_VN_MKDIR: 714 { 715 struct puffs_vnmsg_mkdir *auxt = auxbuf; 716 struct puffs_newinfo pni; 717 struct puffs_cn pcn; 718 719 if (pops->puffs_node_mkdir == NULL) { 720 error = 0; 721 break; 722 } 723 724 pcn.pcn_pkcnp = &auxt->pvnr_cn; 725 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 726 727 memset(&pni, 0, sizeof(pni)); 728 pni.pni_cookie = &auxt->pvnr_newnode; 729 730 if (buildpath) { 731 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 732 if (error) 733 break; 734 } 735 736 error = pops->puffs_node_mkdir(pu, 737 opcookie, &pni, &pcn, &auxt->pvnr_va); 738 739 if (buildpath) { 740 if (error) { 741 pu->pu_pathfree(pu, &pcn.pcn_po_full); 742 } else { 743 struct puffs_node *pn; 744 745 pn = PU_CMAP(pu, auxt->pvnr_newnode); 746 pn->pn_po = pcn.pcn_po_full; 747 } 748 } 749 750 break; 751 } 752 753 case PUFFS_VN_RMDIR: 754 { 755 struct puffs_vnmsg_rmdir *auxt = auxbuf; 756 struct puffs_cn pcn; 757 if (pops->puffs_node_rmdir == NULL) { 758 error = 0; 759 break; 760 } 761 762 pcn.pcn_pkcnp = &auxt->pvnr_cn; 763 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 764 765 error = pops->puffs_node_rmdir(pu, 766 opcookie, auxt->pvnr_cookie_targ, &pcn); 767 break; 768 } 769 770 case PUFFS_VN_SYMLINK: 771 { 772 struct puffs_vnmsg_symlink *auxt = auxbuf; 773 struct puffs_newinfo pni; 774 struct puffs_cn pcn; 775 776 if (pops->puffs_node_symlink == NULL) { 777 error = 0; 778 break; 779 } 780 781 pcn.pcn_pkcnp = &auxt->pvnr_cn; 782 PUFFS_KCREDTOCRED(pcn.pcn_cred, &auxt->pvnr_cn_cred); 783 784 memset(&pni, 0, sizeof(pni)); 785 pni.pni_cookie = &auxt->pvnr_newnode; 786 787 if (buildpath) { 788 error = puffs_path_pcnbuild(pu, &pcn, opcookie); 789 if (error) 790 break; 791 } 792 793 error = pops->puffs_node_symlink(pu, 794 opcookie, &pni, &pcn, 795 &auxt->pvnr_va, auxt->pvnr_link); 796 797 if (buildpath) { 798 if (error) { 799 pu->pu_pathfree(pu, &pcn.pcn_po_full); 800 } else { 801 struct puffs_node *pn; 802 803 pn = PU_CMAP(pu, auxt->pvnr_newnode); 804 pn->pn_po = pcn.pcn_po_full; 805 } 806 } 807 808 break; 809 } 810 811 case PUFFS_VN_READDIR: 812 { 813 struct puffs_vnmsg_readdir *auxt = auxbuf; 814 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 815 struct dirent *dent; 816 off_t *cookies; 817 size_t res, origcookies; 818 819 if (pops->puffs_node_readdir == NULL) { 820 error = 0; 821 break; 822 } 823 824 if (auxt->pvnr_ncookies) { 825 /* LINTED: pvnr_data is __aligned() */ 826 cookies = (off_t *)auxt->pvnr_data; 827 origcookies = auxt->pvnr_ncookies; 828 } else { 829 cookies = NULL; 830 origcookies = 0; 831 } 832 /* LINTED: dentoff is aligned in the kernel */ 833 dent = (struct dirent *) 834 (auxt->pvnr_data + auxt->pvnr_dentoff); 835 836 res = auxt->pvnr_resid; 837 error = pops->puffs_node_readdir(pu, 838 opcookie, dent, &auxt->pvnr_offset, 839 &auxt->pvnr_resid, pcr, &auxt->pvnr_eofflag, 840 cookies, &auxt->pvnr_ncookies); 841 842 /* much easier to track non-working NFS */ 843 assert(auxt->pvnr_ncookies <= origcookies); 844 845 /* need to move a bit more */ 846 preq->preq_buflen = sizeof(struct puffs_vnmsg_readdir) 847 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid); 848 break; 849 } 850 851 case PUFFS_VN_READLINK: 852 { 853 struct puffs_vnmsg_readlink *auxt = auxbuf; 854 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 855 856 if (pops->puffs_node_readlink == NULL) { 857 error = EOPNOTSUPP; 858 break; 859 } 860 861 /*LINTED*/ 862 error = pops->puffs_node_readlink(pu, opcookie, pcr, 863 auxt->pvnr_link, &auxt->pvnr_linklen); 864 break; 865 } 866 867 case PUFFS_VN_RECLAIM: 868 { 869 870 if (pops->puffs_node_reclaim == NULL) { 871 error = 0; 872 break; 873 } 874 875 error = pops->puffs_node_reclaim(pu, opcookie); 876 break; 877 } 878 879 case PUFFS_VN_INACTIVE: 880 { 881 882 if (pops->puffs_node_inactive == NULL) { 883 error = EOPNOTSUPP; 884 break; 885 } 886 887 error = pops->puffs_node_inactive(pu, opcookie); 888 break; 889 } 890 891 case PUFFS_VN_PATHCONF: 892 { 893 struct puffs_vnmsg_pathconf *auxt = auxbuf; 894 if (pops->puffs_node_pathconf == NULL) { 895 error = 0; 896 break; 897 } 898 899 error = pops->puffs_node_pathconf(pu, 900 opcookie, auxt->pvnr_name, 901 &auxt->pvnr_retval); 902 break; 903 } 904 905 case PUFFS_VN_ADVLOCK: 906 { 907 struct puffs_vnmsg_advlock *auxt = auxbuf; 908 if (pops->puffs_node_advlock == NULL) { 909 error = 0; 910 break; 911 } 912 913 error = pops->puffs_node_advlock(pu, 914 opcookie, auxt->pvnr_id, auxt->pvnr_op, 915 &auxt->pvnr_fl, auxt->pvnr_flags); 916 break; 917 } 918 919 case PUFFS_VN_PRINT: 920 { 921 if (pops->puffs_node_print == NULL) { 922 error = 0; 923 break; 924 } 925 926 error = pops->puffs_node_print(pu, 927 opcookie); 928 break; 929 } 930 931 case PUFFS_VN_READ: 932 { 933 struct puffs_vnmsg_read *auxt = auxbuf; 934 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 935 size_t res; 936 937 if (pops->puffs_node_read == NULL) { 938 error = EIO; 939 break; 940 } 941 942 res = auxt->pvnr_resid; 943 error = pops->puffs_node_read(pu, 944 opcookie, auxt->pvnr_data, 945 auxt->pvnr_offset, &auxt->pvnr_resid, 946 pcr, auxt->pvnr_ioflag); 947 948 /* need to move a bit more */ 949 preq->preq_buflen = sizeof(struct puffs_vnmsg_read) 950 + (res - auxt->pvnr_resid); 951 break; 952 } 953 954 case PUFFS_VN_WRITE: 955 { 956 struct puffs_vnmsg_write *auxt = auxbuf; 957 PUFFS_MAKECRED(pcr, &auxt->pvnr_cred); 958 959 if (pops->puffs_node_write == NULL) { 960 error = EIO; 961 break; 962 } 963 964 error = pops->puffs_node_write(pu, 965 opcookie, auxt->pvnr_data, 966 auxt->pvnr_offset, &auxt->pvnr_resid, 967 pcr, auxt->pvnr_ioflag); 968 969 /* don't need to move data back to the kernel */ 970 preq->preq_buflen = sizeof(struct puffs_vnmsg_write); 971 break; 972 } 973 974 case PUFFS_VN_POLL: 975 { 976 struct puffs_vnmsg_poll *auxt = auxbuf; 977 978 if (pops->puffs_node_poll == NULL) { 979 error = 0; 980 981 /* emulate genfs_poll() */ 982 auxt->pvnr_events &= (POLLIN | POLLOUT 983 | POLLRDNORM | POLLWRNORM); 984 985 break; 986 } 987 988 error = pops->puffs_node_poll(pu, 989 opcookie, &auxt->pvnr_events); 990 break; 991 } 992 993 default: 994 printf("inval op %d\n", preq->preq_optype); 995 error = EINVAL; 996 break; 997 } 998 } else { 999 /* 1000 * this one also 1001 */ 1002 error = EINVAL; 1003 } 1004 1005 preq->preq_rv = error; 1006 pcc->pcc_flags |= PCC_DONE; 1007 1008 if (pu->pu_oppost) 1009 pu->pu_oppost(pu); 1010 1011 /* 1012 * Note, we are calling this from here so that we can run it 1013 * off of the continuation stack. Otherwise puffs_goto() would 1014 * not work. 1015 */ 1016 processresult(pcc, rv); 1017 } 1018 1019 static void 1020 processresult(struct puffs_cc *pcc, int how) 1021 { 1022 struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 1023 struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 1024 int pccflags = pcc->pcc_flags; 1025 1026 /* check if we need to store this reply */ 1027 switch (how) { 1028 case PUFFCALL_ANSWER: 1029 if (pu->pu_flags & PUFFS_FLAG_OPDUMP) 1030 puffsdump_rv(preq); 1031 1032 puffs_framev_enqueue_justsend(pu, pu->pu_fd, 1033 pcc->pcc_pb, 0, 0); 1034 /*FALLTHROUGH*/ 1035 1036 case PUFFCALL_IGNORE: 1037 PU_LOCK(); 1038 LIST_INSERT_HEAD(&pu->pu_ccnukelst, pcc, nlst_entries); 1039 PU_UNLOCK(); 1040 break; 1041 1042 case PUFFCALL_AGAIN: 1043 if ((pcc->pcc_flags & PCC_REALCC) == 0) 1044 assert(pcc->pcc_flags & PCC_DONE); 1045 break; 1046 1047 default: 1048 assert(/*CONSTCOND*/0); 1049 } 1050 1051 /* who needs information when you're living on borrowed time? */ 1052 if (pccflags & PCC_BORROWED) { 1053 assert((pccflags & PCC_THREADED) == 0); 1054 puffs_cc_yield(pcc); /* back to borrow source */ 1055 } 1056 } 1057