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