xref: /freebsd/sys/fs/fifofs/fifo_vnops.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
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/poll.h>
50 #include <sys/un.h>
51 #include <miscfs/fifofs/fifo.h>
52 
53 /*
54  * This structure is associated with the FIFO vnode and stores
55  * the state associated with the FIFO.
56  */
57 struct fifoinfo {
58 	struct socket	*fi_readsock;
59 	struct socket	*fi_writesock;
60 	long		fi_readers;
61 	long		fi_writers;
62 };
63 
64 static int	fifo_badop __P((void));
65 static int	fifo_print __P((struct vop_print_args *));
66 static int	fifo_lookup __P((struct vop_lookup_args *));
67 static int	fifo_open __P((struct vop_open_args *));
68 static int	fifo_close __P((struct vop_close_args *));
69 static int	fifo_read __P((struct vop_read_args *));
70 static int	fifo_write __P((struct vop_write_args *));
71 static int	fifo_ioctl __P((struct vop_ioctl_args *));
72 static int	fifo_poll __P((struct vop_poll_args *));
73 static int	fifo_inactive __P((struct  vop_inactive_args *));
74 static int	fifo_bmap __P((struct vop_bmap_args *));
75 static int	fifo_pathconf __P((struct vop_pathconf_args *));
76 static int	fifo_advlock __P((struct vop_advlock_args *));
77 
78 
79 vop_t **fifo_vnodeop_p;
80 static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
81 	{ &vop_default_desc,		(vop_t *) vop_defaultop },
82 	{ &vop_abortop_desc,		(vop_t *) fifo_badop },
83 	{ &vop_access_desc,		(vop_t *) vop_ebadf },
84 	{ &vop_advlock_desc,		(vop_t *) fifo_advlock },
85 	{ &vop_bmap_desc,		(vop_t *) fifo_bmap },
86 	{ &vop_close_desc,		(vop_t *) fifo_close },
87 	{ &vop_create_desc,		(vop_t *) fifo_badop },
88 	{ &vop_getattr_desc,		(vop_t *) vop_ebadf },
89 	{ &vop_inactive_desc,		(vop_t *) fifo_inactive },
90 	{ &vop_ioctl_desc,		(vop_t *) fifo_ioctl },
91 	{ &vop_lease_desc,		(vop_t *) vop_null },
92 	{ &vop_link_desc,		(vop_t *) fifo_badop },
93 	{ &vop_lookup_desc,		(vop_t *) fifo_lookup },
94 	{ &vop_mkdir_desc,		(vop_t *) fifo_badop },
95 	{ &vop_mknod_desc,		(vop_t *) fifo_badop },
96 	{ &vop_open_desc,		(vop_t *) fifo_open },
97 	{ &vop_pathconf_desc,		(vop_t *) fifo_pathconf },
98 	{ &vop_poll_desc,		(vop_t *) fifo_poll },
99 	{ &vop_print_desc,		(vop_t *) fifo_print },
100 	{ &vop_read_desc,		(vop_t *) fifo_read },
101 	{ &vop_readdir_desc,		(vop_t *) fifo_badop },
102 	{ &vop_readlink_desc,		(vop_t *) fifo_badop },
103 	{ &vop_reallocblks_desc,	(vop_t *) fifo_badop },
104 	{ &vop_reclaim_desc,		(vop_t *) vop_null },
105 	{ &vop_remove_desc,		(vop_t *) fifo_badop },
106 	{ &vop_rename_desc,		(vop_t *) fifo_badop },
107 	{ &vop_rmdir_desc,		(vop_t *) fifo_badop },
108 	{ &vop_setattr_desc,		(vop_t *) vop_ebadf },
109 	{ &vop_symlink_desc,		(vop_t *) fifo_badop },
110 	{ &vop_write_desc,		(vop_t *) fifo_write },
111 	{ NULL, NULL }
112 };
113 static struct vnodeopv_desc fifo_vnodeop_opv_desc =
114 	{ &fifo_vnodeop_p, fifo_vnodeop_entries };
115 
116 VNODEOP_SET(fifo_vnodeop_opv_desc);
117 
118 int
119 fifo_vnoperate(ap)
120 	struct vop_generic_args /* {
121 		struct vnodeop_desc *a_desc;
122 		<other random data follows, presumably>
123 	} */ *ap;
124 {
125 	return (VOCALL(fifo_vnodeop_p, ap->a_desc->vdesc_offset, ap));
126 }
127 
128 /*
129  * Trivial lookup routine that always fails.
130  */
131 /* ARGSUSED */
132 static int
133 fifo_lookup(ap)
134 	struct vop_lookup_args /* {
135 		struct vnode * a_dvp;
136 		struct vnode ** a_vpp;
137 		struct componentname * a_cnp;
138 	} */ *ap;
139 {
140 
141 	*ap->a_vpp = NULL;
142 	return (ENOTDIR);
143 }
144 
145 /*
146  * Open called to set up a new instance of a fifo or
147  * to find an active instance of a fifo.
148  */
149 /* ARGSUSED */
150 static int
151 fifo_open(ap)
152 	struct vop_open_args /* {
153 		struct vnode *a_vp;
154 		int  a_mode;
155 		struct ucred *a_cred;
156 		struct proc *a_p;
157 	} */ *ap;
158 {
159 	struct vnode *vp = ap->a_vp;
160 	struct fifoinfo *fip;
161 	struct proc *p = ap->a_p;
162 	struct socket *rso, *wso;
163 	int error;
164 
165 	if ((fip = vp->v_fifoinfo) == NULL) {
166 		MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
167 		vp->v_fifoinfo = fip;
168 		error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, ap->a_p);
169 		if (error) {
170 			free(fip, M_VNODE);
171 			vp->v_fifoinfo = NULL;
172 			return (error);
173 		}
174 		fip->fi_readsock = rso;
175 		error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, ap->a_p);
176 		if (error) {
177 			(void)soclose(rso);
178 			free(fip, M_VNODE);
179 			vp->v_fifoinfo = NULL;
180 			return (error);
181 		}
182 		fip->fi_writesock = wso;
183 		error = unp_connect2(wso, rso);
184 		if (error) {
185 			(void)soclose(wso);
186 			(void)soclose(rso);
187 			free(fip, M_VNODE);
188 			vp->v_fifoinfo = NULL;
189 			return (error);
190 		}
191 		fip->fi_readers = fip->fi_writers = 0;
192 		wso->so_snd.sb_lowat = PIPE_BUF;
193 		rso->so_state |= SS_CANTRCVMORE;
194 	}
195 	if (ap->a_mode & FREAD) {
196 		fip->fi_readers++;
197 		if (fip->fi_readers == 1) {
198 			fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
199 			if (fip->fi_writers > 0)
200 				wakeup((caddr_t)&fip->fi_writers);
201 		}
202 	}
203 	if (ap->a_mode & FWRITE) {
204 		fip->fi_writers++;
205 		if (fip->fi_writers == 1) {
206 			fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
207 			if (fip->fi_readers > 0)
208 				wakeup((caddr_t)&fip->fi_readers);
209 		}
210 	}
211 	if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) {
212 		while (fip->fi_writers == 0) {
213 			VOP_UNLOCK(vp, 0, p);
214 			error = tsleep((caddr_t)&fip->fi_readers,
215 			    PCATCH | PSOCK, "fifoor", 0);
216 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
217 			if (error)
218 				goto bad;
219 		}
220 	}
221 	if (ap->a_mode & FWRITE) {
222 		if (ap->a_mode & O_NONBLOCK) {
223 			if (fip->fi_readers == 0) {
224 				error = ENXIO;
225 				goto bad;
226 			}
227 		} else {
228 			while (fip->fi_readers == 0) {
229 				VOP_UNLOCK(vp, 0, p);
230 				error = tsleep((caddr_t)&fip->fi_writers,
231 				    PCATCH | PSOCK, "fifoow", 0);
232 				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
233 				if (error)
234 					goto bad;
235 			}
236 		}
237 	}
238 	return (0);
239 bad:
240 	VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p);
241 	return (error);
242 }
243 
244 /*
245  * Vnode op for read
246  */
247 /* ARGSUSED */
248 static int
249 fifo_read(ap)
250 	struct vop_read_args /* {
251 		struct vnode *a_vp;
252 		struct uio *a_uio;
253 		int  a_ioflag;
254 		struct ucred *a_cred;
255 	} */ *ap;
256 {
257 	struct uio *uio = ap->a_uio;
258 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
259 	struct proc *p = uio->uio_procp;
260 	int error, startresid;
261 
262 #ifdef DIAGNOSTIC
263 	if (uio->uio_rw != UIO_READ)
264 		panic("fifo_read mode");
265 #endif
266 	if (uio->uio_resid == 0)
267 		return (0);
268 	if (ap->a_ioflag & IO_NDELAY)
269 		rso->so_state |= SS_NBIO;
270 	startresid = uio->uio_resid;
271 	VOP_UNLOCK(ap->a_vp, 0, p);
272 	error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0,
273 	    (struct mbuf **)0, (int *)0);
274 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
275 	if (ap->a_ioflag & IO_NDELAY)
276 		rso->so_state &= ~SS_NBIO;
277 	return (error);
278 }
279 
280 /*
281  * Vnode op for write
282  */
283 /* ARGSUSED */
284 static int
285 fifo_write(ap)
286 	struct vop_write_args /* {
287 		struct vnode *a_vp;
288 		struct uio *a_uio;
289 		int  a_ioflag;
290 		struct ucred *a_cred;
291 	} */ *ap;
292 {
293 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
294 	struct proc *p = ap->a_uio->uio_procp;
295 	int error;
296 
297 #ifdef DIAGNOSTIC
298 	if (ap->a_uio->uio_rw != UIO_WRITE)
299 		panic("fifo_write mode");
300 #endif
301 	if (ap->a_ioflag & IO_NDELAY)
302 		wso->so_state |= SS_NBIO;
303 	VOP_UNLOCK(ap->a_vp, 0, p);
304 	error = sosend(wso, (struct sockaddr *)0, ap->a_uio, 0,
305 		       (struct mbuf *)0, 0, p);
306 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
307 	if (ap->a_ioflag & IO_NDELAY)
308 		wso->so_state &= ~SS_NBIO;
309 	return (error);
310 }
311 
312 /*
313  * Device ioctl operation.
314  */
315 /* ARGSUSED */
316 static int
317 fifo_ioctl(ap)
318 	struct vop_ioctl_args /* {
319 		struct vnode *a_vp;
320 		int  a_command;
321 		caddr_t  a_data;
322 		int  a_fflag;
323 		struct ucred *a_cred;
324 		struct proc *a_p;
325 	} */ *ap;
326 {
327 	struct file filetmp;
328 	int error;
329 
330 	if (ap->a_command == FIONBIO)
331 		return (0);
332 	if (ap->a_fflag & FREAD) {
333 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
334 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
335 		if (error)
336 			return (error);
337 	}
338 	if (ap->a_fflag & FWRITE) {
339 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
340 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
341 		if (error)
342 			return (error);
343 	}
344 	return (0);
345 }
346 
347 /* ARGSUSED */
348 static int
349 fifo_poll(ap)
350 	struct vop_poll_args /* {
351 		struct vnode *a_vp;
352 		int  a_events;
353 		struct ucred *a_cred;
354 		struct proc *a_p;
355 	} */ *ap;
356 {
357 	struct file filetmp;
358 	int revents = 0;
359 
360 	if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
361 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
362 		if (filetmp.f_data)
363 			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
364 			    ap->a_p);
365 	}
366 	if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
367 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
368 		if (filetmp.f_data)
369 			revents |= soo_poll(&filetmp, ap->a_events, ap->a_cred,
370 			    ap->a_p);
371 	}
372 	return (revents);
373 }
374 
375 static int
376 fifo_inactive(ap)
377 	struct vop_inactive_args /* {
378 		struct vnode *a_vp;
379 		struct proc *a_p;
380 	} */ *ap;
381 {
382 
383 	VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
384 	return (0);
385 }
386 
387 /*
388  * This is a noop, simply returning what one has been given.
389  */
390 static int
391 fifo_bmap(ap)
392 	struct vop_bmap_args /* {
393 		struct vnode *a_vp;
394 		daddr_t  a_bn;
395 		struct vnode **a_vpp;
396 		daddr_t *a_bnp;
397 		int *a_runp;
398 		int *a_runb;
399 	} */ *ap;
400 {
401 
402 	if (ap->a_vpp != NULL)
403 		*ap->a_vpp = ap->a_vp;
404 	if (ap->a_bnp != NULL)
405 		*ap->a_bnp = ap->a_bn;
406 	if (ap->a_runp != NULL)
407 		*ap->a_runp = 0;
408 	if (ap->a_runb != NULL)
409 		*ap->a_runb = 0;
410 	return (0);
411 }
412 
413 /*
414  * Device close routine
415  */
416 /* ARGSUSED */
417 static int
418 fifo_close(ap)
419 	struct vop_close_args /* {
420 		struct vnode *a_vp;
421 		int  a_fflag;
422 		struct ucred *a_cred;
423 		struct proc *a_p;
424 	} */ *ap;
425 {
426 	register struct vnode *vp = ap->a_vp;
427 	register struct fifoinfo *fip = vp->v_fifoinfo;
428 	int error1, error2;
429 
430 	if (ap->a_fflag & FREAD) {
431 		fip->fi_readers--;
432 		if (fip->fi_readers == 0)
433 			socantsendmore(fip->fi_writesock);
434 	}
435 	if (ap->a_fflag & FWRITE) {
436 		fip->fi_writers--;
437 		if (fip->fi_writers == 0)
438 			socantrcvmore(fip->fi_readsock);
439 	}
440 	if (vp->v_usecount > 1)
441 		return (0);
442 	error1 = soclose(fip->fi_readsock);
443 	error2 = soclose(fip->fi_writesock);
444 	FREE(fip, M_VNODE);
445 	vp->v_fifoinfo = NULL;
446 	if (error1)
447 		return (error1);
448 	return (error2);
449 }
450 
451 
452 /*
453  * Print out internal contents of a fifo vnode.
454  */
455 int
456 fifo_printinfo(vp)
457 	struct vnode *vp;
458 {
459 	register struct fifoinfo *fip = vp->v_fifoinfo;
460 
461 	printf(", fifo with %ld readers and %ld writers",
462 		fip->fi_readers, fip->fi_writers);
463 	return (0);
464 }
465 
466 /*
467  * Print out the contents of a fifo vnode.
468  */
469 static int
470 fifo_print(ap)
471 	struct vop_print_args /* {
472 		struct vnode *a_vp;
473 	} */ *ap;
474 {
475 
476 	printf("tag VT_NON");
477 	fifo_printinfo(ap->a_vp);
478 	printf("\n");
479 	return (0);
480 }
481 
482 /*
483  * Return POSIX pathconf information applicable to fifo's.
484  */
485 int
486 fifo_pathconf(ap)
487 	struct vop_pathconf_args /* {
488 		struct vnode *a_vp;
489 		int a_name;
490 		int *a_retval;
491 	} */ *ap;
492 {
493 
494 	switch (ap->a_name) {
495 	case _PC_LINK_MAX:
496 		*ap->a_retval = LINK_MAX;
497 		return (0);
498 	case _PC_PIPE_BUF:
499 		*ap->a_retval = PIPE_BUF;
500 		return (0);
501 	case _PC_CHOWN_RESTRICTED:
502 		*ap->a_retval = 1;
503 		return (0);
504 	default:
505 		return (EINVAL);
506 	}
507 	/* NOTREACHED */
508 }
509 
510 /*
511  * Fifo advisory byte-level locks.
512  */
513 /* ARGSUSED */
514 static int
515 fifo_advlock(ap)
516 	struct vop_advlock_args /* {
517 		struct vnode *a_vp;
518 		caddr_t  a_id;
519 		int  a_op;
520 		struct flock *a_fl;
521 		int  a_flags;
522 	} */ *ap;
523 {
524 
525 	return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
526 }
527 
528 /*
529  * Fifo bad operation
530  */
531 static int
532 fifo_badop()
533 {
534 
535 	panic("fifo_badop called");
536 	/* NOTREACHED */
537 }
538