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 82extern int soo_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, vfs_context_t ctx); 83extern int soo_select(struct fileproc *fp, int which, void * wql, vfs_context_t ctx); 84 85int (**fifo_vnodeop_p)(void *); 86struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { 87 { &vnop_default_desc, (VOPFUNC)vn_default_error }, 88 { &vnop_lookup_desc, (VOPFUNC)fifo_lookup }, /* lookup */ 89 { &vnop_create_desc, (VOPFUNC)err_create }, /* create */ 90 { &vnop_mknod_desc, (VOPFUNC)err_mknod }, /* mknod */ 91 { &vnop_open_desc, (VOPFUNC)fifo_open }, /* open */ 92 { &vnop_close_desc, (VOPFUNC)fifo_close }, /* close */ 93 { &vnop_access_desc, (VOPFUNC)fifo_access }, /* access */ 94 { &vnop_getattr_desc, (VOPFUNC)fifo_getattr }, /* getattr */ 95 { &vnop_setattr_desc, (VOPFUNC)fifo_setattr }, /* setattr */ 96 { &vnop_read_desc, (VOPFUNC)fifo_read }, /* read */ 97 { &vnop_write_desc, (VOPFUNC)fifo_write }, /* write */ 98 { &vnop_ioctl_desc, (VOPFUNC)fifo_ioctl }, /* ioctl */ 99 { &vnop_select_desc, (VOPFUNC)fifo_select }, /* select */ 100 { &vnop_revoke_desc, (VOPFUNC)fifo_revoke }, /* revoke */ 101 { &vnop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */ 102 { &vnop_fsync_desc, (VOPFUNC)fifo_fsync }, /* fsync */ 103 { &vnop_remove_desc, (VOPFUNC)err_remove }, /* remove */ 104 { &vnop_link_desc, (VOPFUNC)err_link }, /* link */ 105 { &vnop_rename_desc, (VOPFUNC)err_rename }, /* rename */ 106 { &vnop_mkdir_desc, (VOPFUNC)err_mkdir }, /* mkdir */ 107 { &vnop_rmdir_desc, (VOPFUNC)err_rmdir }, /* rmdir */ 108 { &vnop_symlink_desc, (VOPFUNC)err_symlink }, /* symlink */ 109 { &vnop_readdir_desc, (VOPFUNC)err_readdir }, /* readdir */ 110 { &vnop_readlink_desc, (VOPFUNC)err_readlink }, /* readlink */ 111 { &vnop_inactive_desc, (VOPFUNC)fifo_inactive }, /* inactive */ 112 { &vnop_reclaim_desc, (VOPFUNC)fifo_reclaim }, /* reclaim */ 113 { &vnop_strategy_desc, (VOPFUNC)err_strategy }, /* strategy */ 114 { &vnop_pathconf_desc, (VOPFUNC)fifo_pathconf }, /* pathconf */ 115 { &vnop_advlock_desc, (VOPFUNC)fifo_advlock }, /* advlock */ 116 { &vnop_bwrite_desc, (VOPFUNC)fifo_bwrite }, /* bwrite */ 117 { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */ 118 { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */ 119 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */ 120 { &vnop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff */ 121 { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk */ 122 { &vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap */ 123 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 124}; 125struct vnodeopv_desc fifo_vnodeop_opv_desc = 126 { &fifo_vnodeop_p, fifo_vnodeop_entries }; 127 128/* 129 * Trivial lookup routine that always fails. 130 */ 131/* ARGSUSED */ 132int 133fifo_lookup(struct vnop_lookup_args *ap) 134{ 135 136 *ap->a_vpp = NULL; 137 return (ENOTDIR); 138} 139 140/* 141 * Open called to set up a new instance of a fifo or 142 * to find an active instance of a fifo. 143 */ 144/* ARGSUSED */ 145int 146fifo_open(struct vnop_open_args *ap) 147{ 148 struct vnode *vp = ap->a_vp; 149 struct fifoinfo *fip; 150 struct socket *rso, *wso; 151 int error; 152 153 vnode_lock(vp); 154 155retry: 156 157 fip = vp->v_fifoinfo; 158 159 if (fip == (struct fifoinfo *)0) 160 panic("fifo_open with no fifoinfo"); 161 162 if ((fip->fi_flags & FIFO_CREATED) == 0) { 163 if (fip->fi_flags & FIFO_INCREATE) { 164 fip->fi_flags |= FIFO_CREATEWAIT; 165 error = msleep(&fip->fi_flags, &vp->v_lock, PRIBIO | PCATCH, "fifocreatewait", NULL); 166 if (error) { 167 vnode_unlock(vp); 168 return(error); 169 } 170 goto retry; 171 } else { 172 fip->fi_flags |= FIFO_INCREATE; 173 vnode_unlock(vp); 174 if ( (error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) ) { 175 goto bad1; 176 } 177 fip->fi_readsock = rso; 178 179 if ( (error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) ) { 180 (void)soclose(rso); 181 goto bad1; 182 } 183 fip->fi_writesock = wso; 184 185 if ( (error = soconnect2(wso, rso)) ) { 186 (void)soclose(wso); 187 (void)soclose(rso); 188 goto bad1; 189 } 190 fip->fi_readers = fip->fi_writers = 0; 191 192 socket_lock(wso, 1); 193 wso->so_state |= SS_CANTRCVMORE; 194 wso->so_snd.sb_lowat = PIPE_BUF; 195#if 0 196 /* Because all the unp is protected by single mutex 197 * doing it in two step may actually cause problems 198 * as it opens up window between the drop and acquire 199 */ 200 socket_unlock(wso, 1); 201 202 socket_lock(rso, 1); 203#endif 204 rso->so_state |= SS_CANTSENDMORE; 205 socket_unlock(wso, 1); 206 207 vnode_lock(vp); 208 fip->fi_flags |= FIFO_CREATED; 209 fip->fi_flags &= ~FIFO_INCREATE; 210 211 if ((fip->fi_flags & FIFO_CREATEWAIT)) { 212 fip->fi_flags &= ~FIFO_CREATEWAIT; 213 wakeup(&fip->fi_flags); 214 } 215 /* vnode lock is held to process further */ 216 } 217 } 218 219 /* vnode is locked at this point */ 220 /* fifo in created already */ 221 if (ap->a_mode & FREAD) { 222 fip->fi_readers++; 223 if (fip->fi_readers == 1) { 224 socket_lock(fip->fi_writesock, 1); 225 fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; 226 socket_unlock(fip->fi_writesock, 1); 227 228 if (fip->fi_writers > 0) 229 wakeup((caddr_t)&fip->fi_writers); 230 } 231 } 232 if (ap->a_mode & FWRITE) { 233 fip->fi_writers++; 234 if (fip->fi_writers == 1) { 235 socket_lock(fip->fi_readsock, 1); 236 fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; 237 socket_unlock(fip->fi_readsock, 1); 238 239 if (fip->fi_readers > 0) 240 wakeup((caddr_t)&fip->fi_readers); 241 } 242 } 243 if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) { 244 if (fip->fi_writers == 0) { 245 error = msleep((caddr_t)&fip->fi_readers, &vp->v_lock, 246 PCATCH | PSOCK, "fifoor", NULL); 247 if (error) 248 goto bad; 249 if (fip->fi_readers == 1) { 250 if (fip->fi_writers > 0) 251 wakeup((caddr_t)&fip->fi_writers); 252 } 253 } 254 } 255 if (ap->a_mode & FWRITE) { 256 if (ap->a_mode & O_NONBLOCK) { 257 if (fip->fi_readers == 0) { 258 error = ENXIO; 259 goto bad; 260 } 261 } else { 262 if (fip->fi_readers == 0) { 263 error = msleep((caddr_t)&fip->fi_writers,&vp->v_lock, 264 PCATCH | PSOCK, "fifoow", NULL); 265 if (error) 266 goto bad; 267 if (fip->fi_writers == 1) { 268 if (fip->fi_readers > 0) 269 wakeup((caddr_t)&fip->fi_readers); 270 } 271 } 272 } 273 } 274 275 vnode_unlock(vp); 276 return (0); 277bad: 278 fifo_close_internal(vp, ap->a_mode, ap->a_context, 1); 279 280 vnode_unlock(vp); 281 return (error); 282bad1: 283 vnode_lock(vp); 284 285 fip->fi_flags &= ~FIFO_INCREATE; 286 287 if ((fip->fi_flags & FIFO_CREATEWAIT)) { 288 fip->fi_flags &= ~FIFO_CREATEWAIT; 289 wakeup(&fip->fi_flags); 290 } 291 vnode_unlock(vp); 292 293 return (error); 294} 295 296/* 297 * Vnode op for read 298 */ 299int 300fifo_read(struct vnop_read_args *ap) 301{ 302 struct uio *uio = ap->a_uio; 303 struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; 304 int error, startresid; 305 int rflags; 306 307#if DIAGNOSTIC 308 if (uio->uio_rw != UIO_READ) 309 panic("fifo_read mode"); 310#endif 311 if (uio_resid(uio) == 0) 312 return (0); 313 314 rflags = (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0; 315 316 // LP64todo - fix this! 317 startresid = uio_resid(uio); 318 319 /* fifo conformance - if we have a reader open on the fifo but no 320 * writers then we need to make sure we do not block. We do that by 321 * checking the receive buffer and if empty set error to EWOULDBLOCK. 322 * If error is set to EWOULDBLOCK we skip the call into soreceive 323 */ 324 error = 0; 325 if (ap->a_vp->v_fifoinfo->fi_writers < 1) { 326 socket_lock(rso, 1); 327 error = (rso->so_rcv.sb_cc == 0) ? EWOULDBLOCK : 0; 328 socket_unlock(rso, 1); 329 } 330 331 /* skip soreceive to avoid blocking when we have no writers */ 332 if (error != EWOULDBLOCK) { 333 error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0, 334 (struct mbuf **)0, &rflags); 335 } 336 else { 337 /* clear EWOULDBLOCK and return EOF (zero) */ 338 error = 0; 339 } 340 /* 341 * Clear EOF indication after first such return. 342 */ 343 if (uio_resid(uio) == startresid) { 344 socket_lock(rso, 1); 345 rso->so_state &= ~SS_CANTRCVMORE; 346 socket_unlock(rso, 1); 347 } 348 return (error); 349} 350 351/* 352 * Vnode op for write 353 */ 354int 355fifo_write(struct vnop_write_args *ap) 356{ 357 struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock; 358 int error; 359 360#if DIAGNOSTIC 361 if (ap->a_uio->uio_rw != UIO_WRITE) 362 panic("fifo_write mode"); 363#endif 364 error = sosend(wso, (struct sockaddr *)0, ap->a_uio, NULL, 365 (struct mbuf *)0, (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0); 366 367 return (error); 368} 369 370/* 371 * Device ioctl operation. 372 */ 373int 374fifo_ioctl(struct vnop_ioctl_args *ap) 375{ 376 struct fileproc filetmp; 377 struct fileglob filefg; 378 int error; 379 380 if (ap->a_command == FIONBIO) 381 return (0); 382 bzero(&filetmp, sizeof(struct fileproc)); 383 filetmp.f_fglob = &filefg; 384 if (ap->a_fflag & FREAD) { 385 filetmp.f_fglob->fg_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; 386 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context); 387 if (error) 388 return (error); 389 } 390 if (ap->a_fflag & FWRITE) { 391 filetmp.f_fglob->fg_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; 392 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context); 393 if (error) 394 return (error); 395 } 396 return (0); 397} 398 399int 400fifo_select(struct vnop_select_args *ap) 401{ 402 struct fileproc filetmp; 403 struct fileglob filefg; 404 int ready; 405 406 bzero(&filetmp, sizeof(struct fileproc)); 407 filetmp.f_fglob = &filefg; 408 if (ap->a_which & FREAD) { 409 filetmp.f_fglob->fg_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; 410 ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context); 411 if (ready) 412 return (ready); 413 } 414 if (ap->a_which & FWRITE) { 415 filetmp.f_fglob->fg_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; 416 ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context); 417 if (ready) 418 return (ready); 419 } 420 return (0); 421} 422 423int 424fifo_inactive(__unused struct vnop_inactive_args *ap) 425{ 426 return (0); 427} 428 429 430/* 431 * Device close routine 432 */ 433int 434fifo_close(struct vnop_close_args *ap) 435{ 436 return fifo_close_internal(ap->a_vp, ap->a_fflag, ap->a_context, 0); 437} 438 439int 440fifo_close_internal(vnode_t vp, int fflag, __unused vfs_context_t context, int locked) 441{ 442 struct fifoinfo *fip = vp->v_fifoinfo; 443 int error1, error2; 444 struct socket *rso; 445 struct socket *wso; 446 447 if (!locked) 448 vnode_lock(vp); 449 450 if ((fip->fi_flags & FIFO_CREATED) == 0) { 451 if (!locked) 452 vnode_unlock(vp); 453 return(0); 454 455 } 456 457 if (fflag & FREAD) { 458 fip->fi_readers--; 459 if (fip->fi_readers == 0){ 460 socket_lock(fip->fi_writesock, 1); 461 socantsendmore(fip->fi_writesock); 462 socket_unlock(fip->fi_writesock, 1); 463 } 464 } 465 466 if (fflag & FWRITE) { 467 fip->fi_writers--; 468 if (fip->fi_writers == 0) { 469 socket_lock(fip->fi_readsock, 1); 470 socantrcvmore(fip->fi_readsock); 471 socket_unlock(fip->fi_readsock, 1); 472 } 473 } 474#if 0 475 if (vnode_isinuse_locked(vp, 0, 1)) { 476 if (!locked) 477 vnode_unlock(vp); 478 return (0); 479 } 480#endif 481 482 if (fip->fi_writers || fip->fi_readers) { 483 if (!locked) 484 vnode_unlock(vp); 485 return (0); 486 } 487 488 wso = fip->fi_writesock; 489 rso = fip->fi_readsock; 490 fip->fi_readsock = NULL; 491 fip->fi_writesock = NULL; 492 fip->fi_flags &= ~FIFO_CREATED; 493 if (!locked) 494 vnode_unlock(vp); 495 error1 = soclose(rso); 496 error2 = soclose(wso); 497 498 if (error1) 499 return (error1); 500 return (error2); 501} 502 503#if !CONFIG_NO_PRINTF_STRINGS 504/* 505 * Print out internal contents of a fifo vnode. 506 */ 507void 508fifo_printinfo(struct vnode *vp) 509{ 510 struct fifoinfo *fip = vp->v_fifoinfo; 511 512 printf(", fifo with %ld readers and %ld writers", 513 fip->fi_readers, fip->fi_writers); 514} 515#endif /* !CONFIG_NO_PRINTF_STRINGS */ 516 517/* 518 * Return POSIX pathconf information applicable to fifo's. 519 */ 520int 521fifo_pathconf(struct vnop_pathconf_args *ap) 522{ 523 switch (ap->a_name) { 524 case _PC_LINK_MAX: 525 *ap->a_retval = LINK_MAX; 526 return (0); 527 case _PC_PIPE_BUF: 528 *ap->a_retval = PIPE_BUF; 529 return (0); 530 case _PC_CHOWN_RESTRICTED: 531 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */ 532 return (0); 533 default: 534 return (EINVAL); 535 } 536 /* NOTREACHED */ 537} 538 539/* 540 * Fifo failed operation 541 */ 542int 543fifo_ebadf(__unused void *dummy) 544{ 545 546 return (EBADF); 547} 548 549/* 550 * Fifo advisory byte-level locks. 551 */ 552int 553fifo_advlock(__unused struct vnop_advlock_args *ap) 554{ 555 556 return (ENOTSUP); 557} 558 559