]>
git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_vnops.c
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1982, 1986, 1989, 1993
28 * The Regents of the University of California. All rights reserved.
29 * (c) UNIX System Laboratories, Inc.
30 * All or some portions of this file are derived from material licensed
31 * to the University of California by American Telephone and Telegraph
32 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33 * the permission of UNIX System Laboratories, Inc.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * @(#)vfs_vnops.c 8.14 (Berkeley) 6/15/95
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
74 #include <sys/mount.h>
75 #include <sys/namei.h>
76 #include <sys/vnode.h>
77 #include <sys/ioctl.h>
83 #include <vm/vm_kern.h>
85 #include <miscfs/specfs/specdev.h>
87 static int vn_closefile
__P((struct file
*fp
, struct proc
*p
));
88 static int vn_ioctl
__P((struct file
*fp
, u_long com
, caddr_t data
,
90 static int vn_read
__P((struct file
*fp
, struct uio
*uio
,
91 struct ucred
*cred
, int flags
, struct proc
*p
));
92 static int vn_write
__P((struct file
*fp
, struct uio
*uio
,
93 struct ucred
*cred
, int flags
, struct proc
*p
));
94 static int vn_select
__P(( struct file
*fp
, int which
, void * wql
,
96 static int vn_kqfilt_add
__P((struct file
*fp
, struct knote
*kn
, struct proc
*p
));
97 static int vn_kqfilt_remove
__P((struct vnode
*vp
, uintptr_t ident
, struct proc
*p
));
99 struct fileops vnops
=
100 { vn_read
, vn_write
, vn_ioctl
, vn_select
, vn_closefile
, vn_kqfilt_add
};
103 * Common code for vnode open operations.
104 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
107 vn_open(ndp
, fmode
, cmode
)
108 register struct nameidata
*ndp
;
111 return vn_open_modflags(ndp
,&fmode
,cmode
);
114 __private_extern__
int
115 vn_open_modflags(ndp
, fmodep
, cmode
)
116 register struct nameidata
*ndp
;
120 register struct vnode
*vp
;
121 register struct proc
*p
= ndp
->ni_cnd
.cn_proc
;
122 register struct ucred
*cred
= p
->p_ucred
;
124 struct vattr
*vap
= &vat
;
130 if (fmode
& O_CREAT
) {
131 ndp
->ni_cnd
.cn_nameiop
= CREATE
;
132 ndp
->ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| AUDITVNPATH1
;
133 if ((fmode
& O_EXCL
) == 0)
134 ndp
->ni_cnd
.cn_flags
|= FOLLOW
;
136 if (error
= namei(ndp
))
138 if (ndp
->ni_vp
== NULL
) {
139 nameptr
= add_name(ndp
->ni_cnd
.cn_nameptr
,
140 ndp
->ni_cnd
.cn_namelen
,
141 ndp
->ni_cnd
.cn_hash
, 0);
145 vap
->va_mode
= cmode
;
147 vap
->va_vaflags
|= VA_EXCLUSIVE
;
148 VOP_LEASE(ndp
->ni_dvp
, p
, cred
, LEASE_WRITE
);
149 if (error
= VOP_CREATE(ndp
->ni_dvp
, &ndp
->ni_vp
,
150 &ndp
->ni_cnd
, vap
)) {
151 remove_name(nameptr
);
158 if (vget(ndp
->ni_dvp
, 0, p
) == 0) {
159 VPARENT(vp
) = ndp
->ni_dvp
;
162 VOP_ABORTOP(ndp
->ni_dvp
, &ndp
->ni_cnd
);
163 if (ndp
->ni_dvp
== ndp
->ni_vp
)
169 if (fmode
& O_EXCL
) {
176 ndp
->ni_cnd
.cn_nameiop
= LOOKUP
;
177 ndp
->ni_cnd
.cn_flags
= FOLLOW
| LOCKLEAF
| AUDITVNPATH1
;
178 if (error
= namei(ndp
))
182 if (vp
->v_type
== VSOCK
) {
188 if (UBCINFOMISSING(vp
))
189 panic("vn_open: ubc_info_init");
190 #endif /* DIAGNOSTIC */
192 if (UBCINFOEXISTS(vp
) && ((didhold
= ubc_hold(vp
)) == 0)) {
197 if ((fmode
& O_CREAT
) == 0) {
198 if (fmode
& FREAD
&& fmode
& (FWRITE
| O_TRUNC
)) {
200 if (vp
->v_type
== VDIR
)
203 err
= vn_writechk(vp
);
204 if (err
&& !(error
= VOP_ACCESS(vp
, VREAD
, cred
, p
)))
206 if (error
|| (error
= VOP_ACCESS(vp
, VREAD
|VWRITE
,
209 } else if (fmode
& FREAD
) {
210 if ((error
= VOP_ACCESS(vp
, VREAD
, cred
, p
)))
212 } else if (fmode
& (FWRITE
| O_TRUNC
)) {
213 if (vp
->v_type
== VDIR
) {
217 if ((error
= vn_writechk(vp
)) ||
218 (error
= VOP_ACCESS(vp
, VWRITE
, cred
, p
)))
223 if (error
= VOP_OPEN(vp
, fmode
, cred
, p
)) {
228 if (++vp
->v_writecount
<= 0)
229 panic("vn_open: v_writecount");
233 VOP_UNLOCK(vp
, 0, p
);
242 * Check for write permissions on the specified vnode.
243 * Prototype text segments cannot be written.
247 register struct vnode
*vp
;
251 * If there's shared text associated with
252 * the vnode, try to free it up once. If
253 * we fail, we can't allow writing.
256 /* XXXXX Not sure we need this */
257 if (vp
->v_flag
& VTEXT
)
267 vn_close(vp
, flags
, cred
, p
)
268 register struct vnode
*vp
;
275 if (flags
& FWRITE
) {
280 extern void notify_filemod_watchers(struct vnode
*vp
, struct proc
*p
);
282 notify_filemod_watchers(vp
, p
);
286 error
= VOP_CLOSE(vp
, flags
, cred
, p
);
293 * Package up an I/O request on a vnode into a uio and do it.
296 vn_rdwr(rw
, vp
, base
, len
, offset
, segflg
, ioflg
, cred
, aresid
, p
)
313 if ((ioflg
& IO_NODELOCKED
) == 0)
314 (void)vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
315 auio
.uio_iov
= &aiov
;
317 aiov
.iov_base
= base
;
319 auio
.uio_resid
= len
;
320 auio
.uio_offset
= offset
;
321 auio
.uio_segflg
= segflg
;
326 error
= VOP_READ(vp
, &auio
, ioflg
, cred
);
328 error
= VOP_WRITE(vp
, &auio
, ioflg
, cred
);
331 *aresid
= auio
.uio_resid
;
333 if (auio
.uio_resid
&& error
== 0)
335 if ((ioflg
& IO_NODELOCKED
) == 0)
336 VOP_UNLOCK(vp
, 0, p
);
341 * File table vnode read routine.
344 vn_read(fp
, uio
, cred
, flags
, p
)
355 if (p
!= uio
->uio_procp
)
356 panic("vn_read: uio_procp does not match p");
358 vp
= (struct vnode
*)fp
->f_data
;
360 if (fp
->f_flag
& FNONBLOCK
)
362 VOP_LEASE(vp
, p
, cred
, LEASE_READ
);
363 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
366 if ((flags
& FOF_OFFSET
) == 0)
367 uio
->uio_offset
= fp
->f_offset
;
368 count
= uio
->uio_resid
;
370 if(UBCINFOEXISTS(vp
)) {
371 memory_object_t pager
;
374 kern_return_t kr
= KERN_SUCCESS
;
375 kern_return_t ret
= KERN_SUCCESS
;
378 pager
= (memory_object_t
)ubc_getpager(vp
);
379 file_off
= uio
->uio_offset
;
381 count
= uio
->uio_iovcnt
;
383 kr
= vm_conflict_check(current_map(),
384 (vm_offset_t
)iov
->iov_base
, iov
->iov_len
,
386 if(kr
== KERN_ALREADY_WAITING
) {
387 if((count
!= uio
->uio_iovcnt
) &&
388 (ret
!= KERN_ALREADY_WAITING
)) {
392 ret
= KERN_ALREADY_WAITING
;
393 } else if (kr
!= KERN_SUCCESS
) {
401 file_off
+= iov
->iov_len
;
405 if(ret
== KERN_ALREADY_WAITING
) {
407 if ((flags
& FOF_OFFSET
) == 0)
409 count
- uio
->uio_resid
;
414 error
= VOP_READ(vp
, uio
, ioflag
, cred
);
415 if ((flags
& FOF_OFFSET
) == 0)
416 fp
->f_offset
+= count
- uio
->uio_resid
;
418 VOP_UNLOCK(vp
, 0, p
);
424 * File table vnode write routine.
427 vn_write(fp
, uio
, cred
, flags
, p
)
438 if (p
!= uio
->uio_procp
)
439 panic("vn_write: uio_procp does not match p");
441 vp
= (struct vnode
*)fp
->f_data
;
443 if (vp
->v_type
== VREG
)
445 if (vp
->v_type
== VREG
&& (fp
->f_flag
& O_APPEND
))
447 if (fp
->f_flag
& FNONBLOCK
)
449 if ((fp
->f_flag
& O_FSYNC
) ||
450 (vp
->v_mount
&& (vp
->v_mount
->mnt_flag
& MNT_SYNCHRONOUS
)))
452 VOP_LEASE(vp
, p
, cred
, LEASE_WRITE
);
453 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
456 if ((flags
& FOF_OFFSET
) == 0) {
457 uio
->uio_offset
= fp
->f_offset
;
458 count
= uio
->uio_resid
;
461 if(UBCINFOEXISTS(vp
)) {
462 memory_object_t pager
;
465 kern_return_t kr
= KERN_SUCCESS
;
466 kern_return_t ret
= KERN_SUCCESS
;
469 pager
= (memory_object_t
)ubc_getpager(vp
);
470 file_off
= uio
->uio_offset
;
472 count
= uio
->uio_iovcnt
;
474 kr
= vm_conflict_check(current_map(),
475 (vm_offset_t
)iov
->iov_base
,
476 iov
->iov_len
, pager
, file_off
);
477 if(kr
== KERN_ALREADY_WAITING
) {
478 if((count
!= uio
->uio_iovcnt
) &&
479 (ret
!= KERN_ALREADY_WAITING
)) {
483 ret
= KERN_ALREADY_WAITING
;
484 } else if (kr
!= KERN_SUCCESS
) {
492 file_off
+= iov
->iov_len
;
496 if(ret
== KERN_ALREADY_WAITING
) {
498 if ((flags
& FOF_OFFSET
) == 0)
500 count
- uio
->uio_resid
;
505 error
= VOP_WRITE(vp
, uio
, ioflag
, cred
);
507 if ((flags
& FOF_OFFSET
) == 0) {
508 if (ioflag
& IO_APPEND
)
509 fp
->f_offset
= uio
->uio_offset
;
511 fp
->f_offset
+= count
- uio
->uio_resid
;
515 * Set the credentials on successful writes
517 if ((error
== 0) && (vp
->v_tag
== VT_NFS
) && (UBCINFOEXISTS(vp
))) {
522 VOP_UNLOCK(vp
, 0, p
);
527 * File table vnode stat routine.
532 register struct stat
*sb
;
536 register struct vattr
*vap
;
541 error
= VOP_GETATTR(vp
, vap
, p
->p_ucred
, p
);
545 * Copy from vattr table
547 sb
->st_dev
= vap
->va_fsid
;
548 sb
->st_ino
= vap
->va_fileid
;
550 switch (vp
->v_type
) {
576 sb
->st_nlink
= vap
->va_nlink
;
577 sb
->st_uid
= vap
->va_uid
;
578 sb
->st_gid
= vap
->va_gid
;
579 sb
->st_rdev
= vap
->va_rdev
;
580 sb
->st_size
= vap
->va_size
;
581 sb
->st_atimespec
= vap
->va_atime
;
582 sb
->st_mtimespec
= vap
->va_mtime
;
583 sb
->st_ctimespec
= vap
->va_ctime
;
584 sb
->st_blksize
= vap
->va_blocksize
;
585 sb
->st_flags
= vap
->va_flags
;
586 /* Do not give the generation number out to unpriviledged users */
587 if (vap
->va_gen
&& suser(p
->p_ucred
, &p
->p_acflag
))
590 sb
->st_gen
= vap
->va_gen
;
591 sb
->st_blocks
= vap
->va_bytes
/ S_BLKSIZE
;
596 * File table vnode ioctl routine.
599 vn_ioctl(fp
, com
, data
, p
)
605 register struct vnode
*vp
= ((struct vnode
*)fp
->f_data
);
610 switch (vp
->v_type
) {
614 if (com
== FIONREAD
) {
615 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
617 *(int *)data
= vattr
.va_size
- fp
->f_offset
;
620 if (com
== FIONBIO
|| com
== FIOASYNC
) /* XXX */
621 return (0); /* XXX */
631 /* Should not be able to set block size from user space */
632 if(com
== DKIOCSETBLOCKSIZE
)
635 if (com
== FIODTYPE
) {
636 if (vp
->v_type
== VBLK
) {
637 if (major(vp
->v_rdev
) >= nblkdev
)
639 *(int *)data
= bdevsw
[major(vp
->v_rdev
)].d_type
;
640 } else if (vp
->v_type
== VCHR
) {
641 if (major(vp
->v_rdev
) >= nchrdev
)
643 *(int *)data
= cdevsw
[major(vp
->v_rdev
)].d_type
;
649 error
= VOP_IOCTL(vp
, com
, data
, fp
->f_flag
, p
->p_ucred
, p
);
650 if (error
== 0 && com
== TIOCSCTTY
) {
652 ttyvp
= p
->p_session
->s_ttyvp
;
653 p
->p_session
->s_ttyvp
= vp
;
662 * File table vnode select routine.
665 vn_select(fp
, which
, wql
, p
)
672 return(VOP_SELECT(((struct vnode
*)fp
->f_data
), which
, fp
->f_flag
,
673 fp
->f_cred
, wql
, p
));
677 * Check that the vnode is still valid, and if so
678 * acquire requested lock.
681 vn_lock(vp
, flags
, p
)
689 if ((flags
& LK_INTERLOCK
) == 0)
690 simple_lock(&vp
->v_interlock
);
691 if (vp
->v_flag
& VXLOCK
) {
692 while (vp
->v_flag
& VXLOCK
) {
693 vp
->v_flag
|= VXWANT
;
694 simple_unlock(&vp
->v_interlock
);
695 (void)tsleep((caddr_t
)vp
, PINOD
, "vn_lock", 0);
699 error
= VOP_LOCK(vp
, flags
| LK_INTERLOCK
, p
);
703 flags
&= ~LK_INTERLOCK
;
704 } while (flags
& LK_RETRY
);
709 * File table vnode close routine.
717 return (vn_close(((struct vnode
*)fp
->f_data
), fp
->f_flag
,
722 vn_kqfilt_add(fp
, kn
, p
)
727 struct vnode
*vp
= (struct vnode
*)fp
->f_data
;
730 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
731 if (error
) return (error
);
732 error
= VOP_KQFILT_ADD(vp
, kn
, p
);
733 (void)VOP_UNLOCK(vp
, 0, p
);
738 vn_kqfilt_remove(vp
, ident
, p
)
745 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
746 if (error
) return (error
);
747 error
= VOP_KQFILT_REMOVE(vp
, ident
, p
);
748 (void)VOP_UNLOCK(vp
, 0, p
);