]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/fifofs/fifo_vnops.c
7406534b570fcc00d0c36fc8b0de15b9966b9d18
[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)err_create }, /* create */
92 { &vop_mknod_desc, (VOPFUNC)err_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)err_mmap }, /* mmap */
105 { &vop_fsync_desc, (VOPFUNC)fifo_fsync }, /* fsync */
106 { &vop_seek_desc, (VOPFUNC)err_seek }, /* seek */
107 { &vop_remove_desc, (VOPFUNC)err_remove }, /* remove */
108 { &vop_link_desc, (VOPFUNC)err_link }, /* link */
109 { &vop_rename_desc, (VOPFUNC)err_rename }, /* rename */
110 { &vop_mkdir_desc, (VOPFUNC)err_mkdir }, /* mkdir */
111 { &vop_rmdir_desc, (VOPFUNC)err_rmdir }, /* rmdir */
112 { &vop_symlink_desc, (VOPFUNC)err_symlink }, /* symlink */
113 { &vop_readdir_desc, (VOPFUNC)err_readdir }, /* readdir */
114 { &vop_readlink_desc, (VOPFUNC)err_readlink }, /* readlink */
115 { &vop_abortop_desc, (VOPFUNC)err_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)err_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)err_blkatoff }, /* blkatoff */
127 { &vop_valloc_desc, (VOPFUNC)err_valloc }, /* valloc */
128 { &vop_vfree_desc, (VOPFUNC)err_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 void * a_wql;
386 struct proc *a_p;
387 } */ *ap;
388 {
389 struct file filetmp;
390 int ready;
391
392 if (ap->a_fflags & FREAD) {
393 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
394 ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_p);
395 if (ready)
396 return (ready);
397 }
398 if (ap->a_fflags & FWRITE) {
399 filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
400 ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_p);
401 if (ready)
402 return (ready);
403 }
404 return (0);
405 }
406
407 int
408 fifo_inactive(ap)
409 struct vop_inactive_args /* {
410 struct vnode *a_vp;
411 struct proc *a_p;
412 } */ *ap;
413 {
414
415 VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
416 return (0);
417 }
418
419 /*
420 * This is a noop, simply returning what one has been given.
421 */
422 fifo_bmap(ap)
423 struct vop_bmap_args /* {
424 struct vnode *a_vp;
425 daddr_t a_bn;
426 struct vnode **a_vpp;
427 daddr_t *a_bnp;
428 int *a_runp;
429 } */ *ap;
430 {
431
432 if (ap->a_vpp != NULL)
433 *ap->a_vpp = ap->a_vp;
434 if (ap->a_bnp != NULL)
435 *ap->a_bnp = ap->a_bn;
436 if (ap->a_runp != NULL)
437 *ap->a_runp = 0;
438 return (0);
439 }
440
441 /*
442 * Device close routine
443 */
444 /* ARGSUSED */
445 fifo_close(ap)
446 struct vop_close_args /* {
447 struct vnode *a_vp;
448 int a_fflag;
449 struct ucred *a_cred;
450 struct proc *a_p;
451 } */ *ap;
452 {
453 register struct vnode *vp = ap->a_vp;
454 register struct fifoinfo *fip = vp->v_fifoinfo;
455 int error1, error2;
456
457 if (ap->a_fflag & FREAD) {
458 fip->fi_readers--;
459 if (fip->fi_readers == 0){
460 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
461 socantsendmore(fip->fi_writesock);
462 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
463 }
464 }
465 if (ap->a_fflag & FWRITE) {
466 fip->fi_writers--;
467 if (fip->fi_writers == 0) {
468 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
469 socantrcvmore(fip->fi_readsock);
470 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
471 }
472 }
473 if (vp->v_usecount > 1)
474 return (0);
475 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
476 error1 = soclose(fip->fi_readsock);
477 error2 = soclose(fip->fi_writesock);
478 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
479 FREE_ZONE(fip, sizeof *fip, M_VNODE);
480 vp->v_fifoinfo = NULL;
481 if (error1)
482 return (error1);
483 return (error2);
484 }
485
486 /*
487 * Print out the contents of a fifo vnode.
488 */
489 fifo_print(ap)
490 struct vop_print_args /* {
491 struct vnode *a_vp;
492 } */ *ap;
493 {
494
495 printf("tag VT_NON");
496 fifo_printinfo(ap->a_vp);
497 printf("\n");
498 }
499
500 /*
501 * Print out internal contents of a fifo vnode.
502 */
503 fifo_printinfo(vp)
504 struct vnode *vp;
505 {
506 register struct fifoinfo *fip = vp->v_fifoinfo;
507
508 printf(", fifo with %d readers and %d writers",
509 fip->fi_readers, fip->fi_writers);
510 }
511
512 /*
513 * Return POSIX pathconf information applicable to fifo's.
514 */
515 fifo_pathconf(ap)
516 struct vop_pathconf_args /* {
517 struct vnode *a_vp;
518 int a_name;
519 int *a_retval;
520 } */ *ap;
521 {
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 = 1;
532 return (0);
533 default:
534 return (EINVAL);
535 }
536 /* NOTREACHED */
537 }
538
539 /*
540 * Fifo failed operation
541 */
542 fifo_ebadf()
543 {
544
545 return (EBADF);
546 }
547
548 /*
549 * Fifo advisory byte-level locks.
550 */
551 /* ARGSUSED */
552 fifo_advlock(ap)
553 struct vop_advlock_args /* {
554 struct vnode *a_vp;
555 caddr_t a_id;
556 int a_op;
557 struct flock *a_fl;
558 int a_flags;
559 } */ *ap;
560 {
561
562 return (EOPNOTSUPP);
563 }
564