1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Google Summer of Code program and the Ulla Tuominen Foundation. 8 * The Google SoC project was mentored by Bill Studenmund. 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__KERNEL_RCSID(0, "$NetBSD$"); 34 35#include <sys/param.h> 36#include <sys/kernel.h> 37#include <sys/atomic.h> 38#include <sys/kmem.h> 39#include <sys/kthread.h> 40#include <sys/lock.h> 41#include <sys/malloc.h> 42#include <sys/mount.h> 43#include <sys/namei.h> 44#include <sys/proc.h> 45#include <sys/vnode.h> 46#include <sys/atomic.h> 47 48#include <uvm/uvm.h> 49 50#include <dev/putter/putter_sys.h> 51 52#include <fs/puffs/puffs_msgif.h> 53#include <fs/puffs/puffs_sys.h> 54 55#include <miscfs/syncfs/syncfs.h> /* XXX: for syncer_mutex reference */ 56 57/* 58 * waitq data structures 59 */ 60 61/* 62 * While a request is going to userspace, park the caller within the 63 * kernel. This is the kernel counterpart of "struct puffs_req". 64 */ 65struct puffs_msgpark { 66 struct puffs_req *park_preq; /* req followed by buf */ 67 68 size_t park_copylen; /* userspace copylength */ 69 size_t park_maxlen; /* max size in comeback */ 70 71 struct puffs_req *park_creq; /* non-compat preq */ 72 size_t park_creqlen; /* non-compat preq len */ 73 74 parkdone_fn park_done; /* "biodone" a'la puffs */ 75 void *park_donearg; 76 77 int park_flags; 78 int park_refcount; 79 80 kcondvar_t park_cv; 81 kmutex_t park_mtx; 82 83 TAILQ_ENTRY(puffs_msgpark) park_entries; 84}; 85#define PARKFLAG_WAITERGONE 0x01 86#define PARKFLAG_DONE 0x02 87#define PARKFLAG_ONQUEUE1 0x04 88#define PARKFLAG_ONQUEUE2 0x08 89#define PARKFLAG_CALL 0x10 90#define PARKFLAG_WANTREPLY 0x20 91#define PARKFLAG_HASERROR 0x40 92 93static pool_cache_t parkpc; 94#ifdef PUFFSDEBUG 95static int totalpark; 96#endif 97 98int puffs_sopreq_expire_timeout = PUFFS_SOPREQ_EXPIRE_TIMEOUT; 99 100static int 101makepark(void *arg, void *obj, int flags) 102{ 103 struct puffs_msgpark *park = obj; 104 105 mutex_init(&park->park_mtx, MUTEX_DEFAULT, IPL_NONE); 106 cv_init(&park->park_cv, "puffsrpl"); 107 108 return 0; 109} 110 111static void 112nukepark(void *arg, void *obj) 113{ 114 struct puffs_msgpark *park = obj; 115 116 cv_destroy(&park->park_cv); 117 mutex_destroy(&park->park_mtx); 118} 119 120void 121puffs_msgif_init(void) 122{ 123 124 parkpc = pool_cache_init(sizeof(struct puffs_msgpark), 0, 0, 0, 125 "puffprkl", NULL, IPL_NONE, makepark, nukepark, NULL); 126} 127 128void 129puffs_msgif_destroy(void) 130{ 131 132 pool_cache_destroy(parkpc); 133} 134 135static struct puffs_msgpark * 136puffs_msgpark_alloc(int waitok) 137{ 138 struct puffs_msgpark *park; 139 140 KASSERT(curlwp != uvm.pagedaemon_lwp || !waitok); 141 142 park = pool_cache_get(parkpc, waitok ? PR_WAITOK : PR_NOWAIT); 143 if (park == NULL) 144 return park; 145 146 park->park_refcount = 1; 147 park->park_preq = park->park_creq = NULL; 148 park->park_flags = PARKFLAG_WANTREPLY; 149 150#ifdef PUFFSDEBUG 151 totalpark++; 152#endif 153 154 return park; 155} 156 157static void 158puffs_msgpark_reference(struct puffs_msgpark *park) 159{ 160 161 KASSERT(mutex_owned(&park->park_mtx)); 162 park->park_refcount++; 163} 164 165/* 166 * Release reference to park structure. 167 */ 168static void 169puffs_msgpark_release1(struct puffs_msgpark *park, int howmany) 170{ 171 struct puffs_req *preq = park->park_preq; 172 struct puffs_req *creq = park->park_creq; 173 int refcnt; 174 175 KASSERT(mutex_owned(&park->park_mtx)); 176 refcnt = park->park_refcount -= howmany; 177 mutex_exit(&park->park_mtx); 178 179 KASSERT(refcnt >= 0); 180 181 if (refcnt == 0) { 182 if (preq) 183 kmem_free(preq, park->park_maxlen); 184#if 1 185 if (creq) 186 kmem_free(creq, park->park_creqlen); 187#endif 188 pool_cache_put(parkpc, park); 189 190#ifdef PUFFSDEBUG 191 totalpark--; 192#endif 193 } 194} 195#define puffs_msgpark_release(a) puffs_msgpark_release1(a, 1) 196 197#ifdef PUFFSDEBUG 198static void 199parkdump(struct puffs_msgpark *park) 200{ 201 202 DPRINTF(("park %p, preq %p, id %" PRIu64 "\n" 203 "\tcopy %zu, max %zu - done: %p/%p\n" 204 "\tflags 0x%08x, refcount %d, cv/mtx: %p/%p\n", 205 park, park->park_preq, park->park_preq->preq_id, 206 park->park_copylen, park->park_maxlen, 207 park->park_done, park->park_donearg, 208 park->park_flags, park->park_refcount, 209 &park->park_cv, &park->park_mtx)); 210} 211 212static void 213parkqdump(struct puffs_wq *q, int dumpall) 214{ 215 struct puffs_msgpark *park; 216 int total = 0; 217 218 TAILQ_FOREACH(park, q, park_entries) { 219 if (dumpall) 220 parkdump(park); 221 total++; 222 } 223 DPRINTF(("puffs waitqueue at %p dumped, %d total\n", q, total)); 224 225} 226#endif /* PUFFSDEBUG */ 227 228/* 229 * A word about locking in the park structures: the lock protects the 230 * fields of the *park* structure (not preq) and acts as an interlock 231 * in cv operations. The lock is always internal to this module and 232 * callers do not need to worry about it. 233 */ 234 235int 236puffs_msgmem_alloc(size_t len, struct puffs_msgpark **ppark, void **mem, 237 int cansleep) 238{ 239 struct puffs_msgpark *park; 240 void *m; 241 242 KASSERT(curlwp != uvm.pagedaemon_lwp || !cansleep); 243 m = kmem_zalloc(len, cansleep ? KM_SLEEP : KM_NOSLEEP); 244 if (m == NULL) { 245 KASSERT(cansleep == 0); 246 return ENOMEM; 247 } 248 249 park = puffs_msgpark_alloc(cansleep); 250 if (park == NULL) { 251 KASSERT(cansleep == 0); 252 kmem_free(m, len); 253 return ENOMEM; 254 } 255 256 park->park_preq = m; 257 park->park_maxlen = park->park_copylen = len; 258 259 *ppark = park; 260 *mem = m; 261 262 return 0; 263} 264 265void 266puffs_msgmem_release(struct puffs_msgpark *park) 267{ 268 269 if (park == NULL) 270 return; 271 272 mutex_enter(&park->park_mtx); 273 puffs_msgpark_release(park); 274} 275 276void 277puffs_msg_setfaf(struct puffs_msgpark *park) 278{ 279 280 KASSERT((park->park_flags & PARKFLAG_CALL) == 0); 281 park->park_flags &= ~PARKFLAG_WANTREPLY; 282} 283 284void 285puffs_msg_setdelta(struct puffs_msgpark *park, size_t delta) 286{ 287 288 KASSERT(delta < park->park_maxlen); /* "<=" wouldn't make sense */ 289 park->park_copylen = park->park_maxlen - delta; 290} 291 292void 293puffs_msg_setinfo(struct puffs_msgpark *park, int class, int type, 294 puffs_cookie_t ck) 295{ 296 297 park->park_preq->preq_opclass = PUFFSOP_OPCLASS(class); 298 park->park_preq->preq_optype = type; 299 park->park_preq->preq_cookie = ck; 300} 301 302void 303puffs_msg_setcall(struct puffs_msgpark *park, parkdone_fn donefn, void *donearg) 304{ 305 306 KASSERT(park->park_flags & PARKFLAG_WANTREPLY); 307 park->park_done = donefn; 308 park->park_donearg = donearg; 309 park->park_flags |= PARKFLAG_CALL; 310} 311 312/* 313 * kernel-user-kernel waitqueues 314 */ 315 316static uint64_t 317puffs_getmsgid(struct puffs_mount *pmp) 318{ 319 uint64_t rv; 320 321 mutex_enter(&pmp->pmp_lock); 322 rv = pmp->pmp_nextmsgid++; 323 mutex_exit(&pmp->pmp_lock); 324 325 return rv; 326} 327 328/* 329 * A word about reference counting of parks. A reference must be taken 330 * when accessing a park and additionally when it is on a queue. So 331 * when taking it off a queue and releasing the access reference, the 332 * reference count is generally decremented by 2. 333 */ 334 335void 336puffs_msg_enqueue(struct puffs_mount *pmp, struct puffs_msgpark *park) 337{ 338 struct lwp *l = curlwp; 339 struct mount *mp; 340 struct puffs_req *preq, *creq; 341 ssize_t delta; 342 343 /* 344 * Some clients reuse a park, so reset some flags. We might 345 * want to provide a caller-side interface for this and add 346 * a few more invariant checks here, but this will do for now. 347 */ 348 park->park_flags &= ~(PARKFLAG_DONE | PARKFLAG_HASERROR); 349 KASSERT((park->park_flags & PARKFLAG_WAITERGONE) == 0); 350 351 mp = PMPTOMP(pmp); 352 preq = park->park_preq; 353 354#if 1 355 /* check if we do compat adjustments */ 356 if (pmp->pmp_docompat && puffs_compat_outgoing(preq, &creq, &delta)) { 357 park->park_creq = park->park_preq; 358 park->park_creqlen = park->park_maxlen; 359 360 park->park_maxlen += delta; 361 park->park_copylen += delta; 362 park->park_preq = preq = creq; 363 } 364#endif 365 366 preq->preq_buflen = park->park_maxlen; 367 KASSERT(preq->preq_id == 0 368 || (preq->preq_opclass & PUFFSOPFLAG_ISRESPONSE)); 369 370 if ((park->park_flags & PARKFLAG_WANTREPLY) == 0) 371 preq->preq_opclass |= PUFFSOPFLAG_FAF; 372 else 373 preq->preq_id = puffs_getmsgid(pmp); 374 375 /* fill in caller information */ 376 preq->preq_pid = l->l_proc->p_pid; 377 preq->preq_lid = l->l_lid; 378 379 /* 380 * To support cv_sig, yet another movie: check if there are signals 381 * pending and we are issueing a non-FAF. If so, return an error 382 * directly UNLESS we are issueing INACTIVE/RECLAIM. In that case, 383 * convert it to a FAF, fire off to the file server and return 384 * an error. Yes, this is bordering disgusting. Barfbags are on me. 385 */ 386 if (__predict_false((park->park_flags & PARKFLAG_WANTREPLY) 387 && (park->park_flags & PARKFLAG_CALL) == 0 388 && (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0))) { 389 sigset_t ss; 390 391 /* 392 * see the comment about signals in puffs_msg_wait. 393 */ 394 sigpending1(l, &ss); 395 if (sigismember(&ss, SIGINT) || 396 sigismember(&ss, SIGTERM) || 397 sigismember(&ss, SIGKILL) || 398 sigismember(&ss, SIGHUP) || 399 sigismember(&ss, SIGQUIT)) { 400 park->park_flags |= PARKFLAG_HASERROR; 401 preq->preq_rv = EINTR; 402 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN 403 && (preq->preq_optype == PUFFS_VN_INACTIVE 404 || preq->preq_optype == PUFFS_VN_RECLAIM)) { 405 park->park_preq->preq_opclass |= 406 PUFFSOPFLAG_FAF; 407 park->park_flags &= ~PARKFLAG_WANTREPLY; 408 DPRINTF(("puffs_msg_enqueue: " 409 "converted to FAF %p\n", park)); 410 } else { 411 return; 412 } 413 } 414 } 415 416 mutex_enter(&pmp->pmp_lock); 417 if (pmp->pmp_status != PUFFSTAT_RUNNING) { 418 mutex_exit(&pmp->pmp_lock); 419 park->park_flags |= PARKFLAG_HASERROR; 420 preq->preq_rv = ENXIO; 421 return; 422 } 423 424#ifdef PUFFSDEBUG 425 parkqdump(&pmp->pmp_msg_touser, puffsdebug > 1); 426 parkqdump(&pmp->pmp_msg_replywait, puffsdebug > 1); 427#endif 428 429 /* 430 * Note: we don't need to lock park since we have the only 431 * reference to it at this point. 432 */ 433 TAILQ_INSERT_TAIL(&pmp->pmp_msg_touser, park, park_entries); 434 park->park_flags |= PARKFLAG_ONQUEUE1; 435 pmp->pmp_msg_touser_count++; 436 park->park_refcount++; 437 mutex_exit(&pmp->pmp_lock); 438 439 cv_broadcast(&pmp->pmp_msg_waiter_cv); 440 putter_notify(pmp->pmp_pi); 441 442 DPRINTF(("touser: req %" PRIu64 ", preq: %p, park: %p, " 443 "c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, park, 444 preq->preq_opclass, preq->preq_optype, park->park_flags)); 445} 446 447int 448puffs_msg_wait(struct puffs_mount *pmp, struct puffs_msgpark *park) 449{ 450 lwp_t *l = curlwp; 451 proc_t *p = l->l_proc; 452 struct puffs_req *preq = park->park_preq; /* XXX: hmmm */ 453 sigset_t ss; 454 sigset_t oss; 455 int error = 0; 456 int rv; 457 458 /* 459 * block unimportant signals. 460 * 461 * The set of "important" signals here was chosen to be same as 462 * nfs interruptible mount. 463 */ 464 sigfillset(&ss); 465 sigdelset(&ss, SIGINT); 466 sigdelset(&ss, SIGTERM); 467 sigdelset(&ss, SIGKILL); 468 sigdelset(&ss, SIGHUP); 469 sigdelset(&ss, SIGQUIT); 470 mutex_enter(p->p_lock); 471 sigprocmask1(l, SIG_BLOCK, &ss, &oss); 472 mutex_exit(p->p_lock); 473 474 mutex_enter(&pmp->pmp_lock); 475 puffs_mp_reference(pmp); 476 mutex_exit(&pmp->pmp_lock); 477 478 mutex_enter(&park->park_mtx); 479 /* did the response beat us to the wait? */ 480 if (__predict_false((park->park_flags & PARKFLAG_DONE) 481 || (park->park_flags & PARKFLAG_HASERROR))) { 482 rv = park->park_preq->preq_rv; 483 mutex_exit(&park->park_mtx); 484 goto skipwait; 485 } 486 487 if ((park->park_flags & PARKFLAG_WANTREPLY) == 0 488 || (park->park_flags & PARKFLAG_CALL)) { 489 mutex_exit(&park->park_mtx); 490 rv = 0; 491 goto skipwait; 492 } 493 494 error = cv_wait_sig(&park->park_cv, &park->park_mtx); 495 DPRINTF(("puffs_touser: waiter for %p woke up with %d\n", 496 park, error)); 497 if (error) { 498 park->park_flags |= PARKFLAG_WAITERGONE; 499 if (park->park_flags & PARKFLAG_DONE) { 500 rv = preq->preq_rv; 501 mutex_exit(&park->park_mtx); 502 } else { 503 /* 504 * ok, we marked it as going away, but 505 * still need to do queue ops. take locks 506 * in correct order. 507 * 508 * We don't want to release our reference 509 * if it's on replywait queue to avoid error 510 * to file server. putop() code will DTRT. 511 */ 512 mutex_exit(&park->park_mtx); 513 mutex_enter(&pmp->pmp_lock); 514 mutex_enter(&park->park_mtx); 515 516 /* 517 * Still on queue1? We can safely remove it 518 * without any consequences since the file 519 * server hasn't seen it. "else" we need to 520 * wait for the response and just ignore it 521 * to avoid signalling an incorrect error to 522 * the file server. 523 */ 524 if (park->park_flags & PARKFLAG_ONQUEUE1) { 525 TAILQ_REMOVE(&pmp->pmp_msg_touser, 526 park, park_entries); 527 puffs_msgpark_release(park); 528 pmp->pmp_msg_touser_count--; 529 park->park_flags &= ~PARKFLAG_ONQUEUE1; 530 } else { 531 mutex_exit(&park->park_mtx); 532 } 533 mutex_exit(&pmp->pmp_lock); 534 535 rv = EINTR; 536 } 537 } else { 538 rv = preq->preq_rv; 539 mutex_exit(&park->park_mtx); 540 } 541 542 skipwait: 543 mutex_enter(&pmp->pmp_lock); 544 puffs_mp_release(pmp); 545 mutex_exit(&pmp->pmp_lock); 546 547 mutex_enter(p->p_lock); 548 sigprocmask1(l, SIG_SETMASK, &oss, NULL); 549 mutex_exit(p->p_lock); 550 551 return rv; 552} 553 554/* 555 * XXX: this suuuucks. Hopefully I'll get rid of this lossage once 556 * the whole setback-nonsense gets fixed. 557 */ 558int 559puffs_msg_wait2(struct puffs_mount *pmp, struct puffs_msgpark *park, 560 struct puffs_node *pn1, struct puffs_node *pn2) 561{ 562 struct puffs_req *preq; 563 int rv; 564 565 rv = puffs_msg_wait(pmp, park); 566 567 preq = park->park_preq; 568 if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N1) 569 pn1->pn_stat |= PNODE_DOINACT; 570 if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N2) 571 pn2->pn_stat |= PNODE_DOINACT; 572 573 if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N1) 574 pn1->pn_stat |= PNODE_NOREFS; 575 if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N2) 576 pn2->pn_stat |= PNODE_NOREFS; 577 578 return rv; 579 580} 581 582/* 583 * XXX: lazy bum. please, for the love of foie gras, fix me. 584 * This should *NOT* depend on setfaf. Also "memcpy" could 585 * be done more nicely. 586 */ 587void 588puffs_msg_sendresp(struct puffs_mount *pmp, struct puffs_req *origpreq, int rv) 589{ 590 struct puffs_msgpark *park; 591 struct puffs_req *preq; 592 593 puffs_msgmem_alloc(sizeof(struct puffs_req), &park, (void *)&preq, 1); 594 puffs_msg_setfaf(park); /* XXXXXX: avoids reqid override */ 595 596 memcpy(preq, origpreq, sizeof(struct puffs_req)); 597 preq->preq_rv = rv; 598 preq->preq_opclass |= PUFFSOPFLAG_ISRESPONSE; 599 600 puffs_msg_enqueue(pmp, park); 601 puffs_msgmem_release(park); 602} 603 604/* 605 * Get next request in the outgoing queue. "maxsize" controls the 606 * size the caller can accommodate and "nonblock" signals if this 607 * should block while waiting for input. Handles all locking internally. 608 */ 609int 610puffs_msgif_getout(void *this, size_t maxsize, int nonblock, 611 uint8_t **data, size_t *dlen, void **parkptr) 612{ 613 struct puffs_mount *pmp = this; 614 struct puffs_msgpark *park = NULL; 615 struct puffs_req *preq = NULL; 616 int error; 617 618 error = 0; 619 mutex_enter(&pmp->pmp_lock); 620 puffs_mp_reference(pmp); 621 for (;;) { 622 /* RIP? */ 623 if (pmp->pmp_status != PUFFSTAT_RUNNING) { 624 error = ENXIO; 625 break; 626 } 627 628 /* need platinum yendorian express card? */ 629 if (TAILQ_EMPTY(&pmp->pmp_msg_touser)) { 630 DPRINTF(("puffs_getout: no outgoing op, ")); 631 if (nonblock) { 632 DPRINTF(("returning EWOULDBLOCK\n")); 633 error = EWOULDBLOCK; 634 break; 635 } 636 DPRINTF(("waiting ...\n")); 637 638 error = cv_wait_sig(&pmp->pmp_msg_waiter_cv, 639 &pmp->pmp_lock); 640 if (error) 641 break; 642 else 643 continue; 644 } 645 646 park = TAILQ_FIRST(&pmp->pmp_msg_touser); 647 if (park == NULL) 648 continue; 649 650 mutex_enter(&park->park_mtx); 651 puffs_msgpark_reference(park); 652 653 DPRINTF(("puffs_getout: found park at %p, ", park)); 654 655 /* If it's a goner, don't process any furher */ 656 if (park->park_flags & PARKFLAG_WAITERGONE) { 657 DPRINTF(("waitergone!\n")); 658 puffs_msgpark_release(park); 659 continue; 660 } 661 preq = park->park_preq; 662 663#if 0 664 /* check size */ 665 /* 666 * XXX: this check is not valid for now, we don't know 667 * the size of the caller's input buffer. i.e. this 668 * will most likely go away 669 */ 670 if (maxsize < preq->preq_frhdr.pfr_len) { 671 DPRINTF(("buffer too small\n")); 672 puffs_msgpark_release(park); 673 error = E2BIG; 674 break; 675 } 676#endif 677 678 DPRINTF(("returning\n")); 679 680 /* 681 * Ok, we found what we came for. Release it from the 682 * outgoing queue but do not unlock. We will unlock 683 * only after we "releaseout" it to avoid complications: 684 * otherwise it is (theoretically) possible for userland 685 * to race us into "put" before we have a change to put 686 * this baby on the receiving queue. 687 */ 688 TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries); 689 KASSERT(park->park_flags & PARKFLAG_ONQUEUE1); 690 park->park_flags &= ~PARKFLAG_ONQUEUE1; 691 mutex_exit(&park->park_mtx); 692 693 pmp->pmp_msg_touser_count--; 694 KASSERT(pmp->pmp_msg_touser_count >= 0); 695 696 break; 697 } 698 puffs_mp_release(pmp); 699 mutex_exit(&pmp->pmp_lock); 700 701 if (error == 0) { 702 *data = (uint8_t *)preq; 703 preq->preq_pth.pth_framelen = park->park_copylen; 704 *dlen = preq->preq_pth.pth_framelen; 705 *parkptr = park; 706 } 707 708 return error; 709} 710 711/* 712 * Release outgoing structure. Now, depending on the success of the 713 * outgoing send, it is either going onto the result waiting queue 714 * or the death chamber. 715 */ 716void 717puffs_msgif_releaseout(void *this, void *parkptr, int status) 718{ 719 struct puffs_mount *pmp = this; 720 struct puffs_msgpark *park = parkptr; 721 722 DPRINTF(("puffs_releaseout: returning park %p, errno %d: " , 723 park, status)); 724 mutex_enter(&pmp->pmp_lock); 725 mutex_enter(&park->park_mtx); 726 if (park->park_flags & PARKFLAG_WANTREPLY) { 727 if (status == 0) { 728 DPRINTF(("enqueue replywait\n")); 729 TAILQ_INSERT_TAIL(&pmp->pmp_msg_replywait, park, 730 park_entries); 731 park->park_flags |= PARKFLAG_ONQUEUE2; 732 } else { 733 DPRINTF(("error path!\n")); 734 park->park_preq->preq_rv = status; 735 park->park_flags |= PARKFLAG_DONE; 736 cv_signal(&park->park_cv); 737 } 738 puffs_msgpark_release(park); 739 } else { 740 DPRINTF(("release\n")); 741 puffs_msgpark_release1(park, 2); 742 } 743 mutex_exit(&pmp->pmp_lock); 744} 745 746size_t 747puffs_msgif_waitcount(void *this) 748{ 749 struct puffs_mount *pmp = this; 750 size_t rv; 751 752 mutex_enter(&pmp->pmp_lock); 753 rv = pmp->pmp_msg_touser_count; 754 mutex_exit(&pmp->pmp_lock); 755 756 return rv; 757} 758 759/* 760 * XXX: locking with this one? 761 */ 762static void 763puffsop_msg(void *this, struct puffs_req *preq) 764{ 765 struct puffs_mount *pmp = this; 766 struct putter_hdr *pth = &preq->preq_pth; 767 struct puffs_msgpark *park; 768 int wgone; 769 770 mutex_enter(&pmp->pmp_lock); 771 772 /* Locate waiter */ 773 TAILQ_FOREACH(park, &pmp->pmp_msg_replywait, park_entries) { 774 if (park->park_preq->preq_id == preq->preq_id) 775 break; 776 } 777 if (park == NULL) { 778 DPRINTF(("puffsop_msg: no request: %" PRIu64 "\n", 779 preq->preq_id)); 780 mutex_exit(&pmp->pmp_lock); 781 return; /* XXX send error */ 782 } 783 784 mutex_enter(&park->park_mtx); 785 puffs_msgpark_reference(park); 786 if (pth->pth_framelen > park->park_maxlen) { 787 DPRINTF(("puffsop_msg: invalid buffer length: " 788 "%" PRIu64 " (req %" PRIu64 ", \n", pth->pth_framelen, 789 preq->preq_id)); 790 park->park_preq->preq_rv = EPROTO; 791 cv_signal(&park->park_cv); 792 puffs_msgpark_release1(park, 2); 793 mutex_exit(&pmp->pmp_lock); 794 return; /* XXX: error */ 795 } 796 wgone = park->park_flags & PARKFLAG_WAITERGONE; 797 798 KASSERT(park->park_flags & PARKFLAG_ONQUEUE2); 799 TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries); 800 park->park_flags &= ~PARKFLAG_ONQUEUE2; 801 mutex_exit(&pmp->pmp_lock); 802 803 if (wgone) { 804 DPRINTF(("puffsop_msg: bad service - waiter gone for " 805 "park %p\n", park)); 806 } else { 807#if 1 808 if (park->park_creq) { 809 struct puffs_req *creq; 810 size_t csize; 811 812 KASSERT(pmp->pmp_docompat); 813 puffs_compat_incoming(preq, park->park_creq); 814 creq = park->park_creq; 815 csize = park->park_creqlen; 816 park->park_creq = park->park_preq; 817 park->park_creqlen = park->park_maxlen; 818 819 park->park_preq = creq; 820 park->park_maxlen = csize; 821 822 memcpy(park->park_creq, preq, pth->pth_framelen); 823 } else { 824#endif 825 memcpy(park->park_preq, preq, pth->pth_framelen); 826 } 827 828 if (park->park_flags & PARKFLAG_CALL) { 829 DPRINTF(("puffsop_msg: call for %p, arg %p\n", 830 park->park_preq, park->park_donearg)); 831 park->park_done(pmp, preq, park->park_donearg); 832 } 833 } 834 835 if (!wgone) { 836 DPRINTF(("puffs_putop: flagging done for " 837 "park %p\n", park)); 838 cv_signal(&park->park_cv); 839 } 840 841 park->park_flags |= PARKFLAG_DONE; 842 puffs_msgpark_release1(park, 2); 843} 844 845/* 846 * Node expiry. We come here after an inactive on an unexpired node. 847 * The expiry has been queued and is done in sop thread. 848 */ 849static void 850puffsop_expire(struct puffs_mount *pmp, puffs_cookie_t cookie) 851{ 852 struct vnode *vp; 853 854 KASSERT(PUFFS_USE_FS_TTL(pmp)); 855 856 /* 857 * If it still exists and has no reference, 858 * vrele should cause it to be reclaimed. 859 * Otherwise, we have nothing to do. 860 */ 861 if (puffs_cookie2vnode(pmp, cookie, 0, 0, &vp) == 0) { 862 VPTOPP(vp)->pn_stat &= ~PNODE_SOPEXP; 863 vrele(vp); 864 } 865 866 return; 867} 868 869static void 870puffsop_flush(struct puffs_mount *pmp, struct puffs_flush *pf) 871{ 872 struct vnode *vp; 873 voff_t offlo, offhi; 874 int rv, flags = 0; 875 876 KASSERT(pf->pf_req.preq_pth.pth_framelen == sizeof(struct puffs_flush)); 877 878 /* XXX: slurry */ 879 if (pf->pf_op == PUFFS_INVAL_NAMECACHE_ALL) { 880 cache_purgevfs(PMPTOMP(pmp)); 881 rv = 0; 882 goto out; 883 } 884 885 /* 886 * Get vnode, don't lock it. Namecache is protected by its own lock 887 * and we have a reference to protect against premature harvesting. 888 * 889 * The node we want here might be locked and the op is in 890 * userspace waiting for us to complete ==> deadlock. Another 891 * reason we need to eventually bump locking to userspace, as we 892 * will need to lock the node if we wish to do flushes. 893 */ 894 rv = puffs_cookie2vnode(pmp, pf->pf_cookie, 0, 0, &vp); 895 if (rv) { 896 if (rv == PUFFS_NOSUCHCOOKIE) 897 rv = ENOENT; 898 goto out; 899 } 900 901 switch (pf->pf_op) { 902#if 0 903 /* not quite ready, yet */ 904 case PUFFS_INVAL_NAMECACHE_NODE: 905 struct componentname *pf_cn; 906 char *name; 907 /* get comfortab^Wcomponentname */ 908 pf_cn = kmem_alloc(componentname); 909 memset(pf_cn, 0, sizeof(struct componentname)); 910 break; 911 912#endif 913 case PUFFS_INVAL_NAMECACHE_DIR: 914 if (vp->v_type != VDIR) { 915 rv = EINVAL; 916 break; 917 } 918 cache_purge1(vp, NULL, PURGE_CHILDREN); 919 break; 920 921 case PUFFS_INVAL_PAGECACHE_NODE_RANGE: 922 flags = PGO_FREE; 923 /*FALLTHROUGH*/ 924 case PUFFS_FLUSH_PAGECACHE_NODE_RANGE: 925 if (flags == 0) 926 flags = PGO_CLEANIT; 927 928 if (pf->pf_end > vp->v_size || vp->v_type != VREG) { 929 rv = EINVAL; 930 break; 931 } 932 933 offlo = trunc_page(pf->pf_start); 934 offhi = round_page(pf->pf_end); 935 if (offhi != 0 && offlo >= offhi) { 936 rv = EINVAL; 937 break; 938 } 939 940 mutex_enter(vp->v_uobj.vmobjlock); 941 rv = VOP_PUTPAGES(vp, offlo, offhi, flags); 942 break; 943 944 default: 945 rv = EINVAL; 946 } 947 948 vrele(vp); 949 950 out: 951 puffs_msg_sendresp(pmp, &pf->pf_req, rv); 952} 953 954int 955puffs_msgif_dispatch(void *this, struct putter_hdr *pth) 956{ 957 struct puffs_mount *pmp = this; 958 struct puffs_req *preq = (struct puffs_req *)pth; 959 struct puffs_sopreq *psopr; 960 961 if (pth->pth_framelen < sizeof(struct puffs_req)) { 962 puffs_msg_sendresp(pmp, preq, EINVAL); /* E2SMALL */ 963 return 0; 964 } 965 966 switch (PUFFSOP_OPCLASS(preq->preq_opclass)) { 967 case PUFFSOP_VN: 968 case PUFFSOP_VFS: 969 DPRINTF(("dispatch: vn/vfs message 0x%x\n", preq->preq_optype)); 970 puffsop_msg(pmp, preq); 971 break; 972 973 case PUFFSOP_FLUSH: /* process in sop thread */ 974 { 975 struct puffs_flush *pf; 976 977 DPRINTF(("dispatch: flush 0x%x\n", preq->preq_optype)); 978 979 if (preq->preq_pth.pth_framelen != sizeof(struct puffs_flush)) { 980 puffs_msg_sendresp(pmp, preq, EINVAL); /* E2SMALL */ 981 break; 982 } 983 pf = (struct puffs_flush *)preq; 984 985 KASSERT(curlwp != uvm.pagedaemon_lwp); 986 psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP); 987 memcpy(&psopr->psopr_pf, pf, sizeof(*pf)); 988 psopr->psopr_sopreq = PUFFS_SOPREQ_FLUSH; 989 990 mutex_enter(&pmp->pmp_sopmtx); 991 if (pmp->pmp_sopthrcount == 0) { 992 mutex_exit(&pmp->pmp_sopmtx); 993 kmem_free(psopr, sizeof(*psopr)); 994 puffs_msg_sendresp(pmp, preq, ENXIO); 995 } else { 996 TAILQ_INSERT_TAIL(&pmp->pmp_sopfastreqs, 997 psopr, psopr_entries); 998 cv_signal(&pmp->pmp_sopcv); 999 mutex_exit(&pmp->pmp_sopmtx); 1000 } 1001 break; 1002 } 1003 1004 case PUFFSOP_UNMOUNT: /* process in sop thread */ 1005 { 1006 1007 DPRINTF(("dispatch: unmount 0x%x\n", preq->preq_optype)); 1008 1009 KASSERT(curlwp != uvm.pagedaemon_lwp); 1010 psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP); 1011 psopr->psopr_preq = *preq; 1012 psopr->psopr_sopreq = PUFFS_SOPREQ_UNMOUNT; 1013 1014 mutex_enter(&pmp->pmp_sopmtx); 1015 if (pmp->pmp_sopthrcount == 0) { 1016 mutex_exit(&pmp->pmp_sopmtx); 1017 kmem_free(psopr, sizeof(*psopr)); 1018 puffs_msg_sendresp(pmp, preq, ENXIO); 1019 } else { 1020 TAILQ_INSERT_TAIL(&pmp->pmp_sopfastreqs, 1021 psopr, psopr_entries); 1022 cv_signal(&pmp->pmp_sopcv); 1023 mutex_exit(&pmp->pmp_sopmtx); 1024 } 1025 break; 1026 } 1027 1028 default: 1029 DPRINTF(("dispatch: invalid class 0x%x\n", preq->preq_opclass)); 1030 puffs_msg_sendresp(pmp, preq, EOPNOTSUPP); 1031 break; 1032 } 1033 1034 return 0; 1035} 1036 1037/* 1038 * Work loop for thread processing all ops from server which 1039 * cannot safely be handled in caller context. This includes 1040 * everything which might need a lock currently "held" by the file 1041 * server, i.e. a long-term kernel lock which will be released only 1042 * once the file server acknowledges a request 1043 */ 1044#define TIMED_OUT(expire) \ 1045 ((int)((unsigned int)hardclock_ticks - (unsigned int)expire) > 0) 1046void 1047puffs_sop_thread(void *arg) 1048{ 1049 struct puffs_mount *pmp = arg; 1050 struct mount *mp = PMPTOMP(pmp); 1051 struct puffs_sopreq *psopr; 1052 bool keeprunning; 1053 bool unmountme = false; 1054 int timeo; 1055 1056 timeo = PUFFS_USE_FS_TTL(pmp) ? puffs_sopreq_expire_timeout : 0; 1057 1058 mutex_enter(&pmp->pmp_sopmtx); 1059 for (keeprunning = true; keeprunning; ) { 1060 /* 1061 * We have a fast queue for flush and umount, and a node 1062 * queue for delayes node reclaims. Requests on node queue * are not honoured before clock reaches psopr_at. This 1063 * code assumes that requests are ordered by psopr_at. 1064 */ 1065 do { 1066 psopr = TAILQ_FIRST(&pmp->pmp_sopfastreqs); 1067 if (psopr != NULL) { 1068 TAILQ_REMOVE(&pmp->pmp_sopfastreqs, 1069 psopr, psopr_entries); 1070 break; 1071 } 1072 1073 psopr = TAILQ_FIRST(&pmp->pmp_sopnodereqs); 1074 if ((psopr != NULL) && TIMED_OUT(psopr->psopr_at)) { 1075 TAILQ_REMOVE(&pmp->pmp_sopnodereqs, 1076 psopr, psopr_entries); 1077 break; 1078 } 1079 1080 cv_timedwait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx, timeo); 1081 } while (1 /* CONSTCOND */); 1082 1083 mutex_exit(&pmp->pmp_sopmtx); 1084 1085 switch (psopr->psopr_sopreq) { 1086 case PUFFS_SOPREQSYS_EXIT: 1087 keeprunning = false; 1088 break; 1089 case PUFFS_SOPREQ_FLUSH: 1090 puffsop_flush(pmp, &psopr->psopr_pf); 1091 break; 1092 case PUFFS_SOPREQ_EXPIRE: 1093 puffsop_expire(pmp, psopr->psopr_ck); 1094 break; 1095 case PUFFS_SOPREQ_UNMOUNT: 1096 puffs_msg_sendresp(pmp, &psopr->psopr_preq, 0); 1097 1098 unmountme = true; 1099 keeprunning = false; 1100 1101 /* 1102 * We know the mountpoint is still alive because 1103 * the thread that is us (poetic?) is still alive. 1104 */ 1105 atomic_inc_uint((unsigned int*)&mp->mnt_refcnt); 1106 break; 1107 } 1108 1109 kmem_free(psopr, sizeof(*psopr)); 1110 mutex_enter(&pmp->pmp_sopmtx); 1111 } 1112 1113 /* 1114 * Purge remaining ops. 1115 */ 1116 while ((psopr = TAILQ_FIRST(&pmp->pmp_sopfastreqs)) != NULL) { 1117 TAILQ_REMOVE(&pmp->pmp_sopfastreqs, psopr, psopr_entries); 1118 mutex_exit(&pmp->pmp_sopmtx); 1119 puffs_msg_sendresp(pmp, &psopr->psopr_preq, ENXIO); 1120 kmem_free(psopr, sizeof(*psopr)); 1121 mutex_enter(&pmp->pmp_sopmtx); 1122 } 1123 1124 while ((psopr = TAILQ_FIRST(&pmp->pmp_sopnodereqs)) != NULL) { 1125 TAILQ_REMOVE(&pmp->pmp_sopnodereqs, psopr, psopr_entries); 1126 mutex_exit(&pmp->pmp_sopmtx); 1127 KASSERT(psopr->psopr_sopreq == PUFFS_SOPREQ_EXPIRE); 1128 kmem_free(psopr, sizeof(*psopr)); 1129 mutex_enter(&pmp->pmp_sopmtx); 1130 } 1131 1132 pmp->pmp_sopthrcount--; 1133 cv_broadcast(&pmp->pmp_sopcv); 1134 mutex_exit(&pmp->pmp_sopmtx); /* not allowed to access fs after this */ 1135 1136 /* 1137 * If unmount was requested, we can now safely do it here, since 1138 * our context is dead from the point-of-view of puffs_unmount() 1139 * and we are just another thread. dounmount() makes internally 1140 * sure that VFS_UNMOUNT() isn't called reentrantly and that it 1141 * is eventually completed. 1142 */ 1143 if (unmountme) { 1144 (void)dounmount(mp, MNT_FORCE, curlwp); 1145 vfs_destroy(mp); 1146 } 1147 1148 kthread_exit(0); 1149} 1150 1151int 1152puffs_msgif_close(void *this) 1153{ 1154 struct puffs_mount *pmp = this; 1155 struct mount *mp = PMPTOMP(pmp); 1156 1157 mutex_enter(&pmp->pmp_lock); 1158 puffs_mp_reference(pmp); 1159 1160 /* 1161 * Free the waiting callers before proceeding any further. 1162 * The syncer might be jogging around in this file system 1163 * currently. If we allow it to go to the userspace of no 1164 * return while trying to get the syncer lock, well ... 1165 */ 1166 puffs_userdead(pmp); 1167 1168 /* 1169 * Make sure someone from puffs_unmount() isn't currently in 1170 * userspace. If we don't take this precautionary step, 1171 * they might notice that the mountpoint has disappeared 1172 * from under them once they return. Especially note that we 1173 * cannot simply test for an unmounter before calling 1174 * dounmount(), since it might be possible that that particular 1175 * invocation of unmount was called without MNT_FORCE. Here we 1176 * *must* make sure unmount succeeds. Also, restart is necessary 1177 * since pmp isn't locked. We might end up with PUTTER_DEAD after 1178 * restart and exit from there. 1179 */ 1180 if (pmp->pmp_unmounting) { 1181 cv_wait(&pmp->pmp_unmounting_cv, &pmp->pmp_lock); 1182 puffs_mp_release(pmp); 1183 mutex_exit(&pmp->pmp_lock); 1184 DPRINTF(("puffs_fop_close: unmount was in progress for pmp %p, " 1185 "restart\n", pmp)); 1186 return ERESTART; 1187 } 1188 1189 /* Won't access pmp from here anymore */ 1190 atomic_inc_uint((unsigned int*)&mp->mnt_refcnt); 1191 puffs_mp_release(pmp); 1192 mutex_exit(&pmp->pmp_lock); 1193 1194 /* Detach from VFS. */ 1195 (void)dounmount(mp, MNT_FORCE, curlwp); 1196 vfs_destroy(mp); 1197 1198 return 0; 1199} 1200 1201/* 1202 * We're dead, kaput, RIP, slightly more than merely pining for the 1203 * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet 1204 * our maker, ceased to be, etcetc. YASD. It's a dead FS! 1205 * 1206 * Caller must hold puffs mutex. 1207 */ 1208void 1209puffs_userdead(struct puffs_mount *pmp) 1210{ 1211 struct puffs_msgpark *park, *park_next; 1212 1213 /* 1214 * Mark filesystem status as dying so that operations don't 1215 * attempt to march to userspace any longer. 1216 */ 1217 pmp->pmp_status = PUFFSTAT_DYING; 1218 1219 /* signal waiters on REQUEST TO file server queue */ 1220 for (park = TAILQ_FIRST(&pmp->pmp_msg_touser); park; park = park_next) { 1221 uint8_t opclass; 1222 1223 mutex_enter(&park->park_mtx); 1224 puffs_msgpark_reference(park); 1225 park_next = TAILQ_NEXT(park, park_entries); 1226 1227 KASSERT(park->park_flags & PARKFLAG_ONQUEUE1); 1228 TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries); 1229 park->park_flags &= ~PARKFLAG_ONQUEUE1; 1230 pmp->pmp_msg_touser_count--; 1231 1232 /* 1233 * Even though waiters on QUEUE1 are removed in touser() 1234 * in case of WAITERGONE, it is still possible for us to 1235 * get raced here due to having to retake locks in said 1236 * touser(). In the race case simply "ignore" the item 1237 * on the queue and move on to the next one. 1238 */ 1239 if (park->park_flags & PARKFLAG_WAITERGONE) { 1240 KASSERT((park->park_flags & PARKFLAG_CALL) == 0); 1241 KASSERT(park->park_flags & PARKFLAG_WANTREPLY); 1242 puffs_msgpark_release(park); 1243 1244 } else { 1245 opclass = park->park_preq->preq_opclass; 1246 park->park_preq->preq_rv = ENXIO; 1247 1248 if (park->park_flags & PARKFLAG_CALL) { 1249 park->park_done(pmp, park->park_preq, 1250 park->park_donearg); 1251 puffs_msgpark_release1(park, 2); 1252 } else if ((park->park_flags & PARKFLAG_WANTREPLY)==0) { 1253 puffs_msgpark_release1(park, 2); 1254 } else { 1255 park->park_preq->preq_rv = ENXIO; 1256 cv_signal(&park->park_cv); 1257 puffs_msgpark_release(park); 1258 } 1259 } 1260 } 1261 1262 /* signal waiters on RESPONSE FROM file server queue */ 1263 for (park=TAILQ_FIRST(&pmp->pmp_msg_replywait); park; park=park_next) { 1264 mutex_enter(&park->park_mtx); 1265 puffs_msgpark_reference(park); 1266 park_next = TAILQ_NEXT(park, park_entries); 1267 1268 KASSERT(park->park_flags & PARKFLAG_ONQUEUE2); 1269 KASSERT(park->park_flags & PARKFLAG_WANTREPLY); 1270 1271 TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries); 1272 park->park_flags &= ~PARKFLAG_ONQUEUE2; 1273 1274 if (park->park_flags & PARKFLAG_WAITERGONE) { 1275 KASSERT((park->park_flags & PARKFLAG_CALL) == 0); 1276 puffs_msgpark_release(park); 1277 } else { 1278 park->park_preq->preq_rv = ENXIO; 1279 if (park->park_flags & PARKFLAG_CALL) { 1280 park->park_done(pmp, park->park_preq, 1281 park->park_donearg); 1282 puffs_msgpark_release1(park, 2); 1283 } else { 1284 cv_signal(&park->park_cv); 1285 puffs_msgpark_release(park); 1286 } 1287 } 1288 } 1289 1290 cv_broadcast(&pmp->pmp_msg_waiter_cv); 1291} 1292