xref: /xnu-10063.121.3/bsd/miscfs/fifofs/fifo_vnops.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1 /*
2  * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30  * Copyright (c) 1990, 1993, 1995
31  *	The Regents of the University of California.  All rights reserved.
32  *
33  * Redistribution and use in source and binary forms, with or without
34  * modification, are permitted provided that the following conditions
35  * are met:
36  * 1. Redistributions of source code must retain the above copyright
37  *    notice, this list of conditions and the following disclaimer.
38  * 2. Redistributions in binary form must reproduce the above copyright
39  *    notice, this list of conditions and the following disclaimer in the
40  *    documentation and/or other materials provided with the distribution.
41  * 3. All advertising materials mentioning features or use of this software
42  *    must display the following acknowledgement:
43  *	This product includes software developed by the University of
44  *	California, Berkeley and its contributors.
45  * 4. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  *
61  *	@(#)fifo_vnops.c	8.4 (Berkeley) 8/10/94
62  */
63 
64 #include <sys/param.h>
65 #include <sys/proc.h>
66 #include <sys/time.h>
67 #include <sys/namei.h>
68 #include <sys/vnode_internal.h>
69 #include <sys/socket.h>
70 #include <sys/socketvar.h>
71 #include <sys/stat.h>
72 #include <sys/systm.h>
73 #include <sys/ioctl.h>
74 #include <sys/file_internal.h>
75 #include <sys/errno.h>
76 #include <sys/malloc.h>
77 #include <miscfs/fifofs/fifo.h>
78 #include <vfs/vfs_support.h>
79 
80 #define VOPFUNC int (*)(void *)
81 
82 int(**fifo_vnodeop_p)(void *);
83 const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
84 	{ .opve_op = &vnop_default_desc, .opve_impl = (VOPFUNC)(void (*)(void))vn_default_error },
85 	{ .opve_op = &vnop_lookup_desc, .opve_impl = (VOPFUNC)fifo_lookup },            /* lookup */
86 	{ .opve_op = &vnop_create_desc, .opve_impl = (VOPFUNC)err_create },             /* create */
87 	{ .opve_op = &vnop_mknod_desc, .opve_impl = (VOPFUNC)err_mknod },               /* mknod */
88 	{ .opve_op = &vnop_open_desc, .opve_impl = (VOPFUNC)fifo_open },                        /* open */
89 	{ .opve_op = &vnop_close_desc, .opve_impl = (VOPFUNC)fifo_close },              /* close */
90 	{ .opve_op = &vnop_access_desc, .opve_impl = (VOPFUNC)fifo_access },            /* access */
91 	{ .opve_op = &vnop_getattr_desc, .opve_impl = (VOPFUNC)fifo_getattr },          /* getattr */
92 	{ .opve_op = &vnop_setattr_desc, .opve_impl = (VOPFUNC)fifo_setattr },          /* setattr */
93 	{ .opve_op = &vnop_read_desc, .opve_impl = (VOPFUNC)fifo_read },                        /* read */
94 	{ .opve_op = &vnop_write_desc, .opve_impl = (VOPFUNC)fifo_write },              /* write */
95 	{ .opve_op = &vnop_ioctl_desc, .opve_impl = (VOPFUNC)fifo_ioctl },              /* ioctl */
96 	{ .opve_op = &vnop_select_desc, .opve_impl = (VOPFUNC)fifo_select },            /* select */
97 	{ .opve_op = &vnop_revoke_desc, .opve_impl = (VOPFUNC)fifo_revoke },            /* revoke */
98 	{ .opve_op = &vnop_mmap_desc, .opve_impl = (VOPFUNC)err_mmap },                 /* mmap */
99 	{ .opve_op = &vnop_fsync_desc, .opve_impl = (VOPFUNC)fifo_fsync },              /* fsync */
100 	{ .opve_op = &vnop_remove_desc, .opve_impl = (VOPFUNC)err_remove },             /* remove */
101 	{ .opve_op = &vnop_link_desc, .opve_impl = (VOPFUNC)err_link },                 /* link */
102 	{ .opve_op = &vnop_rename_desc, .opve_impl = (VOPFUNC)err_rename },             /* rename */
103 	{ .opve_op = &vnop_mkdir_desc, .opve_impl = (VOPFUNC)err_mkdir },               /* mkdir */
104 	{ .opve_op = &vnop_rmdir_desc, .opve_impl = (VOPFUNC)err_rmdir },               /* rmdir */
105 	{ .opve_op = &vnop_symlink_desc, .opve_impl = (VOPFUNC)err_symlink },           /* symlink */
106 	{ .opve_op = &vnop_readdir_desc, .opve_impl = (VOPFUNC)err_readdir },           /* readdir */
107 	{ .opve_op = &vnop_readlink_desc, .opve_impl = (VOPFUNC)err_readlink },         /* readlink */
108 	{ .opve_op = &vnop_inactive_desc, .opve_impl = (VOPFUNC)fifo_inactive },                /* inactive */
109 	{ .opve_op = &vnop_reclaim_desc, .opve_impl = (VOPFUNC)fifo_reclaim },          /* reclaim */
110 	{ .opve_op = &vnop_strategy_desc, .opve_impl = (VOPFUNC)err_strategy },         /* strategy */
111 	{ .opve_op = &vnop_pathconf_desc, .opve_impl = (VOPFUNC)fifo_pathconf },                /* pathconf */
112 	{ .opve_op = &vnop_advlock_desc, .opve_impl = (VOPFUNC)fifo_advlock },          /* advlock */
113 	{ .opve_op = &vnop_bwrite_desc, .opve_impl = (VOPFUNC)fifo_bwrite },            /* bwrite */
114 	{ .opve_op = &vnop_pagein_desc, .opve_impl = (VOPFUNC)err_pagein },             /* Pagein */
115 	{ .opve_op = &vnop_pageout_desc, .opve_impl = (VOPFUNC)err_pageout },           /* Pageout */
116 	{ .opve_op = &vnop_copyfile_desc, .opve_impl = (VOPFUNC)err_copyfile },         /* Copyfile */
117 	{ .opve_op = &vnop_blktooff_desc, .opve_impl = (VOPFUNC)err_blktooff },         /* blktooff */
118 	{ .opve_op = &vnop_offtoblk_desc, .opve_impl = (VOPFUNC)err_offtoblk },         /* offtoblk */
119 	{ .opve_op = &vnop_blockmap_desc, .opve_impl = (VOPFUNC)err_blockmap },                 /* blockmap */
120 	{ .opve_op = (struct vnodeop_desc*)NULL, .opve_impl = (int (*)(void *))NULL }
121 };
122 const struct vnodeopv_desc fifo_vnodeop_opv_desc =
123 { .opv_desc_vector_p = &fifo_vnodeop_p, .opv_desc_ops = fifo_vnodeop_entries };
124 
125 static const struct fileops fifoops = {
126 	.fo_type     = DTYPE_SOCKET,
127 	.fo_read     = NULL,
128 	.fo_write    = NULL,
129 	.fo_ioctl    = NULL,
130 	.fo_select   = NULL,
131 	.fo_close    = NULL,
132 	.fo_drain    = NULL,
133 	.fo_kqfilter = NULL,
134 };
135 /*
136  * Trivial lookup routine that always fails.
137  */
138 /* ARGSUSED */
139 int
fifo_lookup(struct vnop_lookup_args * ap)140 fifo_lookup(struct vnop_lookup_args *ap)
141 {
142 	*ap->a_vpp = NULL;
143 	return ENOTDIR;
144 }
145 
146 /*
147  * Open called to set up a new instance of a fifo or
148  * to find an active instance of a fifo.
149  */
150 /* ARGSUSED */
151 int
fifo_open(struct vnop_open_args * ap)152 fifo_open(struct vnop_open_args *ap)
153 {
154 	struct vnode *vp = ap->a_vp;
155 	struct fifoinfo *fip;
156 	struct socket *rso, *wso;
157 	int error;
158 
159 	if ((ap->a_mode & (FREAD | FWRITE)) == 0) {
160 		ap->a_mode |= FREAD;
161 	}
162 
163 	vnode_lock(vp);
164 
165 retry:
166 
167 	fip = vp->v_fifoinfo;
168 
169 	if (fip == (struct fifoinfo *)0) {
170 		panic("fifo_open with no fifoinfo");
171 	}
172 
173 	if ((fip->fi_flags & FIFO_CREATED) == 0) {
174 		if (fip->fi_flags & FIFO_INCREATE) {
175 			fip->fi_flags |= FIFO_CREATEWAIT;
176 			error = msleep(&fip->fi_flags, &vp->v_lock, PRIBIO | PCATCH, "fifocreatewait", NULL);
177 			if (error) {
178 				vnode_unlock(vp);
179 				return error;
180 			}
181 			goto retry;
182 		} else {
183 			fip->fi_flags |= FIFO_INCREATE;
184 			vnode_unlock(vp);
185 			if ((error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0))) {
186 				goto bad1;
187 			}
188 
189 			if ((error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0))) {
190 				(void)soclose(rso);
191 				goto bad1;
192 			}
193 
194 			if ((error = soconnect2(wso, rso))) {
195 				(void)soclose(wso);
196 				(void)soclose(rso);
197 				goto bad1;
198 			}
199 			fip->fi_readers = fip->fi_writers = 0;
200 
201 			/* Lock ordering between wso and rso does not matter here
202 			 * because they are just created and no one has a reference to them
203 			 */
204 			socket_lock(wso, 1);
205 			wso->so_state |= SS_CANTRCVMORE;
206 			wso->so_snd.sb_lowat = PIPE_BUF;
207 			socket_unlock(wso, 1);
208 
209 			socket_lock(rso, 1);
210 			rso->so_state |= SS_CANTSENDMORE;
211 			socket_unlock(rso, 1);
212 
213 			vnode_lock(vp);
214 			fip->fi_readsock = rso;
215 			fip->fi_writesock = wso;
216 
217 			fip->fi_flags |= FIFO_CREATED;
218 			fip->fi_flags &= ~FIFO_INCREATE;
219 
220 			if ((fip->fi_flags & FIFO_CREATEWAIT)) {
221 				fip->fi_flags &= ~FIFO_CREATEWAIT;
222 				wakeup(&fip->fi_flags);
223 			}
224 			/* vnode lock is held  to process further */
225 		}
226 	}
227 
228 	/* vnode is locked at this point */
229 	/* fifo in created already */
230 	if (ap->a_mode & FREAD) {
231 		fip->fi_readers++;
232 		if (fip->fi_readers == 1) {
233 			socket_lock(fip->fi_writesock, 1);
234 			fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
235 			socket_unlock(fip->fi_writesock, 1);
236 
237 			if (fip->fi_writers > 0) {
238 				wakeup((caddr_t)&fip->fi_writers);
239 			}
240 		}
241 	}
242 	if (ap->a_mode & FWRITE) {
243 		fip->fi_writers++;
244 		if (fip->fi_writers == 1) {
245 			socket_lock(fip->fi_readsock, 1);
246 			fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
247 			socket_unlock(fip->fi_readsock, 1);
248 
249 			if (fip->fi_readers > 0) {
250 				wakeup((caddr_t)&fip->fi_readers);
251 			}
252 		}
253 	}
254 	if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) {
255 		if (fip->fi_writers == 0) {
256 			error = msleep((caddr_t)&fip->fi_readers, &vp->v_lock,
257 			    PCATCH | PSOCK, "fifoor", NULL);
258 			if (error) {
259 				goto bad;
260 			}
261 			if (fip->fi_readers == 1) {
262 				if (fip->fi_writers > 0) {
263 					wakeup((caddr_t)&fip->fi_writers);
264 				}
265 			}
266 		}
267 	}
268 	if (ap->a_mode & FWRITE) {
269 		if (ap->a_mode & O_NONBLOCK) {
270 			if (fip->fi_readers == 0) {
271 				error = ENXIO;
272 				goto bad;
273 			}
274 		} else {
275 			if (fip->fi_readers == 0) {
276 				error = msleep((caddr_t)&fip->fi_writers, &vp->v_lock,
277 				    PCATCH | PSOCK, "fifoow", NULL);
278 				if (error) {
279 					goto bad;
280 				}
281 				if (fip->fi_writers == 1) {
282 					if (fip->fi_readers > 0) {
283 						wakeup((caddr_t)&fip->fi_readers);
284 					}
285 				}
286 			}
287 		}
288 	}
289 
290 	vnode_unlock(vp);
291 	return 0;
292 bad:
293 	fifo_close_internal(vp, ap->a_mode, ap->a_context, 1);
294 
295 	vnode_unlock(vp);
296 	return error;
297 bad1:
298 	vnode_lock(vp);
299 
300 	fip->fi_flags &= ~FIFO_INCREATE;
301 
302 	if ((fip->fi_flags & FIFO_CREATEWAIT)) {
303 		fip->fi_flags &= ~FIFO_CREATEWAIT;
304 		wakeup(&fip->fi_flags);
305 	}
306 	vnode_unlock(vp);
307 
308 	return error;
309 }
310 
311 /*
312  * Vnode op for read
313  */
314 int
fifo_read(struct vnop_read_args * ap)315 fifo_read(struct vnop_read_args *ap)
316 {
317 	struct uio *uio = ap->a_uio;
318 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
319 	user_ssize_t startresid;
320 	int error;
321 	int rflags;
322 
323 #if DIAGNOSTIC
324 	if (uio->uio_rw != UIO_READ) {
325 		panic("fifo_read mode");
326 	}
327 #endif
328 	if (uio_resid(uio) == 0) {
329 		return 0;
330 	}
331 
332 	rflags = (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0;
333 
334 	startresid = uio_resid(uio);
335 
336 	/* fifo conformance - if we have a reader open on the fifo but no
337 	 * writers then we need to make sure we do not block.  We do that by
338 	 * checking the receive buffer and if empty set error to EWOULDBLOCK.
339 	 * If error is set to EWOULDBLOCK we skip the call into soreceive
340 	 */
341 	error = 0;
342 	if (ap->a_vp->v_fifoinfo->fi_writers < 1) {
343 		socket_lock(rso, 1);
344 		error = (rso->so_rcv.sb_cc == 0) ? EWOULDBLOCK : 0;
345 		socket_unlock(rso, 1);
346 	}
347 
348 	/* skip soreceive to avoid blocking when we have no writers */
349 	if (error != EWOULDBLOCK) {
350 		error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0,
351 		    (struct mbuf **)0, &rflags);
352 		if (error == 0) {
353 			lock_vnode_and_post(ap->a_vp, 0);
354 		}
355 	} else {
356 		/* clear EWOULDBLOCK and return EOF (zero) */
357 		error = 0;
358 	}
359 	/*
360 	 * Clear EOF indication after first such return.
361 	 */
362 	if (uio_resid(uio) == startresid) {
363 		socket_lock(rso, 1);
364 		rso->so_state &= ~SS_CANTRCVMORE;
365 		socket_unlock(rso, 1);
366 	}
367 	return error;
368 }
369 
370 /*
371  * Vnode op for write
372  */
373 int
fifo_write(struct vnop_write_args * ap)374 fifo_write(struct vnop_write_args *ap)
375 {
376 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
377 	int error;
378 	user_ssize_t len;
379 
380 #if DIAGNOSTIC
381 	if (ap->a_uio->uio_rw != UIO_WRITE) {
382 		panic("fifo_write mode");
383 	}
384 #endif
385 
386 	len = uio_resid(ap->a_uio);
387 	error = sosend(wso, (struct sockaddr *)0, ap->a_uio, NULL,
388 	    (struct mbuf *)0, (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0);
389 	/* Also post kevent in the case of partial write due to full fifo buffer. */
390 	if (error == 0 || (uio_resid(ap->a_uio) != len && error == EWOULDBLOCK)) {
391 		lock_vnode_and_post(ap->a_vp, 0);
392 	}
393 
394 	return error;
395 }
396 
397 /*
398  * Device ioctl operation.
399  */
400 int
fifo_ioctl(struct vnop_ioctl_args * ap)401 fifo_ioctl(struct vnop_ioctl_args *ap)
402 {
403 	struct fileproc filetmp;
404 	struct fileglob filefg;
405 	int error;
406 
407 	if (ap->a_command == FIONBIO) {
408 		return 0;
409 	}
410 	bzero(&filetmp, sizeof(struct fileproc));
411 	bzero(&filefg, sizeof(struct fileglob));
412 
413 	filefg.fg_ops = &fifoops;
414 	filetmp.fp_glob = &filefg;
415 
416 	if (ap->a_fflag & FREAD) {
417 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_readsock);
418 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context);
419 		if (error) {
420 			return error;
421 		}
422 	}
423 	if (ap->a_fflag & FWRITE) {
424 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_writesock);
425 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context);
426 		if (error) {
427 			return error;
428 		}
429 	}
430 	return 0;
431 }
432 
433 int
fifo_select(struct vnop_select_args * ap)434 fifo_select(struct vnop_select_args *ap)
435 {
436 	struct fileproc filetmp;
437 	struct fileglob filefg;
438 	int ready;
439 
440 	bzero(&filetmp, sizeof(struct fileproc));
441 	bzero(&filefg, sizeof(struct fileglob));
442 
443 	filefg.fg_ops = &fifoops;
444 	filetmp.fp_glob = &filefg;
445 
446 	if (ap->a_which & FREAD) {
447 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_readsock);
448 		ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context);
449 		if (ready) {
450 			return ready;
451 		}
452 	}
453 	if (ap->a_which & FWRITE) {
454 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_writesock);
455 		ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context);
456 		if (ready) {
457 			return ready;
458 		}
459 	}
460 	return 0;
461 }
462 
463 int
fifo_inactive(__unused struct vnop_inactive_args * ap)464 fifo_inactive(__unused struct vnop_inactive_args *ap)
465 {
466 	return 0;
467 }
468 
469 
470 /*
471  * Device close routine
472  */
473 int
fifo_close(struct vnop_close_args * ap)474 fifo_close(struct vnop_close_args *ap)
475 {
476 	return fifo_close_internal(ap->a_vp, ap->a_fflag, ap->a_context, 0);
477 }
478 
479 int
fifo_close_internal(vnode_t vp,int fflag,__unused vfs_context_t context,int locked)480 fifo_close_internal(vnode_t vp, int fflag, __unused vfs_context_t context, int locked)
481 {
482 	struct fifoinfo *fip = vp->v_fifoinfo;
483 	int error1, error2;
484 	struct socket *rso;
485 	struct socket *wso;
486 
487 	if ((fflag & (FREAD | FWRITE)) == 0) {
488 		fflag |= FREAD;
489 	}
490 
491 	if (!locked) {
492 		vnode_lock(vp);
493 	}
494 
495 	if ((fip->fi_flags & FIFO_CREATED) == 0) {
496 		if (!locked) {
497 			vnode_unlock(vp);
498 		}
499 		return 0;
500 	}
501 
502 	if (fflag & FREAD) {
503 		fip->fi_readers--;
504 		if (fip->fi_readers == 0) {
505 			socket_lock(fip->fi_writesock, 1);
506 			socantsendmore(fip->fi_writesock);
507 			socket_unlock(fip->fi_writesock, 1);
508 		}
509 	}
510 
511 	if (fflag & FWRITE) {
512 		fip->fi_writers--;
513 		if (fip->fi_writers == 0) {
514 			socket_lock(fip->fi_readsock, 1);
515 			socantrcvmore(fip->fi_readsock);
516 			socket_unlock(fip->fi_readsock, 1);
517 		}
518 	}
519 #if 0
520 	if (vnode_isinuse_locked(vp, 0, 1)) {
521 		if (!locked) {
522 			vnode_unlock(vp);
523 		}
524 		return 0;
525 	}
526 #endif
527 
528 	if (fip->fi_writers || fip->fi_readers) {
529 		if (!locked) {
530 			vnode_unlock(vp);
531 		}
532 		return 0;
533 	}
534 
535 	wso = fip->fi_writesock;
536 	rso = fip->fi_readsock;
537 	fip->fi_readsock = NULL;
538 	fip->fi_writesock = NULL;
539 	fip->fi_flags &= ~FIFO_CREATED;
540 	if (!locked) {
541 		vnode_unlock(vp);
542 	}
543 	error1 = soclose(rso);
544 	error2 = soclose(wso);
545 
546 	if (error1) {
547 		return error1;
548 	}
549 	return error2;
550 }
551 
552 /*
553  * Print out internal contents of a fifo vnode.
554  */
555 void
fifo_printinfo(struct vnode * vp)556 fifo_printinfo(struct vnode *vp)
557 {
558 	struct fifoinfo *fip = vp->v_fifoinfo;
559 
560 	printf(", fifo with %ld readers and %ld writers",
561 	    fip->fi_readers, fip->fi_writers);
562 }
563 
564 /*
565  * Return POSIX pathconf information applicable to fifo's.
566  */
567 int
fifo_pathconf(struct vnop_pathconf_args * ap)568 fifo_pathconf(struct vnop_pathconf_args *ap)
569 {
570 	switch (ap->a_name) {
571 	case _PC_LINK_MAX:
572 		*ap->a_retval = LINK_MAX;
573 		return 0;
574 	case _PC_PIPE_BUF:
575 		*ap->a_retval = PIPE_BUF;
576 		return 0;
577 	case _PC_CHOWN_RESTRICTED:
578 		*ap->a_retval = 200112;         /* _POSIX_CHOWN_RESTRICTED */
579 		return 0;
580 	default:
581 		return EINVAL;
582 	}
583 	/* NOTREACHED */
584 }
585 
586 /*
587  * Fifo failed operation
588  */
589 int
fifo_ebadf(__unused void * dummy)590 fifo_ebadf(__unused void *dummy)
591 {
592 	return EBADF;
593 }
594 
595 /*
596  * Fifo advisory byte-level locks.
597  */
598 int
fifo_advlock(__unused struct vnop_advlock_args * ap)599 fifo_advlock(__unused struct vnop_advlock_args *ap)
600 {
601 	return ENOTSUP;
602 }
603 
604 
605 /* You'd certainly better have an iocount on the vnode! */
606 int
fifo_freespace(struct vnode * vp,long * count)607 fifo_freespace(struct vnode *vp, long *count)
608 {
609 	struct socket *rsock;
610 	rsock = vp->v_fifoinfo->fi_readsock;
611 	socket_lock(rsock, 1);
612 	*count = sbspace(&rsock->so_rcv);
613 	socket_unlock(rsock, 1);
614 	return 0;
615 }
616 
617 int
fifo_charcount(struct vnode * vp,int * count)618 fifo_charcount(struct vnode *vp, int *count)
619 {
620 	int mcount;
621 	int err = sock_ioctl(vp->v_fifoinfo->fi_readsock, FIONREAD, (void*)&mcount);
622 	if (err == 0) {
623 		*count = mcount;
624 	}
625 	return err;
626 }
627