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