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