xref: /netbsd-src/sys/miscfs/fifofs/fifo_vnops.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
1 /*	$NetBSD: fifo_vnops.c,v 1.14 1994/12/14 18:45:42 mycroft Exp $	*/
2 
3 /*
4  * Copyright (c) 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)fifo_vnops.c	8.4 (Berkeley) 8/10/94
36  */
37 
38 #include <sys/param.h>
39 #include <sys/proc.h>
40 #include <sys/time.h>
41 #include <sys/namei.h>
42 #include <sys/vnode.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/stat.h>
46 #include <sys/systm.h>
47 #include <sys/ioctl.h>
48 #include <sys/file.h>
49 #include <sys/errno.h>
50 #include <sys/malloc.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 int (**fifo_vnodeop_p)();
65 struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
66 	{ &vop_default_desc, vn_default_error },
67 	{ &vop_lookup_desc, fifo_lookup },		/* lookup */
68 	{ &vop_create_desc, fifo_create },		/* create */
69 	{ &vop_mknod_desc, fifo_mknod },		/* mknod */
70 	{ &vop_open_desc, fifo_open },			/* open */
71 	{ &vop_close_desc, fifo_close },		/* close */
72 	{ &vop_access_desc, fifo_access },		/* access */
73 	{ &vop_getattr_desc, fifo_getattr },		/* getattr */
74 	{ &vop_setattr_desc, fifo_setattr },		/* setattr */
75 	{ &vop_read_desc, fifo_read },			/* read */
76 	{ &vop_write_desc, fifo_write },		/* write */
77 	{ &vop_lease_desc, fifo_lease_check },		/* lease */
78 	{ &vop_ioctl_desc, fifo_ioctl },		/* ioctl */
79 	{ &vop_select_desc, fifo_select },		/* select */
80 	{ &vop_mmap_desc, fifo_mmap },			/* mmap */
81 	{ &vop_fsync_desc, fifo_fsync },		/* fsync */
82 	{ &vop_seek_desc, fifo_seek },			/* seek */
83 	{ &vop_remove_desc, fifo_remove },		/* remove */
84 	{ &vop_link_desc, fifo_link },			/* link */
85 	{ &vop_rename_desc, fifo_rename },		/* rename */
86 	{ &vop_mkdir_desc, fifo_mkdir },		/* mkdir */
87 	{ &vop_rmdir_desc, fifo_rmdir },		/* rmdir */
88 	{ &vop_symlink_desc, fifo_symlink },		/* symlink */
89 	{ &vop_readdir_desc, fifo_readdir },		/* readdir */
90 	{ &vop_readlink_desc, fifo_readlink },		/* readlink */
91 	{ &vop_abortop_desc, fifo_abortop },		/* abortop */
92 	{ &vop_inactive_desc, fifo_inactive },		/* inactive */
93 	{ &vop_reclaim_desc, fifo_reclaim },		/* reclaim */
94 	{ &vop_lock_desc, fifo_lock },			/* lock */
95 	{ &vop_unlock_desc, fifo_unlock },		/* unlock */
96 	{ &vop_bmap_desc, fifo_bmap },			/* bmap */
97 	{ &vop_strategy_desc, fifo_strategy },		/* strategy */
98 	{ &vop_print_desc, fifo_print },		/* print */
99 	{ &vop_islocked_desc, fifo_islocked },		/* islocked */
100 	{ &vop_pathconf_desc, fifo_pathconf },		/* pathconf */
101 	{ &vop_advlock_desc, fifo_advlock },		/* advlock */
102 	{ &vop_blkatoff_desc, fifo_blkatoff },		/* blkatoff */
103 	{ &vop_valloc_desc, fifo_valloc },		/* valloc */
104 	{ &vop_vfree_desc, fifo_vfree },		/* vfree */
105 	{ &vop_truncate_desc, fifo_truncate },		/* truncate */
106 	{ &vop_update_desc, fifo_update },		/* update */
107 	{ &vop_bwrite_desc, fifo_bwrite },		/* bwrite */
108 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
109 };
110 struct vnodeopv_desc fifo_vnodeop_opv_desc =
111 	{ &fifo_vnodeop_p, fifo_vnodeop_entries };
112 
113 /*
114  * Trivial lookup routine that always fails.
115  */
116 /* ARGSUSED */
117 fifo_lookup(ap)
118 	struct vop_lookup_args /* {
119 		struct vnode * a_dvp;
120 		struct vnode ** a_vpp;
121 		struct componentname * a_cnp;
122 	} */ *ap;
123 {
124 
125 	*ap->a_vpp = NULL;
126 	return (ENOTDIR);
127 }
128 
129 /*
130  * Open called to set up a new instance of a fifo or
131  * to find an active instance of a fifo.
132  */
133 /* ARGSUSED */
134 fifo_open(ap)
135 	struct vop_open_args /* {
136 		struct vnode *a_vp;
137 		int  a_mode;
138 		struct ucred *a_cred;
139 		struct proc *a_p;
140 	} */ *ap;
141 {
142 	register struct vnode *vp = ap->a_vp;
143 	register struct fifoinfo *fip;
144 	struct socket *rso, *wso;
145 	int error;
146 	static char openstr[] = "fifo";
147 
148 	if ((ap->a_mode & (FREAD|FWRITE)) == (FREAD|FWRITE))
149 		return (EINVAL);
150 	if ((fip = vp->v_fifoinfo) == NULL) {
151 		MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
152 		vp->v_fifoinfo = fip;
153 		if (error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) {
154 			free(fip, M_VNODE);
155 			vp->v_fifoinfo = NULL;
156 			return (error);
157 		}
158 		fip->fi_readsock = rso;
159 		if (error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) {
160 			(void)soclose(rso);
161 			free(fip, M_VNODE);
162 			vp->v_fifoinfo = NULL;
163 			return (error);
164 		}
165 		fip->fi_writesock = wso;
166 		if (error = unp_connect2(wso, rso)) {
167 			(void)soclose(wso);
168 			(void)soclose(rso);
169 			free(fip, M_VNODE);
170 			vp->v_fifoinfo = NULL;
171 			return (error);
172 		}
173 		fip->fi_readers = fip->fi_writers = 0;
174 		wso->so_state |= SS_CANTRCVMORE;
175 		rso->so_state |= SS_CANTSENDMORE;
176 	}
177 	error = 0;
178 	if (ap->a_mode & FREAD) {
179 		fip->fi_readers++;
180 		if (fip->fi_readers == 1) {
181 			fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
182 			if (fip->fi_writers > 0)
183 				wakeup((caddr_t)&fip->fi_writers);
184 		}
185 		if (ap->a_mode & O_NONBLOCK)
186 			return (0);
187 		while (fip->fi_writers == 0) {
188 			VOP_UNLOCK(vp);
189 			error = tsleep((caddr_t)&fip->fi_readers,
190 			    PCATCH | PSOCK, openstr, 0);
191 			VOP_LOCK(vp);
192 			if (error)
193 				break;
194 		}
195 	} else {
196 		fip->fi_writers++;
197 		if (fip->fi_readers == 0 && (ap->a_mode & O_NONBLOCK)) {
198 			error = ENXIO;
199 		} else {
200 			if (fip->fi_writers == 1) {
201 				fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
202 				if (fip->fi_readers > 0)
203 					wakeup((caddr_t)&fip->fi_readers);
204 			}
205 			while (fip->fi_readers == 0) {
206 				VOP_UNLOCK(vp);
207 				error = tsleep((caddr_t)&fip->fi_writers,
208 				    PCATCH | PSOCK, openstr, 0);
209 				VOP_LOCK(vp);
210 				if (error)
211 					break;
212 			}
213 		}
214 	}
215 	if (error)
216 		VOP_CLOSE(vp, ap->a_mode, ap->a_cred, ap->a_p);
217 	return (error);
218 }
219 
220 /*
221  * Vnode op for read
222  */
223 /* ARGSUSED */
224 fifo_read(ap)
225 	struct vop_read_args /* {
226 		struct vnode *a_vp;
227 		struct uio *a_uio;
228 		int  a_ioflag;
229 		struct ucred *a_cred;
230 	} */ *ap;
231 {
232 	register struct uio *uio = ap->a_uio;
233 	register struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
234 	int error, startresid;
235 
236 #ifdef DIAGNOSTIC
237 	if (uio->uio_rw != UIO_READ)
238 		panic("fifo_read mode");
239 #endif
240 	if (uio->uio_resid == 0)
241 		return (0);
242 	if (ap->a_ioflag & IO_NDELAY)
243 		rso->so_state |= SS_NBIO;
244 	startresid = uio->uio_resid;
245 	VOP_UNLOCK(ap->a_vp);
246 	error = soreceive(rso, (struct mbuf **)0, uio, (struct mbuf **)0,
247 	    (struct mbuf **)0, (int *)0);
248 	VOP_LOCK(ap->a_vp);
249 	/*
250 	 * Clear EOF indication after first such return.
251 	 */
252 	if (uio->uio_resid == startresid)
253 		rso->so_state &= ~SS_CANTRCVMORE;
254 	if (ap->a_ioflag & IO_NDELAY)
255 		rso->so_state &= ~SS_NBIO;
256 	return (error);
257 }
258 
259 /*
260  * Vnode op for write
261  */
262 /* ARGSUSED */
263 fifo_write(ap)
264 	struct vop_write_args /* {
265 		struct vnode *a_vp;
266 		struct uio *a_uio;
267 		int  a_ioflag;
268 		struct ucred *a_cred;
269 	} */ *ap;
270 {
271 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
272 	int error;
273 
274 #ifdef DIAGNOSTIC
275 	if (ap->a_uio->uio_rw != UIO_WRITE)
276 		panic("fifo_write mode");
277 #endif
278 	if (ap->a_ioflag & IO_NDELAY)
279 		wso->so_state |= SS_NBIO;
280 	VOP_UNLOCK(ap->a_vp);
281 	error = sosend(wso, (struct mbuf *)0, ap->a_uio, 0, (struct mbuf *)0, 0);
282 	VOP_LOCK(ap->a_vp);
283 	if (ap->a_ioflag & IO_NDELAY)
284 		wso->so_state &= ~SS_NBIO;
285 	return (error);
286 }
287 
288 /*
289  * Device ioctl operation.
290  */
291 /* ARGSUSED */
292 fifo_ioctl(ap)
293 	struct vop_ioctl_args /* {
294 		struct vnode *a_vp;
295 		u_long a_command;
296 		caddr_t  a_data;
297 		int  a_fflag;
298 		struct ucred *a_cred;
299 		struct proc *a_p;
300 	} */ *ap;
301 {
302 	struct file filetmp;
303 
304 	if (ap->a_command == FIONBIO)
305 		return (0);
306 	if (ap->a_fflag & FREAD)
307 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
308 	else
309 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
310 	return (soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p));
311 }
312 
313 /* ARGSUSED */
314 fifo_select(ap)
315 	struct vop_select_args /* {
316 		struct vnode *a_vp;
317 		int  a_which;
318 		int  a_fflags;
319 		struct ucred *a_cred;
320 		struct proc *a_p;
321 	} */ *ap;
322 {
323 	struct file filetmp;
324 
325 	if (ap->a_fflags & FREAD)
326 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
327 	else
328 		filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
329 	return (soo_select(&filetmp, ap->a_which, ap->a_p));
330 }
331 
332 /*
333  * This is a noop, simply returning what one has been given.
334  */
335 fifo_bmap(ap)
336 	struct vop_bmap_args /* {
337 		struct vnode *a_vp;
338 		daddr_t  a_bn;
339 		struct vnode **a_vpp;
340 		daddr_t *a_bnp;
341 	} */ *ap;
342 {
343 
344 	if (ap->a_vpp != NULL)
345 		*ap->a_vpp = ap->a_vp;
346 	if (ap->a_bnp != NULL)
347 		*ap->a_bnp = ap->a_bn;
348 	return (0);
349 }
350 
351 /*
352  * At the moment we do not do any locking.
353  */
354 /* ARGSUSED */
355 fifo_lock(ap)
356 	struct vop_lock_args /* {
357 		struct vnode *a_vp;
358 	} */ *ap;
359 {
360 
361 	return (0);
362 }
363 
364 /* ARGSUSED */
365 fifo_unlock(ap)
366 	struct vop_unlock_args /* {
367 		struct vnode *a_vp;
368 	} */ *ap;
369 {
370 
371 	return (0);
372 }
373 
374 /*
375  * Device close routine
376  */
377 /* ARGSUSED */
378 fifo_close(ap)
379 	struct vop_close_args /* {
380 		struct vnode *a_vp;
381 		int  a_fflag;
382 		struct ucred *a_cred;
383 		struct proc *a_p;
384 	} */ *ap;
385 {
386 	register struct vnode *vp = ap->a_vp;
387 	register struct fifoinfo *fip = vp->v_fifoinfo;
388 	int error1, error2;
389 
390 	if (ap->a_fflag & FWRITE) {
391 		fip->fi_writers--;
392 		if (fip->fi_writers == 0)
393 			socantrcvmore(fip->fi_readsock);
394 	} else {
395 		fip->fi_readers--;
396 		if (fip->fi_readers == 0)
397 			socantsendmore(fip->fi_writesock);
398 	}
399 	if (vp->v_usecount > 1)
400 		return (0);
401 	error1 = soclose(fip->fi_readsock);
402 	error2 = soclose(fip->fi_writesock);
403 	FREE(fip, M_VNODE);
404 	vp->v_fifoinfo = NULL;
405 	if (error1)
406 		return (error1);
407 	return (error2);
408 }
409 
410 /*
411  * Print out the contents of a fifo vnode.
412  */
413 fifo_print(ap)
414 	struct vop_print_args /* {
415 		struct vnode *a_vp;
416 	} */ *ap;
417 {
418 
419 	printf("tag VT_NON");
420 	fifo_printinfo(ap->a_vp);
421 	printf("\n");
422 }
423 
424 /*
425  * Print out internal contents of a fifo vnode.
426  */
427 fifo_printinfo(vp)
428 	struct vnode *vp;
429 {
430 	register struct fifoinfo *fip = vp->v_fifoinfo;
431 
432 	printf(", fifo with %d readers and %d writers",
433 		fip->fi_readers, fip->fi_writers);
434 }
435 
436 /*
437  * Return POSIX pathconf information applicable to fifo's.
438  */
439 fifo_pathconf(ap)
440 	struct vop_pathconf_args /* {
441 		struct vnode *a_vp;
442 		int a_name;
443 		register_t *a_retval;
444 	} */ *ap;
445 {
446 
447 	switch (ap->a_name) {
448 	case _PC_LINK_MAX:
449 		*ap->a_retval = LINK_MAX;
450 		return (0);
451 	case _PC_PIPE_BUF:
452 		*ap->a_retval = PIPE_BUF;
453 		return (0);
454 	case _PC_CHOWN_RESTRICTED:
455 		*ap->a_retval = 1;
456 		return (0);
457 	default:
458 		return (EINVAL);
459 	}
460 	/* NOTREACHED */
461 }
462 
463 /*
464  * Fifo failed operation
465  */
466 fifo_ebadf()
467 {
468 
469 	return (EBADF);
470 }
471 
472 /*
473  * Fifo advisory byte-level locks.
474  */
475 /* ARGSUSED */
476 fifo_advlock(ap)
477 	struct vop_advlock_args /* {
478 		struct vnode *a_vp;
479 		caddr_t  a_id;
480 		int  a_op;
481 		struct flock *a_fl;
482 		int  a_flags;
483 	} */ *ap;
484 {
485 
486 	return (EOPNOTSUPP);
487 }
488 
489 /*
490  * Fifo bad operation
491  */
492 fifo_badop()
493 {
494 
495 	panic("fifo_badop called");
496 	/* NOTREACHED */
497 }
498