]> git.saurik.com Git - apple/xnu.git/blame - bsd/vfs/vfs_vnops.c
xnu-344.12.2.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_vnops.c
CommitLineData
1c79356b 1/*
9bccf70c 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
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 *
1c79356b
A
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>
9bccf70c
A
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
84static int vn_closefile __P((struct file *fp, struct proc *p));
85static int vn_ioctl __P((struct file *fp, u_long com, caddr_t data,
86 struct proc *p));
87static int vn_read __P((struct file *fp, struct uio *uio,
88 struct ucred *cred, int flags, struct proc *p));
89static int vn_write __P((struct file *fp, struct uio *uio,
90 struct ucred *cred, int flags, struct proc *p));
91static int vn_select __P(( struct file *fp, int which, void * wql,
92 struct proc *p));
1c79356b
A
93
94struct fileops vnops =
95 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
96
97/*
98 * Common code for vnode open operations.
99 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
100 */
9bccf70c 101int
1c79356b
A
102vn_open(ndp, fmode, cmode)
103 register struct nameidata *ndp;
104 int fmode, cmode;
105{
106 register struct vnode *vp;
107 register struct proc *p = ndp->ni_cnd.cn_proc;
108 register struct ucred *cred = p->p_ucred;
109 struct vattr vat;
110 struct vattr *vap = &vat;
111 int error;
9bccf70c 112 int didhold = 0;
1c79356b
A
113
114 if (fmode & O_CREAT) {
115 ndp->ni_cnd.cn_nameiop = CREATE;
116 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
117 if ((fmode & O_EXCL) == 0)
118 ndp->ni_cnd.cn_flags |= FOLLOW;
9bccf70c 119 bwillwrite();
1c79356b
A
120 if (error = namei(ndp))
121 return (error);
122 if (ndp->ni_vp == NULL) {
123 VATTR_NULL(vap);
124 vap->va_type = VREG;
125 vap->va_mode = cmode;
126 if (fmode & O_EXCL)
127 vap->va_vaflags |= VA_EXCLUSIVE;
128 VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
129 if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
130 &ndp->ni_cnd, vap))
131 return (error);
132 fmode &= ~O_TRUNC;
133 vp = ndp->ni_vp;
134 } else {
135 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
136 if (ndp->ni_dvp == ndp->ni_vp)
137 vrele(ndp->ni_dvp);
138 else
139 vput(ndp->ni_dvp);
140 ndp->ni_dvp = NULL;
141 vp = ndp->ni_vp;
142 if (fmode & O_EXCL) {
143 error = EEXIST;
144 goto bad;
145 }
146 fmode &= ~O_CREAT;
147 }
148 } else {
149 ndp->ni_cnd.cn_nameiop = LOOKUP;
150 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
151 if (error = namei(ndp))
152 return (error);
153 vp = ndp->ni_vp;
154 }
155 if (vp->v_type == VSOCK) {
156 error = EOPNOTSUPP;
157 goto bad;
158 }
9bccf70c
A
159
160#if DIAGNOSTIC
161 if (UBCINFOMISSING(vp))
162 panic("vn_open: ubc_info_init");
163#endif /* DIAGNOSTIC */
164
165 if (UBCINFOEXISTS(vp) && ((didhold = ubc_hold(vp)) == 0)) {
166 error = ENOENT;
167 goto bad;
168 }
169
1c79356b
A
170 if ((fmode & O_CREAT) == 0) {
171 if (fmode & FREAD && fmode & (FWRITE | O_TRUNC)) {
172 int err = 0;
173 if (vp->v_type == VDIR)
174 err = EISDIR;
175 else
176 err = vn_writechk(vp);
177 if (err && !(error = VOP_ACCESS(vp, VREAD, cred, p)))
178 error = err;
179 if (error || (error = VOP_ACCESS(vp, VREAD|VWRITE,
180 cred, p)))
181 goto bad;
182 } else if (fmode & FREAD) {
183 if ((error = VOP_ACCESS(vp, VREAD, cred, p)))
184 goto bad;
185 } else if (fmode & (FWRITE | O_TRUNC)) {
186 if (vp->v_type == VDIR) {
187 error = EISDIR;
188 goto bad;
189 }
190 if ((error = vn_writechk(vp)) ||
191 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
192 goto bad;
193 }
194 }
195 if (fmode & O_TRUNC) {
196 VOP_UNLOCK(vp, 0, p); /* XXX */
197 VOP_LEASE(vp, p, cred, LEASE_WRITE);
0b4e3aa0 198 (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
1c79356b
A
199 VATTR_NULL(vap);
200 vap->va_size = 0;
201 if (error = VOP_SETATTR(vp, vap, cred, p))
202 goto bad;
203 }
0b4e3aa0 204
0b4e3aa0 205 if (error = VOP_OPEN(vp, fmode, cred, p)) {
0b4e3aa0
A
206 goto bad;
207 }
208
1c79356b
A
209 if (fmode & FWRITE)
210 if (++vp->v_writecount <= 0)
211 panic("vn_open: v_writecount");
212 return (0);
213bad:
9bccf70c
A
214 VOP_UNLOCK(vp, 0, p);
215 if (didhold)
216 ubc_rele(vp);
217 vrele(vp);
1c79356b
A
218 return (error);
219}
220
221/*
222 * Check for write permissions on the specified vnode.
223 * Prototype text segments cannot be written.
224 */
9bccf70c 225int
1c79356b
A
226vn_writechk(vp)
227 register struct vnode *vp;
228{
229
230 /*
231 * If there's shared text associated with
232 * the vnode, try to free it up once. If
233 * we fail, we can't allow writing.
234 */
235#if 0
236 /* XXXXX Not sure we need this */
237 if (vp->v_flag & VTEXT)
238 return (ETXTBSY);
239#endif /* 0 */
240 return (0);
241}
242
243/*
244 * Vnode close call
245 */
9bccf70c 246int
1c79356b
A
247vn_close(vp, flags, cred, p)
248 register struct vnode *vp;
249 int flags;
250 struct ucred *cred;
251 struct proc *p;
252{
253 int error;
1c79356b
A
254
255 if (flags & FWRITE)
256 vp->v_writecount--;
257 error = VOP_CLOSE(vp, flags, cred, p);
258 ubc_rele(vp);
259 vrele(vp);
260 return (error);
261}
262
263/*
264 * Package up an I/O request on a vnode into a uio and do it.
265 */
9bccf70c 266int
1c79356b
A
267vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
268 enum uio_rw rw;
269 struct vnode *vp;
270 caddr_t base;
271 int len;
272 off_t offset;
273 enum uio_seg segflg;
274 int ioflg;
275 struct ucred *cred;
276 int *aresid;
277 struct proc *p;
278{
279 struct uio auio;
280 struct iovec aiov;
281 int error=0;
282
283 /* FIXME XXX */
284 if ((ioflg & IO_NODELOCKED) == 0)
0b4e3aa0 285 (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1c79356b
A
286 auio.uio_iov = &aiov;
287 auio.uio_iovcnt = 1;
288 aiov.iov_base = base;
289 aiov.iov_len = len;
290 auio.uio_resid = len;
291 auio.uio_offset = offset;
292 auio.uio_segflg = segflg;
293 auio.uio_rw = rw;
294 auio.uio_procp = p;
295
296 if (rw == UIO_READ)
297 error = VOP_READ(vp, &auio, ioflg, cred);
298 else
299 error = VOP_WRITE(vp, &auio, ioflg, cred);
300
301 if (aresid)
302 *aresid = auio.uio_resid;
303 else
304 if (auio.uio_resid && error == 0)
305 error = EIO;
306 if ((ioflg & IO_NODELOCKED) == 0)
307 VOP_UNLOCK(vp, 0, p);
308 return (error);
309}
310
311/*
312 * File table vnode read routine.
313 */
9bccf70c
A
314static int
315vn_read(fp, uio, cred, flags, p)
1c79356b
A
316 struct file *fp;
317 struct uio *uio;
318 struct ucred *cred;
9bccf70c
A
319 int flags;
320 struct proc *p;
1c79356b 321{
9bccf70c
A
322 struct vnode *vp;
323 int error, ioflag;
1c79356b
A
324 off_t count;
325
9bccf70c
A
326 if (p != uio->uio_procp)
327 panic("vn_read: uio_procp does not match p");
328
329 vp = (struct vnode *)fp->f_data;
330 ioflag = 0;
331 if (fp->f_flag & FNONBLOCK)
332 ioflag |= IO_NDELAY;
1c79356b 333 VOP_LEASE(vp, p, cred, LEASE_READ);
9bccf70c
A
334 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
335 if (error)
336 return (error);
337 if ((flags & FOF_OFFSET) == 0)
338 uio->uio_offset = fp->f_offset;
1c79356b
A
339 count = uio->uio_resid;
340
9bccf70c
A
341 if(UBCINFOEXISTS(vp)) {
342 memory_object_t pager;
343 struct iovec *iov;
344 off_t file_off;
345 kern_return_t kr = KERN_SUCCESS;
346 kern_return_t ret = KERN_SUCCESS;
347 int count;
348
349 pager = (memory_object_t)ubc_getpager(vp);
350 file_off = uio->uio_offset;
351 iov = uio->uio_iov;
352 count = uio->uio_iovcnt;
353 while(count) {
354 kr = vm_conflict_check(current_map(),
355 (vm_offset_t)iov->iov_base, iov->iov_len,
356 pager, file_off);
357 if(kr == KERN_ALREADY_WAITING) {
358 if((count != uio->uio_iovcnt) &&
359 (ret != KERN_ALREADY_WAITING)) {
360 error = EINVAL;
361 goto done;
362 }
363 ret = KERN_ALREADY_WAITING;
364 } else if (kr != KERN_SUCCESS) {
365 error = EINVAL;
366 goto done;
367 }
368 if(kr != ret) {
369 error = EINVAL;
370 goto done;
371 }
372 file_off += iov->iov_len;
373 iov++;
374 count--;
375 }
376 if(ret == KERN_ALREADY_WAITING) {
377 uio->uio_resid = 0;
378 if ((flags & FOF_OFFSET) == 0)
379 fp->f_offset +=
380 count - uio->uio_resid;
381 error = 0;
382 goto done;
383 }
384 }
385 error = VOP_READ(vp, uio, ioflag, cred);
386 if ((flags & FOF_OFFSET) == 0)
387 fp->f_offset += count - uio->uio_resid;
388done:
1c79356b
A
389 VOP_UNLOCK(vp, 0, p);
390 return (error);
391}
392
393
394/*
395 * File table vnode write routine.
396 */
9bccf70c
A
397static int
398vn_write(fp, uio, cred, flags, p)
1c79356b
A
399 struct file *fp;
400 struct uio *uio;
401 struct ucred *cred;
9bccf70c
A
402 int flags;
403 struct proc *p;
1c79356b 404{
9bccf70c
A
405 struct vnode *vp;
406 int error, ioflag;
1c79356b
A
407 off_t count;
408
9bccf70c
A
409 if (p != uio->uio_procp)
410 panic("vn_write: uio_procp does not match p");
411
412 vp = (struct vnode *)fp->f_data;
413 ioflag = IO_UNIT;
414 if (vp->v_type == VREG)
415 bwillwrite();
1c79356b
A
416 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
417 ioflag |= IO_APPEND;
418 if (fp->f_flag & FNONBLOCK)
419 ioflag |= IO_NDELAY;
420 if ((fp->f_flag & O_FSYNC) ||
421 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
422 ioflag |= IO_SYNC;
423 VOP_LEASE(vp, p, cred, LEASE_WRITE);
9bccf70c
A
424 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
425 if (error)
426 return (error);
427 if ((flags & FOF_OFFSET) == 0) {
428 uio->uio_offset = fp->f_offset;
429 count = uio->uio_resid;
430 }
1c79356b 431
9bccf70c
A
432 if(UBCINFOEXISTS(vp)) {
433 memory_object_t pager;
434 struct iovec *iov;
435 off_t file_off;
436 kern_return_t kr = KERN_SUCCESS;
437 kern_return_t ret = KERN_SUCCESS;
438 int count;
439
440 pager = (memory_object_t)ubc_getpager(vp);
441 file_off = uio->uio_offset;
442 iov = uio->uio_iov;
443 count = uio->uio_iovcnt;
444 while(count) {
445 kr = vm_conflict_check(current_map(),
446 (vm_offset_t)iov->iov_base,
447 iov->iov_len, pager, file_off);
448 if(kr == KERN_ALREADY_WAITING) {
449 if((count != uio->uio_iovcnt) &&
450 (ret != KERN_ALREADY_WAITING)) {
451 error = EINVAL;
452 goto done;
453 }
454 ret = KERN_ALREADY_WAITING;
455 } else if (kr != KERN_SUCCESS) {
456 error = EINVAL;
457 goto done;
458 }
459 if(kr != ret) {
460 error = EINVAL;
461 goto done;
462 }
463 file_off += iov->iov_len;
464 iov++;
465 count--;
466 }
467 if(ret == KERN_ALREADY_WAITING) {
468 uio->uio_resid = 0;
469 if ((flags & FOF_OFFSET) == 0)
470 fp->f_offset +=
471 count - uio->uio_resid;
472 error = 0;
473 goto done;
474 }
475 }
1c79356b
A
476 error = VOP_WRITE(vp, uio, ioflag, cred);
477
9bccf70c
A
478 if ((flags & FOF_OFFSET) == 0) {
479 if (ioflag & IO_APPEND)
480 fp->f_offset = uio->uio_offset;
481 else
482 fp->f_offset += count - uio->uio_resid;
483 }
484
1c79356b
A
485 /*
486 * Set the credentials on successful writes
487 */
488 if ((error == 0) && (vp->v_tag == VT_NFS) && (UBCINFOEXISTS(vp))) {
489 ubc_setcred(vp, p);
490 }
491
9bccf70c 492done:
1c79356b
A
493 VOP_UNLOCK(vp, 0, p);
494 return (error);
495}
496
497/*
498 * File table vnode stat routine.
499 */
9bccf70c 500int
1c79356b
A
501vn_stat(vp, sb, p)
502 struct vnode *vp;
503 register struct stat *sb;
504 struct proc *p;
505{
506 struct vattr vattr;
507 register struct vattr *vap;
508 int error;
509 u_short mode;
510
511 vap = &vattr;
512 error = VOP_GETATTR(vp, vap, p->p_ucred, p);
513 if (error)
514 return (error);
515 /*
516 * Copy from vattr table
517 */
518 sb->st_dev = vap->va_fsid;
519 sb->st_ino = vap->va_fileid;
520 mode = vap->va_mode;
521 switch (vp->v_type) {
522 case VREG:
523 mode |= S_IFREG;
524 break;
525 case VDIR:
526 mode |= S_IFDIR;
527 break;
528 case VBLK:
529 mode |= S_IFBLK;
530 break;
531 case VCHR:
532 mode |= S_IFCHR;
533 break;
534 case VLNK:
535 mode |= S_IFLNK;
536 break;
537 case VSOCK:
538 mode |= S_IFSOCK;
539 break;
540 case VFIFO:
541 mode |= S_IFIFO;
542 break;
543 default:
544 return (EBADF);
545 };
546 sb->st_mode = mode;
547 sb->st_nlink = vap->va_nlink;
548 sb->st_uid = vap->va_uid;
549 sb->st_gid = vap->va_gid;
550 sb->st_rdev = vap->va_rdev;
551 sb->st_size = vap->va_size;
552 sb->st_atimespec = vap->va_atime;
553 sb->st_mtimespec = vap->va_mtime;
554 sb->st_ctimespec = vap->va_ctime;
555 sb->st_blksize = vap->va_blocksize;
556 sb->st_flags = vap->va_flags;
557 /* Do not give the generation number out to unpriviledged users */
558 if (suser(p->p_ucred, &p->p_acflag))
559 sb->st_gen = 0;
560 else
561 sb->st_gen = vap->va_gen;
562 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
563 return (0);
564}
565
566/*
567 * File table vnode ioctl routine.
568 */
9bccf70c 569static int
1c79356b
A
570vn_ioctl(fp, com, data, p)
571 struct file *fp;
572 u_long com;
573 caddr_t data;
574 struct proc *p;
575{
576 register struct vnode *vp = ((struct vnode *)fp->f_data);
577 struct vattr vattr;
578 int error;
fa4905b1 579 struct vnode *ttyvp;
9bccf70c 580
1c79356b
A
581 switch (vp->v_type) {
582
583 case VREG:
584 case VDIR:
585 if (com == FIONREAD) {
586 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
587 return (error);
588 *(int *)data = vattr.va_size - fp->f_offset;
589 return (0);
590 }
591 if (com == FIONBIO || com == FIOASYNC) /* XXX */
592 return (0); /* XXX */
593 /* fall into ... */
594
595 default:
596 return (ENOTTY);
597
598 case VFIFO:
599 case VCHR:
600 case VBLK:
9bccf70c
A
601
602 /* Should not be able to set block size from user space */
603 if(com == DKIOCSETBLOCKSIZE)
604 return (EPERM);
605
606 if (com == FIODTYPE) {
607 if (vp->v_type == VBLK) {
608 if (major(vp->v_rdev) >= nblkdev)
609 return (ENXIO);
610 *(int *)data = bdevsw[major(vp->v_rdev)].d_type;
611 } else if (vp->v_type == VCHR) {
612 if (major(vp->v_rdev) >= nchrdev)
613 return (ENXIO);
614 *(int *)data = cdevsw[major(vp->v_rdev)].d_type;
615 } else {
616 return (ENOTTY);
617 }
618 return (0);
619 }
620 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
621 if (error == 0 && com == TIOCSCTTY) {
622 VREF(vp);
623 ttyvp = p->p_session->s_ttyvp;
624 p->p_session->s_ttyvp = vp;
625 if (ttyvp)
626 vrele(ttyvp);
627 }
628 return (error);
1c79356b
A
629 }
630}
631
632/*
633 * File table vnode select routine.
634 */
9bccf70c 635static int
0b4e3aa0 636vn_select(fp, which, wql, p)
1c79356b
A
637 struct file *fp;
638 int which;
0b4e3aa0 639 void * wql;
1c79356b
A
640 struct proc *p;
641{
642
0b4e3aa0
A
643 return(VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
644 fp->f_cred, wql, p));
1c79356b
A
645}
646
647/*
648 * Check that the vnode is still valid, and if so
649 * acquire requested lock.
650 */
651int
652vn_lock(vp, flags, p)
653 struct vnode *vp;
654 int flags;
655 struct proc *p;
656{
657 int error;
658
659 do {
660 if ((flags & LK_INTERLOCK) == 0)
661 simple_lock(&vp->v_interlock);
662 if (vp->v_flag & VXLOCK) {
663 while (vp->v_flag & VXLOCK) {
664 vp->v_flag |= VXWANT;
665 simple_unlock(&vp->v_interlock);
0b4e3aa0 666 (void)tsleep((caddr_t)vp, PINOD, "vn_lock", 0);
1c79356b
A
667 }
668 error = ENOENT;
669 } else {
670 error = VOP_LOCK(vp, flags | LK_INTERLOCK, p);
671 if (error == 0)
672 return (error);
673 }
674 flags &= ~LK_INTERLOCK;
675 } while (flags & LK_RETRY);
676 return (error);
677}
678
679/*
680 * File table vnode close routine.
681 */
9bccf70c 682static int
1c79356b
A
683vn_closefile(fp, p)
684 struct file *fp;
685 struct proc *p;
686{
687
688 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
689 fp->f_cred, p));
690}