]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_vnops.c
xnu-517.9.4.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_vnops.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1982, 1986, 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 * (c) UNIX System Laboratories, Inc.
27 * All or some portions of this file are derived from material licensed
28 * to the University of California by American Telephone and Telegraph
29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
30 * the permission of UNIX System Laboratories, Inc.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)vfs_vnops.c 8.14 (Berkeley) 6/15/95
61 *
62 */
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/kernel.h>
67 #include <sys/file.h>
68 #include <sys/stat.h>
69 #include <sys/buf.h>
70 #include <sys/proc.h>
71 #include <sys/mount.h>
72 #include <sys/namei.h>
73 #include <sys/vnode.h>
74 #include <sys/ioctl.h>
75 #include <sys/tty.h>
76 #include <sys/ubc.h>
77 #include <sys/conf.h>
78 #include <sys/disk.h>
79
80 #include <vm/vm_kern.h>
81
82 #include <miscfs/specfs/specdev.h>
83
84 static int vn_closefile __P((struct file *fp, struct proc *p));
85 static int vn_ioctl __P((struct file *fp, u_long com, caddr_t data,
86 struct proc *p));
87 static int vn_read __P((struct file *fp, struct uio *uio,
88 struct ucred *cred, int flags, struct proc *p));
89 static int vn_write __P((struct file *fp, struct uio *uio,
90 struct ucred *cred, int flags, struct proc *p));
91 static int vn_select __P(( struct file *fp, int which, void * wql,
92 struct proc *p));
93 static int vn_kqfilt_add __P((struct file *fp, struct knote *kn, struct proc *p));
94 static int vn_kqfilt_remove __P((struct vnode *vp, uintptr_t ident, struct proc *p));
95
96 struct fileops vnops =
97 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile, vn_kqfilt_add };
98
99 /*
100 * Common code for vnode open operations.
101 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
102 */
103 int
104 vn_open(ndp, fmode, cmode)
105 register struct nameidata *ndp;
106 int fmode, cmode;
107 {
108 return vn_open_modflags(ndp,&fmode,cmode);
109 }
110
111 __private_extern__ int
112 vn_open_modflags(ndp, fmodep, cmode)
113 register struct nameidata *ndp;
114 int *fmodep;
115 int cmode;
116 {
117 register struct vnode *vp;
118 register struct proc *p = ndp->ni_cnd.cn_proc;
119 register struct ucred *cred = p->p_ucred;
120 struct vattr vat;
121 struct vattr *vap = &vat;
122 int error;
123 int didhold = 0;
124 char *nameptr;
125 int fmode = *fmodep;
126
127 if (fmode & O_CREAT) {
128 ndp->ni_cnd.cn_nameiop = CREATE;
129 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | AUDITVNPATH1;
130 if ((fmode & O_EXCL) == 0)
131 ndp->ni_cnd.cn_flags |= FOLLOW;
132 bwillwrite();
133 if (error = namei(ndp))
134 return (error);
135 if (ndp->ni_vp == NULL) {
136 nameptr = add_name(ndp->ni_cnd.cn_nameptr,
137 ndp->ni_cnd.cn_namelen,
138 ndp->ni_cnd.cn_hash, 0);
139
140 VATTR_NULL(vap);
141 vap->va_type = VREG;
142 vap->va_mode = cmode;
143 if (fmode & O_EXCL)
144 vap->va_vaflags |= VA_EXCLUSIVE;
145 VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
146 if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
147 &ndp->ni_cnd, vap)) {
148 remove_name(nameptr);
149 return (error);
150 }
151 fmode &= ~O_TRUNC;
152 vp = ndp->ni_vp;
153
154 VNAME(vp) = nameptr;
155 if (vget(ndp->ni_dvp, 0, p) == 0) {
156 VPARENT(vp) = ndp->ni_dvp;
157 }
158 } else {
159 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
160 if (ndp->ni_dvp == ndp->ni_vp)
161 vrele(ndp->ni_dvp);
162 else
163 vput(ndp->ni_dvp);
164 ndp->ni_dvp = NULL;
165 vp = ndp->ni_vp;
166 if (fmode & O_EXCL) {
167 error = EEXIST;
168 goto bad;
169 }
170 fmode &= ~O_CREAT;
171 }
172 } else {
173 ndp->ni_cnd.cn_nameiop = LOOKUP;
174 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF | AUDITVNPATH1;
175 if (error = namei(ndp))
176 return (error);
177 vp = ndp->ni_vp;
178 }
179 if (vp->v_type == VSOCK) {
180 error = EOPNOTSUPP;
181 goto bad;
182 }
183
184 #if DIAGNOSTIC
185 if (UBCINFOMISSING(vp))
186 panic("vn_open: ubc_info_init");
187 #endif /* DIAGNOSTIC */
188
189 if (UBCINFOEXISTS(vp) && ((didhold = ubc_hold(vp)) == 0)) {
190 error = ENOENT;
191 goto bad;
192 }
193
194 if ((fmode & O_CREAT) == 0) {
195 if (fmode & FREAD && fmode & (FWRITE | O_TRUNC)) {
196 int err = 0;
197 if (vp->v_type == VDIR)
198 err = EISDIR;
199 else
200 err = vn_writechk(vp);
201 if (err && !(error = VOP_ACCESS(vp, VREAD, cred, p)))
202 error = err;
203 if (error || (error = VOP_ACCESS(vp, VREAD|VWRITE,
204 cred, p)))
205 goto bad;
206 } else if (fmode & FREAD) {
207 if ((error = VOP_ACCESS(vp, VREAD, cred, p)))
208 goto bad;
209 } else if (fmode & (FWRITE | O_TRUNC)) {
210 if (vp->v_type == VDIR) {
211 error = EISDIR;
212 goto bad;
213 }
214 if ((error = vn_writechk(vp)) ||
215 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
216 goto bad;
217 }
218 }
219
220 if (error = VOP_OPEN(vp, fmode, cred, p)) {
221 goto bad;
222 }
223
224 if (fmode & FWRITE)
225 if (++vp->v_writecount <= 0)
226 panic("vn_open: v_writecount");
227 *fmodep = fmode;
228 return (0);
229 bad:
230 VOP_UNLOCK(vp, 0, p);
231 if (didhold)
232 ubc_rele(vp);
233 vrele(vp);
234 ndp->ni_vp = NULL;
235 return (error);
236 }
237
238 /*
239 * Check for write permissions on the specified vnode.
240 * Prototype text segments cannot be written.
241 */
242 int
243 vn_writechk(vp)
244 register struct vnode *vp;
245 {
246
247 /*
248 * If there's shared text associated with
249 * the vnode, try to free it up once. If
250 * we fail, we can't allow writing.
251 */
252 #if 0
253 /* XXXXX Not sure we need this */
254 if (vp->v_flag & VTEXT)
255 return (ETXTBSY);
256 #endif /* 0 */
257 return (0);
258 }
259
260 /*
261 * Vnode close call
262 */
263 int
264 vn_close(vp, flags, cred, p)
265 register struct vnode *vp;
266 int flags;
267 struct ucred *cred;
268 struct proc *p;
269 {
270 int error;
271
272 if (flags & FWRITE) {
273
274 vp->v_writecount--;
275
276 {
277 extern void notify_filemod_watchers(struct vnode *vp, struct proc *p);
278
279 notify_filemod_watchers(vp, p);
280 }
281 }
282
283 error = VOP_CLOSE(vp, flags, cred, p);
284 ubc_rele(vp);
285 vrele(vp);
286 return (error);
287 }
288
289 /*
290 * Package up an I/O request on a vnode into a uio and do it.
291 */
292 int
293 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
294 enum uio_rw rw;
295 struct vnode *vp;
296 caddr_t base;
297 int len;
298 off_t offset;
299 enum uio_seg segflg;
300 int ioflg;
301 struct ucred *cred;
302 int *aresid;
303 struct proc *p;
304 {
305 struct uio auio;
306 struct iovec aiov;
307 int error=0;
308
309 /* FIXME XXX */
310 if ((ioflg & IO_NODELOCKED) == 0)
311 (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
312 auio.uio_iov = &aiov;
313 auio.uio_iovcnt = 1;
314 aiov.iov_base = base;
315 aiov.iov_len = len;
316 auio.uio_resid = len;
317 auio.uio_offset = offset;
318 auio.uio_segflg = segflg;
319 auio.uio_rw = rw;
320 auio.uio_procp = p;
321
322 if (rw == UIO_READ)
323 error = VOP_READ(vp, &auio, ioflg, cred);
324 else
325 error = VOP_WRITE(vp, &auio, ioflg, cred);
326
327 if (aresid)
328 *aresid = auio.uio_resid;
329 else
330 if (auio.uio_resid && error == 0)
331 error = EIO;
332 if ((ioflg & IO_NODELOCKED) == 0)
333 VOP_UNLOCK(vp, 0, p);
334 return (error);
335 }
336
337 /*
338 * File table vnode read routine.
339 */
340 static int
341 vn_read(fp, uio, cred, flags, p)
342 struct file *fp;
343 struct uio *uio;
344 struct ucred *cred;
345 int flags;
346 struct proc *p;
347 {
348 struct vnode *vp;
349 int error, ioflag;
350 off_t count;
351
352 if (p != uio->uio_procp)
353 panic("vn_read: uio_procp does not match p");
354
355 vp = (struct vnode *)fp->f_data;
356 ioflag = 0;
357 if (fp->f_flag & FNONBLOCK)
358 ioflag |= IO_NDELAY;
359 VOP_LEASE(vp, p, cred, LEASE_READ);
360 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
361 if (error)
362 return (error);
363 if ((flags & FOF_OFFSET) == 0)
364 uio->uio_offset = fp->f_offset;
365 count = uio->uio_resid;
366
367 if(UBCINFOEXISTS(vp)) {
368 memory_object_t pager;
369 struct iovec *iov;
370 off_t file_off;
371 kern_return_t kr = KERN_SUCCESS;
372 kern_return_t ret = KERN_SUCCESS;
373 int count;
374
375 pager = (memory_object_t)ubc_getpager(vp);
376 file_off = uio->uio_offset;
377 iov = uio->uio_iov;
378 count = uio->uio_iovcnt;
379 while(count) {
380 kr = vm_conflict_check(current_map(),
381 (vm_offset_t)iov->iov_base, iov->iov_len,
382 pager, file_off);
383 if(kr == KERN_ALREADY_WAITING) {
384 if((count != uio->uio_iovcnt) &&
385 (ret != KERN_ALREADY_WAITING)) {
386 error = EINVAL;
387 goto done;
388 }
389 ret = KERN_ALREADY_WAITING;
390 } else if (kr != KERN_SUCCESS) {
391 error = EINVAL;
392 goto done;
393 }
394 if(kr != ret) {
395 error = EINVAL;
396 goto done;
397 }
398 file_off += iov->iov_len;
399 iov++;
400 count--;
401 }
402 if(ret == KERN_ALREADY_WAITING) {
403 uio->uio_resid = 0;
404 if ((flags & FOF_OFFSET) == 0)
405 fp->f_offset +=
406 count - uio->uio_resid;
407 error = 0;
408 goto done;
409 }
410 }
411 error = VOP_READ(vp, uio, ioflag, cred);
412 if ((flags & FOF_OFFSET) == 0)
413 fp->f_offset += count - uio->uio_resid;
414 done:
415 VOP_UNLOCK(vp, 0, p);
416 return (error);
417 }
418
419
420 /*
421 * File table vnode write routine.
422 */
423 static int
424 vn_write(fp, uio, cred, flags, p)
425 struct file *fp;
426 struct uio *uio;
427 struct ucred *cred;
428 int flags;
429 struct proc *p;
430 {
431 struct vnode *vp;
432 int error, ioflag;
433 off_t count;
434
435 if (p != uio->uio_procp)
436 panic("vn_write: uio_procp does not match p");
437
438 vp = (struct vnode *)fp->f_data;
439 ioflag = IO_UNIT;
440 if (vp->v_type == VREG)
441 bwillwrite();
442 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
443 ioflag |= IO_APPEND;
444 if (fp->f_flag & FNONBLOCK)
445 ioflag |= IO_NDELAY;
446 if ((fp->f_flag & O_FSYNC) ||
447 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
448 ioflag |= IO_SYNC;
449 VOP_LEASE(vp, p, cred, LEASE_WRITE);
450 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
451 if (error)
452 return (error);
453 if ((flags & FOF_OFFSET) == 0) {
454 uio->uio_offset = fp->f_offset;
455 count = uio->uio_resid;
456 }
457
458 if(UBCINFOEXISTS(vp)) {
459 memory_object_t pager;
460 struct iovec *iov;
461 off_t file_off;
462 kern_return_t kr = KERN_SUCCESS;
463 kern_return_t ret = KERN_SUCCESS;
464 int count;
465
466 pager = (memory_object_t)ubc_getpager(vp);
467 file_off = uio->uio_offset;
468 iov = uio->uio_iov;
469 count = uio->uio_iovcnt;
470 while(count) {
471 kr = vm_conflict_check(current_map(),
472 (vm_offset_t)iov->iov_base,
473 iov->iov_len, pager, file_off);
474 if(kr == KERN_ALREADY_WAITING) {
475 if((count != uio->uio_iovcnt) &&
476 (ret != KERN_ALREADY_WAITING)) {
477 error = EINVAL;
478 goto done;
479 }
480 ret = KERN_ALREADY_WAITING;
481 } else if (kr != KERN_SUCCESS) {
482 error = EINVAL;
483 goto done;
484 }
485 if(kr != ret) {
486 error = EINVAL;
487 goto done;
488 }
489 file_off += iov->iov_len;
490 iov++;
491 count--;
492 }
493 if(ret == KERN_ALREADY_WAITING) {
494 uio->uio_resid = 0;
495 if ((flags & FOF_OFFSET) == 0)
496 fp->f_offset +=
497 count - uio->uio_resid;
498 error = 0;
499 goto done;
500 }
501 }
502 error = VOP_WRITE(vp, uio, ioflag, cred);
503
504 if ((flags & FOF_OFFSET) == 0) {
505 if (ioflag & IO_APPEND)
506 fp->f_offset = uio->uio_offset;
507 else
508 fp->f_offset += count - uio->uio_resid;
509 }
510
511 /*
512 * Set the credentials on successful writes
513 */
514 if ((error == 0) && (vp->v_tag == VT_NFS) && (UBCINFOEXISTS(vp))) {
515 ubc_setcred(vp, p);
516 }
517
518 done:
519 VOP_UNLOCK(vp, 0, p);
520 return (error);
521 }
522
523 /*
524 * File table vnode stat routine.
525 */
526 int
527 vn_stat(vp, sb, p)
528 struct vnode *vp;
529 register struct stat *sb;
530 struct proc *p;
531 {
532 struct vattr vattr;
533 register struct vattr *vap;
534 int error;
535 u_short mode;
536
537 vap = &vattr;
538 error = VOP_GETATTR(vp, vap, p->p_ucred, p);
539 if (error)
540 return (error);
541 /*
542 * Copy from vattr table
543 */
544 sb->st_dev = vap->va_fsid;
545 sb->st_ino = vap->va_fileid;
546 mode = vap->va_mode;
547 switch (vp->v_type) {
548 case VREG:
549 mode |= S_IFREG;
550 break;
551 case VDIR:
552 mode |= S_IFDIR;
553 break;
554 case VBLK:
555 mode |= S_IFBLK;
556 break;
557 case VCHR:
558 mode |= S_IFCHR;
559 break;
560 case VLNK:
561 mode |= S_IFLNK;
562 break;
563 case VSOCK:
564 mode |= S_IFSOCK;
565 break;
566 case VFIFO:
567 mode |= S_IFIFO;
568 break;
569 default:
570 return (EBADF);
571 };
572 sb->st_mode = mode;
573 sb->st_nlink = vap->va_nlink;
574 sb->st_uid = vap->va_uid;
575 sb->st_gid = vap->va_gid;
576 sb->st_rdev = vap->va_rdev;
577 sb->st_size = vap->va_size;
578 sb->st_atimespec = vap->va_atime;
579 sb->st_mtimespec = vap->va_mtime;
580 sb->st_ctimespec = vap->va_ctime;
581 sb->st_blksize = vap->va_blocksize;
582 sb->st_flags = vap->va_flags;
583 /* Do not give the generation number out to unpriviledged users */
584 if (vap->va_gen && suser(p->p_ucred, &p->p_acflag))
585 sb->st_gen = 0;
586 else
587 sb->st_gen = vap->va_gen;
588 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
589 return (0);
590 }
591
592 /*
593 * File table vnode ioctl routine.
594 */
595 static int
596 vn_ioctl(fp, com, data, p)
597 struct file *fp;
598 u_long com;
599 caddr_t data;
600 struct proc *p;
601 {
602 register struct vnode *vp = ((struct vnode *)fp->f_data);
603 struct vattr vattr;
604 int error;
605 struct vnode *ttyvp;
606
607 switch (vp->v_type) {
608
609 case VREG:
610 case VDIR:
611 if (com == FIONREAD) {
612 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
613 return (error);
614 *(int *)data = vattr.va_size - fp->f_offset;
615 return (0);
616 }
617 if (com == FIONBIO || com == FIOASYNC) /* XXX */
618 return (0); /* XXX */
619 /* fall into ... */
620
621 default:
622 return (ENOTTY);
623
624 case VFIFO:
625 case VCHR:
626 case VBLK:
627
628 /* Should not be able to set block size from user space */
629 if(com == DKIOCSETBLOCKSIZE)
630 return (EPERM);
631
632 if (com == FIODTYPE) {
633 if (vp->v_type == VBLK) {
634 if (major(vp->v_rdev) >= nblkdev)
635 return (ENXIO);
636 *(int *)data = bdevsw[major(vp->v_rdev)].d_type;
637 } else if (vp->v_type == VCHR) {
638 if (major(vp->v_rdev) >= nchrdev)
639 return (ENXIO);
640 *(int *)data = cdevsw[major(vp->v_rdev)].d_type;
641 } else {
642 return (ENOTTY);
643 }
644 return (0);
645 }
646 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
647 if (error == 0 && com == TIOCSCTTY) {
648 VREF(vp);
649 ttyvp = p->p_session->s_ttyvp;
650 p->p_session->s_ttyvp = vp;
651 if (ttyvp)
652 vrele(ttyvp);
653 }
654 return (error);
655 }
656 }
657
658 /*
659 * File table vnode select routine.
660 */
661 static int
662 vn_select(fp, which, wql, p)
663 struct file *fp;
664 int which;
665 void * wql;
666 struct proc *p;
667 {
668
669 return(VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
670 fp->f_cred, wql, p));
671 }
672
673 /*
674 * Check that the vnode is still valid, and if so
675 * acquire requested lock.
676 */
677 int
678 vn_lock(vp, flags, p)
679 struct vnode *vp;
680 int flags;
681 struct proc *p;
682 {
683 int error;
684
685 do {
686 if ((flags & LK_INTERLOCK) == 0)
687 simple_lock(&vp->v_interlock);
688 if (vp->v_flag & VXLOCK) {
689 while (vp->v_flag & VXLOCK) {
690 vp->v_flag |= VXWANT;
691 simple_unlock(&vp->v_interlock);
692 (void)tsleep((caddr_t)vp, PINOD, "vn_lock", 0);
693 }
694 error = ENOENT;
695 } else {
696 error = VOP_LOCK(vp, flags | LK_INTERLOCK, p);
697 if (error == 0)
698 return (error);
699 }
700 flags &= ~LK_INTERLOCK;
701 } while (flags & LK_RETRY);
702 return (error);
703 }
704
705 /*
706 * File table vnode close routine.
707 */
708 static int
709 vn_closefile(fp, p)
710 struct file *fp;
711 struct proc *p;
712 {
713
714 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
715 fp->f_cred, p));
716 }
717
718 static int
719 vn_kqfilt_add(fp, kn, p)
720 struct file *fp;
721 struct knote *kn;
722 struct proc *p;
723 {
724 struct vnode *vp = (struct vnode *)fp->f_data;
725 int error;
726
727 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
728 if (error) return (error);
729 error = VOP_KQFILT_ADD(vp, kn, p);
730 (void)VOP_UNLOCK(vp, 0, p);
731 return (error);
732 }
733
734 static int
735 vn_kqfilt_remove(vp, ident, p)
736 struct vnode *vp;
737 uintptr_t ident;
738 struct proc *p;
739 {
740 int error;
741
742 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
743 if (error) return (error);
744 error = VOP_KQFILT_REMOVE(vp, ident, p);
745 (void)VOP_UNLOCK(vp, 0, p);
746 return (error);
747 }