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