xref: /freebsd/sys/fs/fifofs/fifo_vnops.c (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
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_print_desc,		(vop_t *) fifo_print },
111 	{ &vop_read_desc,		(vop_t *) fifo_read },
112 	{ &vop_readdir_desc,		(vop_t *) fifo_badop },
113 	{ &vop_readlink_desc,		(vop_t *) fifo_badop },
114 	{ &vop_reallocblks_desc,	(vop_t *) fifo_badop },
115 	{ &vop_reclaim_desc,		(vop_t *) vop_null },
116 	{ &vop_remove_desc,		(vop_t *) fifo_badop },
117 	{ &vop_rename_desc,		(vop_t *) fifo_badop },
118 	{ &vop_rmdir_desc,		(vop_t *) fifo_badop },
119 	{ &vop_setattr_desc,		(vop_t *) vop_ebadf },
120 	{ &vop_symlink_desc,		(vop_t *) fifo_badop },
121 	{ &vop_write_desc,		(vop_t *) fifo_write },
122 	{ NULL, NULL }
123 };
124 static struct vnodeopv_desc fifo_vnodeop_opv_desc =
125 	{ &fifo_vnodeop_p, fifo_vnodeop_entries };
126 
127 VNODEOP_SET(fifo_vnodeop_opv_desc);
128 
129 int
130 fifo_vnoperate(ap)
131 	struct vop_generic_args /* {
132 		struct vnodeop_desc *a_desc;
133 		<other random data follows, presumably>
134 	} */ *ap;
135 {
136 	return (VOCALL(fifo_vnodeop_p, ap->a_desc->vdesc_offset, ap));
137 }
138 
139 /*
140  * Trivial lookup routine that always fails.
141  */
142 /* ARGSUSED */
143 static int
144 fifo_lookup(ap)
145 	struct vop_lookup_args /* {
146 		struct vnode * a_dvp;
147 		struct vnode ** a_vpp;
148 		struct componentname * a_cnp;
149 	} */ *ap;
150 {
151 
152 	*ap->a_vpp = NULL;
153 	return (ENOTDIR);
154 }
155 
156 /*
157  * Open called to set up a new instance of a fifo or
158  * to find an active instance of a fifo.
159  */
160 /* ARGSUSED */
161 static int
162 fifo_open(ap)
163 	struct vop_open_args /* {
164 		struct vnode *a_vp;
165 		int  a_mode;
166 		struct ucred *a_cred;
167 		struct proc *a_p;
168 	} */ *ap;
169 {
170 	struct vnode *vp = ap->a_vp;
171 	struct fifoinfo *fip;
172 	struct proc *p = ap->a_p;
173 	struct socket *rso, *wso;
174 	int error;
175 
176 	if ((fip = vp->v_fifoinfo) == NULL) {
177 		MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
178 		vp->v_fifoinfo = fip;
179 		error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, ap->a_p);
180 		if (error) {
181 			free(fip, M_VNODE);
182 			vp->v_fifoinfo = NULL;
183 			return (error);
184 		}
185 		fip->fi_readsock = rso;
186 		error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, ap->a_p);
187 		if (error) {
188 			(void)soclose(rso);
189 			free(fip, M_VNODE);
190 			vp->v_fifoinfo = NULL;
191 			return (error);
192 		}
193 		fip->fi_writesock = wso;
194 		error = unp_connect2(wso, rso);
195 		if (error) {
196 			(void)soclose(wso);
197 			(void)soclose(rso);
198 			free(fip, M_VNODE);
199 			vp->v_fifoinfo = NULL;
200 			return (error);
201 		}
202 		fip->fi_readers = fip->fi_writers = 0;
203 		wso->so_snd.sb_lowat = PIPE_BUF;
204 		rso->so_state |= SS_CANTRCVMORE;
205 	}
206 	if (ap->a_mode & FREAD) {
207 		fip->fi_readers++;
208 		if (fip->fi_readers == 1) {
209 			fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
210 			if (fip->fi_writers > 0)
211 				wakeup((caddr_t)&fip->fi_writers);
212 		}
213 	}
214 	if (ap->a_mode & FWRITE) {
215 		fip->fi_writers++;
216 		if (fip->fi_writers == 1) {
217 			fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
218 			if (fip->fi_readers > 0)
219 				wakeup((caddr_t)&fip->fi_readers);
220 		}
221 	}
222 	if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) {
223 		while (fip->fi_writers == 0) {
224 			VOP_UNLOCK(vp, 0, p);
225 			error = tsleep((caddr_t)&fip->fi_readers,
226 			    PCATCH | PSOCK, "fifoor", 0);
227 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
228 			if (error)
229 				goto bad;
230 		}
231 	}
232 	if (ap->a_mode & FWRITE) {
233 		if (ap->a_mode & O_NONBLOCK) {
234 			if (fip->fi_readers == 0) {
235 				error = ENXIO;
236 				goto bad;
237 			}
238 		} else {
239 			while (fip->fi_readers == 0) {
240 				VOP_UNLOCK(vp, 0, p);
241 				error = tsleep((caddr_t)&fip->fi_writers,
242 				    PCATCH | PSOCK, "fifoow", 0);
243 				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
244 				if (error)
245 					goto bad;
246 			}
247 		}
248 	}
249 	return (0);
250 bad:
251 	VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p);
252 	return (error);
253 }
254 
255 /*
256  * Vnode op for read
257  */
258 /* ARGSUSED */
259 static int
260 fifo_read(ap)
261 	struct vop_read_args /* {
262 		struct vnode *a_vp;
263 		struct uio *a_uio;
264 		int  a_ioflag;
265 		struct ucred *a_cred;
266 	} */ *ap;
267 {
268 	struct uio *uio = ap->a_uio;
269 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
270 	struct proc *p = uio->uio_procp;
271 	int error, startresid;
272 
273 #ifdef DIAGNOSTIC
274 	if (uio->uio_rw != UIO_READ)
275 		panic("fifo_read mode");
276 #endif
277 	if (uio->uio_resid == 0)
278 		return (0);
279 	if (ap->a_ioflag & IO_NDELAY)
280 		rso->so_state |= SS_NBIO;
281 	startresid = uio->uio_resid;
282 	VOP_UNLOCK(ap->a_vp, 0, p);
283 	error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0,
284 	    (struct mbuf **)0, (int *)0);
285 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
286 	if (ap->a_ioflag & IO_NDELAY)
287 		rso->so_state &= ~SS_NBIO;
288 	return (error);
289 }
290 
291 /*
292  * Vnode op for write
293  */
294 /* ARGSUSED */
295 static int
296 fifo_write(ap)
297 	struct vop_write_args /* {
298 		struct vnode *a_vp;
299 		struct uio *a_uio;
300 		int  a_ioflag;
301 		struct ucred *a_cred;
302 	} */ *ap;
303 {
304 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
305 	struct proc *p = ap->a_uio->uio_procp;
306 	int error;
307 
308 #ifdef DIAGNOSTIC
309 	if (ap->a_uio->uio_rw != UIO_WRITE)
310 		panic("fifo_write mode");
311 #endif
312 	if (ap->a_ioflag & IO_NDELAY)
313 		wso->so_state |= SS_NBIO;
314 	VOP_UNLOCK(ap->a_vp, 0, p);
315 	error = sosend(wso, (struct sockaddr *)0, ap->a_uio, 0,
316 		       (struct mbuf *)0, 0, p);
317 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
318 	if (ap->a_ioflag & IO_NDELAY)
319 		wso->so_state &= ~SS_NBIO;
320 	return (error);
321 }
322 
323 /*
324  * Device ioctl operation.
325  */
326 /* ARGSUSED */
327 static int
328 fifo_ioctl(ap)
329 	struct vop_ioctl_args /* {
330 		struct vnode *a_vp;
331 		int  a_command;
332 		caddr_t  a_data;
333 		int  a_fflag;
334 		struct ucred *a_cred;
335 		struct proc *a_p;
336 	} */ *ap;
337 {
338 	struct file filetmp;
339 	int error;
340 
341 	if (ap->a_command == FIONBIO)
342 		return (0);
343 	if (ap->a_fflag & FREAD) {
344 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
345 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
346 		if (error)
347 			return (error);
348 	}
349 	if (ap->a_fflag & FWRITE) {
350 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
351 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
352 		if (error)
353 			return (error);
354 	}
355 	return (0);
356 }
357 
358 static int
359 filt_fiforattach(struct knote *kn)
360 {
361 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
362 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
363 
364 	SLIST_INSERT_HEAD(&so->so_rcv.sb_sel.si_note, kn, kn_selnext);
365 	so->so_rcv.sb_flags |= SB_KNOTE;
366 	return (0);
367 }
368 
369 static void
370 filt_fifordetach(struct knote *kn)
371 {
372 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
373 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
374 
375 	SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext);
376 	if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note))
377 		so->so_rcv.sb_flags &= ~SB_KNOTE;
378 }
379 
380 static int
381 filt_fiforead(struct knote *kn, long hint)
382 {
383 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
384 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
385 
386 	kn->kn_data = so->so_rcv.sb_cc;
387 	if (so->so_state & SS_CANTRCVMORE) {
388 		kn->kn_flags |= EV_EOF;
389 		return (1);
390 	}
391 	kn->kn_flags &= ~EV_EOF;
392 	return (kn->kn_data > 0);
393 }
394 
395 static int
396 filt_fifowattach(struct knote *kn)
397 {
398 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
399 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_writesock;
400 
401 	SLIST_INSERT_HEAD(&so->so_snd.sb_sel.si_note, kn, kn_selnext);
402 	so->so_rcv.sb_flags |= SB_KNOTE;
403 	return (0);
404 }
405 
406 static void
407 filt_fifowdetach(struct knote *kn)
408 {
409 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
410 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
411 
412 	SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext);
413 	if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note))
414 		so->so_snd.sb_flags &= ~SB_KNOTE;
415 }
416 
417 static int
418 filt_fifowrite(struct knote *kn, long hint)
419 {
420 	struct vnode *vn = (struct vnode *)kn->kn_fp->f_data;
421 	struct socket *so = (struct socket *)vn->v_fifoinfo->fi_readsock;
422 
423 	kn->kn_data = sbspace(&so->so_snd);
424 	if (so->so_state & SS_CANTSENDMORE) {
425 		kn->kn_flags |= EV_EOF;
426 		return (1);
427 	}
428 	kn->kn_flags &= ~EV_EOF;
429 	return (kn->kn_data >= so->so_snd.sb_lowat);
430 }
431 
432 /* ARGSUSED */
433 static int
434 fifo_poll(ap)
435 	struct vop_poll_args /* {
436 		struct vnode *a_vp;
437 		int  a_events;
438 		struct ucred *a_cred;
439 		struct proc *a_p;
440 	} */ *ap;
441 {
442 	struct file filetmp;
443 	int revents = 0;
444 
445 	if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
446 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
447 		if (filetmp.f_data)
448 			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
449 			    ap->a_p);
450 	}
451 	if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
452 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
453 		if (filetmp.f_data)
454 			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
455 			    ap->a_p);
456 	}
457 	return (revents);
458 }
459 
460 static int
461 fifo_inactive(ap)
462 	struct vop_inactive_args /* {
463 		struct vnode *a_vp;
464 		struct proc *a_p;
465 	} */ *ap;
466 {
467 
468 	VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
469 	return (0);
470 }
471 
472 /*
473  * This is a noop, simply returning what one has been given.
474  */
475 static int
476 fifo_bmap(ap)
477 	struct vop_bmap_args /* {
478 		struct vnode *a_vp;
479 		daddr_t  a_bn;
480 		struct vnode **a_vpp;
481 		daddr_t *a_bnp;
482 		int *a_runp;
483 		int *a_runb;
484 	} */ *ap;
485 {
486 
487 	if (ap->a_vpp != NULL)
488 		*ap->a_vpp = ap->a_vp;
489 	if (ap->a_bnp != NULL)
490 		*ap->a_bnp = ap->a_bn;
491 	if (ap->a_runp != NULL)
492 		*ap->a_runp = 0;
493 	if (ap->a_runb != NULL)
494 		*ap->a_runb = 0;
495 	return (0);
496 }
497 
498 /*
499  * Device close routine
500  */
501 /* ARGSUSED */
502 static int
503 fifo_close(ap)
504 	struct vop_close_args /* {
505 		struct vnode *a_vp;
506 		int  a_fflag;
507 		struct ucred *a_cred;
508 		struct proc *a_p;
509 	} */ *ap;
510 {
511 	register struct vnode *vp = ap->a_vp;
512 	register struct fifoinfo *fip = vp->v_fifoinfo;
513 	int error1, error2;
514 
515 	if (ap->a_fflag & FREAD) {
516 		fip->fi_readers--;
517 		if (fip->fi_readers == 0)
518 			socantsendmore(fip->fi_writesock);
519 	}
520 	if (ap->a_fflag & FWRITE) {
521 		fip->fi_writers--;
522 		if (fip->fi_writers == 0)
523 			socantrcvmore(fip->fi_readsock);
524 	}
525 	if (vp->v_usecount > 1)
526 		return (0);
527 	error1 = soclose(fip->fi_readsock);
528 	error2 = soclose(fip->fi_writesock);
529 	FREE(fip, M_VNODE);
530 	vp->v_fifoinfo = NULL;
531 	if (error1)
532 		return (error1);
533 	return (error2);
534 }
535 
536 
537 /*
538  * Print out internal contents of a fifo vnode.
539  */
540 int
541 fifo_printinfo(vp)
542 	struct vnode *vp;
543 {
544 	register struct fifoinfo *fip = vp->v_fifoinfo;
545 
546 	printf(", fifo with %ld readers and %ld writers",
547 		fip->fi_readers, fip->fi_writers);
548 	return (0);
549 }
550 
551 /*
552  * Print out the contents of a fifo vnode.
553  */
554 static int
555 fifo_print(ap)
556 	struct vop_print_args /* {
557 		struct vnode *a_vp;
558 	} */ *ap;
559 {
560 
561 	printf("tag VT_NON");
562 	fifo_printinfo(ap->a_vp);
563 	printf("\n");
564 	return (0);
565 }
566 
567 /*
568  * Return POSIX pathconf information applicable to fifo's.
569  */
570 int
571 fifo_pathconf(ap)
572 	struct vop_pathconf_args /* {
573 		struct vnode *a_vp;
574 		int a_name;
575 		int *a_retval;
576 	} */ *ap;
577 {
578 
579 	switch (ap->a_name) {
580 	case _PC_LINK_MAX:
581 		*ap->a_retval = LINK_MAX;
582 		return (0);
583 	case _PC_PIPE_BUF:
584 		*ap->a_retval = PIPE_BUF;
585 		return (0);
586 	case _PC_CHOWN_RESTRICTED:
587 		*ap->a_retval = 1;
588 		return (0);
589 	default:
590 		return (EINVAL);
591 	}
592 	/* NOTREACHED */
593 }
594 
595 /*
596  * Fifo advisory byte-level locks.
597  */
598 /* ARGSUSED */
599 static int
600 fifo_advlock(ap)
601 	struct vop_advlock_args /* {
602 		struct vnode *a_vp;
603 		caddr_t  a_id;
604 		int  a_op;
605 		struct flock *a_fl;
606 		int  a_flags;
607 	} */ *ap;
608 {
609 
610 	return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
611 }
612 
613 /*
614  * Fifo bad operation
615  */
616 static int
617 fifo_badop()
618 {
619 
620 	panic("fifo_badop called");
621 	/* NOTREACHED */
622 }
623