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