1 /*-
2 * Copyright (c) 1990, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)fifo_vnops.c 8.10 (Berkeley) 5/27/95
30 * $FreeBSD$
31 */
32
33 #include <sys/param.h>
34 #include <sys/event.h>
35 #include <sys/filio.h>
36 #include <sys/fcntl.h>
37 #include <sys/file.h>
38 #include <sys/kernel.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/malloc.h>
42 #include <sys/poll.h>
43 #include <sys/proc.h> /* XXXKSE */
44 #include <sys/signalvar.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/sx.h>
48 #include <sys/systm.h>
49 #include <sys/un.h>
50 #include <sys/unistd.h>
51 #include <sys/vnode.h>
52 #include <fs/fifofs/fifo.h>
53
54 /*
55 * This structure is associated with the FIFO vnode and stores
56 * the state associated with the FIFO.
57 */
58 struct fifoinfo {
59 struct socket *fi_readsock;
60 struct socket *fi_writesock;
61 long fi_readers;
62 long fi_writers;
63 };
64
65 static int fifo_print(struct vop_print_args *);
66 static int fifo_lookup(struct vop_lookup_args *);
67 static int fifo_open(struct vop_open_args *);
68 static int fifo_close(struct vop_close_args *);
69 static int fifo_read(struct vop_read_args *);
70 static int fifo_write(struct vop_write_args *);
71 static int fifo_ioctl(struct vop_ioctl_args *);
72 static int fifo_poll(struct vop_poll_args *);
73 static int fifo_kqfilter(struct vop_kqfilter_args *);
74 static int fifo_pathconf(struct vop_pathconf_args *);
75 static int fifo_advlock(struct vop_advlock_args *);
76
77 static void filt_fifordetach(struct knote *kn);
78 static int filt_fiforead(struct knote *kn, long hint);
79 static void filt_fifowdetach(struct knote *kn);
80 static int filt_fifowrite(struct knote *kn, long hint);
81
82 static struct filterops fiforead_filtops =
83 { 1, NULL, filt_fifordetach, filt_fiforead };
84 static struct filterops fifowrite_filtops =
85 { 1, NULL, filt_fifowdetach, filt_fifowrite };
86
87 vop_t **fifo_vnodeop_p;
88 static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
89 { &vop_default_desc, (vop_t *) vop_defaultop },
90 { &vop_access_desc, (vop_t *) vop_ebadf },
91 { &vop_advlock_desc, (vop_t *) fifo_advlock },
92 { &vop_close_desc, (vop_t *) fifo_close },
93 { &vop_create_desc, (vop_t *) vop_panic },
94 { &vop_getattr_desc, (vop_t *) vop_ebadf },
95 { &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
96 { &vop_ioctl_desc, (vop_t *) fifo_ioctl },
97 { &vop_kqfilter_desc, (vop_t *) fifo_kqfilter },
98 { &vop_lease_desc, (vop_t *) vop_null },
99 { &vop_link_desc, (vop_t *) vop_panic },
100 { &vop_lookup_desc, (vop_t *) fifo_lookup },
101 { &vop_mkdir_desc, (vop_t *) vop_panic },
102 { &vop_mknod_desc, (vop_t *) vop_panic },
103 { &vop_open_desc, (vop_t *) fifo_open },
104 { &vop_pathconf_desc, (vop_t *) fifo_pathconf },
105 { &vop_poll_desc, (vop_t *) fifo_poll },
106 { &vop_print_desc, (vop_t *) fifo_print },
107 { &vop_read_desc, (vop_t *) fifo_read },
108 { &vop_readdir_desc, (vop_t *) vop_panic },
109 { &vop_readlink_desc, (vop_t *) vop_panic },
110 { &vop_reallocblks_desc, (vop_t *) vop_panic },
111 { &vop_reclaim_desc, (vop_t *) vop_null },
112 { &vop_remove_desc, (vop_t *) vop_panic },
113 { &vop_rename_desc, (vop_t *) vop_panic },
114 { &vop_rmdir_desc, (vop_t *) vop_panic },
115 { &vop_setattr_desc, (vop_t *) vop_ebadf },
116 { &vop_symlink_desc, (vop_t *) vop_panic },
117 { &vop_write_desc, (vop_t *) fifo_write },
118 { NULL, NULL }
119 };
120 static struct vnodeopv_desc fifo_vnodeop_opv_desc =
121 { &fifo_vnodeop_p, fifo_vnodeop_entries };
122
123 VNODEOP_SET(fifo_vnodeop_opv_desc);
124
125 struct mtx fifo_mtx;
126 MTX_SYSINIT(fifo, &fifo_mtx, "fifo mutex", MTX_DEF);
127
128 int
129 fifo_vnoperate(ap)
130 struct vop_generic_args /* {
131 struct vnodeop_desc *a_desc;
132 <other random data follows, presumably>
133 } */ *ap;
134 {
135 return (VOCALL(fifo_vnodeop_p, ap->a_desc->vdesc_offset, ap));
136 }
137
138 /*
139 * Trivial lookup routine that always fails.
140 */
141 /* ARGSUSED */
142 static int
143 fifo_lookup(ap)
144 struct vop_lookup_args /* {
145 struct vnode * a_dvp;
146 struct vnode ** a_vpp;
147 struct componentname * a_cnp;
148 } */ *ap;
149 {
150
151 *ap->a_vpp = NULL;
152 return (ENOTDIR);
153 }
154
155 /*
156 * Dispose of fifo resources.
157 */
158 static void
159 fifo_cleanup(struct vnode *vp)
160 {
161 struct fifoinfo *fip = vp->v_fifoinfo;
162
163 ASSERT_VOP_LOCKED(vp, "fifo_cleanup");
164 if (fip->fi_readers == 0 && fip->fi_writers == 0) {
165 vp->v_fifoinfo = NULL;
166 (void)soclose(fip->fi_readsock);
167 (void)soclose(fip->fi_writesock);
168 FREE(fip, M_VNODE);
169 }
170 }
171
172 /*
173 * Open called to set up a new instance of a fifo or
174 * to find an active instance of a fifo.
175 */
176 /* ARGSUSED */
177 static int
178 fifo_open(ap)
179 struct vop_open_args /* {
180 struct vnode *a_vp;
181 int a_mode;
182 struct ucred *a_cred;
183 struct thread *a_td;
184 } */ *ap;
185 {
186 struct vnode *vp = ap->a_vp;
187 struct fifoinfo *fip;
188 struct thread *td = ap->a_td;
189 struct ucred *cred = ap->a_cred;
190 struct socket *rso, *wso;
191 int error;
192
193 ASSERT_VOP_LOCKED(vp, "fifo_open");
194 if ((fip = vp->v_fifoinfo) == NULL) {
195 MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
196 error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, cred, td);
197 if (error)
198 goto fail1;
199 fip->fi_readsock = rso;
200 error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, cred, td);
201 if (error)
202 goto fail2;
203 fip->fi_writesock = wso;
204 error = soconnect2(wso, rso);
205 if (error) {
206 (void)soclose(wso);
207 fail2:
208 (void)soclose(rso);
209 fail1:
210 free(fip, M_VNODE);
211 return (error);
212 }
213 fip->fi_readers = fip->fi_writers = 0;
214 wso->so_snd.sb_lowat = PIPE_BUF;
215 SOCKBUF_LOCK(&rso->so_rcv);
216 rso->so_rcv.sb_state |= SBS_CANTRCVMORE;
217 SOCKBUF_UNLOCK(&rso->so_rcv);
218 KASSERT(vp->v_fifoinfo == NULL,
219 ("fifo_open: v_fifoinfo race"));
220 vp->v_fifoinfo = fip;
221 }
222
223 /*
224 * General access to fi_readers and fi_writers is protected using
225 * the vnode lock.
226 *
227 * Protect the increment of fi_readers and fi_writers and the
228 * associated calls to wakeup() with the fifo mutex in addition
229 * to the vnode lock. This allows the vnode lock to be dropped
230 * for the msleep() calls below, and using the fifo mutex with
231 * msleep() prevents the wakeup from being missed.
232 */
233 mtx_lock(&fifo_mtx);
234 if (ap->a_mode & FREAD) {
235 fip->fi_readers++;
236 if (fip->fi_readers == 1) {
237 SOCKBUF_LOCK(&fip->fi_writesock->so_snd);
238 fip->fi_writesock->so_snd.sb_state &= ~SBS_CANTSENDMORE;
239 SOCKBUF_UNLOCK(&fip->fi_writesock->so_snd);
240 if (fip->fi_writers > 0) {
241 wakeup(&fip->fi_writers);
242 sowwakeup(fip->fi_writesock);
243 }
244 }
245 }
246 if (ap->a_mode & FWRITE) {
247 if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
248 mtx_unlock(&fifo_mtx);
249 return (ENXIO);
250 }
251 fip->fi_writers++;
252 if (fip->fi_writers == 1) {
253 SOCKBUF_LOCK(&fip->fi_readsock->so_rcv);
254 fip->fi_readsock->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
255 SOCKBUF_UNLOCK(&fip->fi_readsock->so_rcv);
256 if (fip->fi_readers > 0) {
257 wakeup(&fip->fi_readers);
258 sorwakeup(fip->fi_readsock);
259 }
260 }
261 }
262 if ((ap->a_mode & O_NONBLOCK) == 0) {
263 if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
264 VOP_UNLOCK(vp, 0, td);
265 error = msleep(&fip->fi_readers, &fifo_mtx,
266 PDROP | PCATCH | PSOCK, "fifoor", 0);
267 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
268 if (error) {
269 fip->fi_readers--;
270 if (fip->fi_readers == 0) {
271 socantsendmore(fip->fi_writesock);
272 fifo_cleanup(vp);
273 }
274 return (error);
275 }
276 mtx_lock(&fifo_mtx);
277 /*
278 * We must have got woken up because we had a writer.
279 * That (and not still having one) is the condition
280 * that we must wait for.
281 */
282 }
283 if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) {
284 VOP_UNLOCK(vp, 0, td);
285 error = msleep(&fip->fi_writers, &fifo_mtx,
286 PDROP | PCATCH | PSOCK, "fifoow", 0);
287 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
288 if (error) {
289 fip->fi_writers--;
290 if (fip->fi_writers == 0) {
291 socantrcvmore(fip->fi_readsock);
292 fifo_cleanup(vp);
293 }
294 return (error);
295 }
296 /*
297 * We must have got woken up because we had
298 * a reader. That (and not still having one)
299 * is the condition that we must wait for.
300 */
301 return (0);
302 }
303 }
304 mtx_unlock(&fifo_mtx);
305 return (0);
306 }
307
308 /*
309 * Vnode op for read
310 */
311 /* ARGSUSED */
312 static int
313 fifo_read(ap)
314 struct vop_read_args /* {
315 struct vnode *a_vp;
316 struct uio *a_uio;
317 int a_ioflag;
318 struct ucred *a_cred;
319 } */ *ap;
320 {
321 struct uio *uio = ap->a_uio;
322 struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
323 struct thread *td = uio->uio_td;
324 int error, flags;
325
326 #ifdef DIAGNOSTIC
327 if (uio->uio_rw != UIO_READ)
328 panic("fifo_read mode");
329 #endif
330 if (uio->uio_resid == 0)
331 return (0);
332 VOP_UNLOCK(ap->a_vp, 0, td);
333 flags = (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0;
334 error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0,
335 (struct mbuf **)0, &flags);
336 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td);
337 return (error);
338 }
339
340 /*
341 * Vnode op for write
342 */
343 /* ARGSUSED */
344 static int
345 fifo_write(ap)
346 struct vop_write_args /* {
347 struct vnode *a_vp;
348 struct uio *a_uio;
349 int a_ioflag;
350 struct ucred *a_cred;
351 } */ *ap;
352 {
353 struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
354 struct thread *td = ap->a_uio->uio_td;
355 int error, flags;
356
357 #ifdef DIAGNOSTIC
358 if (ap->a_uio->uio_rw != UIO_WRITE)
359 panic("fifo_write mode");
360 #endif
361 VOP_UNLOCK(ap->a_vp, 0, td);
362 flags = (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0;
363 error = sosend(wso, (struct sockaddr *)0, ap->a_uio, 0,
364 (struct mbuf *)0, flags, td);
365 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td);
366 return (error);
367 }
368
369 /*
370 * Device ioctl operation.
371 */
372 /* ARGSUSED */
373 static int
374 fifo_ioctl(ap)
375 struct vop_ioctl_args /* {
376 struct vnode *a_vp;
377 u_long a_command;
378 caddr_t a_data;
379 int a_fflag;
380 struct ucred *a_cred;
381 struct thread *a_td;
382 } */ *ap;
383 {
384 struct file filetmp; /* Local, so need not be locked. */
385 int error;
386
387 if (ap->a_command == FIONBIO)
388 return (0);
389 if (ap->a_fflag & FREAD) {
390 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
391 filetmp.f_cred = ap->a_cred;
392 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data,
393 ap->a_td->td_ucred, ap->a_td);
394 if (error)
395 return (error);
396 }
397 if (ap->a_fflag & FWRITE) {
398 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
399 filetmp.f_cred = ap->a_cred;
400 error = soo_ioctl(&filetmp, ap->a_command, ap->a_data,
401 ap->a_td->td_ucred, ap->a_td);
402 if (error)
403 return (error);
404 }
405 return (0);
406 }
407
408 /* ARGSUSED */
409 static int
410 fifo_kqfilter(ap)
411 struct vop_kqfilter_args /* {
412 struct vnode *a_vp;
413 struct knote *a_kn;
414 } */ *ap;
415 {
416 struct fifoinfo *fi = ap->a_vp->v_fifoinfo;
417 struct socket *so;
418 struct sockbuf *sb;
419
420 switch (ap->a_kn->kn_filter) {
421 case EVFILT_READ:
422 ap->a_kn->kn_fop = &fiforead_filtops;
423 so = fi->fi_readsock;
424 sb = &so->so_rcv;
425 break;
426 case EVFILT_WRITE:
427 ap->a_kn->kn_fop = &fifowrite_filtops;
428 so = fi->fi_writesock;
429 sb = &so->so_snd;
430 break;
431 default:
432 return (EINVAL);
433 }
434
435 ap->a_kn->kn_hook = (caddr_t)so;
436
437 SOCKBUF_LOCK(sb);
438 knlist_add(&sb->sb_sel.si_note, ap->a_kn, 1);
439 sb->sb_flags |= SB_KNOTE;
440 SOCKBUF_UNLOCK(sb);
441
442 return (0);
443 }
444
445 static void
446 filt_fifordetach(struct knote *kn)
447 {
448 struct socket *so = (struct socket *)kn->kn_hook;
449
450 SOCKBUF_LOCK(&so->so_rcv);
451 knlist_remove(&so->so_rcv.sb_sel.si_note, kn, 1);
452 if (knlist_empty(&so->so_rcv.sb_sel.si_note))
453 so->so_rcv.sb_flags &= ~SB_KNOTE;
454 SOCKBUF_UNLOCK(&so->so_rcv);
455 }
456
457 static int
458 filt_fiforead(struct knote *kn, long hint)
459 {
460 struct socket *so = (struct socket *)kn->kn_hook;
461
462 SOCKBUF_LOCK_ASSERT(&so->so_rcv);
463 kn->kn_data = so->so_rcv.sb_cc;
464 if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
465 kn->kn_flags |= EV_EOF;
466 return (1);
467 } else {
468 kn->kn_flags &= ~EV_EOF;
469 return (kn->kn_data > 0);
470 }
471 }
472
473 static void
474 filt_fifowdetach(struct knote *kn)
475 {
476 struct socket *so = (struct socket *)kn->kn_hook;
477
478 SOCKBUF_LOCK(&so->so_snd);
479 knlist_remove(&so->so_snd.sb_sel.si_note, kn, 1);
480 if (knlist_empty(&so->so_snd.sb_sel.si_note))
481 so->so_snd.sb_flags &= ~SB_KNOTE;
482 SOCKBUF_UNLOCK(&so->so_snd);
483 }
484
485 static int
486 filt_fifowrite(struct knote *kn, long hint)
487 {
488 struct socket *so = (struct socket *)kn->kn_hook;
489
490 SOCKBUF_LOCK_ASSERT(&so->so_snd);
491 kn->kn_data = sbspace(&so->so_snd);
492 if (so->so_snd.sb_state & SBS_CANTSENDMORE) {
493 kn->kn_flags |= EV_EOF;
494 return (1);
495 } else {
496 kn->kn_flags &= ~EV_EOF;
497 return (kn->kn_data >= so->so_snd.sb_lowat);
498 }
499 }
500
501 /* ARGSUSED */
502 static int
503 fifo_poll(ap)
504 struct vop_poll_args /* {
505 struct vnode *a_vp;
506 int a_events;
507 struct ucred *a_cred;
508 struct thread *a_td;
509 } */ *ap;
510 {
511 struct file filetmp;
512 int events, revents = 0;
513
514 events = ap->a_events &
515 (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND);
516 if (events) {
517 /*
518 * If POLLIN or POLLRDNORM is requested and POLLINIGNEOF is
519 * not, then convert the first two to the last one. This
520 * tells the socket poll function to ignore EOF so that we
521 * block if there is no writer (and no data). Callers can
522 * set POLLINIGNEOF to get non-blocking behavior.
523 */
524 if (events & (POLLIN | POLLRDNORM) &&
525 !(events & POLLINIGNEOF)) {
526 events &= ~(POLLIN | POLLRDNORM);
527 events |= POLLINIGNEOF;
528 }
529
530 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_readsock;
531 filetmp.f_cred = ap->a_cred;
532 revents |= soo_poll(&filetmp, events, ap->a_td->td_ucred,
533 ap->a_td);
534
535 /* Reverse the above conversion. */
536 if ((revents & POLLINIGNEOF) &&
537 !(ap->a_events & POLLINIGNEOF)) {
538 revents |= (ap->a_events & (POLLIN | POLLRDNORM));
539 revents &= ~POLLINIGNEOF;
540 }
541 }
542 events = ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND);
543 if (events) {
544 filetmp.f_data = ap->a_vp->v_fifoinfo->fi_writesock;
545 filetmp.f_cred = ap->a_cred;
546 revents |= soo_poll(&filetmp, events, ap->a_td->td_ucred,
547 ap->a_td);
548 }
549 return (revents);
550 }
551
552 /*
553 * Device close routine
554 */
555 /* ARGSUSED */
556 static int
557 fifo_close(ap)
558 struct vop_close_args /* {
559 struct vnode *a_vp;
560 int a_fflag;
561 struct ucred *a_cred;
562 struct thread *a_td;
563 } */ *ap;
564 {
565 struct vnode *vp = ap->a_vp;
566 struct thread *td = ap->a_td;
567 struct fifoinfo *fip = vp->v_fifoinfo;
568
569 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
570
571 ASSERT_VOP_LOCKED(vp, "fifo_close");
572 if (ap->a_fflag & FREAD) {
573 fip->fi_readers--;
574 if (fip->fi_readers == 0)
575 socantsendmore(fip->fi_writesock);
576 }
577 if (ap->a_fflag & FWRITE) {
578 fip->fi_writers--;
579 if (fip->fi_writers == 0)
580 socantrcvmore(fip->fi_readsock);
581 }
582 fifo_cleanup(vp);
583 VOP_UNLOCK(vp, 0, td);
584 return (0);
585 }
586
587 /*
588 * Print out internal contents of a fifo vnode.
589 */
590 int
591 fifo_printinfo(vp)
592 struct vnode *vp;
593 {
594 register struct fifoinfo *fip = vp->v_fifoinfo;
595
596 printf(", fifo with %ld readers and %ld writers",
597 fip->fi_readers, fip->fi_writers);
598 return (0);
599 }
600
601 /*
602 * Print out the contents of a fifo vnode.
603 */
604 static int
605 fifo_print(ap)
606 struct vop_print_args /* {
607 struct vnode *a_vp;
608 } */ *ap;
609 {
610 fifo_printinfo(ap->a_vp);
611 printf("\n");
612 return (0);
613 }
614
615 /*
616 * Return POSIX pathconf information applicable to fifo's.
617 */
618 static int
619 fifo_pathconf(ap)
620 struct vop_pathconf_args /* {
621 struct vnode *a_vp;
622 int a_name;
623 int *a_retval;
624 } */ *ap;
625 {
626
627 switch (ap->a_name) {
628 case _PC_LINK_MAX:
629 *ap->a_retval = LINK_MAX;
630 return (0);
631 case _PC_PIPE_BUF:
632 *ap->a_retval = PIPE_BUF;
633 return (0);
634 case _PC_CHOWN_RESTRICTED:
635 *ap->a_retval = 1;
636 return (0);
637 default:
638 return (EINVAL);
639 }
640 /* NOTREACHED */
641 }
642
643 /*
644 * Fifo advisory byte-level locks.
645 */
646 /* ARGSUSED */
647 static int
648 fifo_advlock(ap)
649 struct vop_advlock_args /* {
650 struct vnode *a_vp;
651 caddr_t a_id;
652 int a_op;
653 struct flock *a_fl;
654 int a_flags;
655 } */ *ap;
656 {
657
658 return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
659 }
Cache object: 95d1d22fb31edf138341d89e78dec5c7
|