1/* $NetBSD: framebuf.c,v 1.30 2010/01/12 18:42:38 pooka Exp $ */ 2 3/* 4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Finnish Cultural Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31/* 32 * The event portion of this code is a twisty maze of pointers, 33 * flags, yields and continues. Sincere aplogies. 34 */ 35 36#include <sys/cdefs.h> 37#if !defined(lint) 38__RCSID("$NetBSD: framebuf.c,v 1.30 2010/01/12 18:42:38 pooka Exp $"); 39#endif /* !lint */ 40 41#include <sys/types.h> 42#include <sys/queue.h> 43 44#include <assert.h> 45#include <errno.h> 46#include <poll.h> 47#include <puffs.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <unistd.h> 51 52#include "puffs_priv.h" 53 54struct puffs_framebuf { 55 struct puffs_cc *pcc; /* pcc to continue with */ 56 /* OR */ 57 puffs_framev_cb fcb; /* non-blocking callback */ 58 void *fcb_arg; /* argument for previous */ 59 60 uint8_t *buf; /* buffer base */ 61 size_t len; /* total length */ 62 63 size_t offset; /* cursor, telloff() */ 64 size_t maxoff; /* maximum offset for data, tellsize() */ 65 66 volatile int rv; /* errno value */ 67 68 int istat; 69 70 TAILQ_ENTRY(puffs_framebuf) pfb_entries; 71}; 72#define ISTAT_NODESTROY 0x01 /* indestructible by framebuf_destroy() */ 73#define ISTAT_INTERNAL 0x02 /* never leaves library */ 74#define ISTAT_NOREPLY 0x04 /* nuke after sending */ 75#define ISTAT_DIRECT 0x08 /* receive directly, no moveinfo */ 76 77#define ISTAT_ONQUEUE ISTAT_NODESTROY /* alias */ 78 79#define PUFBUF_INCRALLOC 4096 80#define PUFBUF_REMAIN(p) (p->len - p->offset) 81 82/* for poll/kqueue */ 83struct puffs_fbevent { 84 struct puffs_cc *pcc; 85 int what; 86 volatile int rv; 87 88 LIST_ENTRY(puffs_fbevent) pfe_entries; 89}; 90 91static struct puffs_fctrl_io * 92getfiobyfd(struct puffs_usermount *pu, int fd) 93{ 94 struct puffs_fctrl_io *fio; 95 96 LIST_FOREACH(fio, &pu->pu_ios, fio_entries) 97 if (fio->io_fd == fd) 98 return fio; 99 return NULL; 100} 101 102struct puffs_framebuf * 103puffs_framebuf_make() 104{ 105 struct puffs_framebuf *pufbuf; 106 107 pufbuf = malloc(sizeof(struct puffs_framebuf)); 108 if (pufbuf == NULL) 109 return NULL; 110 memset(pufbuf, 0, sizeof(struct puffs_framebuf)); 111 112 pufbuf->buf = malloc(PUFBUF_INCRALLOC); 113 if (pufbuf->buf == NULL) { 114 free(pufbuf); 115 return NULL; 116 } 117 pufbuf->len = PUFBUF_INCRALLOC; 118 119 puffs_framebuf_recycle(pufbuf); 120 return pufbuf; 121} 122 123void 124puffs_framebuf_destroy(struct puffs_framebuf *pufbuf) 125{ 126 127 assert((pufbuf->istat & ISTAT_NODESTROY) == 0); 128 129 free(pufbuf->buf); 130 free(pufbuf); 131} 132 133void 134puffs_framebuf_recycle(struct puffs_framebuf *pufbuf) 135{ 136 137 assert((pufbuf->istat & ISTAT_NODESTROY) == 0); 138 139 pufbuf->offset = 0; 140 pufbuf->maxoff = 0; 141 pufbuf->istat = 0; 142} 143 144static int 145reservespace(struct puffs_framebuf *pufbuf, size_t off, size_t wantsize) 146{ 147 size_t incr; 148 void *nd; 149 150 if (off <= pufbuf->len && pufbuf->len - off >= wantsize) 151 return 0; 152 153 for (incr = PUFBUF_INCRALLOC; 154 pufbuf->len + incr < off + wantsize; 155 incr += PUFBUF_INCRALLOC) 156 continue; 157 158 nd = realloc(pufbuf->buf, pufbuf->len + incr); 159 if (nd == NULL) 160 return -1; 161 162 pufbuf->buf = nd; 163 pufbuf->len += incr; 164 165 return 0; 166} 167 168int 169puffs_framebuf_dup(struct puffs_framebuf *pb, struct puffs_framebuf **pbp) 170{ 171 struct puffs_framebuf *newpb; 172 173 newpb = puffs_framebuf_make(); 174 if (newpb == NULL) { 175 errno = ENOMEM; 176 return -1; 177 } 178 memcpy(newpb, pb, sizeof(struct puffs_framebuf)); 179 180 newpb->buf = NULL; 181 newpb->len = 0; 182 if (reservespace(newpb, 0, pb->maxoff) == -1) { 183 puffs_framebuf_destroy(newpb); 184 return -1; 185 } 186 187 memcpy(newpb->buf, pb->buf, pb->maxoff); 188 newpb->istat = 0; 189 *pbp = newpb; 190 191 return 0; 192} 193 194int 195puffs_framebuf_reserve_space(struct puffs_framebuf *pufbuf, size_t wantsize) 196{ 197 198 return reservespace(pufbuf, pufbuf->offset, wantsize); 199} 200 201int 202puffs_framebuf_putdata(struct puffs_framebuf *pufbuf, 203 const void *data, size_t dlen) 204{ 205 206 if (PUFBUF_REMAIN(pufbuf) < dlen) 207 if (puffs_framebuf_reserve_space(pufbuf, dlen) == -1) 208 return -1; 209 210 memcpy(pufbuf->buf + pufbuf->offset, data, dlen); 211 pufbuf->offset += dlen; 212 213 if (pufbuf->offset > pufbuf->maxoff) 214 pufbuf->maxoff = pufbuf->offset; 215 216 return 0; 217} 218 219int 220puffs_framebuf_putdata_atoff(struct puffs_framebuf *pufbuf, size_t offset, 221 const void *data, size_t dlen) 222{ 223 224 if (reservespace(pufbuf, offset, dlen) == -1) 225 return -1; 226 227 memcpy(pufbuf->buf + offset, data, dlen); 228 229 if (offset + dlen > pufbuf->maxoff) 230 pufbuf->maxoff = offset + dlen; 231 232 return 0; 233} 234 235int 236puffs_framebuf_getdata(struct puffs_framebuf *pufbuf, void *data, size_t dlen) 237{ 238 239 if (pufbuf->maxoff < pufbuf->offset + dlen) { 240 errno = ENOBUFS; 241 return -1; 242 } 243 244 memcpy(data, pufbuf->buf + pufbuf->offset, dlen); 245 pufbuf->offset += dlen; 246 247 return 0; 248} 249 250int 251puffs_framebuf_getdata_atoff(struct puffs_framebuf *pufbuf, size_t offset, 252 void *data, size_t dlen) 253{ 254 255 if (pufbuf->maxoff < offset + dlen) { 256 errno = ENOBUFS; 257 return -1; 258 } 259 260 memcpy(data, pufbuf->buf + offset, dlen); 261 return 0; 262} 263 264size_t 265puffs_framebuf_telloff(struct puffs_framebuf *pufbuf) 266{ 267 268 return pufbuf->offset; 269} 270 271size_t 272puffs_framebuf_tellsize(struct puffs_framebuf *pufbuf) 273{ 274 275 return pufbuf->maxoff; 276} 277 278size_t 279puffs_framebuf_remaining(struct puffs_framebuf *pufbuf) 280{ 281 282 return puffs_framebuf_tellsize(pufbuf) - puffs_framebuf_telloff(pufbuf); 283} 284 285int 286puffs_framebuf_seekset(struct puffs_framebuf *pufbuf, size_t newoff) 287{ 288 289 if (reservespace(pufbuf, newoff, 0) == -1) 290 return -1; 291 292 pufbuf->offset = newoff; 293 return 0; 294} 295 296int 297puffs_framebuf_getwindow(struct puffs_framebuf *pufbuf, size_t winoff, 298 void **data, size_t *dlen) 299{ 300 size_t winlen; 301 302#ifdef WINTESTING 303 winlen = MIN(*dlen, 32); 304#else 305 winlen = *dlen; 306#endif 307 308 if (reservespace(pufbuf, winoff, winlen) == -1) 309 return -1; 310 311 *data = pufbuf->buf + winoff; 312 if (pufbuf->maxoff < winoff + winlen) 313 pufbuf->maxoff = winoff + winlen; 314 315 return 0; 316} 317 318void * 319puffs__framebuf_getdataptr(struct puffs_framebuf *pufbuf) 320{ 321 322 return pufbuf->buf; 323} 324 325static void 326errnotify(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, int error) 327{ 328 329 pufbuf->rv = error; 330 if (pufbuf->pcc) { 331 puffs__goto(pufbuf->pcc); 332 } else if (pufbuf->fcb) { 333 pufbuf->istat &= ~ISTAT_NODESTROY; 334 pufbuf->fcb(pu, pufbuf, pufbuf->fcb_arg, error); 335 } else { 336 pufbuf->istat &= ~ISTAT_NODESTROY; 337 puffs_framebuf_destroy(pufbuf); 338 } 339} 340 341#define GETFIO(fd) \ 342do { \ 343 fio = getfiobyfd(pu, fd); \ 344 if (fio == NULL) { \ 345 errno = EINVAL; \ 346 return -1; \ 347 } \ 348 if (fio->stat & FIO_WRGONE) { \ 349 errno = ESHUTDOWN; \ 350 return -1; \ 351 } \ 352} while (/*CONSTCOND*/0) 353 354int 355puffs_framev_enqueue_cc(struct puffs_cc *pcc, int fd, 356 struct puffs_framebuf *pufbuf, int flags) 357{ 358 struct puffs_usermount *pu = pcc->pcc_pu; 359 struct puffs_fctrl_io *fio; 360 361 /* 362 * Technically we shouldn't allow this if RDGONE, but it's 363 * difficult to trap write close without allowing writes. 364 * And besides, there's probably a disconnect sequence in 365 * the protocol, so unexpectedly getting a closed fd is 366 * most likely an error condition. 367 */ 368 GETFIO(fd); 369 370 pufbuf->pcc = pcc; 371 pufbuf->fcb = NULL; 372 pufbuf->fcb_arg = NULL; 373 374 pufbuf->offset = 0; 375 pufbuf->istat |= ISTAT_NODESTROY; 376 377 if (flags & PUFFS_FBQUEUE_URGENT) 378 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries); 379 else 380 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 381 382 puffs_cc_yield(pcc); 383 if (pufbuf->rv) { 384 pufbuf->istat &= ~ISTAT_NODESTROY; 385 errno = pufbuf->rv; 386 return -1; 387 } 388 389 return 0; 390} 391 392int 393puffs_framev_enqueue_cb(struct puffs_usermount *pu, int fd, 394 struct puffs_framebuf *pufbuf, puffs_framev_cb fcb, void *arg, 395 int flags) 396{ 397 struct puffs_fctrl_io *fio; 398 399 /* see enqueue_cc */ 400 GETFIO(fd); 401 402 pufbuf->pcc = NULL; 403 pufbuf->fcb = fcb; 404 pufbuf->fcb_arg = arg; 405 406 pufbuf->offset = 0; 407 pufbuf->istat |= ISTAT_NODESTROY; 408 409 if (flags & PUFFS_FBQUEUE_URGENT) 410 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries); 411 else 412 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 413 414 return 0; 415} 416 417int 418puffs_framev_enqueue_justsend(struct puffs_usermount *pu, int fd, 419 struct puffs_framebuf *pufbuf, int reply, int flags) 420{ 421 struct puffs_fctrl_io *fio; 422 423 assert((pufbuf->istat & ISTAT_INTERNAL) == 0); 424 425 GETFIO(fd); 426 427 pufbuf->pcc = NULL; 428 pufbuf->fcb = NULL; 429 pufbuf->fcb_arg = NULL; 430 431 pufbuf->offset = 0; 432 pufbuf->istat |= ISTAT_NODESTROY; 433 if (!reply) 434 pufbuf->istat |= ISTAT_NOREPLY; 435 436 if (flags & PUFFS_FBQUEUE_URGENT) 437 TAILQ_INSERT_HEAD(&fio->snd_qing, pufbuf, pfb_entries); 438 else 439 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 440 441 return 0; 442} 443 444/* ARGSUSED */ 445int 446puffs_framev_enqueue_directreceive(struct puffs_cc *pcc, int fd, 447 struct puffs_framebuf *pufbuf, int flags /* used in the future */) 448{ 449 struct puffs_usermount *pu = pcc->pcc_pu; 450 struct puffs_fctrl_io *fio; 451 452 assert((pufbuf->istat & ISTAT_INTERNAL) == 0); 453 454 fio = getfiobyfd(pu, fd); 455 if (fio == NULL) { 456 errno = EINVAL; 457 return -1; 458 } 459 460 /* XXX: should have cur_in queue */ 461 assert(fio->cur_in == NULL); 462 fio->cur_in = pufbuf; 463 464 pufbuf->pcc = pcc; 465 pufbuf->fcb = NULL; 466 pufbuf->fcb_arg = NULL; 467 468 pufbuf->offset = 0; 469 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT; 470 471 puffs_cc_yield(pcc); 472 pufbuf->istat &= ~ISTAT_NODESTROY; /* XXX: not the right place */ 473 if (pufbuf->rv) { 474 errno = pufbuf->rv; 475 return -1; 476 } 477 478 return 0; 479} 480 481int 482puffs_framev_enqueue_directsend(struct puffs_cc *pcc, int fd, 483 struct puffs_framebuf *pufbuf, int flags) 484{ 485 struct puffs_usermount *pu = pcc->pcc_pu; 486 struct puffs_fctrl_io *fio; 487 488 assert((pufbuf->istat & ISTAT_INTERNAL) == 0); 489 490 if (flags & PUFFS_FBQUEUE_URGENT) 491 abort(); /* EOPNOTSUPP for now */ 492 493 GETFIO(fd); 494 495 pufbuf->pcc = pcc; 496 pufbuf->fcb = NULL; 497 pufbuf->fcb_arg = NULL; 498 499 pufbuf->offset = 0; 500 pufbuf->istat |= ISTAT_NODESTROY | ISTAT_DIRECT; 501 502 TAILQ_INSERT_TAIL(&fio->snd_qing, pufbuf, pfb_entries); 503 504 puffs_cc_yield(pcc); 505 if (pufbuf->rv) { 506 pufbuf->istat &= ~ISTAT_NODESTROY; 507 errno = pufbuf->rv; 508 return -1; 509 } 510 511 return 0; 512} 513 514int 515puffs_framev_framebuf_ccpromote(struct puffs_framebuf *pufbuf, 516 struct puffs_cc *pcc) 517{ 518 519 if ((pufbuf->istat & ISTAT_ONQUEUE) == 0) { 520 errno = EBUSY; 521 return -1; 522 } 523 524 pufbuf->pcc = pcc; 525 pufbuf->fcb = NULL; 526 pufbuf->fcb_arg = NULL; 527 pufbuf->istat &= ~ISTAT_NOREPLY; 528 529 puffs_cc_yield(pcc); 530 531 return 0; 532} 533 534int 535puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what) 536{ 537 struct puffs_usermount *pu = pcc->pcc_pu; 538 struct puffs_fctrl_io *fio; 539 struct puffs_fbevent feb; 540 struct kevent kev; 541 int rv, svwhat; 542 543 svwhat = *what; 544 545 if (*what == 0) { 546 errno = EINVAL; 547 return -1; 548 } 549 550 fio = getfiobyfd(pu, fd); 551 if (fio == NULL) { 552 errno = EINVAL; 553 return -1; 554 } 555 556 feb.pcc = pcc; 557 feb.what = *what & (PUFFS_FBIO_READ|PUFFS_FBIO_WRITE|PUFFS_FBIO_ERROR); 558 559 if (*what & PUFFS_FBIO_READ) 560 if ((fio->stat & FIO_ENABLE_R) == 0) 561 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 562 0, 0, (uintptr_t)fio); 563 564 if (kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL) == -1) 565 return -1; 566 567 if (*what & PUFFS_FBIO_READ) 568 fio->rwait++; 569 if (*what & PUFFS_FBIO_WRITE) 570 fio->wwait++; 571 572 LIST_INSERT_HEAD(&fio->ev_qing, &feb, pfe_entries); 573 puffs_cc_yield(pcc); 574 575 assert(svwhat == *what); 576 577 if (*what & PUFFS_FBIO_READ) { 578 fio->rwait--; 579 if (fio->rwait == 0 && (fio->stat & FIO_ENABLE_R) == 0) { 580 EV_SET(&kev, fd, EVFILT_READ, EV_DISABLE, 581 0, 0, (uintptr_t)fio); 582 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 583#if 0 584 if (rv != 0) 585 /* XXXXX oh dear */; 586#endif 587 } 588 } 589 if (*what & PUFFS_FBIO_WRITE) 590 fio->wwait--; 591 592 if (feb.rv == 0) { 593 *what = feb.what; 594 rv = 0; 595 } else { 596 *what = PUFFS_FBIO_ERROR; 597 errno = feb.rv; 598 rv = -1; 599 } 600 601 return rv; 602} 603 604void 605puffs__framev_notify(struct puffs_fctrl_io *fio, int what) 606{ 607 struct puffs_fbevent *fbevp; 608 609 restart: 610 LIST_FOREACH(fbevp, &fio->ev_qing, pfe_entries) { 611 if (fbevp->what & what) { 612 fbevp->what = what; 613 fbevp->rv = 0; 614 LIST_REMOVE(fbevp, pfe_entries); 615 puffs_cc_continue(fbevp->pcc); 616 goto restart; 617 } 618 } 619} 620 621static struct puffs_framebuf * 622findbuf(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 623 struct puffs_fctrl_io *fio, struct puffs_framebuf *findme) 624{ 625 struct puffs_framebuf *cand; 626 int notresp = 0; 627 628 TAILQ_FOREACH(cand, &fio->res_qing, pfb_entries) 629 if (fctrl->cmpfb(pu, findme, cand, ¬resp) == 0 || notresp) 630 break; 631 632 assert(!(notresp && cand == NULL)); 633 if (notresp || cand == NULL) 634 return NULL; 635 636 TAILQ_REMOVE(&fio->res_qing, cand, pfb_entries); 637 return cand; 638} 639 640void 641puffs__framebuf_moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to) 642{ 643 644 assert(from->istat & ISTAT_INTERNAL); 645 646 /* migrate buffer */ 647 free(to->buf); 648 to->buf = from->buf; 649 650 /* migrate buffer info */ 651 to->len = from->len; 652 to->offset = from->offset; 653 to->maxoff = from->maxoff; 654 655 from->buf = NULL; 656 from->len = 0; 657} 658 659void 660puffs__framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 661 struct puffs_fctrl_io *fio) 662{ 663 struct puffs_framebuf *pufbuf, *appbuf; 664 int rv, complete; 665 666 while ((fio->stat & FIO_DEAD) == 0 && (fio->stat & FIO_ENABLE_R)) { 667 if ((pufbuf = fio->cur_in) == NULL) { 668 pufbuf = puffs_framebuf_make(); 669 if (pufbuf == NULL) 670 return; 671 pufbuf->istat |= ISTAT_INTERNAL; 672 fio->cur_in = pufbuf; 673 } 674 675 complete = 0; 676 rv = fctrl->rfb(pu, pufbuf, fio->io_fd, &complete); 677 678 /* error */ 679 if (rv) { 680 puffs__framev_readclose(pu, fio, rv); 681 fio->cur_in = NULL; 682 return; 683 } 684 685 /* partial read, come back to fight another day */ 686 if (complete == 0) 687 break; 688 689 /* else: full read, process */ 690 fio->cur_in = NULL; 691 if ((pufbuf->istat & ISTAT_DIRECT) == 0) { 692 appbuf = findbuf(pu, fctrl, fio, pufbuf); 693 694 /* 695 * No request for this frame? If fs implements 696 * gotfb, give frame to that. Otherwise drop it. 697 */ 698 if (appbuf == NULL) { 699 if (fctrl->gotfb) { 700 pufbuf->istat &= ~ISTAT_INTERNAL; 701 fctrl->gotfb(pu, pufbuf); 702 } else { 703 puffs_framebuf_destroy(pufbuf); 704 } 705 continue; 706 } 707 708 puffs__framebuf_moveinfo(pufbuf, appbuf); 709 puffs_framebuf_destroy(pufbuf); 710 } else { 711 appbuf = pufbuf; 712 } 713 appbuf->istat &= ~ISTAT_NODESTROY; 714 715 if (appbuf->pcc) { 716 puffs__cc_cont(appbuf->pcc); 717 } else if (appbuf->fcb) { 718 appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0); 719 } else { 720 puffs_framebuf_destroy(appbuf); 721 } 722 723 /* hopeless romantics, here we go again */ 724 } 725} 726 727int 728puffs__framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl, 729 struct puffs_fctrl_io *fio) 730{ 731 struct puffs_framebuf *pufbuf; 732 int rv, complete, done; 733 734 if (fio->stat & FIO_DEAD) 735 return 0; 736 737 for (pufbuf = TAILQ_FIRST(&fio->snd_qing), done = 0; 738 pufbuf && (fio->stat & FIO_DEAD) == 0 && fio->stat & FIO_ENABLE_W; 739 pufbuf = TAILQ_FIRST(&fio->snd_qing)) { 740 complete = 0; 741 rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete); 742 743 if (rv) { 744 puffs__framev_writeclose(pu, fio, rv); 745 done = 1; 746 break; 747 } 748 749 /* partial write */ 750 if (complete == 0) 751 return done; 752 753 /* else, complete write */ 754 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries); 755 756 /* can't wait for result if we can't read */ 757 if (fio->stat & FIO_RDGONE) { 758 errnotify(pu, pufbuf, ENXIO); 759 done = 1; 760 } else if ((pufbuf->istat & ISTAT_DIRECT)) { 761 pufbuf->istat &= ~ISTAT_NODESTROY; 762 done = 1; 763 puffs__cc_cont(pufbuf->pcc); 764 } else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) { 765 TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf, 766 pfb_entries); 767 } else { 768 pufbuf->istat &= ~ISTAT_NODESTROY; 769 puffs_framebuf_destroy(pufbuf); 770 } 771 772 /* omstart! */ 773 } 774 775 return done; 776} 777 778int 779puffs__framev_addfd_ctrl(struct puffs_usermount *pu, int fd, int what, 780 struct puffs_framectrl *pfctrl) 781{ 782 struct puffs_fctrl_io *fio; 783 struct kevent *newevs; 784 struct kevent kev[2]; 785 size_t nevs; 786 int rv, readenable; 787 788 nevs = pu->pu_nevs+2; 789 newevs = realloc(pu->pu_evs, nevs*sizeof(struct kevent)); 790 if (newevs == NULL) 791 return -1; 792 pu->pu_evs = newevs; 793 794 fio = malloc(sizeof(struct puffs_fctrl_io)); 795 if (fio == NULL) 796 return -1; 797 memset(fio, 0, sizeof(struct puffs_fctrl_io)); 798 fio->io_fd = fd; 799 fio->cur_in = NULL; 800 fio->fctrl = pfctrl; 801 TAILQ_INIT(&fio->snd_qing); 802 TAILQ_INIT(&fio->res_qing); 803 LIST_INIT(&fio->ev_qing); 804 805 readenable = 0; 806 if ((what & PUFFS_FBIO_READ) == 0) 807 readenable = EV_DISABLE; 808 809 if (pu->pu_state & PU_INLOOP) { 810 EV_SET(&kev[0], fd, EVFILT_READ, 811 EV_ADD|readenable, 0, 0, (intptr_t)fio); 812 EV_SET(&kev[1], fd, EVFILT_WRITE, 813 EV_ADD|EV_DISABLE, 0, 0, (intptr_t)fio); 814 rv = kevent(pu->pu_kq, kev, 2, NULL, 0, NULL); 815 if (rv == -1) { 816 free(fio); 817 return -1; 818 } 819 } 820 if (what & PUFFS_FBIO_READ) 821 fio->stat |= FIO_ENABLE_R; 822 if (what & PUFFS_FBIO_WRITE) 823 fio->stat |= FIO_ENABLE_W; 824 825 LIST_INSERT_HEAD(&pu->pu_ios, fio, fio_entries); 826 pu->pu_nevs = nevs; 827 828 return 0; 829} 830 831int 832puffs_framev_addfd(struct puffs_usermount *pu, int fd, int what) 833{ 834 835 return puffs__framev_addfd_ctrl(pu, fd, what, 836 &pu->pu_framectrl[PU_FRAMECTRL_USER]); 837} 838 839/* 840 * XXX: the following en/disable should be coalesced and executed 841 * only during the actual kevent call. So feel free to fix if 842 * threatened by mindblowing boredom. 843 */ 844 845int 846puffs_framev_enablefd(struct puffs_usermount *pu, int fd, int what) 847{ 848 struct kevent kev; 849 struct puffs_fctrl_io *fio; 850 int rv = 0; 851 852 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0); 853 854 fio = getfiobyfd(pu, fd); 855 if (fio == NULL) { 856 errno = ENXIO; 857 return -1; 858 } 859 860 /* write is enabled in the event loop if there is output */ 861 if (what & PUFFS_FBIO_READ && fio->rwait == 0) { 862 EV_SET(&kev, fd, EVFILT_READ, EV_ENABLE, 0, 0, (uintptr_t)fio); 863 rv = kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 864 } 865 866 if (rv == 0) { 867 if (what & PUFFS_FBIO_READ) 868 fio->stat |= FIO_ENABLE_R; 869 if (what & PUFFS_FBIO_WRITE) 870 fio->stat |= FIO_ENABLE_W; 871 } 872 873 return rv; 874} 875 876int 877puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what) 878{ 879 struct kevent kev[2]; 880 struct puffs_fctrl_io *fio; 881 size_t i; 882 int rv; 883 884 assert((what & (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) != 0); 885 886 fio = getfiobyfd(pu, fd); 887 if (fio == NULL) { 888 errno = ENXIO; 889 return -1; 890 } 891 892 i = 0; 893 if (what & PUFFS_FBIO_READ && fio->rwait == 0) { 894 EV_SET(&kev[0], fd, 895 EVFILT_READ, EV_DISABLE, 0, 0, (uintptr_t)fio); 896 i++; 897 } 898 if (what & PUFFS_FBIO_WRITE && fio->stat & FIO_WR && fio->wwait == 0) { 899 EV_SET(&kev[1], fd, 900 EVFILT_WRITE, EV_DISABLE, 0, 0, (uintptr_t)fio); 901 i++; 902 } 903 if (i) 904 rv = kevent(pu->pu_kq, kev, i, NULL, 0, NULL); 905 else 906 rv = 0; 907 908 if (rv == 0) { 909 if (what & PUFFS_FBIO_READ) 910 fio->stat &= ~FIO_ENABLE_R; 911 if (what & PUFFS_FBIO_WRITE) 912 fio->stat &= ~FIO_ENABLE_W; 913 } 914 915 return rv; 916} 917 918void 919puffs__framev_readclose(struct puffs_usermount *pu, 920 struct puffs_fctrl_io *fio, int error) 921{ 922 struct puffs_framebuf *pufbuf; 923 struct kevent kev; 924 int notflag; 925 926 if (fio->stat & FIO_RDGONE || fio->stat & FIO_DEAD) 927 return; 928 fio->stat |= FIO_RDGONE; 929 930 if (fio->cur_in) { 931 if ((fio->cur_in->istat & ISTAT_DIRECT) == 0) { 932 puffs_framebuf_destroy(fio->cur_in); 933 fio->cur_in = NULL; 934 } else { 935 errnotify(pu, fio->cur_in, error); 936 } 937 } 938 939 while ((pufbuf = TAILQ_FIRST(&fio->res_qing)) != NULL) { 940 TAILQ_REMOVE(&fio->res_qing, pufbuf, pfb_entries); 941 errnotify(pu, pufbuf, error); 942 } 943 944 EV_SET(&kev, fio->io_fd, EVFILT_READ, EV_DELETE, 0, 0, 0); 945 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 946 947 notflag = PUFFS_FBIO_READ; 948 if (fio->stat & FIO_WRGONE) 949 notflag |= PUFFS_FBIO_WRITE; 950 951 if (fio->fctrl->fdnotfn) 952 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag); 953} 954 955void 956puffs__framev_writeclose(struct puffs_usermount *pu, 957 struct puffs_fctrl_io *fio, int error) 958{ 959 struct puffs_framebuf *pufbuf; 960 struct kevent kev; 961 int notflag; 962 963 if (fio->stat & FIO_WRGONE || fio->stat & FIO_DEAD) 964 return; 965 fio->stat |= FIO_WRGONE; 966 967 while ((pufbuf = TAILQ_FIRST(&fio->snd_qing)) != NULL) { 968 TAILQ_REMOVE(&fio->snd_qing, pufbuf, pfb_entries); 969 errnotify(pu, pufbuf, error); 970 } 971 972 EV_SET(&kev, fio->io_fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); 973 (void) kevent(pu->pu_kq, &kev, 1, NULL, 0, NULL); 974 975 notflag = PUFFS_FBIO_WRITE; 976 if (fio->stat & FIO_RDGONE) 977 notflag |= PUFFS_FBIO_READ; 978 979 if (fio->fctrl->fdnotfn) 980 fio->fctrl->fdnotfn(pu, fio->io_fd, notflag); 981} 982 983static int 984removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error) 985{ 986 struct puffs_fbevent *fbevp; 987 988 LIST_REMOVE(fio, fio_entries); 989 if (pu->pu_state & PU_INLOOP) { 990 puffs__framev_readclose(pu, fio, error); 991 puffs__framev_writeclose(pu, fio, error); 992 } 993 994 while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) { 995 fbevp->rv = error; 996 LIST_REMOVE(fbevp, pfe_entries); 997 puffs__goto(fbevp->pcc); 998 } 999 1000 /* don't bother with realloc */ 1001 pu->pu_nevs -= 2; 1002 1003 /* don't free us yet, might have some references in event arrays */ 1004 fio->stat |= FIO_DEAD; 1005 LIST_INSERT_HEAD(&pu->pu_ios_rmlist, fio, fio_entries); 1006 1007 return 0; 1008 1009} 1010 1011int 1012puffs_framev_removefd(struct puffs_usermount *pu, int fd, int error) 1013{ 1014 struct puffs_fctrl_io *fio; 1015 1016 fio = getfiobyfd(pu, fd); 1017 if (fio == NULL) { 1018 errno = ENXIO; 1019 return -1; 1020 } 1021 1022 return removefio(pu, fio, error ? error : ECONNRESET); 1023} 1024 1025void 1026puffs_framev_removeonclose(struct puffs_usermount *pu, int fd, int what) 1027{ 1028 1029 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) 1030 (void) puffs_framev_removefd(pu, fd, ECONNRESET); 1031} 1032 1033void 1034puffs_framev_unmountonclose(struct puffs_usermount *pu, int fd, int what) 1035{ 1036 1037 /* XXX & X: unmount is non-sensible */ 1038 puffs_framev_removeonclose(pu, fd, what); 1039 if (what == (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) 1040 PU_SETSTATE(pu, PUFFS_STATE_UNMOUNTED); 1041} 1042 1043void 1044puffs_framev_init(struct puffs_usermount *pu, 1045 puffs_framev_readframe_fn rfb, puffs_framev_writeframe_fn wfb, 1046 puffs_framev_cmpframe_fn cmpfb, puffs_framev_gotframe_fn gotfb, 1047 puffs_framev_fdnotify_fn fdnotfn) 1048{ 1049 struct puffs_framectrl *pfctrl; 1050 1051 pfctrl = &pu->pu_framectrl[PU_FRAMECTRL_USER]; 1052 pfctrl->rfb = rfb; 1053 pfctrl->wfb = wfb; 1054 pfctrl->cmpfb = cmpfb; 1055 pfctrl->gotfb = gotfb; 1056 pfctrl->fdnotfn = fdnotfn; 1057} 1058 1059void 1060puffs__framev_exit(struct puffs_usermount *pu) 1061{ 1062 struct puffs_fctrl_io *fio; 1063 1064 while ((fio = LIST_FIRST(&pu->pu_ios)) != NULL) 1065 removefio(pu, fio, ENXIO); 1066 free(pu->pu_evs); 1067 1068 /* closing pu->pu_kq takes care of puffsfd */ 1069} 1070