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