1 /* $NetBSD: puffs_msgif.c,v 1.89 2011/10/19 01:39:29 manu 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.89 2011/10/19 01:39:29 manu Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/atomic.h> 37 #include <sys/kmem.h> 38 #include <sys/kthread.h> 39 #include <sys/lock.h> 40 #include <sys/malloc.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 #include <miscfs/syncfs/syncfs.h> /* XXX: for syncer_mutex reference */ 55 56 /* 57 * waitq data structures 58 */ 59 60 /* 61 * While a request is going to userspace, park the caller within the 62 * kernel. This is the kernel counterpart of "struct puffs_req". 63 */ 64 struct puffs_msgpark { 65 struct puffs_req *park_preq; /* req followed by buf */ 66 67 size_t park_copylen; /* userspace copylength */ 68 size_t park_maxlen; /* max size in comeback */ 69 70 struct puffs_req *park_creq; /* non-compat preq */ 71 size_t park_creqlen; /* non-compat preq len */ 72 73 parkdone_fn park_done; /* "biodone" a'la puffs */ 74 void *park_donearg; 75 76 int park_flags; 77 int park_refcount; 78 79 kcondvar_t park_cv; 80 kmutex_t park_mtx; 81 82 TAILQ_ENTRY(puffs_msgpark) park_entries; 83 }; 84 #define PARKFLAG_WAITERGONE 0x01 85 #define PARKFLAG_DONE 0x02 86 #define PARKFLAG_ONQUEUE1 0x04 87 #define PARKFLAG_ONQUEUE2 0x08 88 #define PARKFLAG_CALL 0x10 89 #define PARKFLAG_WANTREPLY 0x20 90 #define PARKFLAG_HASERROR 0x40 91 92 static pool_cache_t parkpc; 93 #ifdef PUFFSDEBUG 94 static int totalpark; 95 #endif 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 class, int type, 291 puffs_cookie_t ck) 292 { 293 294 park->park_preq->preq_opclass = PUFFSOP_OPCLASS(class); 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 mount *mp; 337 struct puffs_req *preq, *creq; 338 ssize_t delta; 339 340 /* 341 * Some clients reuse a park, so reset some flags. We might 342 * want to provide a caller-side interface for this and add 343 * a few more invariant checks here, but this will do for now. 344 */ 345 park->park_flags &= ~(PARKFLAG_DONE | PARKFLAG_HASERROR); 346 KASSERT((park->park_flags & PARKFLAG_WAITERGONE) == 0); 347 348 mp = PMPTOMP(pmp); 349 preq = park->park_preq; 350 351 #if 1 352 /* check if we do compat adjustments */ 353 if (pmp->pmp_docompat && puffs_compat_outgoing(preq, &creq, &delta)) { 354 park->park_creq = park->park_preq; 355 park->park_creqlen = park->park_maxlen; 356 357 park->park_maxlen += delta; 358 park->park_copylen += delta; 359 park->park_preq = preq = creq; 360 } 361 #endif 362 363 preq->preq_buflen = park->park_maxlen; 364 KASSERT(preq->preq_id == 0 365 || (preq->preq_opclass & PUFFSOPFLAG_ISRESPONSE)); 366 367 if ((park->park_flags & PARKFLAG_WANTREPLY) == 0) 368 preq->preq_opclass |= PUFFSOPFLAG_FAF; 369 else 370 preq->preq_id = puffs_getmsgid(pmp); 371 372 /* fill in caller information */ 373 preq->preq_pid = l->l_proc->p_pid; 374 preq->preq_lid = l->l_lid; 375 376 /* 377 * To support cv_sig, yet another movie: check if there are signals 378 * pending and we are issueing a non-FAF. If so, return an error 379 * directly UNLESS we are issueing INACTIVE/RECLAIM. In that case, 380 * convert it to a FAF, fire off to the file server and return 381 * an error. Yes, this is bordering disgusting. Barfbags are on me. 382 */ 383 if (__predict_false((park->park_flags & PARKFLAG_WANTREPLY) 384 && (park->park_flags & PARKFLAG_CALL) == 0 385 && (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0))) { 386 sigset_t ss; 387 388 /* 389 * see the comment about signals in puffs_msg_wait. 390 */ 391 sigpending1(l, &ss); 392 if (sigismember(&ss, SIGINT) || 393 sigismember(&ss, SIGTERM) || 394 sigismember(&ss, SIGKILL) || 395 sigismember(&ss, SIGHUP) || 396 sigismember(&ss, SIGQUIT)) { 397 park->park_flags |= PARKFLAG_HASERROR; 398 preq->preq_rv = EINTR; 399 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN 400 && (preq->preq_optype == PUFFS_VN_INACTIVE 401 || preq->preq_optype == PUFFS_VN_RECLAIM)) { 402 park->park_preq->preq_opclass |= 403 PUFFSOPFLAG_FAF; 404 park->park_flags &= ~PARKFLAG_WANTREPLY; 405 DPRINTF(("puffs_msg_enqueue: " 406 "converted to FAF %p\n", park)); 407 } else { 408 return; 409 } 410 } 411 } 412 413 mutex_enter(&pmp->pmp_lock); 414 if (pmp->pmp_status != PUFFSTAT_RUNNING) { 415 mutex_exit(&pmp->pmp_lock); 416 park->park_flags |= PARKFLAG_HASERROR; 417 preq->preq_rv = ENXIO; 418 return; 419 } 420 421 #ifdef PUFFSDEBUG 422 parkqdump(&pmp->pmp_msg_touser, puffsdebug > 1); 423 parkqdump(&pmp->pmp_msg_replywait, puffsdebug > 1); 424 #endif 425 426 /* 427 * Note: we don't need to lock park since we have the only 428 * reference to it at this point. 429 */ 430 TAILQ_INSERT_TAIL(&pmp->pmp_msg_touser, park, park_entries); 431 park->park_flags |= PARKFLAG_ONQUEUE1; 432 pmp->pmp_msg_touser_count++; 433 park->park_refcount++; 434 mutex_exit(&pmp->pmp_lock); 435 436 cv_broadcast(&pmp->pmp_msg_waiter_cv); 437 putter_notify(pmp->pmp_pi); 438 439 DPRINTF(("touser: req %" PRIu64 ", preq: %p, park: %p, " 440 "c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, park, 441 preq->preq_opclass, preq->preq_optype, park->park_flags)); 442 } 443 444 int 445 puffs_msg_wait(struct puffs_mount *pmp, struct puffs_msgpark *park) 446 { 447 lwp_t *l = curlwp; 448 proc_t *p = l->l_proc; 449 struct puffs_req *preq = park->park_preq; /* XXX: hmmm */ 450 sigset_t ss; 451 sigset_t oss; 452 int error = 0; 453 int rv; 454 455 /* 456 * block unimportant signals. 457 * 458 * The set of "important" signals here was chosen to be same as 459 * nfs interruptible mount. 460 */ 461 sigfillset(&ss); 462 sigdelset(&ss, SIGINT); 463 sigdelset(&ss, SIGTERM); 464 sigdelset(&ss, SIGKILL); 465 sigdelset(&ss, SIGHUP); 466 sigdelset(&ss, SIGQUIT); 467 mutex_enter(p->p_lock); 468 sigprocmask1(l, SIG_BLOCK, &ss, &oss); 469 mutex_exit(p->p_lock); 470 471 mutex_enter(&pmp->pmp_lock); 472 puffs_mp_reference(pmp); 473 mutex_exit(&pmp->pmp_lock); 474 475 mutex_enter(&park->park_mtx); 476 /* did the response beat us to the wait? */ 477 if (__predict_false((park->park_flags & PARKFLAG_DONE) 478 || (park->park_flags & PARKFLAG_HASERROR))) { 479 rv = park->park_preq->preq_rv; 480 mutex_exit(&park->park_mtx); 481 goto skipwait; 482 } 483 484 if ((park->park_flags & PARKFLAG_WANTREPLY) == 0 485 || (park->park_flags & PARKFLAG_CALL)) { 486 mutex_exit(&park->park_mtx); 487 rv = 0; 488 goto skipwait; 489 } 490 491 error = cv_wait_sig(&park->park_cv, &park->park_mtx); 492 DPRINTF(("puffs_touser: waiter for %p woke up with %d\n", 493 park, error)); 494 if (error) { 495 park->park_flags |= PARKFLAG_WAITERGONE; 496 if (park->park_flags & PARKFLAG_DONE) { 497 rv = preq->preq_rv; 498 mutex_exit(&park->park_mtx); 499 } else { 500 /* 501 * ok, we marked it as going away, but 502 * still need to do queue ops. take locks 503 * in correct order. 504 * 505 * We don't want to release our reference 506 * if it's on replywait queue to avoid error 507 * to file server. putop() code will DTRT. 508 */ 509 mutex_exit(&park->park_mtx); 510 mutex_enter(&pmp->pmp_lock); 511 mutex_enter(&park->park_mtx); 512 513 /* 514 * Still on queue1? We can safely remove it 515 * without any consequences since the file 516 * server hasn't seen it. "else" we need to 517 * wait for the response and just ignore it 518 * to avoid signalling an incorrect error to 519 * the file server. 520 */ 521 if (park->park_flags & PARKFLAG_ONQUEUE1) { 522 TAILQ_REMOVE(&pmp->pmp_msg_touser, 523 park, park_entries); 524 puffs_msgpark_release(park); 525 pmp->pmp_msg_touser_count--; 526 park->park_flags &= ~PARKFLAG_ONQUEUE1; 527 } else { 528 mutex_exit(&park->park_mtx); 529 } 530 mutex_exit(&pmp->pmp_lock); 531 532 rv = EINTR; 533 } 534 } else { 535 rv = preq->preq_rv; 536 mutex_exit(&park->park_mtx); 537 } 538 539 skipwait: 540 mutex_enter(&pmp->pmp_lock); 541 puffs_mp_release(pmp); 542 mutex_exit(&pmp->pmp_lock); 543 544 mutex_enter(p->p_lock); 545 sigprocmask1(l, SIG_SETMASK, &oss, NULL); 546 mutex_exit(p->p_lock); 547 548 return rv; 549 } 550 551 /* 552 * XXX: this suuuucks. Hopefully I'll get rid of this lossage once 553 * the whole setback-nonsense gets fixed. 554 */ 555 int 556 puffs_msg_wait2(struct puffs_mount *pmp, struct puffs_msgpark *park, 557 struct puffs_node *pn1, struct puffs_node *pn2) 558 { 559 struct puffs_req *preq; 560 int rv; 561 562 rv = puffs_msg_wait(pmp, park); 563 564 preq = park->park_preq; 565 if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N1) 566 pn1->pn_stat |= PNODE_DOINACT; 567 if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N2) 568 pn2->pn_stat |= PNODE_DOINACT; 569 570 if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N1) 571 pn1->pn_stat |= PNODE_NOREFS; 572 if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N2) 573 pn2->pn_stat |= PNODE_NOREFS; 574 575 return rv; 576 577 } 578 579 /* 580 * XXX: lazy bum. please, for the love of foie gras, fix me. 581 * This should *NOT* depend on setfaf. Also "memcpy" could 582 * be done more nicely. 583 */ 584 void 585 puffs_msg_sendresp(struct puffs_mount *pmp, struct puffs_req *origpreq, int rv) 586 { 587 struct puffs_msgpark *park; 588 struct puffs_req *preq; 589 590 puffs_msgmem_alloc(sizeof(struct puffs_req), &park, (void *)&preq, 1); 591 puffs_msg_setfaf(park); /* XXXXXX: avoids reqid override */ 592 593 memcpy(preq, origpreq, sizeof(struct puffs_req)); 594 preq->preq_rv = rv; 595 preq->preq_opclass |= PUFFSOPFLAG_ISRESPONSE; 596 597 puffs_msg_enqueue(pmp, park); 598 puffs_msgmem_release(park); 599 } 600 601 /* 602 * Get next request in the outgoing queue. "maxsize" controls the 603 * size the caller can accommodate and "nonblock" signals if this 604 * should block while waiting for input. Handles all locking internally. 605 */ 606 int 607 puffs_msgif_getout(void *this, size_t maxsize, int nonblock, 608 uint8_t **data, size_t *dlen, void **parkptr) 609 { 610 struct puffs_mount *pmp = this; 611 struct puffs_msgpark *park = NULL; 612 struct puffs_req *preq = NULL; 613 int error; 614 615 error = 0; 616 mutex_enter(&pmp->pmp_lock); 617 puffs_mp_reference(pmp); 618 for (;;) { 619 /* RIP? */ 620 if (pmp->pmp_status != PUFFSTAT_RUNNING) { 621 error = ENXIO; 622 break; 623 } 624 625 /* need platinum yendorian express card? */ 626 if (TAILQ_EMPTY(&pmp->pmp_msg_touser)) { 627 DPRINTF(("puffs_getout: no outgoing op, ")); 628 if (nonblock) { 629 DPRINTF(("returning EWOULDBLOCK\n")); 630 error = EWOULDBLOCK; 631 break; 632 } 633 DPRINTF(("waiting ...\n")); 634 635 error = cv_wait_sig(&pmp->pmp_msg_waiter_cv, 636 &pmp->pmp_lock); 637 if (error) 638 break; 639 else 640 continue; 641 } 642 643 park = TAILQ_FIRST(&pmp->pmp_msg_touser); 644 if (park == NULL) 645 continue; 646 647 mutex_enter(&park->park_mtx); 648 puffs_msgpark_reference(park); 649 650 DPRINTF(("puffs_getout: found park at %p, ", park)); 651 652 /* If it's a goner, don't process any furher */ 653 if (park->park_flags & PARKFLAG_WAITERGONE) { 654 DPRINTF(("waitergone!\n")); 655 puffs_msgpark_release(park); 656 continue; 657 } 658 preq = park->park_preq; 659 660 #if 0 661 /* check size */ 662 /* 663 * XXX: this check is not valid for now, we don't know 664 * the size of the caller's input buffer. i.e. this 665 * will most likely go away 666 */ 667 if (maxsize < preq->preq_frhdr.pfr_len) { 668 DPRINTF(("buffer too small\n")); 669 puffs_msgpark_release(park); 670 error = E2BIG; 671 break; 672 } 673 #endif 674 675 DPRINTF(("returning\n")); 676 677 /* 678 * Ok, we found what we came for. Release it from the 679 * outgoing queue but do not unlock. We will unlock 680 * only after we "releaseout" it to avoid complications: 681 * otherwise it is (theoretically) possible for userland 682 * to race us into "put" before we have a change to put 683 * this baby on the receiving queue. 684 */ 685 TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries); 686 KASSERT(park->park_flags & PARKFLAG_ONQUEUE1); 687 park->park_flags &= ~PARKFLAG_ONQUEUE1; 688 mutex_exit(&park->park_mtx); 689 690 pmp->pmp_msg_touser_count--; 691 KASSERT(pmp->pmp_msg_touser_count >= 0); 692 693 break; 694 } 695 puffs_mp_release(pmp); 696 mutex_exit(&pmp->pmp_lock); 697 698 if (error == 0) { 699 *data = (uint8_t *)preq; 700 preq->preq_pth.pth_framelen = park->park_copylen; 701 *dlen = preq->preq_pth.pth_framelen; 702 *parkptr = park; 703 } 704 705 return error; 706 } 707 708 /* 709 * Release outgoing structure. Now, depending on the success of the 710 * outgoing send, it is either going onto the result waiting queue 711 * or the death chamber. 712 */ 713 void 714 puffs_msgif_releaseout(void *this, void *parkptr, int status) 715 { 716 struct puffs_mount *pmp = this; 717 struct puffs_msgpark *park = parkptr; 718 719 DPRINTF(("puffs_releaseout: returning park %p, errno %d: " , 720 park, status)); 721 mutex_enter(&pmp->pmp_lock); 722 mutex_enter(&park->park_mtx); 723 if (park->park_flags & PARKFLAG_WANTREPLY) { 724 if (status == 0) { 725 DPRINTF(("enqueue replywait\n")); 726 TAILQ_INSERT_TAIL(&pmp->pmp_msg_replywait, park, 727 park_entries); 728 park->park_flags |= PARKFLAG_ONQUEUE2; 729 } else { 730 DPRINTF(("error path!\n")); 731 park->park_preq->preq_rv = status; 732 park->park_flags |= PARKFLAG_DONE; 733 cv_signal(&park->park_cv); 734 } 735 puffs_msgpark_release(park); 736 } else { 737 DPRINTF(("release\n")); 738 puffs_msgpark_release1(park, 2); 739 } 740 mutex_exit(&pmp->pmp_lock); 741 } 742 743 size_t 744 puffs_msgif_waitcount(void *this) 745 { 746 struct puffs_mount *pmp = this; 747 size_t rv; 748 749 mutex_enter(&pmp->pmp_lock); 750 rv = pmp->pmp_msg_touser_count; 751 mutex_exit(&pmp->pmp_lock); 752 753 return rv; 754 } 755 756 /* 757 * XXX: locking with this one? 758 */ 759 static void 760 puffsop_msg(void *this, struct puffs_req *preq) 761 { 762 struct puffs_mount *pmp = this; 763 struct putter_hdr *pth = &preq->preq_pth; 764 struct puffs_msgpark *park; 765 int wgone; 766 767 mutex_enter(&pmp->pmp_lock); 768 769 /* Locate waiter */ 770 TAILQ_FOREACH(park, &pmp->pmp_msg_replywait, park_entries) { 771 if (park->park_preq->preq_id == preq->preq_id) 772 break; 773 } 774 if (park == NULL) { 775 DPRINTF(("puffsop_msg: no request: %" PRIu64 "\n", 776 preq->preq_id)); 777 mutex_exit(&pmp->pmp_lock); 778 return; /* XXX send error */ 779 } 780 781 mutex_enter(&park->park_mtx); 782 puffs_msgpark_reference(park); 783 if (pth->pth_framelen > park->park_maxlen) { 784 DPRINTF(("puffsop_msg: invalid buffer length: " 785 "%" PRIu64 " (req %" PRIu64 ", \n", pth->pth_framelen, 786 preq->preq_id)); 787 park->park_preq->preq_rv = EPROTO; 788 cv_signal(&park->park_cv); 789 puffs_msgpark_release1(park, 2); 790 mutex_exit(&pmp->pmp_lock); 791 return; /* XXX: error */ 792 } 793 wgone = park->park_flags & PARKFLAG_WAITERGONE; 794 795 KASSERT(park->park_flags & PARKFLAG_ONQUEUE2); 796 TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries); 797 park->park_flags &= ~PARKFLAG_ONQUEUE2; 798 mutex_exit(&pmp->pmp_lock); 799 800 if (wgone) { 801 DPRINTF(("puffsop_msg: bad service - waiter gone for " 802 "park %p\n", park)); 803 } else { 804 #if 1 805 if (park->park_creq) { 806 struct puffs_req *creq; 807 size_t csize; 808 809 KASSERT(pmp->pmp_docompat); 810 puffs_compat_incoming(preq, park->park_creq); 811 creq = park->park_creq; 812 csize = park->park_creqlen; 813 park->park_creq = park->park_preq; 814 park->park_creqlen = park->park_maxlen; 815 816 park->park_preq = creq; 817 park->park_maxlen = csize; 818 819 memcpy(park->park_creq, preq, pth->pth_framelen); 820 } else { 821 #endif 822 memcpy(park->park_preq, preq, pth->pth_framelen); 823 } 824 825 if (park->park_flags & PARKFLAG_CALL) { 826 DPRINTF(("puffsop_msg: call for %p, arg %p\n", 827 park->park_preq, park->park_donearg)); 828 park->park_done(pmp, preq, park->park_donearg); 829 } 830 } 831 832 if (!wgone) { 833 DPRINTF(("puffs_putop: flagging done for " 834 "park %p\n", park)); 835 cv_signal(&park->park_cv); 836 } 837 838 park->park_flags |= PARKFLAG_DONE; 839 puffs_msgpark_release1(park, 2); 840 } 841 842 static void 843 puffsop_flush(struct puffs_mount *pmp, struct puffs_flush *pf) 844 { 845 struct vnode *vp; 846 voff_t offlo, offhi; 847 int rv, flags = 0; 848 849 KASSERT(pf->pf_req.preq_pth.pth_framelen == sizeof(struct puffs_flush)); 850 851 /* XXX: slurry */ 852 if (pf->pf_op == PUFFS_INVAL_NAMECACHE_ALL) { 853 cache_purgevfs(PMPTOMP(pmp)); 854 rv = 0; 855 goto out; 856 } 857 858 /* 859 * Get vnode, don't lock it. Namecache is protected by its own lock 860 * and we have a reference to protect against premature harvesting. 861 * 862 * The node we want here might be locked and the op is in 863 * userspace waiting for us to complete ==> deadlock. Another 864 * reason we need to eventually bump locking to userspace, as we 865 * will need to lock the node if we wish to do flushes. 866 */ 867 rv = puffs_cookie2vnode(pmp, pf->pf_cookie, 0, 0, &vp); 868 if (rv) { 869 if (rv == PUFFS_NOSUCHCOOKIE) 870 rv = ENOENT; 871 goto out; 872 } 873 874 switch (pf->pf_op) { 875 #if 0 876 /* not quite ready, yet */ 877 case PUFFS_INVAL_NAMECACHE_NODE: 878 struct componentname *pf_cn; 879 char *name; 880 /* get comfortab^Wcomponentname */ 881 pf_cn = kmem_alloc(componentname); 882 memset(pf_cn, 0, sizeof(struct componentname)); 883 break; 884 885 #endif 886 case PUFFS_INVAL_NAMECACHE_DIR: 887 if (vp->v_type != VDIR) { 888 rv = EINVAL; 889 break; 890 } 891 cache_purge1(vp, NULL, PURGE_CHILDREN); 892 break; 893 894 case PUFFS_INVAL_PAGECACHE_NODE_RANGE: 895 flags = PGO_FREE; 896 /*FALLTHROUGH*/ 897 case PUFFS_FLUSH_PAGECACHE_NODE_RANGE: 898 if (flags == 0) 899 flags = PGO_CLEANIT; 900 901 if (pf->pf_end > vp->v_size || vp->v_type != VREG) { 902 rv = EINVAL; 903 break; 904 } 905 906 offlo = trunc_page(pf->pf_start); 907 offhi = round_page(pf->pf_end); 908 if (offhi != 0 && offlo >= offhi) { 909 rv = EINVAL; 910 break; 911 } 912 913 mutex_enter(vp->v_uobj.vmobjlock); 914 rv = VOP_PUTPAGES(vp, offlo, offhi, flags); 915 break; 916 917 default: 918 rv = EINVAL; 919 } 920 921 vrele(vp); 922 923 out: 924 puffs_msg_sendresp(pmp, &pf->pf_req, rv); 925 } 926 927 int 928 puffs_msgif_dispatch(void *this, struct putter_hdr *pth) 929 { 930 struct puffs_mount *pmp = this; 931 struct puffs_req *preq = (struct puffs_req *)pth; 932 struct puffs_sopreq *psopr; 933 934 if (pth->pth_framelen < sizeof(struct puffs_req)) { 935 puffs_msg_sendresp(pmp, preq, EINVAL); /* E2SMALL */ 936 return 0; 937 } 938 939 switch (PUFFSOP_OPCLASS(preq->preq_opclass)) { 940 case PUFFSOP_VN: 941 case PUFFSOP_VFS: 942 DPRINTF(("dispatch: vn/vfs message 0x%x\n", preq->preq_optype)); 943 puffsop_msg(pmp, preq); 944 break; 945 946 case PUFFSOP_FLUSH: /* process in sop thread */ 947 { 948 struct puffs_flush *pf; 949 950 DPRINTF(("dispatch: flush 0x%x\n", preq->preq_optype)); 951 952 if (preq->preq_pth.pth_framelen != sizeof(struct puffs_flush)) { 953 puffs_msg_sendresp(pmp, preq, EINVAL); /* E2SMALL */ 954 break; 955 } 956 pf = (struct puffs_flush *)preq; 957 958 KASSERT(curlwp != uvm.pagedaemon_lwp); 959 psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP); 960 memcpy(&psopr->psopr_pf, pf, sizeof(*pf)); 961 psopr->psopr_sopreq = PUFFS_SOPREQ_FLUSH; 962 963 mutex_enter(&pmp->pmp_sopmtx); 964 if (pmp->pmp_sopthrcount == 0) { 965 mutex_exit(&pmp->pmp_sopmtx); 966 kmem_free(psopr, sizeof(*psopr)); 967 puffs_msg_sendresp(pmp, preq, ENXIO); 968 } else { 969 TAILQ_INSERT_TAIL(&pmp->pmp_sopreqs, 970 psopr, psopr_entries); 971 cv_signal(&pmp->pmp_sopcv); 972 mutex_exit(&pmp->pmp_sopmtx); 973 } 974 break; 975 } 976 977 case PUFFSOP_UNMOUNT: /* process in sop thread */ 978 { 979 980 DPRINTF(("dispatch: unmount 0x%x\n", preq->preq_optype)); 981 982 KASSERT(curlwp != uvm.pagedaemon_lwp); 983 psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP); 984 psopr->psopr_preq = *preq; 985 psopr->psopr_sopreq = PUFFS_SOPREQ_UNMOUNT; 986 987 mutex_enter(&pmp->pmp_sopmtx); 988 if (pmp->pmp_sopthrcount == 0) { 989 mutex_exit(&pmp->pmp_sopmtx); 990 kmem_free(psopr, sizeof(*psopr)); 991 puffs_msg_sendresp(pmp, preq, ENXIO); 992 } else { 993 TAILQ_INSERT_TAIL(&pmp->pmp_sopreqs, 994 psopr, psopr_entries); 995 cv_signal(&pmp->pmp_sopcv); 996 mutex_exit(&pmp->pmp_sopmtx); 997 } 998 break; 999 } 1000 1001 default: 1002 DPRINTF(("dispatch: invalid class 0x%x\n", preq->preq_opclass)); 1003 puffs_msg_sendresp(pmp, preq, EOPNOTSUPP); 1004 break; 1005 } 1006 1007 return 0; 1008 } 1009 1010 /* 1011 * Work loop for thread processing all ops from server which 1012 * cannot safely be handled in caller context. This includes 1013 * everything which might need a lock currently "held" by the file 1014 * server, i.e. a long-term kernel lock which will be released only 1015 * once the file server acknowledges a request 1016 */ 1017 void 1018 puffs_sop_thread(void *arg) 1019 { 1020 struct puffs_mount *pmp = arg; 1021 struct mount *mp = PMPTOMP(pmp); 1022 struct puffs_sopreq *psopr; 1023 bool keeprunning; 1024 bool unmountme = false; 1025 1026 mutex_enter(&pmp->pmp_sopmtx); 1027 for (keeprunning = true; keeprunning; ) { 1028 while ((psopr = TAILQ_FIRST(&pmp->pmp_sopreqs)) == NULL) 1029 cv_wait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx); 1030 TAILQ_REMOVE(&pmp->pmp_sopreqs, psopr, psopr_entries); 1031 mutex_exit(&pmp->pmp_sopmtx); 1032 1033 switch (psopr->psopr_sopreq) { 1034 case PUFFS_SOPREQSYS_EXIT: 1035 keeprunning = false; 1036 break; 1037 case PUFFS_SOPREQ_FLUSH: 1038 puffsop_flush(pmp, &psopr->psopr_pf); 1039 break; 1040 case PUFFS_SOPREQ_UNMOUNT: 1041 puffs_msg_sendresp(pmp, &psopr->psopr_preq, 0); 1042 1043 unmountme = true; 1044 keeprunning = false; 1045 1046 /* 1047 * We know the mountpoint is still alive because 1048 * the thread that is us (poetic?) is still alive. 1049 */ 1050 atomic_inc_uint((unsigned int*)&mp->mnt_refcnt); 1051 break; 1052 } 1053 1054 kmem_free(psopr, sizeof(*psopr)); 1055 mutex_enter(&pmp->pmp_sopmtx); 1056 } 1057 1058 /* 1059 * Purge remaining ops. 1060 */ 1061 while ((psopr = TAILQ_FIRST(&pmp->pmp_sopreqs)) != NULL) { 1062 TAILQ_REMOVE(&pmp->pmp_sopreqs, psopr, psopr_entries); 1063 mutex_exit(&pmp->pmp_sopmtx); 1064 puffs_msg_sendresp(pmp, &psopr->psopr_preq, ENXIO); 1065 kmem_free(psopr, sizeof(*psopr)); 1066 mutex_enter(&pmp->pmp_sopmtx); 1067 } 1068 1069 pmp->pmp_sopthrcount--; 1070 cv_broadcast(&pmp->pmp_sopcv); 1071 mutex_exit(&pmp->pmp_sopmtx); /* not allowed to access fs after this */ 1072 1073 /* 1074 * If unmount was requested, we can now safely do it here, since 1075 * our context is dead from the point-of-view of puffs_unmount() 1076 * and we are just another thread. dounmount() makes internally 1077 * sure that VFS_UNMOUNT() isn't called reentrantly and that it 1078 * is eventually completed. 1079 */ 1080 if (unmountme) { 1081 (void)dounmount(mp, MNT_FORCE, curlwp); 1082 vfs_destroy(mp); 1083 } 1084 1085 kthread_exit(0); 1086 } 1087 1088 int 1089 puffs_msgif_close(void *this) 1090 { 1091 struct puffs_mount *pmp = this; 1092 struct mount *mp = PMPTOMP(pmp); 1093 1094 mutex_enter(&pmp->pmp_lock); 1095 puffs_mp_reference(pmp); 1096 1097 /* 1098 * Free the waiting callers before proceeding any further. 1099 * The syncer might be jogging around in this file system 1100 * currently. If we allow it to go to the userspace of no 1101 * return while trying to get the syncer lock, well ... 1102 */ 1103 puffs_userdead(pmp); 1104 1105 /* 1106 * Make sure someone from puffs_unmount() isn't currently in 1107 * userspace. If we don't take this precautionary step, 1108 * they might notice that the mountpoint has disappeared 1109 * from under them once they return. Especially note that we 1110 * cannot simply test for an unmounter before calling 1111 * dounmount(), since it might be possible that that particular 1112 * invocation of unmount was called without MNT_FORCE. Here we 1113 * *must* make sure unmount succeeds. Also, restart is necessary 1114 * since pmp isn't locked. We might end up with PUTTER_DEAD after 1115 * restart and exit from there. 1116 */ 1117 if (pmp->pmp_unmounting) { 1118 cv_wait(&pmp->pmp_unmounting_cv, &pmp->pmp_lock); 1119 puffs_mp_release(pmp); 1120 mutex_exit(&pmp->pmp_lock); 1121 DPRINTF(("puffs_fop_close: unmount was in progress for pmp %p, " 1122 "restart\n", pmp)); 1123 return ERESTART; 1124 } 1125 1126 /* Won't access pmp from here anymore */ 1127 atomic_inc_uint((unsigned int*)&mp->mnt_refcnt); 1128 puffs_mp_release(pmp); 1129 mutex_exit(&pmp->pmp_lock); 1130 1131 /* Detach from VFS. */ 1132 (void)dounmount(mp, MNT_FORCE, curlwp); 1133 vfs_destroy(mp); 1134 1135 return 0; 1136 } 1137 1138 /* 1139 * We're dead, kaput, RIP, slightly more than merely pining for the 1140 * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet 1141 * our maker, ceased to be, etcetc. YASD. It's a dead FS! 1142 * 1143 * Caller must hold puffs mutex. 1144 */ 1145 void 1146 puffs_userdead(struct puffs_mount *pmp) 1147 { 1148 struct puffs_msgpark *park, *park_next; 1149 1150 /* 1151 * Mark filesystem status as dying so that operations don't 1152 * attempt to march to userspace any longer. 1153 */ 1154 pmp->pmp_status = PUFFSTAT_DYING; 1155 1156 /* signal waiters on REQUEST TO file server queue */ 1157 for (park = TAILQ_FIRST(&pmp->pmp_msg_touser); park; park = park_next) { 1158 uint8_t opclass; 1159 1160 mutex_enter(&park->park_mtx); 1161 puffs_msgpark_reference(park); 1162 park_next = TAILQ_NEXT(park, park_entries); 1163 1164 KASSERT(park->park_flags & PARKFLAG_ONQUEUE1); 1165 TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries); 1166 park->park_flags &= ~PARKFLAG_ONQUEUE1; 1167 pmp->pmp_msg_touser_count--; 1168 1169 /* 1170 * Even though waiters on QUEUE1 are removed in touser() 1171 * in case of WAITERGONE, it is still possible for us to 1172 * get raced here due to having to retake locks in said 1173 * touser(). In the race case simply "ignore" the item 1174 * on the queue and move on to the next one. 1175 */ 1176 if (park->park_flags & PARKFLAG_WAITERGONE) { 1177 KASSERT((park->park_flags & PARKFLAG_CALL) == 0); 1178 KASSERT(park->park_flags & PARKFLAG_WANTREPLY); 1179 puffs_msgpark_release(park); 1180 1181 } else { 1182 opclass = park->park_preq->preq_opclass; 1183 park->park_preq->preq_rv = ENXIO; 1184 1185 if (park->park_flags & PARKFLAG_CALL) { 1186 park->park_done(pmp, park->park_preq, 1187 park->park_donearg); 1188 puffs_msgpark_release1(park, 2); 1189 } else if ((park->park_flags & PARKFLAG_WANTREPLY)==0) { 1190 puffs_msgpark_release1(park, 2); 1191 } else { 1192 park->park_preq->preq_rv = ENXIO; 1193 cv_signal(&park->park_cv); 1194 puffs_msgpark_release(park); 1195 } 1196 } 1197 } 1198 1199 /* signal waiters on RESPONSE FROM file server queue */ 1200 for (park=TAILQ_FIRST(&pmp->pmp_msg_replywait); park; park=park_next) { 1201 mutex_enter(&park->park_mtx); 1202 puffs_msgpark_reference(park); 1203 park_next = TAILQ_NEXT(park, park_entries); 1204 1205 KASSERT(park->park_flags & PARKFLAG_ONQUEUE2); 1206 KASSERT(park->park_flags & PARKFLAG_WANTREPLY); 1207 1208 TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries); 1209 park->park_flags &= ~PARKFLAG_ONQUEUE2; 1210 1211 if (park->park_flags & PARKFLAG_WAITERGONE) { 1212 KASSERT((park->park_flags & PARKFLAG_CALL) == 0); 1213 puffs_msgpark_release(park); 1214 } else { 1215 park->park_preq->preq_rv = ENXIO; 1216 if (park->park_flags & PARKFLAG_CALL) { 1217 park->park_done(pmp, park->park_preq, 1218 park->park_donearg); 1219 puffs_msgpark_release1(park, 2); 1220 } else { 1221 cv_signal(&park->park_cv); 1222 puffs_msgpark_release(park); 1223 } 1224 } 1225 } 1226 1227 cv_broadcast(&pmp->pmp_msg_waiter_cv); 1228 } 1229