xref: /xnu-8792.61.2/bsd/miscfs/fifofs/fifo_vnops.c (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
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 	vnode_lock(vp);
160 
161 retry:
162 
163 	fip = vp->v_fifoinfo;
164 
165 	if (fip == (struct fifoinfo *)0) {
166 		panic("fifo_open with no fifoinfo");
167 	}
168 
169 	if ((fip->fi_flags & FIFO_CREATED) == 0) {
170 		if (fip->fi_flags & FIFO_INCREATE) {
171 			fip->fi_flags |= FIFO_CREATEWAIT;
172 			error = msleep(&fip->fi_flags, &vp->v_lock, PRIBIO | PCATCH, "fifocreatewait", NULL);
173 			if (error) {
174 				vnode_unlock(vp);
175 				return error;
176 			}
177 			goto retry;
178 		} else {
179 			fip->fi_flags |= FIFO_INCREATE;
180 			vnode_unlock(vp);
181 			if ((error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0))) {
182 				goto bad1;
183 			}
184 
185 			if ((error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0))) {
186 				(void)soclose(rso);
187 				goto bad1;
188 			}
189 
190 			if ((error = soconnect2(wso, rso))) {
191 				(void)soclose(wso);
192 				(void)soclose(rso);
193 				goto bad1;
194 			}
195 			fip->fi_readers = fip->fi_writers = 0;
196 
197 			/* Lock ordering between wso and rso does not matter here
198 			 * because they are just created and no one has a reference to them
199 			 */
200 			socket_lock(wso, 1);
201 			wso->so_state |= SS_CANTRCVMORE;
202 			wso->so_snd.sb_lowat = PIPE_BUF;
203 			socket_unlock(wso, 1);
204 
205 			socket_lock(rso, 1);
206 			rso->so_state |= SS_CANTSENDMORE;
207 			socket_unlock(rso, 1);
208 
209 			vnode_lock(vp);
210 			fip->fi_readsock = rso;
211 			fip->fi_writesock = wso;
212 
213 			fip->fi_flags |= FIFO_CREATED;
214 			fip->fi_flags &= ~FIFO_INCREATE;
215 
216 			if ((fip->fi_flags & FIFO_CREATEWAIT)) {
217 				fip->fi_flags &= ~FIFO_CREATEWAIT;
218 				wakeup(&fip->fi_flags);
219 			}
220 			/* vnode lock is held  to process further */
221 		}
222 	}
223 
224 	/* vnode is locked at this point */
225 	/* fifo in created already */
226 	if (ap->a_mode & FREAD) {
227 		fip->fi_readers++;
228 		if (fip->fi_readers == 1) {
229 			socket_lock(fip->fi_writesock, 1);
230 			fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
231 			socket_unlock(fip->fi_writesock, 1);
232 
233 			if (fip->fi_writers > 0) {
234 				wakeup((caddr_t)&fip->fi_writers);
235 			}
236 		}
237 	}
238 	if (ap->a_mode & FWRITE) {
239 		fip->fi_writers++;
240 		if (fip->fi_writers == 1) {
241 			socket_lock(fip->fi_readsock, 1);
242 			fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
243 			socket_unlock(fip->fi_readsock, 1);
244 
245 			if (fip->fi_readers > 0) {
246 				wakeup((caddr_t)&fip->fi_readers);
247 			}
248 		}
249 	}
250 	if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) {
251 		if (fip->fi_writers == 0) {
252 			error = msleep((caddr_t)&fip->fi_readers, &vp->v_lock,
253 			    PCATCH | PSOCK, "fifoor", NULL);
254 			if (error) {
255 				goto bad;
256 			}
257 			if (fip->fi_readers == 1) {
258 				if (fip->fi_writers > 0) {
259 					wakeup((caddr_t)&fip->fi_writers);
260 				}
261 			}
262 		}
263 	}
264 	if (ap->a_mode & FWRITE) {
265 		if (ap->a_mode & O_NONBLOCK) {
266 			if (fip->fi_readers == 0) {
267 				error = ENXIO;
268 				goto bad;
269 			}
270 		} else {
271 			if (fip->fi_readers == 0) {
272 				error = msleep((caddr_t)&fip->fi_writers, &vp->v_lock,
273 				    PCATCH | PSOCK, "fifoow", NULL);
274 				if (error) {
275 					goto bad;
276 				}
277 				if (fip->fi_writers == 1) {
278 					if (fip->fi_readers > 0) {
279 						wakeup((caddr_t)&fip->fi_readers);
280 					}
281 				}
282 			}
283 		}
284 	}
285 
286 	vnode_unlock(vp);
287 	return 0;
288 bad:
289 	fifo_close_internal(vp, ap->a_mode, ap->a_context, 1);
290 
291 	vnode_unlock(vp);
292 	return error;
293 bad1:
294 	vnode_lock(vp);
295 
296 	fip->fi_flags &= ~FIFO_INCREATE;
297 
298 	if ((fip->fi_flags & FIFO_CREATEWAIT)) {
299 		fip->fi_flags &= ~FIFO_CREATEWAIT;
300 		wakeup(&fip->fi_flags);
301 	}
302 	vnode_unlock(vp);
303 
304 	return error;
305 }
306 
307 /*
308  * Vnode op for read
309  */
310 int
fifo_read(struct vnop_read_args * ap)311 fifo_read(struct vnop_read_args *ap)
312 {
313 	struct uio *uio = ap->a_uio;
314 	struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
315 	user_ssize_t startresid;
316 	int error;
317 	int rflags;
318 
319 #if DIAGNOSTIC
320 	if (uio->uio_rw != UIO_READ) {
321 		panic("fifo_read mode");
322 	}
323 #endif
324 	if (uio_resid(uio) == 0) {
325 		return 0;
326 	}
327 
328 	rflags = (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0;
329 
330 	startresid = uio_resid(uio);
331 
332 	/* fifo conformance - if we have a reader open on the fifo but no
333 	 * writers then we need to make sure we do not block.  We do that by
334 	 * checking the receive buffer and if empty set error to EWOULDBLOCK.
335 	 * If error is set to EWOULDBLOCK we skip the call into soreceive
336 	 */
337 	error = 0;
338 	if (ap->a_vp->v_fifoinfo->fi_writers < 1) {
339 		socket_lock(rso, 1);
340 		error = (rso->so_rcv.sb_cc == 0) ? EWOULDBLOCK : 0;
341 		socket_unlock(rso, 1);
342 	}
343 
344 	/* skip soreceive to avoid blocking when we have no writers */
345 	if (error != EWOULDBLOCK) {
346 		error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0,
347 		    (struct mbuf **)0, &rflags);
348 		if (error == 0) {
349 			lock_vnode_and_post(ap->a_vp, 0);
350 		}
351 	} else {
352 		/* clear EWOULDBLOCK and return EOF (zero) */
353 		error = 0;
354 	}
355 	/*
356 	 * Clear EOF indication after first such return.
357 	 */
358 	if (uio_resid(uio) == startresid) {
359 		socket_lock(rso, 1);
360 		rso->so_state &= ~SS_CANTRCVMORE;
361 		socket_unlock(rso, 1);
362 	}
363 	return error;
364 }
365 
366 /*
367  * Vnode op for write
368  */
369 int
fifo_write(struct vnop_write_args * ap)370 fifo_write(struct vnop_write_args *ap)
371 {
372 	struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
373 	int error;
374 
375 #if DIAGNOSTIC
376 	if (ap->a_uio->uio_rw != UIO_WRITE) {
377 		panic("fifo_write mode");
378 	}
379 #endif
380 	error = sosend(wso, (struct sockaddr *)0, ap->a_uio, NULL,
381 	    (struct mbuf *)0, (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0);
382 	if (error == 0) {
383 		lock_vnode_and_post(ap->a_vp, 0);
384 	}
385 
386 	return error;
387 }
388 
389 /*
390  * Device ioctl operation.
391  */
392 int
fifo_ioctl(struct vnop_ioctl_args * ap)393 fifo_ioctl(struct vnop_ioctl_args *ap)
394 {
395 	struct fileproc filetmp;
396 	struct fileglob filefg;
397 	int error;
398 
399 	if (ap->a_command == FIONBIO) {
400 		return 0;
401 	}
402 	bzero(&filetmp, sizeof(struct fileproc));
403 	bzero(&filefg, sizeof(struct fileglob));
404 
405 	filefg.fg_ops = &fifoops;
406 	filetmp.fp_glob = &filefg;
407 
408 	if (ap->a_fflag & FREAD) {
409 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_readsock);
410 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context);
411 		if (error) {
412 			return error;
413 		}
414 	}
415 	if (ap->a_fflag & FWRITE) {
416 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_writesock);
417 		error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_context);
418 		if (error) {
419 			return error;
420 		}
421 	}
422 	return 0;
423 }
424 
425 int
fifo_select(struct vnop_select_args * ap)426 fifo_select(struct vnop_select_args *ap)
427 {
428 	struct fileproc filetmp;
429 	struct fileglob filefg;
430 	int ready;
431 
432 	bzero(&filetmp, sizeof(struct fileproc));
433 	bzero(&filefg, sizeof(struct fileglob));
434 
435 	filefg.fg_ops = &fifoops;
436 	filetmp.fp_glob = &filefg;
437 
438 	if (ap->a_which & FREAD) {
439 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_readsock);
440 		ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context);
441 		if (ready) {
442 			return ready;
443 		}
444 	}
445 	if (ap->a_which & FWRITE) {
446 		fg_set_data(filetmp.fp_glob, ap->a_vp->v_fifoinfo->fi_writesock);
447 		ready = soo_select(&filetmp, ap->a_which, ap->a_wql, ap->a_context);
448 		if (ready) {
449 			return ready;
450 		}
451 	}
452 	return 0;
453 }
454 
455 int
fifo_inactive(__unused struct vnop_inactive_args * ap)456 fifo_inactive(__unused struct vnop_inactive_args *ap)
457 {
458 	return 0;
459 }
460 
461 
462 /*
463  * Device close routine
464  */
465 int
fifo_close(struct vnop_close_args * ap)466 fifo_close(struct vnop_close_args *ap)
467 {
468 	return fifo_close_internal(ap->a_vp, ap->a_fflag, ap->a_context, 0);
469 }
470 
471 int
fifo_close_internal(vnode_t vp,int fflag,__unused vfs_context_t context,int locked)472 fifo_close_internal(vnode_t vp, int fflag, __unused vfs_context_t context, int locked)
473 {
474 	struct fifoinfo *fip = vp->v_fifoinfo;
475 	int error1, error2;
476 	struct socket *rso;
477 	struct socket *wso;
478 
479 	if (!locked) {
480 		vnode_lock(vp);
481 	}
482 
483 	if ((fip->fi_flags & FIFO_CREATED) == 0) {
484 		if (!locked) {
485 			vnode_unlock(vp);
486 		}
487 		return 0;
488 	}
489 
490 	if (fflag & FREAD) {
491 		fip->fi_readers--;
492 		if (fip->fi_readers == 0) {
493 			socket_lock(fip->fi_writesock, 1);
494 			socantsendmore(fip->fi_writesock);
495 			socket_unlock(fip->fi_writesock, 1);
496 		}
497 	}
498 
499 	if (fflag & FWRITE) {
500 		fip->fi_writers--;
501 		if (fip->fi_writers == 0) {
502 			socket_lock(fip->fi_readsock, 1);
503 			socantrcvmore(fip->fi_readsock);
504 			socket_unlock(fip->fi_readsock, 1);
505 		}
506 	}
507 #if 0
508 	if (vnode_isinuse_locked(vp, 0, 1)) {
509 		if (!locked) {
510 			vnode_unlock(vp);
511 		}
512 		return 0;
513 	}
514 #endif
515 
516 	if (fip->fi_writers || fip->fi_readers) {
517 		if (!locked) {
518 			vnode_unlock(vp);
519 		}
520 		return 0;
521 	}
522 
523 	wso = fip->fi_writesock;
524 	rso = fip->fi_readsock;
525 	fip->fi_readsock = NULL;
526 	fip->fi_writesock = NULL;
527 	fip->fi_flags &= ~FIFO_CREATED;
528 	if (!locked) {
529 		vnode_unlock(vp);
530 	}
531 	error1 = soclose(rso);
532 	error2 = soclose(wso);
533 
534 	if (error1) {
535 		return error1;
536 	}
537 	return error2;
538 }
539 
540 /*
541  * Print out internal contents of a fifo vnode.
542  */
543 void
fifo_printinfo(struct vnode * vp)544 fifo_printinfo(struct vnode *vp)
545 {
546 	struct fifoinfo *fip = vp->v_fifoinfo;
547 
548 	printf(", fifo with %ld readers and %ld writers",
549 	    fip->fi_readers, fip->fi_writers);
550 }
551 
552 /*
553  * Return POSIX pathconf information applicable to fifo's.
554  */
555 int
fifo_pathconf(struct vnop_pathconf_args * ap)556 fifo_pathconf(struct vnop_pathconf_args *ap)
557 {
558 	switch (ap->a_name) {
559 	case _PC_LINK_MAX:
560 		*ap->a_retval = LINK_MAX;
561 		return 0;
562 	case _PC_PIPE_BUF:
563 		*ap->a_retval = PIPE_BUF;
564 		return 0;
565 	case _PC_CHOWN_RESTRICTED:
566 		*ap->a_retval = 200112;         /* _POSIX_CHOWN_RESTRICTED */
567 		return 0;
568 	default:
569 		return EINVAL;
570 	}
571 	/* NOTREACHED */
572 }
573 
574 /*
575  * Fifo failed operation
576  */
577 int
fifo_ebadf(__unused void * dummy)578 fifo_ebadf(__unused void *dummy)
579 {
580 	return EBADF;
581 }
582 
583 /*
584  * Fifo advisory byte-level locks.
585  */
586 int
fifo_advlock(__unused struct vnop_advlock_args * ap)587 fifo_advlock(__unused struct vnop_advlock_args *ap)
588 {
589 	return ENOTSUP;
590 }
591 
592 
593 /* You'd certainly better have an iocount on the vnode! */
594 int
fifo_freespace(struct vnode * vp,long * count)595 fifo_freespace(struct vnode *vp, long *count)
596 {
597 	struct socket *rsock;
598 	rsock = vp->v_fifoinfo->fi_readsock;
599 	socket_lock(rsock, 1);
600 	*count = sbspace(&rsock->so_rcv);
601 	socket_unlock(rsock, 1);
602 	return 0;
603 }
604 
605 int
fifo_charcount(struct vnode * vp,int * count)606 fifo_charcount(struct vnode *vp, int *count)
607 {
608 	int mcount;
609 	int err = sock_ioctl(vp->v_fifoinfo->fi_readsock, FIONREAD, (void*)&mcount);
610 	if (err == 0) {
611 		*count = mcount;
612 	}
613 	return err;
614 }
615