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