]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/fifofs/fifo_vnops.c
d4edca03e9465efdbcbd0e41eddd5b757e9d7b72
[apple/xnu.git] / bsd / miscfs / fifofs / fifo_vnops.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1990, 1993, 1995
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * @(#)fifo_vnops.c 8.4 (Berkeley) 8/10/94
56 */
57
58 #include <sys/param.h>
59 #include <sys/proc.h>
60 #include <sys/time.h>
61 #include <sys/namei.h>
62 #include <sys/vnode.h>
63 #include <sys/socket.h>
64 #include <sys/socketvar.h>
65 #include <sys/stat.h>
66 #include <sys/systm.h>
67 #include <sys/ioctl.h>
68 #include <sys/file.h>
69 #include <sys/errno.h>
70 #include <sys/malloc.h>
71 #include <miscfs/fifofs/fifo.h>
72 #include <vfs/vfs_support.h>
73
74 /*
75 * This structure is associated with the FIFO vnode and stores
76 * the state associated with the FIFO.
77 */
78 struct fifoinfo {
79 struct socket *fi_readsock;
80 struct socket *fi_writesock;
81 long fi_readers;
82 long fi_writers;
83 };
84
85 #define VOPFUNC int (*)(void *)
86
87 int (**fifo_vnodeop_p)(void *);
88 struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
89 { &vop_default_desc, (VOPFUNC)vn_default_error },
90 { &vop_lookup_desc, (VOPFUNC)fifo_lookup }, /* lookup */
91 { &vop_create_desc, (VOPFUNC)fifo_create }, /* create */
92 { &vop_mknod_desc, (VOPFUNC)fifo_mknod }, /* mknod */
93 { &vop_open_desc, (VOPFUNC)fifo_open }, /* open */
94 { &vop_close_desc, (VOPFUNC)fifo_close }, /* close */
95 { &vop_access_desc, (VOPFUNC)fifo_access }, /* access */
96 { &vop_getattr_desc, (VOPFUNC)fifo_getattr }, /* getattr */
97 { &vop_setattr_desc, (VOPFUNC)fifo_setattr }, /* setattr */
98 { &vop_read_desc, (VOPFUNC)fifo_read }, /* read */
99 { &vop_write_desc, (VOPFUNC)fifo_write }, /* write */
100 { &vop_lease_desc, (VOPFUNC)fifo_lease_check }, /* lease */
101 { &vop_ioctl_desc, (VOPFUNC)fifo_ioctl }, /* ioctl */
102 { &vop_select_desc, (VOPFUNC)fifo_select }, /* select */
103 { &vop_revoke_desc, (VOPFUNC)fifo_revoke }, /* revoke */
104 { &vop_mmap_desc, (VOPFUNC)fifo_mmap }, /* mmap */
105 { &vop_fsync_desc, (VOPFUNC)fifo_fsync }, /* fsync */
106 { &vop_seek_desc, (VOPFUNC)fifo_seek }, /* seek */
107 { &vop_remove_desc, (VOPFUNC)fifo_remove }, /* remove */
108 { &vop_link_desc, (VOPFUNC)fifo_link }, /* link */
109 { &vop_rename_desc, (VOPFUNC)fifo_rename }, /* rename */
110 { &vop_mkdir_desc, (VOPFUNC)fifo_mkdir }, /* mkdir */
111 { &vop_rmdir_desc, (VOPFUNC)fifo_rmdir }, /* rmdir */
112 { &vop_symlink_desc, (VOPFUNC)fifo_symlink }, /* symlink */
113 { &vop_readdir_desc, (VOPFUNC)fifo_readdir }, /* readdir */
114 { &vop_readlink_desc, (VOPFUNC)fifo_readlink }, /* readlink */
115 { &vop_abortop_desc, (VOPFUNC)fifo_abortop }, /* abortop */
116 { &vop_inactive_desc, (VOPFUNC)fifo_inactive }, /* inactive */
117 { &vop_reclaim_desc, (VOPFUNC)fifo_reclaim }, /* reclaim */
118 { &vop_lock_desc, (VOPFUNC)fifo_lock }, /* lock */
119 { &vop_unlock_desc, (VOPFUNC)fifo_unlock }, /* unlock */
120 { &vop_bmap_desc, (VOPFUNC)fifo_bmap }, /* bmap */
121 { &vop_strategy_desc, (VOPFUNC)fifo_strategy }, /* strategy */
122 { &vop_print_desc, (VOPFUNC)fifo_print }, /* print */
123 { &vop_islocked_desc, (VOPFUNC)fifo_islocked }, /* islocked */
124 { &vop_pathconf_desc, (VOPFUNC)fifo_pathconf }, /* pathconf */
125 { &vop_advlock_desc, (VOPFUNC)fifo_advlock }, /* advlock */
126 { &vop_blkatoff_desc, (VOPFUNC)fifo_blkatoff }, /* blkatoff */
127 { &vop_valloc_desc, (VOPFUNC)fifo_valloc }, /* valloc */
128 { &vop_vfree_desc, (VOPFUNC)fifo_vfree }, /* vfree */
129 { &vop_truncate_desc, (VOPFUNC)fifo_truncate }, /* truncate */
130 { &vop_update_desc, (VOPFUNC)fifo_update }, /* update */
131 { &vop_bwrite_desc, (VOPFUNC)fifo_bwrite }, /* bwrite */
132 { &vop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */
133 { &vop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */
134 { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
135 { &vop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff */
136 { &vop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk */
137 { &vop_cmap_desc, (VOPFUNC)err_cmap }, /* cmap */
138 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
139 };
140 struct vnodeopv_desc fifo_vnodeop_opv_desc =
141 { &fifo_vnodeop_p, fifo_vnodeop_entries };
142
143 /*
144 * Trivial lookup routine that always fails.
145 */
146 /* ARGSUSED */
147 fifo_lookup(ap)
148 struct vop_lookup_args /* {
149 struct vnode * a_dvp;
150 struct vnode ** a_vpp;
151 struct componentname * a_cnp;
152 } */ *ap;
153 {
154
155 *ap->a_vpp = NULL;
156 return (ENOTDIR);
157 }
158
159 /*
160 * Open called to set up a new instance of a fifo or
161 * to find an active instance of a fifo.
162 */
163 /* ARGSUSED */
164 fifo_open(ap)
165 struct vop_open_args /* {
166 struct vnode *a_vp;
167 int a_mode;
168 struct ucred *a_cred;
169 struct proc *a_p;
170 } */ *ap;
171 {
172 struct vnode *vp = ap->a_vp;
173 struct fifoinfo *fip;
174 struct proc *p = ap->a_p;
175 struct socket *rso, *wso;
176 int error;
177
178 if ((fip = vp->v_fifoinfo) == NULL) {
179 MALLOC_ZONE(fip, struct fifoinfo *,
180 sizeof(*fip), M_VNODE, M_WAITOK);
181 vp->v_fifoinfo = fip;
182 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
183 if (error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) {
184 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
185 _FREE_ZONE(fip, sizeof *fip, M_VNODE);
186 vp->v_fifoinfo = NULL;
187 return (error);
188 }
189 fip->fi_readsock = rso;
190 if (error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) {
191 (void)soclose(rso);
192 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
193 _FREE_ZONE(fip, sizeof *fip, M_VNODE);
194 vp->v_fifoinfo = NULL;
195 return (error);
196 }
197 fip->fi_writesock = wso;
198 if (error = unp_connect2(wso, rso)) {
199 (void)soclose(wso);
200 (void)soclose(rso);
201 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
202 _FREE_ZONE(fip, sizeof *fip, M_VNODE);
203 vp->v_fifoinfo = NULL;
204 return (error);
205 }
206 wso->so_state |= SS_CANTRCVMORE;
207 wso->so_snd.sb_lowat = PIPE_BUF;
208 rso->so_state |= SS_CANTSENDMORE;
209 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
210 fip->fi_readers = fip->fi_writers = 0;
211 }
212 if (ap->a_mode & FREAD) {
213 fip->fi_readers++;
214 if (fip->fi_readers == 1) {
215 fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
216 if (fip->fi_writers > 0)
217 wakeup((caddr_t)&fip->fi_writers);
218 }
219 }
220 if (ap->a_mode & FWRITE) {
221 fip->fi_writers++;
222 if (fip->fi_writers == 1) {
223 fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
224 if (fip->fi_readers > 0)
225 wakeup((caddr_t)&fip->fi_readers);
226 }
227 }
228 if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) {
229 if (fip->fi_writers == 0) {
230 VOP_UNLOCK(vp, 0, p);
231 error = tsleep((caddr_t)&fip->fi_readers,
232 PCATCH | PSOCK, "fifoor", 0);
233 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
234 if (error)
235 goto bad;
236 if (fip->fi_readers == 1) {
237 if (fip->fi_writers > 0)
238 wakeup((caddr_t)&fip->fi_writers);
239 }
240 }
241 }
242 if (ap->a_mode & FWRITE) {
243 if (ap->a_mode & O_NONBLOCK) {
244 if (fip->fi_readers == 0) {
245 error = ENXIO;
246 goto bad;
247 }
248 } else {
249 if (fip->fi_readers == 0) {
250 VOP_UNLOCK(vp, 0, p);
251 error = tsleep((caddr_t)&fip->fi_writers,
252 PCATCH | PSOCK, "fifoow", 0);
253 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
254 if (error)
255 goto bad;
256 if (fip->fi_writers == 1) {
257 if (fip->fi_readers > 0)
258 wakeup((caddr_t)&fip->fi_readers);
259 }
260 }
261 }
262 }
263 return (0);
264 bad:
265 if (error)
266 VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p);
267 return (error);
268 }
269
270 /*
271 * Vnode op for read
272 */
273 /* ARGSUSED */
274 fifo_read(ap)
275 struct vop_read_args /* {
276 struct vnode *a_vp;
277 struct uio *a_uio;
278 int a_ioflag;
279 struct ucred *a_cred;
280 } */ *ap;
281 {
282 struct uio *uio = ap->a_uio;
283 struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
284 struct proc *p = uio->uio_procp;
285 int error, startresid;
286
287 #if DIAGNOSTIC
288 if (uio->uio_rw != UIO_READ)
289 panic("fifo_read mode");
290 #endif
291 if (uio->uio_resid == 0)
292 return (0);
293 if (ap->a_ioflag & IO_NDELAY)
294 rso->so_state |= SS_NBIO;
295 startresid = uio->uio_resid;
296 VOP_UNLOCK(ap->a_vp, 0, p);
297 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
298 error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0,
299 (struct mbuf **)0, (int *)0);
300 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
301 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
302 /*
303 * Clear EOF indication after first such return.
304 */
305 if (uio->uio_resid == startresid)
306 rso->so_state &= ~SS_CANTRCVMORE;
307 if (ap->a_ioflag & IO_NDELAY)
308 rso->so_state &= ~SS_NBIO;
309 return (error);
310 }
311
312 /*
313 * Vnode op for write
314 */
315 /* ARGSUSED */
316 fifo_write(ap)
317 struct vop_write_args /* {
318 struct vnode *a_vp;
319 struct uio *a_uio;
320 int a_ioflag;
321 struct ucred *a_cred;
322 } */ *ap;
323 {
324 struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
325 struct proc *p = ap->a_uio->uio_procp;
326 int error;
327
328 #if DIAGNOSTIC
329 if (ap->a_uio->uio_rw != UIO_WRITE)
330 panic("fifo_write mode");
331 #endif
332 if (ap->a_ioflag & IO_NDELAY)
333 wso->so_state |= SS_NBIO;
334 VOP_UNLOCK(ap->a_vp, 0, p);
335 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
336 error = sosend(wso, (struct sockaddr *)0, ap->a_uio, 0, (struct mbuf *)0, 0);
337 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
338 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
339 if (ap->a_ioflag & IO_NDELAY)
340 wso->so_state &= ~SS_NBIO;
341 return (error);
342 }
343
344 /*
345 * Device ioctl operation.
346 */
347 /* ARGSUSED */
348 fifo_ioctl(ap)
349 struct vop_ioctl_args /* {
350 struct vnode *a_vp;
351 int a_command;
352 caddr_t a_data;
353 int a_fflag;
354 struct ucred *a_cred;
355 struct proc *a_p;
356 } */ *ap;
357 {
358 struct file filetmp;
359 int error;
360
361 if (ap->a_command == FIONBIO)
362 return (0);
363 if (ap->a_fflag & FREAD) {
364 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
365 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
366 if (error)
367 return (error);
368 }
369 if (ap->a_fflag & FWRITE) {
370 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
371 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
372 if (error)
373 return (error);
374 }
375 return (0);
376 }
377
378 /* ARGSUSED */
379 fifo_select(ap)
380 struct vop_select_args /* {
381 struct vnode *a_vp;
382 int a_which;
383 int a_fflags;
384 struct ucred *a_cred;
385 struct proc *a_p;
386 } */ *ap;
387 {
388 struct file filetmp;
389 int ready;
390
391 if (ap->a_fflags & FREAD) {
392 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
393 ready = soo_select(&filetmp, ap->a_which, ap->a_p);
394 if (ready)
395 return (ready);
396 }
397 if (ap->a_fflags & FWRITE) {
398 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
399 ready = soo_select(&filetmp, ap->a_which, ap->a_p);
400 if (ready)
401 return (ready);
402 }
403 return (0);
404 }
405
406 int
407 fifo_inactive(ap)
408 struct vop_inactive_args /* {
409 struct vnode *a_vp;
410 struct proc *a_p;
411 } */ *ap;
412 {
413
414 VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
415 return (0);
416 }
417
418 /*
419 * This is a noop, simply returning what one has been given.
420 */
421 fifo_bmap(ap)
422 struct vop_bmap_args /* {
423 struct vnode *a_vp;
424 daddr_t a_bn;
425 struct vnode **a_vpp;
426 daddr_t *a_bnp;
427 int *a_runp;
428 } */ *ap;
429 {
430
431 if (ap->a_vpp != NULL)
432 *ap->a_vpp = ap->a_vp;
433 if (ap->a_bnp != NULL)
434 *ap->a_bnp = ap->a_bn;
435 if (ap->a_runp != NULL)
436 *ap->a_runp = 0;
437 return (0);
438 }
439
440 /*
441 * Device close routine
442 */
443 /* ARGSUSED */
444 fifo_close(ap)
445 struct vop_close_args /* {
446 struct vnode *a_vp;
447 int a_fflag;
448 struct ucred *a_cred;
449 struct proc *a_p;
450 } */ *ap;
451 {
452 register struct vnode *vp = ap->a_vp;
453 register struct fifoinfo *fip = vp->v_fifoinfo;
454 int error1, error2;
455
456 if (ap->a_fflag & FREAD) {
457 fip->fi_readers--;
458 if (fip->fi_readers == 0){
459 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
460 socantsendmore(fip->fi_writesock);
461 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
462 }
463 }
464 if (ap->a_fflag & FWRITE) {
465 fip->fi_writers--;
466 if (fip->fi_writers == 0) {
467 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
468 socantrcvmore(fip->fi_readsock);
469 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
470 }
471 }
472 if (vp->v_usecount > 1)
473 return (0);
474 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
475 error1 = soclose(fip->fi_readsock);
476 error2 = soclose(fip->fi_writesock);
477 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
478 FREE_ZONE(fip, sizeof *fip, M_VNODE);
479 vp->v_fifoinfo = NULL;
480 if (error1)
481 return (error1);
482 return (error2);
483 }
484
485 /*
486 * Print out the contents of a fifo vnode.
487 */
488 fifo_print(ap)
489 struct vop_print_args /* {
490 struct vnode *a_vp;
491 } */ *ap;
492 {
493
494 printf("tag VT_NON");
495 fifo_printinfo(ap->a_vp);
496 printf("\n");
497 }
498
499 /*
500 * Print out internal contents of a fifo vnode.
501 */
502 fifo_printinfo(vp)
503 struct vnode *vp;
504 {
505 register struct fifoinfo *fip = vp->v_fifoinfo;
506
507 printf(", fifo with %d readers and %d writers",
508 fip->fi_readers, fip->fi_writers);
509 }
510
511 /*
512 * Return POSIX pathconf information applicable to fifo's.
513 */
514 fifo_pathconf(ap)
515 struct vop_pathconf_args /* {
516 struct vnode *a_vp;
517 int a_name;
518 int *a_retval;
519 } */ *ap;
520 {
521
522 switch (ap->a_name) {
523 case _PC_LINK_MAX:
524 *ap->a_retval = LINK_MAX;
525 return (0);
526 case _PC_PIPE_BUF:
527 *ap->a_retval = PIPE_BUF;
528 return (0);
529 case _PC_CHOWN_RESTRICTED:
530 *ap->a_retval = 1;
531 return (0);
532 default:
533 return (EINVAL);
534 }
535 /* NOTREACHED */
536 }
537
538 /*
539 * Fifo failed operation
540 */
541 fifo_ebadf()
542 {
543
544 return (EBADF);
545 }
546
547 /*
548 * Fifo advisory byte-level locks.
549 */
550 /* ARGSUSED */
551 fifo_advlock(ap)
552 struct vop_advlock_args /* {
553 struct vnode *a_vp;
554 caddr_t a_id;
555 int a_op;
556 struct flock *a_fl;
557 int a_flags;
558 } */ *ap;
559 {
560
561 return (EOPNOTSUPP);
562 }
563
564 /*
565 * Fifo bad operation
566 */
567 fifo_badop()
568 {
569
570 panic("fifo_badop called");
571 /* NOTREACHED */
572 }