xref: /freebsd/sys/fs/fifofs/fifo_vnops.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
1 /*
2  * Copyright (c) 1990, 1993, 1995
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)fifo_vnops.c	8.10 (Berkeley) 5/27/95
34  * $FreeBSD$
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/unistd.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/vnode.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/filio.h>
47 #include <sys/fcntl.h>
48 #include <sys/file.h>
49 #include <sys/event.h>
50 #include <sys/poll.h>
51 #include <sys/un.h>
52 #include <miscfs/fifofs/fifo.h>
53 
54 /*
55  * This structure is associated with the FIFO vnode and stores
56  * the state associated with the FIFO.
57  */
58 struct fifoinfo {
59 	struct socket	*fi_readsock;
60 	struct socket	*fi_writesock;
61 	long		fi_readers;
62 	long		fi_writers;
63 };
64 
65 static int	fifo_badop __P((void));
66 static int	fifo_print __P((struct vop_print_args *));
67 static int	fifo_lookup __P((struct vop_lookup_args *));
68 static int	fifo_open __P((struct vop_open_args *));
69 static int	fifo_close __P((struct vop_close_args *));
70 static int	fifo_read __P((struct vop_read_args *));
71 static int	fifo_write __P((struct vop_write_args *));
72 static int	fifo_ioctl __P((struct vop_ioctl_args *));
73 static int	fifo_poll __P((struct vop_poll_args *));
74 static int	fifo_inactive __P((struct  vop_inactive_args *));
75 static int	fifo_bmap __P((struct vop_bmap_args *));
76 static int	fifo_pathconf __P((struct vop_pathconf_args *));
77 static int	fifo_advlock __P((struct vop_advlock_args *));
78 
79 static int	filt_fiforattach(struct knote *kn);
80 static void	filt_fifordetach(struct knote *kn);
81 static int	filt_fiforead(struct knote *kn, long hint);
82 static int	filt_fifowattach(struct knote *kn);
83 static void	filt_fifowdetach(struct knote *kn);
84 static int	filt_fifowrite(struct knote *kn, long hint);
85 
86 struct filterops fifo_rwfiltops[] = {
87 	{ 1, filt_fiforattach, filt_fifordetach, filt_fiforead },
88 	{ 1, filt_fifowattach, filt_fifowdetach, filt_fifowrite },
89 };
90 
91 vop_t **fifo_vnodeop_p;
92 static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
93 	{ &vop_default_desc,		(vop_t *) vop_defaultop },
94 	{ &vop_access_desc,		(vop_t *) vop_ebadf },
95 	{ &vop_advlock_desc,		(vop_t *) fifo_advlock },
96 	{ &vop_bmap_desc,		(vop_t *) fifo_bmap },
97 	{ &vop_close_desc,		(vop_t *) fifo_close },
98 	{ &vop_create_desc,		(vop_t *) fifo_badop },
99 	{ &vop_getattr_desc,		(vop_t *) vop_ebadf },
100 	{ &vop_inactive_desc,		(vop_t *) fifo_inactive },
101 	{ &vop_ioctl_desc,		(vop_t *) fifo_ioctl },
102 	{ &vop_lease_desc,		(vop_t *) vop_null },
103 	{ &vop_link_desc,		(vop_t *) fifo_badop },
104 	{ &vop_lookup_desc,		(vop_t *) fifo_lookup },
105 	{ &vop_mkdir_desc,		(vop_t *) fifo_badop },
106 	{ &vop_mknod_desc,		(vop_t *) fifo_badop },
107 	{ &vop_open_desc,		(vop_t *) fifo_open },
108 	{ &vop_pathconf_desc,		(vop_t *) fifo_pathconf },
109 	{ &vop_poll_desc,		(vop_t *) fifo_poll },
110 	{ &vop_getwritemount_desc, 	(vop_t *) vop_stdgetwritemount },
111 	{ &vop_print_desc,		(vop_t *) fifo_print },
112 	{ &vop_read_desc,		(vop_t *) fifo_read },
113 	{ &vop_readdir_desc,		(vop_t *) fifo_badop },
114 	{ &vop_readlink_desc,		(vop_t *) fifo_badop },
115 	{ &vop_reallocblks_desc,	(vop_t *) fifo_badop },
116 	{ &vop_reclaim_desc,		(vop_t *) vop_null },
117 	{ &vop_remove_desc,		(vop_t *) fifo_badop },
118 	{ &vop_rename_desc,		(vop_t *) fifo_badop },
119 	{ &vop_rmdir_desc,		(vop_t *) fifo_badop },
120 	{ &vop_setattr_desc,		(vop_t *) vop_ebadf },
121 	{ &vop_symlink_desc,		(vop_t *) fifo_badop },
122 	{ &vop_write_desc,		(vop_t *) fifo_write },
123 	{ NULL, NULL }
124 };
125 static struct vnodeopv_desc fifo_vnodeop_opv_desc =
126 	{ &fifo_vnodeop_p, fifo_vnodeop_entries };
127 
128 VNODEOP_SET(fifo_vnodeop_opv_desc);
129 
130 int
131 fifo_vnoperate(ap)
132 	struct vop_generic_args /* {
133 		struct vnodeop_desc *a_desc;
134 		<other random data follows, presumably>
135 	} */ *ap;
136 {
137 	return (VOCALL(fifo_vnodeop_p, ap->a_desc->vdesc_offset, ap));
138 }
139 
140 /*
141  * Trivial lookup routine that always fails.
142  */
143 /* ARGSUSED */
144 static int
145 fifo_lookup(ap)
146 	struct vop_lookup_args /* {
147 		struct vnode * a_dvp;
148 		struct vnode ** a_vpp;
149 		struct componentname * a_cnp;
150 	} */ *ap;
151 {
152 
153 	*ap->a_vpp = NULL;
154 	return (ENOTDIR);
155 }
156 
157 /*
158  * Open called to set up a new instance of a fifo or
159  * to find an active instance of a fifo.
160  */
161 /* ARGSUSED */
162 static int
163 fifo_open(ap)
164 	struct vop_open_args /* {
165 		struct vnode *a_vp;
166 		int  a_mode;
167 		struct ucred *a_cred;
168 		struct proc *a_p;
169 	} */ *ap;
170 {
171 	struct vnode *vp = ap->a_vp;
172 	struct fifoinfo *fip;
173 	struct proc *p = ap->a_p;
174 	struct socket *rso, *wso;
175 	int error;
176 
177 	if ((fip = vp->v_fifoinfo) == NULL) {
178 		MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
179 		vp->v_fifoinfo = fip;
180 		error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, ap->a_p);
181 		if (error) {
182 			free(fip, M_VNODE);
183 			vp->v_fifoinfo = NULL;
184 			return (error);
185 		}
186 		fip->fi_readsock = rso;
187 		error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, ap->a_p);
188 		if (error) {
189 			(void)soclose(rso);
190 			free(fip, M_VNODE);
191 			vp->v_fifoinfo = NULL;
192 			return (error);
193 		}
194 		fip->fi_writesock = wso;
195 		error = unp_connect2(wso, rso);
196 		if (error) {
197 			(void)soclose(wso);
198 			(void)soclose(rso);
199 			free(fip, M_VNODE);
200 			vp->v_fifoinfo = NULL;
201 			return (error);
202 		}
203 		fip->fi_readers = fip->fi_writers = 0;
204 		wso->so_snd.sb_lowat = PIPE_BUF;
205 		rso->so_state |= SS_CANTRCVMORE;
206 	}
207 	if (ap->a_mode & FREAD) {
208 		fip->fi_readers++;
209 		if (fip->fi_readers == 1) {
210 			fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
211 			if (fip->fi_writers > 0)
212 				wakeup((caddr_t)&fip->fi_writers);
213 		}
214 	}
215 	if (ap->a_mode & FWRITE) {
216 		fip->fi_writers++;
217 		if (fip->fi_writers == 1) {
218 			fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
219 			if (fip->fi_readers > 0)
220 				wakeup((caddr_t)&fip->fi_readers);
221 		}
222 	}
223 	if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) {
224 		while (fip->fi_writers == 0) {
225 			VOP_UNLOCK(vp, 0, p);
226 			error = tsleep((caddr_t)&fip->fi_readers,
227 			    PCATCH | PSOCK, "fifoor", 0);
228 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
229 			if (error)
230 				goto bad;
231 		}
232 	}
233 	if (ap->a_mode & FWRITE) {
234 		if (ap->a_mode & O_NONBLOCK) {
235 			if (fip->fi_readers == 0) {
236 				error = ENXIO;
237 				goto bad;
238 			}
239 		} else {
240 			while (fip->fi_readers == 0) {
241 				VOP_UNLOCK(vp, 0, p);
242 				error = tsleep((caddr_t)&fip->fi_writers,
243 				    PCATCH | PSOCK, "fifoow", 0);
244 				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
245 				if (error)
246 					goto bad;
247 			}
248 		}
249 	}
250 	return (0);
251 bad:
252 	VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p);
253 	return (error);
254 }
255 
256 /*
257  * Vnode op for read
258  */
259 /* ARGSUSED */
260 static int
261 fifo_read(ap)
262 	struct vop_read_args /* {
263 		struct vnode *a_vp;
264 		struct uio *a_uio;
265 		int  a_ioflag;
266 		struct ucred *a_cred;
267 	} */ *ap;
268 {
269 	struct uio *uio = ap->a_uio;
270 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
271 	struct proc *p = uio->uio_procp;
272 	int error, startresid;
273 
274 #ifdef DIAGNOSTIC
275 	if (uio->uio_rw != UIO_READ)
276 		panic("fifo_read mode");
277 #endif
278 	if (uio->uio_resid == 0)
279 		return (0);
280 	if (ap->a_ioflag & IO_NDELAY)
281 		rso->so_state |= SS_NBIO;
282 	startresid = uio->uio_resid;
283 	VOP_UNLOCK(ap->a_vp, 0, p);
284 	error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0,
285 	    (struct mbuf **)0, (int *)0);
286 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
287 	if (ap->a_ioflag & IO_NDELAY)
288 		rso->so_state &= ~SS_NBIO;
289 	return (error);
290 }
291 
292 /*
293  * Vnode op for write
294  */
295 /* ARGSUSED */
296 static int
297 fifo_write(ap)
298 	struct vop_write_args /* {
299 		struct vnode *a_vp;
300 		struct uio *a_uio;
301 		int  a_ioflag;
302 		struct ucred *a_cred;
303 	} */ *ap;
304 {
305 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
306 	struct proc *p = ap->a_uio->uio_procp;
307 	int error;
308 
309 #ifdef DIAGNOSTIC
310 	if (ap->a_uio->uio_rw != UIO_WRITE)
311 		panic("fifo_write mode");
312 #endif
313 	if (ap->a_ioflag & IO_NDELAY)
314 		wso->so_state |= SS_NBIO;
315 	VOP_UNLOCK(ap->a_vp, 0, p);
316 	error = sosend(wso, (struct sockaddr *)0, ap->a_uio, 0,
317 		       (struct mbuf *)0, 0, p);
318 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
319 	if (ap->a_ioflag & IO_NDELAY)
320 		wso->so_state &= ~SS_NBIO;
321 	return (error);
322 }
323 
324 /*
325  * Device ioctl operation.
326  */
327 /* ARGSUSED */
328 static int
329 fifo_ioctl(ap)
330 	struct vop_ioctl_args /* {
331 		struct vnode *a_vp;
332 		int  a_command;
333 		caddr_t  a_data;
334 		int  a_fflag;
335 		struct ucred *a_cred;
336 		struct proc *a_p;
337 	} */ *ap;
338 {
339 	struct file filetmp;
340 	int error;
341 
342 	if (ap->a_command == FIONBIO)
343 		return (0);
344 	if (ap->a_fflag & FREAD) {
345 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
346 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
347 		if (error)
348 			return (error);
349 	}
350 	if (ap->a_fflag & FWRITE) {
351 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
352 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
353 		if (error)
354 			return (error);
355 	}
356 	return (0);
357 }
358 
359 static int
360 filt_fiforattach(struct knote *kn)
361 {
362 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
363 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
364 
365 	SLIST_INSERT_HEAD(&so->so_rcv.sb_sel.si_note, kn, kn_selnext);
366 	so->so_rcv.sb_flags |= SB_KNOTE;
367 	return (0);
368 }
369 
370 static void
371 filt_fifordetach(struct knote *kn)
372 {
373 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
374 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
375 
376 	SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext);
377 	if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note))
378 		so->so_rcv.sb_flags &= ~SB_KNOTE;
379 }
380 
381 static int
382 filt_fiforead(struct knote *kn, long hint)
383 {
384 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
385 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
386 
387 	kn->kn_data = so->so_rcv.sb_cc;
388 	if (so->so_state & SS_CANTRCVMORE) {
389 		kn->kn_flags |= EV_EOF;
390 		return (1);
391 	}
392 	kn->kn_flags &= ~EV_EOF;
393 	return (kn->kn_data > 0);
394 }
395 
396 static int
397 filt_fifowattach(struct knote *kn)
398 {
399 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
400 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_writesock;
401 
402 	SLIST_INSERT_HEAD(&so->so_snd.sb_sel.si_note, kn, kn_selnext);
403 	so->so_rcv.sb_flags |= SB_KNOTE;
404 	return (0);
405 }
406 
407 static void
408 filt_fifowdetach(struct knote *kn)
409 {
410 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
411 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
412 
413 	SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext);
414 	if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note))
415 		so->so_snd.sb_flags &= ~SB_KNOTE;
416 }
417 
418 static int
419 filt_fifowrite(struct knote *kn, long hint)
420 {
421 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
422 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
423 
424 	kn->kn_data = sbspace(&so->so_snd);
425 	if (so->so_state & SS_CANTSENDMORE) {
426 		kn->kn_flags |= EV_EOF;
427 		return (1);
428 	}
429 	kn->kn_flags &= ~EV_EOF;
430 	return (kn->kn_data >= so->so_snd.sb_lowat);
431 }
432 
433 /* ARGSUSED */
434 static int
435 fifo_poll(ap)
436 	struct vop_poll_args /* {
437 		struct vnode *a_vp;
438 		int  a_events;
439 		struct ucred *a_cred;
440 		struct proc *a_p;
441 	} */ *ap;
442 {
443 	struct file filetmp;
444 	int revents = 0;
445 
446 	if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
447 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
448 		if (filetmp.f_data)
449 			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
450 			    ap->a_p);
451 	}
452 	if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
453 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
454 		if (filetmp.f_data)
455 			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
456 			    ap->a_p);
457 	}
458 	return (revents);
459 }
460 
461 static int
462 fifo_inactive(ap)
463 	struct vop_inactive_args /* {
464 		struct vnode *a_vp;
465 		struct proc *a_p;
466 	} */ *ap;
467 {
468 
469 	VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
470 	return (0);
471 }
472 
473 /*
474  * This is a noop, simply returning what one has been given.
475  */
476 static int
477 fifo_bmap(ap)
478 	struct vop_bmap_args /* {
479 		struct vnode *a_vp;
480 		daddr_t  a_bn;
481 		struct vnode **a_vpp;
482 		daddr_t *a_bnp;
483 		int *a_runp;
484 		int *a_runb;
485 	} */ *ap;
486 {
487 
488 	if (ap->a_vpp != NULL)
489 		*ap->a_vpp = ap->a_vp;
490 	if (ap->a_bnp != NULL)
491 		*ap->a_bnp = ap->a_bn;
492 	if (ap->a_runp != NULL)
493 		*ap->a_runp = 0;
494 	if (ap->a_runb != NULL)
495 		*ap->a_runb = 0;
496 	return (0);
497 }
498 
499 /*
500  * Device close routine
501  */
502 /* ARGSUSED */
503 static int
504 fifo_close(ap)
505 	struct vop_close_args /* {
506 		struct vnode *a_vp;
507 		int  a_fflag;
508 		struct ucred *a_cred;
509 		struct proc *a_p;
510 	} */ *ap;
511 {
512 	register struct vnode *vp = ap->a_vp;
513 	register struct fifoinfo *fip = vp->v_fifoinfo;
514 	int error1, error2;
515 
516 	if (ap->a_fflag & FREAD) {
517 		fip->fi_readers--;
518 		if (fip->fi_readers == 0)
519 			socantsendmore(fip->fi_writesock);
520 	}
521 	if (ap->a_fflag & FWRITE) {
522 		fip->fi_writers--;
523 		if (fip->fi_writers == 0)
524 			socantrcvmore(fip->fi_readsock);
525 	}
526 	if (vp->v_usecount > 1)
527 		return (0);
528 	error1 = soclose(fip->fi_readsock);
529 	error2 = soclose(fip->fi_writesock);
530 	FREE(fip, M_VNODE);
531 	vp->v_fifoinfo = NULL;
532 	if (error1)
533 		return (error1);
534 	return (error2);
535 }
536 
537 
538 /*
539  * Print out internal contents of a fifo vnode.
540  */
541 int
542 fifo_printinfo(vp)
543 	struct vnode *vp;
544 {
545 	register struct fifoinfo *fip = vp->v_fifoinfo;
546 
547 	printf(", fifo with %ld readers and %ld writers",
548 		fip->fi_readers, fip->fi_writers);
549 	return (0);
550 }
551 
552 /*
553  * Print out the contents of a fifo vnode.
554  */
555 static int
556 fifo_print(ap)
557 	struct vop_print_args /* {
558 		struct vnode *a_vp;
559 	} */ *ap;
560 {
561 
562 	printf("tag VT_NON");
563 	fifo_printinfo(ap->a_vp);
564 	printf("\n");
565 	return (0);
566 }
567 
568 /*
569  * Return POSIX pathconf information applicable to fifo's.
570  */
571 int
572 fifo_pathconf(ap)
573 	struct vop_pathconf_args /* {
574 		struct vnode *a_vp;
575 		int a_name;
576 		int *a_retval;
577 	} */ *ap;
578 {
579 
580 	switch (ap->a_name) {
581 	case _PC_LINK_MAX:
582 		*ap->a_retval = LINK_MAX;
583 		return (0);
584 	case _PC_PIPE_BUF:
585 		*ap->a_retval = PIPE_BUF;
586 		return (0);
587 	case _PC_CHOWN_RESTRICTED:
588 		*ap->a_retval = 1;
589 		return (0);
590 	default:
591 		return (EINVAL);
592 	}
593 	/* NOTREACHED */
594 }
595 
596 /*
597  * Fifo advisory byte-level locks.
598  */
599 /* ARGSUSED */
600 static int
601 fifo_advlock(ap)
602 	struct vop_advlock_args /* {
603 		struct vnode *a_vp;
604 		caddr_t  a_id;
605 		int  a_op;
606 		struct flock *a_fl;
607 		int  a_flags;
608 	} */ *ap;
609 {
610 
611 	return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
612 }
613 
614 /*
615  * Fifo bad operation
616  */
617 static int
618 fifo_badop()
619 {
620 
621 	panic("fifo_badop called");
622 	/* NOTREACHED */
623 }
624