xref: /xnu-8796.141.3/bsd/miscfs/fifofs/fifo_vnops.c (revision 1b191cb58250d0705d8a51287127505aa4bc0789)
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 
379 #if DIAGNOSTIC
380 	if (ap->a_uio->uio_rw != UIO_WRITE) {
381 		panic("fifo_write mode");
382 	}
383 #endif
384 	error = sosend(wso, (struct sockaddr *)0, ap->a_uio, NULL,
385 	    (struct mbuf *)0, (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0);
386 	if (error == 0) {
387 		lock_vnode_and_post(ap->a_vp, 0);
388 	}
389 
390 	return error;
391 }
392 
393 /*
394  * Device ioctl operation.
395  */
396 int
fifo_ioctl(struct vnop_ioctl_args * ap)397 fifo_ioctl(struct vnop_ioctl_args *ap)
398 {
399 	struct fileproc filetmp;
400 	struct fileglob filefg;
401 	int error;
402 
403 	if (ap->a_command == FIONBIO) {
404 		return 0;
405 	}
406 	bzero(&filetmp, sizeof(struct fileproc));
407 	bzero(&filefg, sizeof(struct fileglob));
408 
409 	filefg.fg_ops = &fifoops;
410 	filetmp.fp_glob = &filefg;
411 
412 	if (ap->a_fflag & FREAD) {
413 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_readsock);
414 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context);
415 		if (error) {
416 			return error;
417 		}
418 	}
419 	if (ap->a_fflag & FWRITE) {
420 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_writesock);
421 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context);
422 		if (error) {
423 			return error;
424 		}
425 	}
426 	return 0;
427 }
428 
429 int
fifo_select(struct vnop_select_args * ap)430 fifo_select(struct vnop_select_args *ap)
431 {
432 	struct fileproc filetmp;
433 	struct fileglob filefg;
434 	int ready;
435 
436 	bzero(&filetmp, sizeof(struct fileproc));
437 	bzero(&filefg, sizeof(struct fileglob));
438 
439 	filefg.fg_ops = &fifoops;
440 	filetmp.fp_glob = &filefg;
441 
442 	if (ap->a_which & FREAD) {
443 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_readsock);
444 		ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context);
445 		if (ready) {
446 			return ready;
447 		}
448 	}
449 	if (ap->a_which & FWRITE) {
450 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_writesock);
451 		ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context);
452 		if (ready) {
453 			return ready;
454 		}
455 	}
456 	return 0;
457 }
458 
459 int
fifo_inactive(__unused struct vnop_inactive_args * ap)460 fifo_inactive(__unused struct vnop_inactive_args *ap)
461 {
462 	return 0;
463 }
464 
465 
466 /*
467  * Device close routine
468  */
469 int
fifo_close(struct vnop_close_args * ap)470 fifo_close(struct vnop_close_args *ap)
471 {
472 	return fifo_close_internal(ap->a_vp, ap->a_fflag, ap->a_context, 0);
473 }
474 
475 int
fifo_close_internal(vnode_t vp,int fflag,__unused vfs_context_t context,int locked)476 fifo_close_internal(vnode_t vp, int fflag, __unused vfs_context_t context, int locked)
477 {
478 	struct fifoinfo *fip = vp->v_fifoinfo;
479 	int error1, error2;
480 	struct socket *rso;
481 	struct socket *wso;
482 
483 	if ((fflag & (FREAD | FWRITE)) == 0) {
484 		fflag |= FREAD;
485 	}
486 
487 	if (!locked) {
488 		vnode_lock(vp);
489 	}
490 
491 	if ((fip->fi_flags & FIFO_CREATED) == 0) {
492 		if (!locked) {
493 			vnode_unlock(vp);
494 		}
495 		return 0;
496 	}
497 
498 	if (fflag & FREAD) {
499 		fip->fi_readers--;
500 		if (fip->fi_readers == 0) {
501 			socket_lock(fip->fi_writesock, 1);
502 			socantsendmore(fip->fi_writesock);
503 			socket_unlock(fip->fi_writesock, 1);
504 		}
505 	}
506 
507 	if (fflag & FWRITE) {
508 		fip->fi_writers--;
509 		if (fip->fi_writers == 0) {
510 			socket_lock(fip->fi_readsock, 1);
511 			socantrcvmore(fip->fi_readsock);
512 			socket_unlock(fip->fi_readsock, 1);
513 		}
514 	}
515 #if 0
516 	if (vnode_isinuse_locked(vp, 0, 1)) {
517 		if (!locked) {
518 			vnode_unlock(vp);
519 		}
520 		return 0;
521 	}
522 #endif
523 
524 	if (fip->fi_writers || fip->fi_readers) {
525 		if (!locked) {
526 			vnode_unlock(vp);
527 		}
528 		return 0;
529 	}
530 
531 	wso = fip->fi_writesock;
532 	rso = fip->fi_readsock;
533 	fip->fi_readsock = NULL;
534 	fip->fi_writesock = NULL;
535 	fip->fi_flags &= ~FIFO_CREATED;
536 	if (!locked) {
537 		vnode_unlock(vp);
538 	}
539 	error1 = soclose(rso);
540 	error2 = soclose(wso);
541 
542 	if (error1) {
543 		return error1;
544 	}
545 	return error2;
546 }
547 
548 /*
549  * Print out internal contents of a fifo vnode.
550  */
551 void
fifo_printinfo(struct vnode * vp)552 fifo_printinfo(struct vnode *vp)
553 {
554 	struct fifoinfo *fip = vp->v_fifoinfo;
555 
556 	printf(", fifo with %ld readers and %ld writers",
557 	    fip->fi_readers, fip->fi_writers);
558 }
559 
560 /*
561  * Return POSIX pathconf information applicable to fifo's.
562  */
563 int
fifo_pathconf(struct vnop_pathconf_args * ap)564 fifo_pathconf(struct vnop_pathconf_args *ap)
565 {
566 	switch (ap->a_name) {
567 	case _PC_LINK_MAX:
568 		*ap->a_retval = LINK_MAX;
569 		return 0;
570 	case _PC_PIPE_BUF:
571 		*ap->a_retval = PIPE_BUF;
572 		return 0;
573 	case _PC_CHOWN_RESTRICTED:
574 		*ap->a_retval = 200112;         /* _POSIX_CHOWN_RESTRICTED */
575 		return 0;
576 	default:
577 		return EINVAL;
578 	}
579 	/* NOTREACHED */
580 }
581 
582 /*
583  * Fifo failed operation
584  */
585 int
fifo_ebadf(__unused void * dummy)586 fifo_ebadf(__unused void *dummy)
587 {
588 	return EBADF;
589 }
590 
591 /*
592  * Fifo advisory byte-level locks.
593  */
594 int
fifo_advlock(__unused struct vnop_advlock_args * ap)595 fifo_advlock(__unused struct vnop_advlock_args *ap)
596 {
597 	return ENOTSUP;
598 }
599 
600 
601 /* You'd certainly better have an iocount on the vnode! */
602 int
fifo_freespace(struct vnode * vp,long * count)603 fifo_freespace(struct vnode *vp, long *count)
604 {
605 	struct socket *rsock;
606 	rsock = vp->v_fifoinfo->fi_readsock;
607 	socket_lock(rsock, 1);
608 	*count = sbspace(&rsock->so_rcv);
609 	socket_unlock(rsock, 1);
610 	return 0;
611 }
612 
613 int
fifo_charcount(struct vnode * vp,int * count)614 fifo_charcount(struct vnode *vp, int *count)
615 {
616 	int mcount;
617 	int err = sock_ioctl(vp->v_fifoinfo->fi_readsock, FIONREAD, (void*)&mcount);
618 	if (err == 0) {
619 		*count = mcount;
620 	}
621 	return err;
622 }
623