Annotation of sys/miscfs/fifofs/fifo_vnops.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: fifo_vnops.c,v 1.24 2007/06/18 08:30:07 jasper Exp $ */
! 2: /* $NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1990, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)fifo_vnops.c 8.4 (Berkeley) 8/10/94
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/proc.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/time.h>
! 39: #include <sys/namei.h>
! 40: #include <sys/vnode.h>
! 41: #include <sys/socket.h>
! 42: #include <sys/socketvar.h>
! 43: #include <sys/stat.h>
! 44: #include <sys/ioctl.h>
! 45: #include <sys/file.h>
! 46: #include <sys/event.h>
! 47: #include <sys/errno.h>
! 48: #include <sys/malloc.h>
! 49: #include <sys/poll.h>
! 50: #include <sys/un.h>
! 51: #include <miscfs/fifofs/fifo.h>
! 52:
! 53: /*
! 54: * This structure is associated with the FIFO vnode and stores
! 55: * the state associated with the FIFO.
! 56: */
! 57: struct fifoinfo {
! 58: struct socket *fi_readsock;
! 59: struct socket *fi_writesock;
! 60: long fi_readers;
! 61: long fi_writers;
! 62: };
! 63:
! 64: int (**fifo_vnodeop_p)(void *);
! 65: struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
! 66: { &vop_default_desc, vn_default_error },
! 67: { &vop_lookup_desc, fifo_lookup }, /* lookup */
! 68: { &vop_create_desc, fifo_create }, /* create */
! 69: { &vop_mknod_desc, fifo_mknod }, /* mknod */
! 70: { &vop_open_desc, fifo_open }, /* open */
! 71: { &vop_close_desc, fifo_close }, /* close */
! 72: { &vop_access_desc, fifo_access }, /* access */
! 73: { &vop_getattr_desc, fifo_getattr }, /* getattr */
! 74: { &vop_setattr_desc, fifo_setattr }, /* setattr */
! 75: { &vop_read_desc, fifo_read }, /* read */
! 76: { &vop_write_desc, fifo_write }, /* write */
! 77: { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
! 78: { &vop_poll_desc, fifo_poll }, /* poll */
! 79: { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */
! 80: { &vop_revoke_desc, fifo_revoke }, /* revoke */
! 81: { &vop_fsync_desc, fifo_fsync }, /* fsync */
! 82: { &vop_remove_desc, fifo_remove }, /* remove */
! 83: { &vop_link_desc, fifo_link }, /* link */
! 84: { &vop_rename_desc, fifo_rename }, /* rename */
! 85: { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
! 86: { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
! 87: { &vop_symlink_desc, fifo_symlink }, /* symlink */
! 88: { &vop_readdir_desc, fifo_readdir }, /* readdir */
! 89: { &vop_readlink_desc, fifo_readlink }, /* readlink */
! 90: { &vop_abortop_desc, fifo_abortop }, /* abortop */
! 91: { &vop_inactive_desc, fifo_inactive }, /* inactive */
! 92: { &vop_reclaim_desc, fifo_reclaim }, /* reclaim */
! 93: { &vop_lock_desc, fifo_lock }, /* lock */
! 94: { &vop_unlock_desc, fifo_unlock }, /* unlock */
! 95: { &vop_bmap_desc, fifo_bmap }, /* bmap */
! 96: { &vop_strategy_desc, fifo_strategy }, /* strategy */
! 97: { &vop_print_desc, fifo_print }, /* print */
! 98: { &vop_islocked_desc, fifo_islocked }, /* islocked */
! 99: { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
! 100: { &vop_advlock_desc, fifo_advlock }, /* advlock */
! 101: { &vop_bwrite_desc, fifo_bwrite }, /* bwrite */
! 102: { NULL, NULL }
! 103: };
! 104:
! 105: struct vnodeopv_desc fifo_vnodeop_opv_desc =
! 106: { &fifo_vnodeop_p, fifo_vnodeop_entries };
! 107:
! 108: int
! 109: fifo_vnoperate(void *v)
! 110: {
! 111: struct vop_generic_args *ap = v;
! 112:
! 113: return (VOCALL(fifo_vnodeop_p, ap->a_desc->vdesc_offset, ap));
! 114: }
! 115:
! 116: void filt_fifordetach(struct knote *kn);
! 117: int filt_fiforead(struct knote *kn, long hint);
! 118: void filt_fifowdetach(struct knote *kn);
! 119: int filt_fifowrite(struct knote *kn, long hint);
! 120:
! 121: struct filterops fiforead_filtops =
! 122: { 1, NULL, filt_fifordetach, filt_fiforead };
! 123: struct filterops fifowrite_filtops =
! 124: { 1, NULL, filt_fifowdetach, filt_fifowrite };
! 125:
! 126: /*
! 127: * Trivial lookup routine that always fails.
! 128: */
! 129: /* ARGSUSED */
! 130: int
! 131: fifo_lookup(void *v)
! 132: {
! 133: struct vop_lookup_args *ap = v;
! 134:
! 135: *ap->a_vpp = NULL;
! 136: return (ENOTDIR);
! 137: }
! 138:
! 139: /*
! 140: * Open called to set up a new instance of a fifo or
! 141: * to find an active instance of a fifo.
! 142: */
! 143: /* ARGSUSED */
! 144: int
! 145: fifo_open(void *v)
! 146: {
! 147: struct vop_open_args *ap = v;
! 148: struct vnode *vp = ap->a_vp;
! 149: struct fifoinfo *fip;
! 150: struct proc *p = ap->a_p;
! 151: struct socket *rso, *wso;
! 152: int error;
! 153:
! 154: if ((fip = vp->v_fifoinfo) == NULL) {
! 155: MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
! 156: vp->v_fifoinfo = fip;
! 157: if ((error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) != 0) {
! 158: free(fip, M_VNODE);
! 159: vp->v_fifoinfo = NULL;
! 160: return (error);
! 161: }
! 162: fip->fi_readsock = rso;
! 163: if ((error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) != 0) {
! 164: (void)soclose(rso);
! 165: free(fip, M_VNODE);
! 166: vp->v_fifoinfo = NULL;
! 167: return (error);
! 168: }
! 169: fip->fi_writesock = wso;
! 170: if ((error = unp_connect2(wso, rso)) != 0) {
! 171: (void)soclose(wso);
! 172: (void)soclose(rso);
! 173: free(fip, M_VNODE);
! 174: vp->v_fifoinfo = NULL;
! 175: return (error);
! 176: }
! 177: fip->fi_readers = fip->fi_writers = 0;
! 178: wso->so_snd.sb_lowat = PIPE_BUF;
! 179: rso->so_state |= SS_CANTRCVMORE;
! 180: }
! 181: if (ap->a_mode & FREAD) {
! 182: fip->fi_readers++;
! 183: if (fip->fi_readers == 1) {
! 184: fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
! 185: if (fip->fi_writers > 0)
! 186: wakeup(&fip->fi_writers);
! 187: }
! 188: }
! 189: if (ap->a_mode & FWRITE) {
! 190: fip->fi_writers++;
! 191: if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
! 192: error = ENXIO;
! 193: goto bad;
! 194: }
! 195: if (fip->fi_writers == 1) {
! 196: fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
! 197: if (fip->fi_readers > 0)
! 198: wakeup(&fip->fi_readers);
! 199: }
! 200: }
! 201: if ((ap->a_mode & O_NONBLOCK) == 0) {
! 202: if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
! 203: VOP_UNLOCK(vp, 0, p);
! 204: error = tsleep(&fip->fi_readers,
! 205: PCATCH | PSOCK, "fifor", 0);
! 206: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 207: if (error)
! 208: goto bad;
! 209: }
! 210: if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) {
! 211: VOP_UNLOCK(vp, 0, p);
! 212: error = tsleep(&fip->fi_writers,
! 213: PCATCH | PSOCK, "fifow", 0);
! 214: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 215: if (error)
! 216: goto bad;
! 217: }
! 218: }
! 219: return (0);
! 220: bad:
! 221: VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p);
! 222: return (error);
! 223: }
! 224:
! 225: /*
! 226: * Vnode op for read
! 227: */
! 228: /* ARGSUSED */
! 229: int
! 230: fifo_read(void *v)
! 231: {
! 232: struct vop_read_args *ap = v;
! 233: struct uio *uio = ap->a_uio;
! 234: struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
! 235: struct proc *p = uio->uio_procp;
! 236: int error;
! 237:
! 238: #ifdef DIAGNOSTIC
! 239: if (uio->uio_rw != UIO_READ)
! 240: panic("fifo_read mode");
! 241: #endif
! 242: if (uio->uio_resid == 0)
! 243: return (0);
! 244: if (ap->a_ioflag & IO_NDELAY)
! 245: rso->so_state |= SS_NBIO;
! 246: VOP_UNLOCK(ap->a_vp, 0, p);
! 247: error = soreceive(rso, NULL, uio, NULL, NULL, NULL);
! 248: vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
! 249: if (ap->a_ioflag & IO_NDELAY) {
! 250: rso->so_state &= ~SS_NBIO;
! 251: if (error == EWOULDBLOCK &&
! 252: ap->a_vp->v_fifoinfo->fi_writers == 0)
! 253: error = 0;
! 254: }
! 255: return (error);
! 256: }
! 257:
! 258: /*
! 259: * Vnode op for write
! 260: */
! 261: /* ARGSUSED */
! 262: int
! 263: fifo_write(void *v)
! 264: {
! 265: struct vop_write_args *ap = v;
! 266: struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
! 267: struct proc *p = ap->a_uio->uio_procp;
! 268: int error;
! 269:
! 270: #ifdef DIAGNOSTIC
! 271: if (ap->a_uio->uio_rw != UIO_WRITE)
! 272: panic("fifo_write mode");
! 273: #endif
! 274: if (ap->a_ioflag & IO_NDELAY)
! 275: wso->so_state |= SS_NBIO;
! 276: VOP_UNLOCK(ap->a_vp, 0, p);
! 277: error = sosend(wso, NULL, ap->a_uio, NULL, NULL, 0);
! 278: vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
! 279: if (ap->a_ioflag & IO_NDELAY)
! 280: wso->so_state &= ~SS_NBIO;
! 281: return (error);
! 282: }
! 283:
! 284: /*
! 285: * Device ioctl operation.
! 286: */
! 287: /* ARGSUSED */
! 288: int
! 289: fifo_ioctl(void *v)
! 290: {
! 291: struct vop_ioctl_args *ap = v;
! 292: struct file filetmp;
! 293: int error;
! 294:
! 295: if (ap->a_command == FIONBIO)
! 296: return (0);
! 297: if (ap->a_fflag & FREAD) {
! 298: filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
! 299: error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
! 300: if (error)
! 301: return (error);
! 302: }
! 303: if (ap->a_fflag & FWRITE) {
! 304: filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
! 305: error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
! 306: if (error)
! 307: return (error);
! 308: }
! 309: return (0);
! 310: }
! 311:
! 312: /* ARGSUSED */
! 313: int
! 314: fifo_poll(void *v)
! 315: {
! 316: struct vop_poll_args *ap = v;
! 317: struct file filetmp;
! 318: short ostate;
! 319: int revents = 0;
! 320:
! 321: if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
! 322: /*
! 323: * Socket and FIFO poll(2) semantics differ wrt EOF on read.
! 324: * Unlike a normal socket, FIFOs don't care whether or not
! 325: * SS_CANTRCVMORE is set. To get the correct semantics we
! 326: * must clear SS_CANTRCVMORE from so_state temporarily.
! 327: */
! 328: ostate = ap->a_vp->v_fifoinfo->fi_readsock->so_state;
! 329: if (ap->a_events & (POLLIN | POLLRDNORM))
! 330: ap->a_vp->v_fifoinfo->fi_readsock->so_state &=
! 331: ~SS_CANTRCVMORE;
! 332: filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
! 333: if (filetmp.f_data)
! 334: revents |= soo_poll(&filetmp, ap->a_events, ap->a_p);
! 335: ap->a_vp->v_fifoinfo->fi_readsock->so_state = ostate;
! 336: }
! 337: if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
! 338: filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
! 339: if (filetmp.f_data)
! 340: revents |= soo_poll(&filetmp, ap->a_events, ap->a_p);
! 341: }
! 342: return (revents);
! 343: }
! 344:
! 345: int
! 346: fifo_inactive(void *v)
! 347: {
! 348: struct vop_inactive_args *ap = v;
! 349:
! 350: VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
! 351: return (0);
! 352: }
! 353:
! 354: /*
! 355: * This is a noop, simply returning what one has been given.
! 356: */
! 357: int
! 358: fifo_bmap(void *v)
! 359: {
! 360: struct vop_bmap_args *ap = v;
! 361:
! 362: if (ap->a_vpp != NULL)
! 363: *ap->a_vpp = ap->a_vp;
! 364: if (ap->a_bnp != NULL)
! 365: *ap->a_bnp = ap->a_bn;
! 366: return (0);
! 367: }
! 368:
! 369: /*
! 370: * Device close routine
! 371: */
! 372: /* ARGSUSED */
! 373: int
! 374: fifo_close(void *v)
! 375: {
! 376: struct vop_close_args *ap = v;
! 377: struct vnode *vp = ap->a_vp;
! 378: struct fifoinfo *fip = vp->v_fifoinfo;
! 379: int error1 = 0, error2 = 0;
! 380:
! 381: if (fip == NULL)
! 382: return (0);
! 383:
! 384: if (ap->a_fflag & FREAD) {
! 385: if (--fip->fi_readers == 0)
! 386: socantsendmore(fip->fi_writesock);
! 387: }
! 388: if (ap->a_fflag & FWRITE) {
! 389: if (--fip->fi_writers == 0)
! 390: socantrcvmore(fip->fi_readsock);
! 391: }
! 392: if (fip->fi_readers == 0 && fip->fi_writers == 0) {
! 393: error1 = soclose(fip->fi_readsock);
! 394: error2 = soclose(fip->fi_writesock);
! 395: FREE(fip, M_VNODE);
! 396: vp->v_fifoinfo = NULL;
! 397: }
! 398: return (error1 ? error1 : error2);
! 399: }
! 400:
! 401: int
! 402: fifo_reclaim(void *v)
! 403: {
! 404: struct vop_reclaim_args *ap = v;
! 405: struct vnode *vp = ap->a_vp;
! 406: struct fifoinfo *fip = vp->v_fifoinfo;
! 407:
! 408: if (fip == NULL)
! 409: return (0);
! 410:
! 411: soclose(fip->fi_readsock);
! 412: soclose(fip->fi_writesock);
! 413: FREE(fip, M_VNODE);
! 414: vp->v_fifoinfo = NULL;
! 415:
! 416: return (0);
! 417: }
! 418:
! 419: /*
! 420: * Print out the contents of a fifo vnode.
! 421: */
! 422: int
! 423: fifo_print(void *v)
! 424: {
! 425: struct vop_print_args *ap = v;
! 426:
! 427: printf("tag VT_NON");
! 428: fifo_printinfo(ap->a_vp);
! 429: printf("\n");
! 430: return 0;
! 431: }
! 432:
! 433: /*
! 434: * Print out internal contents of a fifo vnode.
! 435: */
! 436: void
! 437: fifo_printinfo(struct vnode *vp)
! 438: {
! 439: struct fifoinfo *fip = vp->v_fifoinfo;
! 440:
! 441: printf(", fifo with %ld readers and %ld writers",
! 442: fip->fi_readers, fip->fi_writers);
! 443: }
! 444:
! 445: /*
! 446: * Return POSIX pathconf information applicable to fifo's.
! 447: */
! 448: int
! 449: fifo_pathconf(void *v)
! 450: {
! 451: struct vop_pathconf_args *ap = v;
! 452:
! 453: switch (ap->a_name) {
! 454: case _PC_LINK_MAX:
! 455: *ap->a_retval = LINK_MAX;
! 456: return (0);
! 457: case _PC_PIPE_BUF:
! 458: *ap->a_retval = PIPE_BUF;
! 459: return (0);
! 460: case _PC_CHOWN_RESTRICTED:
! 461: *ap->a_retval = 1;
! 462: return (0);
! 463: default:
! 464: return (EINVAL);
! 465: }
! 466: /* NOTREACHED */
! 467: }
! 468:
! 469: /*
! 470: * Fifo failed operation
! 471: */
! 472: /*ARGSUSED*/
! 473: int
! 474: fifo_ebadf(void *v)
! 475: {
! 476:
! 477: return (EBADF);
! 478: }
! 479:
! 480: /*
! 481: * Fifo advisory byte-level locks.
! 482: */
! 483: /* ARGSUSED */
! 484: int
! 485: fifo_advlock(void *v)
! 486: {
! 487: return (EOPNOTSUPP);
! 488: }
! 489:
! 490: /*
! 491: * Fifo bad operation
! 492: */
! 493: /*ARGSUSED*/
! 494: int
! 495: fifo_badop(void *v)
! 496: {
! 497:
! 498: panic("fifo_badop called");
! 499: /* NOTREACHED */
! 500: return(0);
! 501: }
! 502:
! 503:
! 504: int
! 505: fifo_kqfilter(void *v)
! 506: {
! 507: struct vop_kqfilter_args *ap = v;
! 508: struct socket *so = (struct socket *)ap->a_vp->v_fifoinfo->fi_readsock;
! 509: struct sockbuf *sb;
! 510:
! 511: switch (ap->a_kn->kn_filter) {
! 512: case EVFILT_READ:
! 513: ap->a_kn->kn_fop = &fiforead_filtops;
! 514: sb = &so->so_rcv;
! 515: break;
! 516: case EVFILT_WRITE:
! 517: ap->a_kn->kn_fop = &fifowrite_filtops;
! 518: sb = &so->so_snd;
! 519: break;
! 520: default:
! 521: return (1);
! 522: }
! 523:
! 524: ap->a_kn->kn_hook = so;
! 525:
! 526: SLIST_INSERT_HEAD(&sb->sb_sel.si_note, ap->a_kn, kn_selnext);
! 527: sb->sb_flags |= SB_KNOTE;
! 528:
! 529: return (0);
! 530: }
! 531:
! 532: void
! 533: filt_fifordetach(struct knote *kn)
! 534: {
! 535: struct socket *so = (struct socket *)kn->kn_hook;
! 536:
! 537: SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext);
! 538: if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note))
! 539: so->so_rcv.sb_flags &= ~SB_KNOTE;
! 540: }
! 541:
! 542: int
! 543: filt_fiforead(struct knote *kn, long hint)
! 544: {
! 545: struct socket *so = (struct socket *)kn->kn_hook;
! 546:
! 547: kn->kn_data = so->so_rcv.sb_cc;
! 548: if (so->so_state & SS_CANTRCVMORE) {
! 549: kn->kn_flags |= EV_EOF;
! 550: return (1);
! 551: }
! 552: kn->kn_flags &= ~EV_EOF;
! 553: return (kn->kn_data > 0);
! 554: }
! 555:
! 556: void
! 557: filt_fifowdetach(struct knote *kn)
! 558: {
! 559: struct socket *so = (struct socket *)kn->kn_hook;
! 560:
! 561: SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext);
! 562: if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note))
! 563: so->so_snd.sb_flags &= ~SB_KNOTE;
! 564: }
! 565:
! 566: int
! 567: filt_fifowrite(struct knote *kn, long hint)
! 568: {
! 569: struct socket *so = (struct socket *)kn->kn_hook;
! 570:
! 571: kn->kn_data = sbspace(&so->so_snd);
! 572: if (so->so_state & SS_CANTSENDMORE) {
! 573: kn->kn_flags |= EV_EOF;
! 574: return (1);
! 575: }
! 576: kn->kn_flags &= ~EV_EOF;
! 577: return (kn->kn_data >= so->so_snd.sb_lowat);
! 578: }
CVSweb