1/* 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ 29/* 30 * Copyright (c) 1990, 1993, 1995 31 * The Regents of the University of California. All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. All advertising materials mentioning features or use of this software 42 * must display the following acknowledgement: 43 * This product includes software developed by the University of 44 * California, Berkeley and its contributors. 45 * 4. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)fifo_vnops.c 8.4 (Berkeley) 8/10/94 62 */ 63 64#include <sys/param.h> 65#include <sys/proc.h> 66#include <sys/time.h> 67#include <sys/namei.h> 68#include <sys/vnode_internal.h> 69#include <sys/socket.h> 70#include <sys/socketvar.h> 71#include <sys/stat.h> 72#include <sys/systm.h> 73#include <sys/ioctl.h> 74#include <sys/file_internal.h> 75#include <sys/errno.h> 76#include <sys/malloc.h> 77#include <miscfs/fifofs/fifo.h> 78#include <vfs/vfs_support.h> 79 80#define VOPFUNC int (*)(void *) 81 82int (**fifo_vnodeop_p)(void *); 83struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { 84 { &vnop_default_desc, (VOPFUNC)vn_default_error }, 85 { &vnop_lookup_desc, (VOPFUNC)fifo_lookup }, /* lookup */ 86 { &vnop_create_desc, (VOPFUNC)err_create }, /* create */ 87 { &vnop_mknod_desc, (VOPFUNC)err_mknod }, /* mknod */ 88 { &vnop_open_desc, (VOPFUNC)fifo_open }, /* open */ 89 { &vnop_close_desc, (VOPFUNC)fifo_close }, /* close */ 90 { &vnop_access_desc, (VOPFUNC)fifo_access }, /* access */ 91 { &vnop_getattr_desc, (VOPFUNC)fifo_getattr }, /* getattr */ 92 { &vnop_setattr_desc, (VOPFUNC)fifo_setattr }, /* setattr */ 93 { &vnop_read_desc, (VOPFUNC)fifo_read }, /* read */ 94 { &vnop_write_desc, (VOPFUNC)fifo_write }, /* write */ 95 { &vnop_ioctl_desc, (VOPFUNC)fifo_ioctl }, /* ioctl */ 96 { &vnop_select_desc, (VOPFUNC)fifo_select }, /* select */ 97 { &vnop_revoke_desc, (VOPFUNC)fifo_revoke }, /* revoke */ 98 { &vnop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */ 99 { &vnop_fsync_desc, (VOPFUNC)fifo_fsync }, /* fsync */ 100 { &vnop_remove_desc, (VOPFUNC)err_remove }, /* remove */ 101 { &vnop_link_desc, (VOPFUNC)err_link }, /* link */ 102 { &vnop_rename_desc, (VOPFUNC)err_rename }, /* rename */ 103 { &vnop_mkdir_desc, (VOPFUNC)err_mkdir }, /* mkdir */ 104 { &vnop_rmdir_desc, (VOPFUNC)err_rmdir }, /* rmdir */ 105 { &vnop_symlink_desc, (VOPFUNC)err_symlink }, /* symlink */ 106 { &vnop_readdir_desc, (VOPFUNC)err_readdir }, /* readdir */ 107 { &vnop_readlink_desc, (VOPFUNC)err_readlink }, /* readlink */ 108 { &vnop_inactive_desc, (VOPFUNC)fifo_inactive }, /* inactive */ 109 { &vnop_reclaim_desc, (VOPFUNC)fifo_reclaim }, /* reclaim */ 110 { &vnop_strategy_desc, (VOPFUNC)err_strategy }, /* strategy */ 111 { &vnop_pathconf_desc, (VOPFUNC)fifo_pathconf }, /* pathconf */ 112 { &vnop_advlock_desc, (VOPFUNC)fifo_advlock }, /* advlock */ 113 { &vnop_bwrite_desc, (VOPFUNC)fifo_bwrite }, /* bwrite */ 114 { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */ 115 { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */ 116 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */ 117 { &vnop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff */ 118 { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk */ 119 { &vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap */ 120 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 121}; 122struct vnodeopv_desc fifo_vnodeop_opv_desc = 123 { &fifo_vnodeop_p, fifo_vnodeop_entries }; 124 125/* 126 * Trivial lookup routine that always fails. 127 */ 128/* ARGSUSED */ 129int 130fifo_lookup(struct vnop_lookup_args *ap) 131{ 132 133 *ap->a_vpp = NULL; 134 return (ENOTDIR); 135} 136 137/* 138 * Open called to set up a new instance of a fifo or 139 * to find an active instance of a fifo. 140 */ 141/* ARGSUSED */ 142int 143fifo_open(struct vnop_open_args *ap) 144{ 145 struct vnode *vp = ap->a_vp; 146 struct fifoinfo *fip; 147 struct socket *rso, *wso; 148 int error; 149 150 vnode_lock(vp); 151 152retry: 153 154 fip = vp->v_fifoinfo; 155 156 if (fip == (struct fifoinfo *)0) 157 panic("fifo_open with no fifoinfo"); 158 159 if ((fip->fi_flags & FIFO_CREATED) == 0) { 160 if (fip->fi_flags & FIFO_INCREATE) { 161 fip->fi_flags |= FIFO_CREATEWAIT; 162 error = msleep(&fip->fi_flags, &vp->v_lock, PRIBIO | PCATCH, "fifocreatewait", NULL); 163 if (error) { 164 vnode_unlock(vp); 165 return(error); 166 } 167 goto retry; 168 } else { 169 fip->fi_flags |= FIFO_INCREATE; 170 vnode_unlock(vp); 171 if ( (error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) ) { 172 goto bad1; 173 } 174 175 if ( (error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) ) { 176 (void)soclose(rso); 177 goto bad1; 178 } 179 180 if ( (error = soconnect2(wso, rso)) ) { 181 (void)soclose(wso); 182 (void)soclose(rso); 183 goto bad1; 184 } 185 fip->fi_readers = fip->fi_writers = 0; 186 187 /* Lock ordering between wso and rso does not matter here 188 * because they are just created and no one has a reference to them 189 */ 190 socket_lock(wso, 1); 191 wso->so_state |= SS_CANTRCVMORE; 192 wso->so_snd.sb_lowat = PIPE_BUF; 193 socket_unlock(wso, 1); 194 195 socket_lock(rso, 1); 196 rso->so_state |= SS_CANTSENDMORE; 197 socket_unlock(rso, 1); 198 199 vnode_lock(vp); 200 fip->fi_readsock = rso; 201 fip->fi_writesock = wso; 202 203 fip->fi_flags |= FIFO_CREATED; 204 fip->fi_flags &= ~FIFO_INCREATE; 205 206 if ((fip->fi_flags & FIFO_CREATEWAIT)) { 207 fip->fi_flags &= ~FIFO_CREATEWAIT; 208 wakeup(&fip->fi_flags); 209 } 210 /* vnode lock is held to process further */ 211 } 212 } 213 214 /* vnode is locked at this point */ 215 /* fifo in created already */ 216 if (ap->a_mode & FREAD) { 217 fip->fi_readers++; 218 if (fip->fi_readers == 1) { 219 socket_lock(fip->fi_writesock, 1); 220 fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; 221 socket_unlock(fip->fi_writesock, 1); 222 223 if (fip->fi_writers > 0) 224 wakeup((caddr_t)&fip->fi_writers); 225 } 226 } 227 if (ap->a_mode & FWRITE) { 228 fip->fi_writers++; 229 if (fip->fi_writers == 1) { 230 socket_lock(fip->fi_readsock, 1); 231 fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; 232 socket_unlock(fip->fi_readsock, 1); 233 234 if (fip->fi_readers > 0) 235 wakeup((caddr_t)&fip->fi_readers); 236 } 237 } 238 if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) { 239 if (fip->fi_writers == 0) { 240 error = msleep((caddr_t)&fip->fi_readers, &vp->v_lock, 241 PCATCH | PSOCK, "fifoor", NULL); 242 if (error) 243 goto bad; 244 if (fip->fi_readers == 1) { 245 if (fip->fi_writers > 0) 246 wakeup((caddr_t)&fip->fi_writers); 247 } 248 } 249 } 250 if (ap->a_mode & FWRITE) { 251 if (ap->a_mode & O_NONBLOCK) { 252 if (fip->fi_readers == 0) { 253 error = ENXIO; 254 goto bad; 255 } 256 } else { 257 if (fip->fi_readers == 0) { 258 error = msleep((caddr_t)&fip->fi_writers,&vp->v_lock, 259 PCATCH | PSOCK, "fifoow", NULL); 260 if (error) 261 goto bad; 262 if (fip->fi_writers == 1) { 263 if (fip->fi_readers > 0) 264 wakeup((caddr_t)&fip->fi_readers); 265 } 266 } 267 } 268 } 269 270 vnode_unlock(vp); 271 return (0); 272bad: 273 fifo_close_internal(vp, ap->a_mode, ap->a_context, 1); 274 275 vnode_unlock(vp); 276 return (error); 277bad1: 278 vnode_lock(vp); 279 280 fip->fi_flags &= ~FIFO_INCREATE; 281 282 if ((fip->fi_flags & FIFO_CREATEWAIT)) { 283 fip->fi_flags &= ~FIFO_CREATEWAIT; 284 wakeup(&fip->fi_flags); 285 } 286 vnode_unlock(vp); 287 288 return (error); 289} 290 291/* 292 * Vnode op for read 293 */ 294int 295fifo_read(struct vnop_read_args *ap) 296{ 297 struct uio *uio = ap->a_uio; 298 struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; 299 user_ssize_t startresid; 300 int error; 301 int rflags; 302 303#if DIAGNOSTIC 304 if (uio->uio_rw != UIO_READ) 305 panic("fifo_read mode"); 306#endif 307 if (uio_resid(uio) == 0) 308 return (0); 309 310 rflags = (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0; 311 312 startresid = uio_resid(uio); 313 314 /* fifo conformance - if we have a reader open on the fifo but no 315 * writers then we need to make sure we do not block. We do that by 316 * checking the receive buffer and if empty set error to EWOULDBLOCK. 317 * If error is set to EWOULDBLOCK we skip the call into soreceive 318 */ 319 error = 0; 320 if (ap->a_vp->v_fifoinfo->fi_writers < 1) { 321 socket_lock(rso, 1); 322 error = (rso->so_rcv.sb_cc == 0) ? EWOULDBLOCK : 0; 323 socket_unlock(rso, 1); 324 } 325 326 /* skip soreceive to avoid blocking when we have no writers */ 327 if (error != EWOULDBLOCK) { 328 error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0, 329 (struct mbuf **)0, &rflags); 330 } 331 else { 332 /* clear EWOULDBLOCK and return EOF (zero) */ 333 error = 0; 334 } 335 /* 336 * Clear EOF indication after first such return. 337 */ 338 if (uio_resid(uio) == startresid) { 339 socket_lock(rso, 1); 340 rso->so_state &= ~SS_CANTRCVMORE; 341 socket_unlock(rso, 1); 342 } 343 return (error); 344} 345 346/* 347 * Vnode op for write 348 */ 349int 350fifo_write(struct vnop_write_args *ap) 351{ 352 struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock; 353 int error; 354 355#if DIAGNOSTIC 356 if (ap->a_uio->uio_rw != UIO_WRITE) 357 panic("fifo_write mode"); 358#endif 359 error = sosend(wso, (struct sockaddr *)0, ap->a_uio, NULL, 360 (struct mbuf *)0, (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0); 361 362 return (error); 363} 364 365/* 366 * Device ioctl operation. 367 */ 368int 369fifo_ioctl(struct vnop_ioctl_args *ap) 370{ 371 struct fileproc filetmp; 372 struct fileglob filefg; 373 int error; 374 375 if (ap->a_command == FIONBIO) 376 return (0); 377 bzero(&filetmp, sizeof(struct fileproc)); 378 filetmp.f_fglob = &filefg; 379 if (ap->a_fflag & FREAD) { 380 filetmp.f_fglob->fg_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; 381 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context); 382 if (error) 383 return (error); 384 } 385 if (ap->a_fflag & FWRITE) { 386 filetmp.f_fglob->fg_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; 387 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context); 388 if (error) 389 return (error); 390 } 391 return (0); 392} 393 394int 395fifo_select(struct vnop_select_args *ap) 396{ 397 struct fileproc filetmp; 398 struct fileglob filefg; 399 int ready; 400 401 bzero(&filetmp, sizeof(struct fileproc)); 402 filetmp.f_fglob = &filefg; 403 if (ap->a_which & FREAD) { 404 filetmp.f_fglob->fg_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; 405 ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context); 406 if (ready) 407 return (ready); 408 } 409 if (ap->a_which & FWRITE) { 410 filetmp.f_fglob->fg_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; 411 ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context); 412 if (ready) 413 return (ready); 414 } 415 return (0); 416} 417 418int 419fifo_inactive(__unused struct vnop_inactive_args *ap) 420{ 421 return (0); 422} 423 424 425/* 426 * Device close routine 427 */ 428int 429fifo_close(struct vnop_close_args *ap) 430{ 431 return fifo_close_internal(ap->a_vp, ap->a_fflag, ap->a_context, 0); 432} 433 434int 435fifo_close_internal(vnode_t vp, int fflag, __unused vfs_context_t context, int locked) 436{ 437 struct fifoinfo *fip = vp->v_fifoinfo; 438 int error1, error2; 439 struct socket *rso; 440 struct socket *wso; 441 442 if (!locked) 443 vnode_lock(vp); 444 445 if ((fip->fi_flags & FIFO_CREATED) == 0) { 446 if (!locked) 447 vnode_unlock(vp); 448 return(0); 449 450 } 451 452 if (fflag & FREAD) { 453 fip->fi_readers--; 454 if (fip->fi_readers == 0){ 455 socket_lock(fip->fi_writesock, 1); 456 socantsendmore(fip->fi_writesock); 457 socket_unlock(fip->fi_writesock, 1); 458 } 459 } 460 461 if (fflag & FWRITE) { 462 fip->fi_writers--; 463 if (fip->fi_writers == 0) { 464 socket_lock(fip->fi_readsock, 1); 465 socantrcvmore(fip->fi_readsock); 466 socket_unlock(fip->fi_readsock, 1); 467 } 468 } 469#if 0 470 if (vnode_isinuse_locked(vp, 0, 1)) { 471 if (!locked) 472 vnode_unlock(vp); 473 return (0); 474 } 475#endif 476 477 if (fip->fi_writers || fip->fi_readers) { 478 if (!locked) 479 vnode_unlock(vp); 480 return (0); 481 } 482 483 wso = fip->fi_writesock; 484 rso = fip->fi_readsock; 485 fip->fi_readsock = NULL; 486 fip->fi_writesock = NULL; 487 fip->fi_flags &= ~FIFO_CREATED; 488 if (!locked) 489 vnode_unlock(vp); 490 error1 = soclose(rso); 491 error2 = soclose(wso); 492 493 if (error1) 494 return (error1); 495 return (error2); 496} 497 498/* 499 * Print out internal contents of a fifo vnode. 500 */ 501void 502fifo_printinfo(struct vnode *vp) 503{ 504 struct fifoinfo *fip = vp->v_fifoinfo; 505 506 printf(", fifo with %ld readers and %ld writers", 507 fip->fi_readers, fip->fi_writers); 508} 509 510/* 511 * Return POSIX pathconf information applicable to fifo's. 512 */ 513int 514fifo_pathconf(struct vnop_pathconf_args *ap) 515{ 516 switch (ap->a_name) { 517 case _PC_LINK_MAX: 518 *ap->a_retval = LINK_MAX; 519 return (0); 520 case _PC_PIPE_BUF: 521 *ap->a_retval = PIPE_BUF; 522 return (0); 523 case _PC_CHOWN_RESTRICTED: 524 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */ 525 return (0); 526 default: 527 return (EINVAL); 528 } 529 /* NOTREACHED */ 530} 531 532/* 533 * Fifo failed operation 534 */ 535int 536fifo_ebadf(__unused void *dummy) 537{ 538 539 return (EBADF); 540} 541 542/* 543 * Fifo advisory byte-level locks. 544 */ 545int 546fifo_advlock(__unused struct vnop_advlock_args *ap) 547{ 548 549 return (ENOTSUP); 550} 551 552 553/* You'd certainly better have an iocount on the vnode! */ 554int 555fifo_freespace(struct vnode *vp, long *count) 556{ 557 struct socket *rsock; 558 rsock = vp->v_fifoinfo->fi_readsock; 559 socket_lock(rsock, 1); 560 *count = sbspace(&rsock->so_rcv); 561 socket_unlock(rsock, 1); 562 return 0; 563} 564 565int 566fifo_charcount(struct vnode *vp, int *count) 567{ 568 int mcount; 569 int err = sock_ioctl(vp->v_fifoinfo->fi_readsock, FIONREAD, (void*)&mcount); 570 if (err == 0) { 571 *count = mcount; 572 } 573 return err; 574} 575