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