2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
30 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
32 * Copyright (c) 1989, 1993
33 * The Regents of the University of California. All rights reserved.
34 * (c) UNIX System Laboratories, Inc.
35 * All or some portions of this file are derived from material licensed
36 * to the University of California by American Telephone and Telegraph
37 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
38 * the permission of UNIX System Laboratories, Inc.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed by the University of
51 * California, Berkeley and its contributors.
52 * 4. Neither the name of the University nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * External virtual filesystem routines
78 #include <sys/param.h>
79 #include <sys/systm.h>
80 #include <sys/proc_internal.h>
81 #include <sys/kauth.h>
82 #include <sys/mount.h>
83 #include <sys/mount_internal.h>
85 #include <sys/vnode_internal.h>
87 #include <sys/namei.h>
88 #include <sys/ucred.h>
90 #include <sys/errno.h>
91 #include <sys/malloc.h>
92 #include <sys/domain.h>
94 #include <sys/syslog.h>
97 #include <sys/sysctl.h>
98 #include <sys/filedesc.h>
99 #include <sys/fsevents.h>
100 #include <sys/user.h>
101 #include <sys/lockf.h>
102 #include <sys/xattr.h>
104 #include <kern/assert.h>
105 #include <kern/kalloc.h>
107 #include <libkern/OSByteOrder.h>
109 #include <miscfs/specfs/specdev.h>
111 #include <mach/mach_types.h>
112 #include <mach/memory_object_types.h>
121 #define THREAD_SAFE_FS(VP) \
122 ((VP)->v_unsafefs ? 0 : 1)
124 #define NATIVE_XATTR(VP) \
125 ((VP)->v_mount ? (VP)->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSNATIVEXATTR : 0)
127 static void xattrfile_remove(vnode_t dvp
, const char * basename
, vfs_context_t context
,
128 int thread_safe
, int force
);
129 static void xattrfile_setattr(vnode_t dvp
, const char * basename
, struct vnode_attr
* vap
,
130 vfs_context_t context
, int thread_safe
);
134 vnode_setneedinactive(vnode_t vp
)
139 vp
->v_lflag
|= VL_NEEDINACTIVE
;
145 lock_fsnode(vnode_t vp
, int *funnel_state
)
148 *funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
150 if (vp
->v_unsafefs
) {
151 if (vp
->v_unsafefs
->fsnodeowner
== current_thread()) {
152 vp
->v_unsafefs
->fsnode_count
++;
154 lck_mtx_lock(&vp
->v_unsafefs
->fsnodelock
);
156 if (vp
->v_lflag
& (VL_TERMWANT
| VL_TERMINATE
| VL_DEAD
)) {
157 lck_mtx_unlock(&vp
->v_unsafefs
->fsnodelock
);
160 (void) thread_funnel_set(kernel_flock
, *funnel_state
);
163 vp
->v_unsafefs
->fsnodeowner
= current_thread();
164 vp
->v_unsafefs
->fsnode_count
= 1;
172 unlock_fsnode(vnode_t vp
, int *funnel_state
)
174 if (vp
->v_unsafefs
) {
175 if (--vp
->v_unsafefs
->fsnode_count
== 0) {
176 vp
->v_unsafefs
->fsnodeowner
= NULL
;
177 lck_mtx_unlock(&vp
->v_unsafefs
->fsnodelock
);
181 (void) thread_funnel_set(kernel_flock
, *funnel_state
);
186 /* ====================================================================== */
187 /* ************ EXTERNAL KERNEL APIS ********************************** */
188 /* ====================================================================== */
191 * prototypes for exported VFS operations
194 VFS_MOUNT(struct mount
* mp
, vnode_t devvp
, user_addr_t data
, vfs_context_t context
)
198 int funnel_state
= 0;
200 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_mount
== 0))
203 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
207 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
210 if (vfs_context_is64bit(context
)) {
211 if (vfs_64bitready(mp
)) {
212 error
= (*mp
->mnt_op
->vfs_mount
)(mp
, devvp
, data
, context
);
219 error
= (*mp
->mnt_op
->vfs_mount
)(mp
, devvp
, data
, context
);
223 (void) thread_funnel_set(kernel_flock
, funnel_state
);
229 VFS_START(struct mount
* mp
, int flags
, vfs_context_t context
)
233 int funnel_state
= 0;
235 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_start
== 0))
238 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
241 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
243 error
= (*mp
->mnt_op
->vfs_start
)(mp
, flags
, context
);
245 (void) thread_funnel_set(kernel_flock
, funnel_state
);
251 VFS_UNMOUNT(struct mount
*mp
, int flags
, vfs_context_t context
)
255 int funnel_state
= 0;
257 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_unmount
== 0))
260 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
263 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
265 error
= (*mp
->mnt_op
->vfs_unmount
)(mp
, flags
, context
);
267 (void) thread_funnel_set(kernel_flock
, funnel_state
);
273 VFS_ROOT(struct mount
* mp
, struct vnode
** vpp
, vfs_context_t context
)
277 int funnel_state
= 0;
278 struct vfs_context acontext
;
280 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_root
== 0))
283 if (context
== NULL
) {
284 acontext
.vc_proc
= current_proc();
285 acontext
.vc_ucred
= kauth_cred_get();
288 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
291 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
293 error
= (*mp
->mnt_op
->vfs_root
)(mp
, vpp
, context
);
295 (void) thread_funnel_set(kernel_flock
, funnel_state
);
301 VFS_QUOTACTL(struct mount
*mp
, int cmd
, uid_t uid
, caddr_t datap
, vfs_context_t context
)
305 int funnel_state
= 0;
307 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_quotactl
== 0))
310 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
313 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
315 error
= (*mp
->mnt_op
->vfs_quotactl
)(mp
, cmd
, uid
, datap
, context
);
317 (void) thread_funnel_set(kernel_flock
, funnel_state
);
323 VFS_GETATTR(struct mount
*mp
, struct vfs_attr
*vfa
, vfs_context_t context
)
327 int funnel_state
= 0;
328 struct vfs_context acontext
;
330 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_getattr
== 0))
333 if (context
== NULL
) {
334 acontext
.vc_proc
= current_proc();
335 acontext
.vc_ucred
= kauth_cred_get();
338 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
341 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
343 error
= (*mp
->mnt_op
->vfs_getattr
)(mp
, vfa
, context
);
345 (void) thread_funnel_set(kernel_flock
, funnel_state
);
351 VFS_SETATTR(struct mount
*mp
, struct vfs_attr
*vfa
, vfs_context_t context
)
355 int funnel_state
= 0;
356 struct vfs_context acontext
;
358 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_setattr
== 0))
361 if (context
== NULL
) {
362 acontext
.vc_proc
= current_proc();
363 acontext
.vc_ucred
= kauth_cred_get();
366 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
369 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
371 error
= (*mp
->mnt_op
->vfs_setattr
)(mp
, vfa
, context
);
373 (void) thread_funnel_set(kernel_flock
, funnel_state
);
379 VFS_SYNC(struct mount
*mp
, int flags
, vfs_context_t context
)
383 int funnel_state
= 0;
384 struct vfs_context acontext
;
386 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_sync
== 0))
389 if (context
== NULL
) {
390 acontext
.vc_proc
= current_proc();
391 acontext
.vc_ucred
= kauth_cred_get();
394 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
397 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
399 error
= (*mp
->mnt_op
->vfs_sync
)(mp
, flags
, context
);
401 (void) thread_funnel_set(kernel_flock
, funnel_state
);
407 VFS_VGET(struct mount
* mp
, ino64_t ino
, struct vnode
**vpp
, vfs_context_t context
)
411 int funnel_state
= 0;
412 struct vfs_context acontext
;
414 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_vget
== 0))
417 if (context
== NULL
) {
418 acontext
.vc_proc
= current_proc();
419 acontext
.vc_ucred
= kauth_cred_get();
422 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
425 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
427 error
= (*mp
->mnt_op
->vfs_vget
)(mp
, ino
, vpp
, context
);
429 (void) thread_funnel_set(kernel_flock
, funnel_state
);
435 VFS_FHTOVP(struct mount
* mp
, int fhlen
, unsigned char * fhp
, vnode_t
* vpp
, vfs_context_t context
)
439 int funnel_state
= 0;
440 struct vfs_context acontext
;
442 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_fhtovp
== 0))
445 if (context
== NULL
) {
446 acontext
.vc_proc
= current_proc();
447 acontext
.vc_ucred
= kauth_cred_get();
450 thread_safe
= mp
->mnt_vtable
->vfc_threadsafe
;
453 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
455 error
= (*mp
->mnt_op
->vfs_fhtovp
)(mp
, fhlen
, fhp
, vpp
, context
);
457 (void) thread_funnel_set(kernel_flock
, funnel_state
);
463 VFS_VPTOFH(struct vnode
* vp
, int *fhlenp
, unsigned char * fhp
, vfs_context_t context
)
467 int funnel_state
= 0;
468 struct vfs_context acontext
;
470 if ((vp
->v_mount
== dead_mountp
) || (vp
->v_mount
->mnt_op
->vfs_vptofh
== 0))
473 if (context
== NULL
) {
474 acontext
.vc_proc
= current_proc();
475 acontext
.vc_ucred
= kauth_cred_get();
478 thread_safe
= THREAD_SAFE_FS(vp
);
481 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
483 error
= (*vp
->v_mount
->mnt_op
->vfs_vptofh
)(vp
, fhlenp
, fhp
, context
);
485 (void) thread_funnel_set(kernel_flock
, funnel_state
);
491 /* returns a copy of vfs type name for the mount_t */
493 vfs_name(mount_t mp
, char * buffer
)
495 strncpy(buffer
, mp
->mnt_vtable
->vfc_name
, MFSNAMELEN
);
498 /* returns vfs type number for the mount_t */
500 vfs_typenum(mount_t mp
)
502 return(mp
->mnt_vtable
->vfc_typenum
);
506 /* returns command modifier flags of mount_t ie. MNT_CMDFLAGS */
508 vfs_flags(mount_t mp
)
510 return((uint64_t)(mp
->mnt_flag
& (MNT_CMDFLAGS
| MNT_VISFLAGMASK
)));
513 /* set any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
515 vfs_setflags(mount_t mp
, uint64_t flags
)
517 uint32_t lflags
= (uint32_t)(flags
& (MNT_CMDFLAGS
| MNT_VISFLAGMASK
));
519 mp
->mnt_flag
|= lflags
;
522 /* clear any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
524 vfs_clearflags(mount_t mp
, uint64_t flags
)
526 uint32_t lflags
= (uint32_t)(flags
& (MNT_CMDFLAGS
| MNT_VISFLAGMASK
));
528 mp
->mnt_flag
&= ~lflags
;
531 /* Is the mount_t ronly and upgrade read/write requested? */
533 vfs_iswriteupgrade(mount_t mp
) /* ronly && MNTK_WANTRDWR */
535 return ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
));
539 /* Is the mount_t mounted ronly */
541 vfs_isrdonly(mount_t mp
)
543 return (mp
->mnt_flag
& MNT_RDONLY
);
546 /* Is the mount_t mounted for filesystem synchronous writes? */
548 vfs_issynchronous(mount_t mp
)
550 return (mp
->mnt_flag
& MNT_SYNCHRONOUS
);
553 /* Is the mount_t mounted read/write? */
555 vfs_isrdwr(mount_t mp
)
557 return ((mp
->mnt_flag
& MNT_RDONLY
) == 0);
561 /* Is mount_t marked for update (ie MNT_UPDATE) */
563 vfs_isupdate(mount_t mp
)
565 return (mp
->mnt_flag
& MNT_UPDATE
);
569 /* Is mount_t marked for reload (ie MNT_RELOAD) */
571 vfs_isreload(mount_t mp
)
573 return ((mp
->mnt_flag
& MNT_UPDATE
) && (mp
->mnt_flag
& MNT_RELOAD
));
576 /* Is mount_t marked for reload (ie MNT_FORCE) */
578 vfs_isforce(mount_t mp
)
580 if ((mp
->mnt_flag
& MNT_FORCE
) || (mp
->mnt_kern_flag
& MNTK_FRCUNMOUNT
))
587 vfs_64bitready(mount_t mp
)
589 if ((mp
->mnt_vtable
->vfc_64bitready
))
596 vfs_authopaque(mount_t mp
)
598 if ((mp
->mnt_kern_flag
& MNTK_AUTH_OPAQUE
))
605 vfs_authopaqueaccess(mount_t mp
)
607 if ((mp
->mnt_kern_flag
& MNTK_AUTH_OPAQUE_ACCESS
))
614 vfs_setauthopaque(mount_t mp
)
617 mp
->mnt_kern_flag
|= MNTK_AUTH_OPAQUE
;
622 vfs_setauthopaqueaccess(mount_t mp
)
625 mp
->mnt_kern_flag
|= MNTK_AUTH_OPAQUE_ACCESS
;
630 vfs_clearauthopaque(mount_t mp
)
633 mp
->mnt_kern_flag
&= ~MNTK_AUTH_OPAQUE
;
638 vfs_clearauthopaqueaccess(mount_t mp
)
641 mp
->mnt_kern_flag
&= ~MNTK_AUTH_OPAQUE_ACCESS
;
646 vfs_setextendedsecurity(mount_t mp
)
649 mp
->mnt_kern_flag
|= MNTK_EXTENDED_SECURITY
;
654 vfs_clearextendedsecurity(mount_t mp
)
657 mp
->mnt_kern_flag
&= ~MNTK_EXTENDED_SECURITY
;
662 vfs_extendedsecurity(mount_t mp
)
664 return(mp
->mnt_kern_flag
& MNTK_EXTENDED_SECURITY
);
667 /* returns the max size of short symlink in this mount_t */
669 vfs_maxsymlen(mount_t mp
)
671 return(mp
->mnt_maxsymlinklen
);
674 /* set max size of short symlink on mount_t */
676 vfs_setmaxsymlen(mount_t mp
, uint32_t symlen
)
678 mp
->mnt_maxsymlinklen
= symlen
;
681 /* return a pointer to the RO vfs_statfs associated with mount_t */
683 vfs_statfs(mount_t mp
)
685 return(&mp
->mnt_vfsstat
);
689 vfs_getattr(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
694 if ((error
= VFS_GETATTR(mp
, vfa
, ctx
)) != 0)
698 * If we have a filesystem create time, use it to default some others.
700 if (VFSATTR_IS_SUPPORTED(vfa
, f_create_time
)) {
701 if (VFSATTR_IS_ACTIVE(vfa
, f_modify_time
) && !VFSATTR_IS_SUPPORTED(vfa
, f_modify_time
))
702 VFSATTR_RETURN(vfa
, f_modify_time
, vfa
->f_create_time
);
709 vfs_setattr(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
713 if (vfs_isrdonly(mp
))
716 error
= VFS_SETATTR(mp
, vfa
, ctx
);
719 * If we had alternate ways of setting vfs attributes, we'd
726 /* return the private data handle stored in mount_t */
728 vfs_fsprivate(mount_t mp
)
730 return(mp
->mnt_data
);
733 /* set the private data handle in mount_t */
735 vfs_setfsprivate(mount_t mp
, void *mntdata
)
737 mp
->mnt_data
= mntdata
;
742 * return the block size of the underlying
743 * device associated with mount_t
746 vfs_devblocksize(mount_t mp
) {
748 return(mp
->mnt_devblocksize
);
753 * return the io attributes associated with mount_t
756 vfs_ioattr(mount_t mp
, struct vfsioattr
*ioattrp
)
759 ioattrp
->io_maxreadcnt
= MAXPHYS
;
760 ioattrp
->io_maxwritecnt
= MAXPHYS
;
761 ioattrp
->io_segreadcnt
= 32;
762 ioattrp
->io_segwritecnt
= 32;
763 ioattrp
->io_maxsegreadsize
= MAXPHYS
;
764 ioattrp
->io_maxsegwritesize
= MAXPHYS
;
765 ioattrp
->io_devblocksize
= DEV_BSIZE
;
767 ioattrp
->io_maxreadcnt
= mp
->mnt_maxreadcnt
;
768 ioattrp
->io_maxwritecnt
= mp
->mnt_maxwritecnt
;
769 ioattrp
->io_segreadcnt
= mp
->mnt_segreadcnt
;
770 ioattrp
->io_segwritecnt
= mp
->mnt_segwritecnt
;
771 ioattrp
->io_maxsegreadsize
= mp
->mnt_maxsegreadsize
;
772 ioattrp
->io_maxsegwritesize
= mp
->mnt_maxsegwritesize
;
773 ioattrp
->io_devblocksize
= mp
->mnt_devblocksize
;
775 ioattrp
->io_reserved
[0] = 0;
776 ioattrp
->io_reserved
[1] = 0;
777 ioattrp
->io_reserved
[2] = 0;
782 * set the IO attributes associated with mount_t
785 vfs_setioattr(mount_t mp
, struct vfsioattr
* ioattrp
)
789 mp
->mnt_maxreadcnt
= ioattrp
->io_maxreadcnt
;
790 mp
->mnt_maxwritecnt
= ioattrp
->io_maxwritecnt
;
791 mp
->mnt_segreadcnt
= ioattrp
->io_segreadcnt
;
792 mp
->mnt_segwritecnt
= ioattrp
->io_segwritecnt
;
793 mp
->mnt_maxsegreadsize
= ioattrp
->io_maxsegreadsize
;
794 mp
->mnt_maxsegwritesize
= ioattrp
->io_maxsegwritesize
;
795 mp
->mnt_devblocksize
= ioattrp
->io_devblocksize
;
799 * Add a new filesystem into the kernel specified in passed in
800 * vfstable structure. It fills in the vnode
801 * dispatch vector that is to be passed to when vnodes are created.
802 * It returns a handle which is to be used to when the FS is to be removed
804 typedef int (*PFI
)(void *);
805 extern int vfs_opv_numops
;
807 vfs_fsadd(struct vfs_fsentry
*vfe
, vfstable_t
* handle
)
810 struct vfstable
*newvfstbl
= NULL
;
812 int (***opv_desc_vector_p
)(void *);
813 int (**opv_desc_vector
)(void *);
814 struct vnodeopv_entry_desc
*opve_descp
;
820 * This routine is responsible for all the initialization that would
821 * ordinarily be done as part of the system startup;
824 if (vfe
== (struct vfs_fsentry
*)0)
827 desccount
= vfe
->vfe_vopcnt
;
828 if ((desccount
<=0) || ((desccount
> 5)) || (vfe
->vfe_vfsops
== (struct vfsops
*)NULL
)
829 || (vfe
->vfe_opvdescs
== (struct vnodeopv_desc
**)NULL
))
833 MALLOC(newvfstbl
, void *, sizeof(struct vfstable
), M_TEMP
,
835 bzero(newvfstbl
, sizeof(struct vfstable
));
836 newvfstbl
->vfc_vfsops
= vfe
->vfe_vfsops
;
837 strncpy(&newvfstbl
->vfc_name
[0], vfe
->vfe_fsname
, MFSNAMELEN
);
838 if ((vfe
->vfe_flags
& VFS_TBLNOTYPENUM
))
839 newvfstbl
->vfc_typenum
= maxvfsconf
++;
841 newvfstbl
->vfc_typenum
= vfe
->vfe_fstypenum
;
843 newvfstbl
->vfc_refcount
= 0;
844 newvfstbl
->vfc_flags
= 0;
845 newvfstbl
->vfc_mountroot
= NULL
;
846 newvfstbl
->vfc_next
= NULL
;
847 newvfstbl
->vfc_threadsafe
= 0;
848 newvfstbl
->vfc_vfsflags
= 0;
849 if (vfe
->vfe_flags
& VFS_TBL64BITREADY
)
850 newvfstbl
->vfc_64bitready
= 1;
851 if (vfe
->vfe_flags
& VFS_TBLTHREADSAFE
)
852 newvfstbl
->vfc_threadsafe
= 1;
853 if (vfe
->vfe_flags
& VFS_TBLFSNODELOCK
)
854 newvfstbl
->vfc_threadsafe
= 1;
855 if ((vfe
->vfe_flags
& VFS_TBLLOCALVOL
) == VFS_TBLLOCALVOL
)
856 newvfstbl
->vfc_flags
|= MNT_LOCAL
;
857 if (vfe
->vfe_flags
& VFS_TBLLOCALVOL
)
858 newvfstbl
->vfc_vfsflags
|= VFC_VFSLOCALARGS
;
860 newvfstbl
->vfc_vfsflags
|= VFC_VFSGENERICARGS
;
864 * Allocate and init the vectors.
865 * Also handle backwards compatibility.
867 * We allocate one large block to hold all <desccount>
868 * vnode operation vectors stored contiguously.
870 /* XXX - shouldn't be M_TEMP */
872 descsize
= desccount
* vfs_opv_numops
* sizeof(PFI
);
873 MALLOC(descptr
, PFI
*, descsize
,
875 bzero(descptr
, descsize
);
877 newvfstbl
->vfc_descptr
= descptr
;
878 newvfstbl
->vfc_descsize
= descsize
;
881 for (i
= 0; i
< desccount
; i
++ ) {
882 opv_desc_vector_p
= vfe
->vfe_opvdescs
[i
]->opv_desc_vector_p
;
884 * Fill in the caller's pointer to the start of the i'th vector.
885 * They'll need to supply it when calling vnode_create.
887 opv_desc_vector
= descptr
+ i
* vfs_opv_numops
;
888 *opv_desc_vector_p
= opv_desc_vector
;
890 for (j
= 0; vfe
->vfe_opvdescs
[i
]->opv_desc_ops
[j
].opve_op
; j
++) {
891 opve_descp
= &(vfe
->vfe_opvdescs
[i
]->opv_desc_ops
[j
]);
894 * Sanity check: is this operation listed
895 * in the list of operations? We check this
896 * by seeing if its offest is zero. Since
897 * the default routine should always be listed
898 * first, it should be the only one with a zero
899 * offset. Any other operation with a zero
900 * offset is probably not listed in
901 * vfs_op_descs, and so is probably an error.
903 * A panic here means the layer programmer
904 * has committed the all-too common bug
905 * of adding a new operation to the layer's
906 * list of vnode operations but
907 * not adding the operation to the system-wide
908 * list of supported operations.
910 if (opve_descp
->opve_op
->vdesc_offset
== 0 &&
911 opve_descp
->opve_op
->vdesc_offset
!= VOFFSET(vnop_default
)) {
912 printf("vfs_fsadd: operation %s not listed in %s.\n",
913 opve_descp
->opve_op
->vdesc_name
,
915 panic("vfs_fsadd: bad operation");
918 * Fill in this entry.
920 opv_desc_vector
[opve_descp
->opve_op
->vdesc_offset
] =
921 opve_descp
->opve_impl
;
926 * Finally, go back and replace unfilled routines
927 * with their default. (Sigh, an O(n^3) algorithm. I
928 * could make it better, but that'd be work, and n is small.)
930 opv_desc_vector_p
= vfe
->vfe_opvdescs
[i
]->opv_desc_vector_p
;
933 * Force every operations vector to have a default routine.
935 opv_desc_vector
= *opv_desc_vector_p
;
936 if (opv_desc_vector
[VOFFSET(vnop_default
)] == NULL
)
937 panic("vfs_fsadd: operation vector without default routine.");
938 for (j
= 0; j
< vfs_opv_numops
; j
++)
939 if (opv_desc_vector
[j
] == NULL
)
941 opv_desc_vector
[VOFFSET(vnop_default
)];
943 } /* end of each vnodeopv_desc parsing */
947 *handle
= vfstable_add(newvfstbl
);
949 if (newvfstbl
->vfc_typenum
<= maxvfsconf
)
950 maxvfsconf
= newvfstbl
->vfc_typenum
+ 1;
953 if (newvfstbl
->vfc_vfsops
->vfs_init
)
954 (*newvfstbl
->vfc_vfsops
->vfs_init
)((struct vfsconf
*)handle
);
956 FREE(newvfstbl
, M_TEMP
);
962 * Removes the filesystem from kernel.
963 * The argument passed in is the handle that was given when
964 * file system was added
967 vfs_fsremove(vfstable_t handle
)
969 struct vfstable
* vfstbl
= (struct vfstable
*)handle
;
970 void *old_desc
= NULL
;
973 /* Preflight check for any mounts */
975 if ( vfstbl
->vfc_refcount
!= 0 ) {
982 * save the old descriptor; the free cannot occur unconditionally,
983 * since vfstable_del() may fail.
985 if (vfstbl
->vfc_descptr
&& vfstbl
->vfc_descsize
) {
986 old_desc
= vfstbl
->vfc_descptr
;
988 err
= vfstable_del(vfstbl
);
990 /* free the descriptor if the delete was successful */
991 if (err
== 0 && old_desc
) {
992 FREE(old_desc
, M_TEMP
);
999 * This returns a reference to mount_t
1000 * which should be dropped using vfs_mountrele().
1001 * Not doing so will leak a mountpoint
1002 * and associated data structures.
1005 vfs_mountref(__unused mount_t mp
) /* gives a reference */
1010 /* This drops the reference on mount_t that was acquired */
1012 vfs_mountrele(__unused mount_t mp
) /* drops reference */
1018 vfs_context_pid(vfs_context_t context
)
1020 return (context
->vc_proc
->p_pid
);
1024 vfs_context_suser(vfs_context_t context
)
1026 return (suser(context
->vc_ucred
, 0));
1029 vfs_context_issignal(vfs_context_t context
, sigset_t mask
)
1031 if (context
->vc_proc
)
1032 return(proc_pendingsignals(context
->vc_proc
, mask
));
1037 vfs_context_is64bit(vfs_context_t context
)
1039 if (context
->vc_proc
)
1040 return(proc_is64bit(context
->vc_proc
));
1045 vfs_context_proc(vfs_context_t context
)
1047 return (context
->vc_proc
);
1051 vfs_context_create(vfs_context_t context
)
1053 struct vfs_context
* newcontext
;
1055 newcontext
= (struct vfs_context
*)kalloc(sizeof(struct vfs_context
));
1059 newcontext
->vc_proc
= context
->vc_proc
;
1060 newcontext
->vc_ucred
= context
->vc_ucred
;
1062 newcontext
->vc_proc
= proc_self();
1063 newcontext
->vc_ucred
= kauth_cred_get();
1067 return((vfs_context_t
)0);
1071 vfs_context_rele(vfs_context_t context
)
1074 kfree(context
, sizeof(struct vfs_context
));
1080 vfs_context_ucred(vfs_context_t context
)
1082 return (context
->vc_ucred
);
1086 * Return true if the context is owned by the superuser.
1089 vfs_context_issuser(vfs_context_t context
)
1091 return(context
->vc_ucred
->cr_uid
== 0);
1095 /* XXXXXXXXXXXXXX VNODE KAPIS XXXXXXXXXXXXXXXXXXXXXXXXX */
1099 * Convert between vnode types and inode formats (since POSIX.1
1100 * defines mode word of stat structure in terms of inode formats).
1103 vnode_iftovt(int mode
)
1105 return(iftovt_tab
[((mode
) & S_IFMT
) >> 12]);
1109 vnode_vttoif(enum vtype indx
)
1111 return(vttoif_tab
[(int)(indx
)]);
1115 vnode_makeimode(int indx
, int mode
)
1117 return (int)(VTTOIF(indx
) | (mode
));
1122 * vnode manipulation functions.
1125 /* returns system root vnode reference; It should be dropped using vrele() */
1131 error
= vnode_get(rootvnode
);
1133 return ((vnode_t
)0);
1140 vnode_vid(vnode_t vp
)
1142 return ((uint32_t)(vp
->v_id
));
1145 /* returns a mount reference; drop it with vfs_mountrelease() */
1147 vnode_mount(vnode_t vp
)
1149 return (vp
->v_mount
);
1152 /* returns a mount reference iff vnode_t is a dir and is a mount point */
1154 vnode_mountedhere(vnode_t vp
)
1158 if ((vp
->v_type
== VDIR
) && ((mp
= vp
->v_mountedhere
) != NULL
) &&
1159 (mp
->mnt_vnodecovered
== vp
))
1162 return (mount_t
)NULL
;
1165 /* returns vnode type of vnode_t */
1167 vnode_vtype(vnode_t vp
)
1169 return (vp
->v_type
);
1172 /* returns FS specific node saved in vnode */
1174 vnode_fsnode(vnode_t vp
)
1176 return (vp
->v_data
);
1180 vnode_clearfsnode(vnode_t vp
)
1186 vnode_specrdev(vnode_t vp
)
1192 /* Accessor functions */
1193 /* is vnode_t a root vnode */
1195 vnode_isvroot(vnode_t vp
)
1197 return ((vp
->v_flag
& VROOT
)? 1 : 0);
1200 /* is vnode_t a system vnode */
1202 vnode_issystem(vnode_t vp
)
1204 return ((vp
->v_flag
& VSYSTEM
)? 1 : 0);
1207 /* if vnode_t mount operation in progress */
1209 vnode_ismount(vnode_t vp
)
1211 return ((vp
->v_flag
& VMOUNT
)? 1 : 0);
1214 /* is this vnode under recyle now */
1216 vnode_isrecycled(vnode_t vp
)
1221 ret
= (vp
->v_lflag
& (VL_TERMINATE
|VL_DEAD
))? 1 : 0;
1226 /* is vnode_t marked to not keep data cached once it's been consumed */
1228 vnode_isnocache(vnode_t vp
)
1230 return ((vp
->v_flag
& VNOCACHE_DATA
)? 1 : 0);
1234 * has sequential readahead been disabled on this vnode
1237 vnode_isnoreadahead(vnode_t vp
)
1239 return ((vp
->v_flag
& VRAOFF
)? 1 : 0);
1242 /* is vnode_t a standard one? */
1244 vnode_isstandard(vnode_t vp
)
1246 return ((vp
->v_flag
& VSTANDARD
)? 1 : 0);
1249 /* don't vflush() if SKIPSYSTEM */
1251 vnode_isnoflush(vnode_t vp
)
1253 return ((vp
->v_flag
& VNOFLUSH
)? 1 : 0);
1256 /* is vnode_t a regular file */
1258 vnode_isreg(vnode_t vp
)
1260 return ((vp
->v_type
== VREG
)? 1 : 0);
1263 /* is vnode_t a directory? */
1265 vnode_isdir(vnode_t vp
)
1267 return ((vp
->v_type
== VDIR
)? 1 : 0);
1270 /* is vnode_t a symbolic link ? */
1272 vnode_islnk(vnode_t vp
)
1274 return ((vp
->v_type
== VLNK
)? 1 : 0);
1277 /* is vnode_t a fifo ? */
1279 vnode_isfifo(vnode_t vp
)
1281 return ((vp
->v_type
== VFIFO
)? 1 : 0);
1284 /* is vnode_t a block device? */
1286 vnode_isblk(vnode_t vp
)
1288 return ((vp
->v_type
== VBLK
)? 1 : 0);
1291 /* is vnode_t a char device? */
1293 vnode_ischr(vnode_t vp
)
1295 return ((vp
->v_type
== VCHR
)? 1 : 0);
1298 /* is vnode_t a socket? */
1300 vnode_issock(vnode_t vp
)
1302 return ((vp
->v_type
== VSOCK
)? 1 : 0);
1306 /* TBD: set vnode_t to not cache data after it is consumed once; used for quota */
1308 vnode_setnocache(vnode_t vp
)
1311 vp
->v_flag
|= VNOCACHE_DATA
;
1316 vnode_clearnocache(vnode_t vp
)
1319 vp
->v_flag
&= ~VNOCACHE_DATA
;
1324 vnode_setnoreadahead(vnode_t vp
)
1327 vp
->v_flag
|= VRAOFF
;
1332 vnode_clearnoreadahead(vnode_t vp
)
1335 vp
->v_flag
&= ~VRAOFF
;
1340 /* mark vnode_t to skip vflush() is SKIPSYSTEM */
1342 vnode_setnoflush(vnode_t vp
)
1345 vp
->v_flag
|= VNOFLUSH
;
1350 vnode_clearnoflush(vnode_t vp
)
1353 vp
->v_flag
&= ~VNOFLUSH
;
1358 /* is vnode_t a blkdevice and has a FS mounted on it */
1360 vnode_ismountedon(vnode_t vp
)
1362 return ((vp
->v_specflags
& SI_MOUNTEDON
)? 1 : 0);
1366 vnode_setmountedon(vnode_t vp
)
1369 vp
->v_specflags
|= SI_MOUNTEDON
;
1374 vnode_clearmountedon(vnode_t vp
)
1377 vp
->v_specflags
&= ~SI_MOUNTEDON
;
1383 vnode_settag(vnode_t vp
, int tag
)
1390 vnode_tag(vnode_t vp
)
1396 vnode_parent(vnode_t vp
)
1399 return(vp
->v_parent
);
1403 vnode_setparent(vnode_t vp
, vnode_t dvp
)
1409 vnode_name(vnode_t vp
)
1411 /* we try to keep v_name a reasonable name for the node */
1416 vnode_setname(vnode_t vp
, char * name
)
1421 /* return the registered FS name when adding the FS to kernel */
1423 vnode_vfsname(vnode_t vp
, char * buf
)
1425 strncpy(buf
, vp
->v_mount
->mnt_vtable
->vfc_name
, MFSNAMELEN
);
1428 /* return the FS type number */
1430 vnode_vfstypenum(vnode_t vp
)
1432 return(vp
->v_mount
->mnt_vtable
->vfc_typenum
);
1436 vnode_vfs64bitready(vnode_t vp
)
1439 if ((vp
->v_mount
->mnt_vtable
->vfc_64bitready
))
1447 /* return the visible flags on associated mount point of vnode_t */
1449 vnode_vfsvisflags(vnode_t vp
)
1451 return(vp
->v_mount
->mnt_flag
& MNT_VISFLAGMASK
);
1454 /* return the command modifier flags on associated mount point of vnode_t */
1456 vnode_vfscmdflags(vnode_t vp
)
1458 return(vp
->v_mount
->mnt_flag
& MNT_CMDFLAGS
);
1461 /* return the max symlink of short links of vnode_t */
1463 vnode_vfsmaxsymlen(vnode_t vp
)
1465 return(vp
->v_mount
->mnt_maxsymlinklen
);
1468 /* return a pointer to the RO vfs_statfs associated with vnode_t's mount point */
1470 vnode_vfsstatfs(vnode_t vp
)
1472 return(&vp
->v_mount
->mnt_vfsstat
);
1475 /* return a handle to the FSs specific private handle associated with vnode_t's mount point */
1477 vnode_vfsfsprivate(vnode_t vp
)
1479 return(vp
->v_mount
->mnt_data
);
1482 /* is vnode_t in a rdonly mounted FS */
1484 vnode_vfsisrdonly(vnode_t vp
)
1486 return ((vp
->v_mount
->mnt_flag
& MNT_RDONLY
)? 1 : 0);
1490 /* returns vnode ref to current working directory */
1492 current_workingdir(void)
1494 struct proc
*p
= current_proc();
1497 if ( (vp
= p
->p_fd
->fd_cdir
) ) {
1498 if ( (vnode_getwithref(vp
)) )
1504 /* returns vnode ref to current root(chroot) directory */
1506 current_rootdir(void)
1508 struct proc
*p
= current_proc();
1511 if ( (vp
= p
->p_fd
->fd_rdir
) ) {
1512 if ( (vnode_getwithref(vp
)) )
1519 * Get a filesec and optional acl contents from an extended attribute.
1520 * Function will attempt to retrive ACL, UUID, and GUID information using a
1521 * read of a named extended attribute (KAUTH_FILESEC_XATTR).
1523 * Parameters: vp The vnode on which to operate.
1524 * fsecp The filesec (and ACL, if any) being
1526 * ctx The vnode context in which the
1527 * operation is to be attempted.
1529 * Returns: 0 Success
1532 * Notes: The kauth_filesec_t in '*fsecp', if retrieved, will be in
1533 * host byte order, as will be the ACL contents, if any.
1534 * Internally, we will cannonize these values from network (PPC)
1535 * byte order after we retrieve them so that the on-disk contents
1536 * of the extended attribute are identical for both PPC and Intel
1537 * (if we were not being required to provide this service via
1538 * fallback, this would be the job of the filesystem
1539 * 'VNOP_GETATTR' call).
1541 * We use ntohl() because it has a transitive property on Intel
1542 * machines and no effect on PPC mancines. This guarantees us
1544 * XXX: Deleting rather than ignoreing a corrupt security structure is
1545 * probably the only way to reset it without assistance from an
1546 * file system integrity checking tool. Right now we ignore it.
1548 * XXX: We should enummerate the possible errno values here, and where
1549 * in the code they originated.
1552 vnode_get_filesec(vnode_t vp
, kauth_filesec_t
*fsecp
, vfs_context_t ctx
)
1554 kauth_filesec_t fsec
;
1557 size_t xsize
, rsize
;
1560 uint32_t host_fsec_magic
;
1561 uint32_t host_acl_entrycount
;
1567 /* find out how big the EA is */
1568 if (vn_getxattr(vp
, KAUTH_FILESEC_XATTR
, NULL
, &xsize
, XATTR_NOSECURITY
, ctx
) != 0) {
1569 /* no EA, no filesec */
1570 if ((error
== ENOATTR
) || (error
== ENOENT
) || (error
== EJUSTRETURN
))
1572 /* either way, we are done */
1576 /* how many entries would fit? */
1577 fsec_size
= KAUTH_FILESEC_COUNT(xsize
);
1579 /* get buffer and uio */
1580 if (((fsec
= kauth_filesec_alloc(fsec_size
)) == NULL
) ||
1581 ((fsec_uio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
)) == NULL
) ||
1582 uio_addiov(fsec_uio
, CAST_USER_ADDR_T(fsec
), xsize
)) {
1583 KAUTH_DEBUG(" ERROR - could not allocate iov to read ACL");
1588 /* read security attribute */
1590 if ((error
= vn_getxattr(vp
,
1591 KAUTH_FILESEC_XATTR
,
1597 /* no attribute - no security data */
1598 if ((error
== ENOATTR
) || (error
== ENOENT
) || (error
== EJUSTRETURN
))
1600 /* either way, we are done */
1605 * Validate security structure; the validation must take place in host
1606 * byte order. If it's corrupt, we will just ignore it.
1609 /* Validate the size before trying to convert it */
1610 if (rsize
< KAUTH_FILESEC_SIZE(0)) {
1611 KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize
);
1615 /* Validate the magic number before trying to convert it */
1616 host_fsec_magic
= ntohl(KAUTH_FILESEC_MAGIC
);
1617 if (fsec
->fsec_magic
!= host_fsec_magic
) {
1618 KAUTH_DEBUG("ACL - BAD MAGIC %x", host_fsec_magic
);
1622 /* Validate the entry count before trying to convert it. */
1623 host_acl_entrycount
= ntohl(fsec
->fsec_acl
.acl_entrycount
);
1624 if (host_acl_entrycount
!= KAUTH_FILESEC_NOACL
) {
1625 if (host_acl_entrycount
> KAUTH_ACL_MAX_ENTRIES
) {
1626 KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", host_acl_entrycount
);
1629 if (KAUTH_FILESEC_SIZE(host_acl_entrycount
) > rsize
) {
1630 KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", host_acl_entrycount
, rsize
);
1635 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST
, fsec
, NULL
);
1642 kauth_filesec_free(fsec
);
1643 if (fsec_uio
!= NULL
)
1651 * Set a filesec and optional acl contents into an extended attribute.
1652 * function will attempt to store ACL, UUID, and GUID information using a
1653 * write to a named extended attribute (KAUTH_FILESEC_XATTR). The 'acl'
1654 * may or may not point to the `fsec->fsec_acl`, depending on whether the
1655 * original caller supplied an acl.
1657 * Parameters: vp The vnode on which to operate.
1658 * fsec The filesec being set.
1659 * acl The acl to be associated with 'fsec'.
1660 * ctx The vnode context in which the
1661 * operation is to be attempted.
1663 * Returns: 0 Success
1666 * Notes: Both the fsec and the acl are always valid.
1668 * The kauth_filesec_t in 'fsec', if any, is in host byte order,
1669 * as are the acl contents, if they are used. Internally, we will
1670 * cannonize these values into network (PPC) byte order before we
1671 * attempt to write them so that the on-disk contents of the
1672 * extended attribute are identical for both PPC and Intel (if we
1673 * were not being required to provide this service via fallback,
1674 * this would be the job of the filesystem 'VNOP_SETATTR' call).
1675 * We reverse this process on the way out, so we leave with the
1676 * same byte order we started with.
1678 * XXX: We should enummerate the possible errno values here, and where
1679 * in the code they originated.
1682 vnode_set_filesec(vnode_t vp
, kauth_filesec_t fsec
, kauth_acl_t acl
, vfs_context_t ctx
)
1687 uint32_t saved_acl_copysize
;
1691 if ((fsec_uio
= uio_create(2, 0, UIO_SYSSPACE
, UIO_WRITE
)) == NULL
) {
1692 KAUTH_DEBUG(" ERROR - could not allocate iov to write ACL");
1697 * Save the pre-converted ACL copysize, because it gets swapped too
1698 * if we are running with the wrong endianness.
1700 saved_acl_copysize
= KAUTH_ACL_COPYSIZE(acl
);
1702 kauth_filesec_acl_setendian(KAUTH_ENDIAN_DISK
, fsec
, acl
);
1704 uio_addiov(fsec_uio
, CAST_USER_ADDR_T(fsec
), sizeof(struct kauth_filesec
) - sizeof(struct kauth_acl
));
1705 uio_addiov(fsec_uio
, CAST_USER_ADDR_T(acl
), saved_acl_copysize
);
1706 error
= vn_setxattr(vp
,
1707 KAUTH_FILESEC_XATTR
,
1709 XATTR_NOSECURITY
, /* we have auth'ed already */
1711 VFS_DEBUG(ctx
, vp
, "SETATTR - set ACL returning %d", error
);
1713 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST
, fsec
, acl
);
1716 if (fsec_uio
!= NULL
)
1723 vnode_getattr(vnode_t vp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
1725 kauth_filesec_t fsec
;
1731 /* don't ask for extended security data if the filesystem doesn't support it */
1732 if (!vfs_extendedsecurity(vnode_mount(vp
))) {
1733 VATTR_CLEAR_ACTIVE(vap
, va_acl
);
1734 VATTR_CLEAR_ACTIVE(vap
, va_uuuid
);
1735 VATTR_CLEAR_ACTIVE(vap
, va_guuid
);
1739 * If the caller wants size values we might have to synthesise, give the
1740 * filesystem the opportunity to supply better intermediate results.
1742 if (VATTR_IS_ACTIVE(vap
, va_data_alloc
) ||
1743 VATTR_IS_ACTIVE(vap
, va_total_size
) ||
1744 VATTR_IS_ACTIVE(vap
, va_total_alloc
)) {
1745 VATTR_SET_ACTIVE(vap
, va_data_size
);
1746 VATTR_SET_ACTIVE(vap
, va_data_alloc
);
1747 VATTR_SET_ACTIVE(vap
, va_total_size
);
1748 VATTR_SET_ACTIVE(vap
, va_total_alloc
);
1751 error
= VNOP_GETATTR(vp
, vap
, ctx
);
1753 KAUTH_DEBUG("ERROR - returning %d", error
);
1758 * If extended security data was requested but not returned, try the fallback
1761 if (VATTR_NOT_RETURNED(vap
, va_acl
) || VATTR_NOT_RETURNED(vap
, va_uuuid
) || VATTR_NOT_RETURNED(vap
, va_guuid
)) {
1764 if ((vp
->v_type
== VDIR
) || (vp
->v_type
== VLNK
) || (vp
->v_type
== VREG
)) {
1765 /* try to get the filesec */
1766 if ((error
= vnode_get_filesec(vp
, &fsec
, ctx
)) != 0)
1769 /* if no filesec, no attributes */
1771 VATTR_RETURN(vap
, va_acl
, NULL
);
1772 VATTR_RETURN(vap
, va_uuuid
, kauth_null_guid
);
1773 VATTR_RETURN(vap
, va_guuid
, kauth_null_guid
);
1776 /* looks good, try to return what we were asked for */
1777 VATTR_RETURN(vap
, va_uuuid
, fsec
->fsec_owner
);
1778 VATTR_RETURN(vap
, va_guuid
, fsec
->fsec_group
);
1780 /* only return the ACL if we were actually asked for it */
1781 if (VATTR_IS_ACTIVE(vap
, va_acl
)) {
1782 if (fsec
->fsec_acl
.acl_entrycount
== KAUTH_FILESEC_NOACL
) {
1783 VATTR_RETURN(vap
, va_acl
, NULL
);
1785 facl
= kauth_acl_alloc(fsec
->fsec_acl
.acl_entrycount
);
1787 kauth_filesec_free(fsec
);
1791 bcopy(&fsec
->fsec_acl
, facl
, KAUTH_ACL_COPYSIZE(&fsec
->fsec_acl
));
1792 VATTR_RETURN(vap
, va_acl
, facl
);
1795 kauth_filesec_free(fsec
);
1799 * If someone gave us an unsolicited filesec, toss it. We promise that
1800 * we're OK with a filesystem giving us anything back, but our callers
1801 * only expect what they asked for.
1803 if (VATTR_IS_SUPPORTED(vap
, va_acl
) && !VATTR_IS_ACTIVE(vap
, va_acl
)) {
1804 if (vap
->va_acl
!= NULL
)
1805 kauth_acl_free(vap
->va_acl
);
1806 VATTR_CLEAR_SUPPORTED(vap
, va_acl
);
1809 #if 0 /* enable when we have a filesystem only supporting UUIDs */
1811 * Handle the case where we need a UID/GID, but only have extended
1812 * security information.
1814 if (VATTR_NOT_RETURNED(vap
, va_uid
) &&
1815 VATTR_IS_SUPPORTED(vap
, va_uuuid
) &&
1816 !kauth_guid_equal(&vap
->va_uuuid
, &kauth_null_guid
)) {
1817 if ((error
= kauth_cred_guid2uid(&vap
->va_uuuid
, &nuid
)) == 0)
1818 VATTR_RETURN(vap
, va_uid
, nuid
);
1820 if (VATTR_NOT_RETURNED(vap
, va_gid
) &&
1821 VATTR_IS_SUPPORTED(vap
, va_guuid
) &&
1822 !kauth_guid_equal(&vap
->va_guuid
, &kauth_null_guid
)) {
1823 if ((error
= kauth_cred_guid2gid(&vap
->va_guuid
, &ngid
)) == 0)
1824 VATTR_RETURN(vap
, va_gid
, ngid
);
1829 * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
1831 if (VATTR_IS_ACTIVE(vap
, va_uid
)) {
1832 if (vp
->v_mount
->mnt_flag
& MNT_IGNORE_OWNERSHIP
) {
1833 nuid
= vp
->v_mount
->mnt_fsowner
;
1834 if (nuid
== KAUTH_UID_NONE
)
1836 } else if (VATTR_IS_SUPPORTED(vap
, va_uid
)) {
1839 /* this will always be something sensible */
1840 nuid
= vp
->v_mount
->mnt_fsowner
;
1842 if ((nuid
== 99) && !vfs_context_issuser(ctx
))
1843 nuid
= kauth_cred_getuid(vfs_context_ucred(ctx
));
1844 VATTR_RETURN(vap
, va_uid
, nuid
);
1846 if (VATTR_IS_ACTIVE(vap
, va_gid
)) {
1847 if (vp
->v_mount
->mnt_flag
& MNT_IGNORE_OWNERSHIP
) {
1848 ngid
= vp
->v_mount
->mnt_fsgroup
;
1849 if (ngid
== KAUTH_GID_NONE
)
1851 } else if (VATTR_IS_SUPPORTED(vap
, va_gid
)) {
1854 /* this will always be something sensible */
1855 ngid
= vp
->v_mount
->mnt_fsgroup
;
1857 if ((ngid
== 99) && !vfs_context_issuser(ctx
))
1858 ngid
= kauth_cred_getgid(vfs_context_ucred(ctx
));
1859 VATTR_RETURN(vap
, va_gid
, ngid
);
1863 * Synthesise some values that can be reasonably guessed.
1865 if (!VATTR_IS_SUPPORTED(vap
, va_iosize
))
1866 VATTR_RETURN(vap
, va_iosize
, vp
->v_mount
->mnt_vfsstat
.f_iosize
);
1868 if (!VATTR_IS_SUPPORTED(vap
, va_flags
))
1869 VATTR_RETURN(vap
, va_flags
, 0);
1871 if (!VATTR_IS_SUPPORTED(vap
, va_filerev
))
1872 VATTR_RETURN(vap
, va_filerev
, 0);
1874 if (!VATTR_IS_SUPPORTED(vap
, va_gen
))
1875 VATTR_RETURN(vap
, va_gen
, 0);
1878 * Default sizes. Ordering here is important, as later defaults build on earlier ones.
1880 if (!VATTR_IS_SUPPORTED(vap
, va_data_size
))
1881 VATTR_RETURN(vap
, va_data_size
, 0);
1883 /* do we want any of the possibly-computed values? */
1884 if (VATTR_IS_ACTIVE(vap
, va_data_alloc
) ||
1885 VATTR_IS_ACTIVE(vap
, va_total_size
) ||
1886 VATTR_IS_ACTIVE(vap
, va_total_alloc
)) {
1887 /* make sure f_bsize is valid */
1888 if (vp
->v_mount
->mnt_vfsstat
.f_bsize
== 0) {
1889 if ((error
= vfs_update_vfsstat(vp
->v_mount
, ctx
)) != 0)
1893 /* default va_data_alloc from va_data_size */
1894 if (!VATTR_IS_SUPPORTED(vap
, va_data_alloc
))
1895 VATTR_RETURN(vap
, va_data_alloc
, roundup(vap
->va_data_size
, vp
->v_mount
->mnt_vfsstat
.f_bsize
));
1897 /* default va_total_size from va_data_size */
1898 if (!VATTR_IS_SUPPORTED(vap
, va_total_size
))
1899 VATTR_RETURN(vap
, va_total_size
, vap
->va_data_size
);
1901 /* default va_total_alloc from va_total_size which is guaranteed at this point */
1902 if (!VATTR_IS_SUPPORTED(vap
, va_total_alloc
))
1903 VATTR_RETURN(vap
, va_total_alloc
, roundup(vap
->va_total_size
, vp
->v_mount
->mnt_vfsstat
.f_bsize
));
1907 * If we don't have a change time, pull it from the modtime.
1909 if (!VATTR_IS_SUPPORTED(vap
, va_change_time
) && VATTR_IS_SUPPORTED(vap
, va_modify_time
))
1910 VATTR_RETURN(vap
, va_change_time
, vap
->va_modify_time
);
1913 * This is really only supported for the creation VNOPs, but since the field is there
1914 * we should populate it correctly.
1916 VATTR_RETURN(vap
, va_type
, vp
->v_type
);
1919 * The fsid can be obtained from the mountpoint directly.
1921 VATTR_RETURN(vap
, va_fsid
, vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
1929 * Set the attributes on a vnode in a vnode context.
1931 * Parameters: vp The vnode whose attributes to set.
1932 * vap A pointer to the attributes to set.
1933 * ctx The vnode context in which the
1934 * operation is to be attempted.
1936 * Returns: 0 Success
1939 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order.
1941 * The contents of the data area pointed to by 'vap' may be
1942 * modified if the vnode is on a filesystem which has been
1943 * mounted with ingore ownership flags, or by the underlyng
1944 * VFS itself, or by the fallback code, if the underlying VFS
1945 * does not support ACL, UUID, or GUUID attributes directly.
1947 * XXX: We should enummerate the possible errno values here, and where
1948 * in the code they originated.
1951 vnode_setattr(vnode_t vp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
1953 int error
, is_ownership_change
=0;
1956 * Make sure the filesystem is mounted R/W.
1957 * If not, return an error.
1959 if (vfs_isrdonly(vp
->v_mount
)) {
1965 * If ownership is being ignored on this volume, we silently discard
1966 * ownership changes.
1968 if (vp
->v_mount
->mnt_flag
& MNT_IGNORE_OWNERSHIP
) {
1969 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
1970 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
1973 if (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
)) {
1974 is_ownership_change
= 1;
1978 * Make sure that extended security is enabled if we're going to try
1981 if (!vfs_extendedsecurity(vnode_mount(vp
)) &&
1982 (VATTR_IS_ACTIVE(vap
, va_acl
) || VATTR_IS_ACTIVE(vap
, va_uuuid
) || VATTR_IS_ACTIVE(vap
, va_guuid
))) {
1983 KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security");
1988 error
= VNOP_SETATTR(vp
, vap
, ctx
);
1990 if ((error
== 0) && !VATTR_ALL_SUPPORTED(vap
))
1991 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
1994 * If we have changed any of the things about the file that are likely
1995 * to result in changes to authorisation results, blow the vnode auth
1998 if (VATTR_IS_SUPPORTED(vap
, va_mode
) ||
1999 VATTR_IS_SUPPORTED(vap
, va_uid
) ||
2000 VATTR_IS_SUPPORTED(vap
, va_gid
) ||
2001 VATTR_IS_SUPPORTED(vap
, va_flags
) ||
2002 VATTR_IS_SUPPORTED(vap
, va_acl
) ||
2003 VATTR_IS_SUPPORTED(vap
, va_uuuid
) ||
2004 VATTR_IS_SUPPORTED(vap
, va_guuid
))
2005 vnode_uncache_credentials(vp
);
2006 // only send a stat_changed event if this is more than
2007 // just an access time update
2008 if (error
== 0 && (vap
->va_active
!= VNODE_ATTR_BIT(va_access_time
))) {
2009 if (need_fsevent(FSE_STAT_CHANGED
, vp
) || (is_ownership_change
&& need_fsevent(FSE_CHOWN
, vp
))) {
2010 if (is_ownership_change
== 0)
2011 add_fsevent(FSE_STAT_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
2013 add_fsevent(FSE_CHOWN
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
2022 * Fallback for setting the attributes on a vnode in a vnode context. This
2023 * Function will attempt to store ACL, UUID, and GUID information utilizing
2024 * a read/modify/write operation against an EA used as a backing store for
2027 * Parameters: vp The vnode whose attributes to set.
2028 * vap A pointer to the attributes to set.
2029 * ctx The vnode context in which the
2030 * operation is to be attempted.
2032 * Returns: 0 Success
2035 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order,
2036 * as are the fsec and lfsec, if they are used.
2038 * The contents of the data area pointed to by 'vap' may be
2039 * modified to indicate that the attribute is supported for
2040 * any given requested attribute.
2042 * XXX: We should enummerate the possible errno values here, and where
2043 * in the code they originated.
2046 vnode_setattr_fallback(vnode_t vp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
2048 kauth_filesec_t fsec
;
2050 struct kauth_filesec lfsec
;
2056 * Extended security fallback via extended attributes.
2058 * Note that we do not free the filesec; the caller is expected to
2061 if (VATTR_NOT_RETURNED(vap
, va_acl
) ||
2062 VATTR_NOT_RETURNED(vap
, va_uuuid
) ||
2063 VATTR_NOT_RETURNED(vap
, va_guuid
)) {
2064 VFS_DEBUG(ctx
, vp
, "SETATTR - doing filesec fallback");
2067 * Fail for file types that we don't permit extended security
2070 if ((vp
->v_type
!= VDIR
) && (vp
->v_type
!= VLNK
) && (vp
->v_type
!= VREG
)) {
2071 VFS_DEBUG(ctx
, vp
, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp
));
2077 * If we don't have all the extended security items, we need
2078 * to fetch the existing data to perform a read-modify-write
2082 if (!VATTR_IS_ACTIVE(vap
, va_acl
) ||
2083 !VATTR_IS_ACTIVE(vap
, va_uuuid
) ||
2084 !VATTR_IS_ACTIVE(vap
, va_guuid
)) {
2085 if ((error
= vnode_get_filesec(vp
, &fsec
, ctx
)) != 0) {
2086 KAUTH_DEBUG("SETATTR - ERROR %d fetching filesec for update", error
);
2090 /* if we didn't get a filesec, use our local one */
2092 KAUTH_DEBUG("SETATTR - using local filesec for new/full update");
2095 KAUTH_DEBUG("SETATTR - updating existing filesec");
2098 facl
= &fsec
->fsec_acl
;
2100 /* if we're using the local filesec, we need to initialise it */
2101 if (fsec
== &lfsec
) {
2102 fsec
->fsec_magic
= KAUTH_FILESEC_MAGIC
;
2103 fsec
->fsec_owner
= kauth_null_guid
;
2104 fsec
->fsec_group
= kauth_null_guid
;
2105 facl
->acl_entrycount
= KAUTH_FILESEC_NOACL
;
2106 facl
->acl_flags
= 0;
2110 * Update with the supplied attributes.
2112 if (VATTR_IS_ACTIVE(vap
, va_uuuid
)) {
2113 KAUTH_DEBUG("SETATTR - updating owner UUID");
2114 fsec
->fsec_owner
= vap
->va_uuuid
;
2115 VATTR_SET_SUPPORTED(vap
, va_uuuid
);
2117 if (VATTR_IS_ACTIVE(vap
, va_guuid
)) {
2118 KAUTH_DEBUG("SETATTR - updating group UUID");
2119 fsec
->fsec_group
= vap
->va_guuid
;
2120 VATTR_SET_SUPPORTED(vap
, va_guuid
);
2122 if (VATTR_IS_ACTIVE(vap
, va_acl
)) {
2123 if (vap
->va_acl
== NULL
) {
2124 KAUTH_DEBUG("SETATTR - removing ACL");
2125 facl
->acl_entrycount
= KAUTH_FILESEC_NOACL
;
2127 KAUTH_DEBUG("SETATTR - setting ACL with %d entries", vap
->va_acl
->acl_entrycount
);
2130 VATTR_SET_SUPPORTED(vap
, va_acl
);
2134 * If the filesec data is all invalid, we can just remove
2135 * the EA completely.
2137 if ((facl
->acl_entrycount
== KAUTH_FILESEC_NOACL
) &&
2138 kauth_guid_equal(&fsec
->fsec_owner
, &kauth_null_guid
) &&
2139 kauth_guid_equal(&fsec
->fsec_group
, &kauth_null_guid
)) {
2140 error
= vn_removexattr(vp
, KAUTH_FILESEC_XATTR
, XATTR_NOSECURITY
, ctx
);
2141 /* no attribute is ok, nothing to delete */
2142 if (error
== ENOATTR
)
2144 VFS_DEBUG(ctx
, vp
, "SETATTR - remove filesec returning %d", error
);
2147 error
= vnode_set_filesec(vp
, fsec
, facl
, ctx
);
2148 VFS_DEBUG(ctx
, vp
, "SETATTR - update filesec returning %d", error
);
2151 /* if we fetched a filesec, dispose of the buffer */
2153 kauth_filesec_free(fsec
);
2161 * Definition of vnode operations.
2167 *#% lookup dvp L ? ?
2168 *#% lookup vpp - L -
2170 struct vnop_lookup_args
{
2171 struct vnodeop_desc
*a_desc
;
2174 struct componentname
*a_cnp
;
2175 vfs_context_t a_context
;
2180 VNOP_LOOKUP(vnode_t dvp
, vnode_t
*vpp
, struct componentname
*cnp
, vfs_context_t context
)
2183 struct vnop_lookup_args a
;
2186 int funnel_state
= 0;
2188 a
.a_desc
= &vnop_lookup_desc
;
2192 a
.a_context
= context
;
2193 thread_safe
= THREAD_SAFE_FS(dvp
);
2195 vnode_cache_credentials(dvp
, context
);
2198 if ( (_err
= lock_fsnode(dvp
, &funnel_state
)) ) {
2202 _err
= (*dvp
->v_op
[vnop_lookup_desc
.vdesc_offset
])(&a
);
2207 if ( (cnp
->cn_flags
& ISLASTCN
) ) {
2208 if ( (cnp
->cn_flags
& LOCKPARENT
) ) {
2209 if ( !(cnp
->cn_flags
& FSNODELOCKHELD
) ) {
2211 * leave the fsnode lock held on
2212 * the directory, but restore the funnel...
2213 * also indicate that we need to drop the
2214 * fsnode_lock when we're done with the
2215 * system call processing for this path
2217 cnp
->cn_flags
|= FSNODELOCKHELD
;
2219 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2224 unlock_fsnode(dvp
, &funnel_state
);
2232 *#% create dvp L L L
2233 *#% create vpp - L -
2237 struct vnop_create_args
{
2238 struct vnodeop_desc
*a_desc
;
2241 struct componentname
*a_cnp
;
2242 struct vnode_attr
*a_vap
;
2243 vfs_context_t a_context
;
2247 VNOP_CREATE(vnode_t dvp
, vnode_t
* vpp
, struct componentname
* cnp
, struct vnode_attr
* vap
, vfs_context_t context
)
2250 struct vnop_create_args a
;
2252 int funnel_state
= 0;
2254 a
.a_desc
= &vnop_create_desc
;
2259 a
.a_context
= context
;
2260 thread_safe
= THREAD_SAFE_FS(dvp
);
2263 if ( (_err
= lock_fsnode(dvp
, &funnel_state
)) ) {
2267 _err
= (*dvp
->v_op
[vnop_create_desc
.vdesc_offset
])(&a
);
2268 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
2270 * Remove stale Apple Double file (if any).
2272 xattrfile_remove(dvp
, cnp
->cn_nameptr
, context
, thread_safe
, 0);
2275 unlock_fsnode(dvp
, &funnel_state
);
2283 *#% whiteout dvp L L L
2284 *#% whiteout cnp - - -
2285 *#% whiteout flag - - -
2288 struct vnop_whiteout_args
{
2289 struct vnodeop_desc
*a_desc
;
2291 struct componentname
*a_cnp
;
2293 vfs_context_t a_context
;
2297 VNOP_WHITEOUT(vnode_t dvp
, struct componentname
* cnp
, int flags
, vfs_context_t context
)
2300 struct vnop_whiteout_args a
;
2302 int funnel_state
= 0;
2304 a
.a_desc
= &vnop_whiteout_desc
;
2308 a
.a_context
= context
;
2309 thread_safe
= THREAD_SAFE_FS(dvp
);
2312 if ( (_err
= lock_fsnode(dvp
, &funnel_state
)) ) {
2316 _err
= (*dvp
->v_op
[vnop_whiteout_desc
.vdesc_offset
])(&a
);
2318 unlock_fsnode(dvp
, &funnel_state
);
2330 struct vnop_mknod_args
{
2331 struct vnodeop_desc
*a_desc
;
2334 struct componentname
*a_cnp
;
2335 struct vnode_attr
*a_vap
;
2336 vfs_context_t a_context
;
2340 VNOP_MKNOD(vnode_t dvp
, vnode_t
* vpp
, struct componentname
* cnp
, struct vnode_attr
* vap
, vfs_context_t context
)
2344 struct vnop_mknod_args a
;
2346 int funnel_state
= 0;
2348 a
.a_desc
= &vnop_mknod_desc
;
2353 a
.a_context
= context
;
2354 thread_safe
= THREAD_SAFE_FS(dvp
);
2357 if ( (_err
= lock_fsnode(dvp
, &funnel_state
)) ) {
2361 _err
= (*dvp
->v_op
[vnop_mknod_desc
.vdesc_offset
])(&a
);
2363 unlock_fsnode(dvp
, &funnel_state
);
2374 struct vnop_open_args
{
2375 struct vnodeop_desc
*a_desc
;
2378 vfs_context_t a_context
;
2382 VNOP_OPEN(vnode_t vp
, int mode
, vfs_context_t context
)
2385 struct vnop_open_args a
;
2387 int funnel_state
= 0;
2388 struct vfs_context acontext
;
2390 if (context
== NULL
) {
2391 acontext
.vc_proc
= current_proc();
2392 acontext
.vc_ucred
= kauth_cred_get();
2393 context
= &acontext
;
2395 a
.a_desc
= &vnop_open_desc
;
2398 a
.a_context
= context
;
2399 thread_safe
= THREAD_SAFE_FS(vp
);
2402 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
2403 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2404 if ( (_err
= lock_fsnode(vp
, NULL
)) ) {
2405 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2410 _err
= (*vp
->v_op
[vnop_open_desc
.vdesc_offset
])(&a
);
2412 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2413 unlock_fsnode(vp
, NULL
);
2415 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2426 struct vnop_close_args
{
2427 struct vnodeop_desc
*a_desc
;
2430 vfs_context_t a_context
;
2434 VNOP_CLOSE(vnode_t vp
, int fflag
, vfs_context_t context
)
2437 struct vnop_close_args a
;
2439 int funnel_state
= 0;
2440 struct vfs_context acontext
;
2442 if (context
== NULL
) {
2443 acontext
.vc_proc
= current_proc();
2444 acontext
.vc_ucred
= kauth_cred_get();
2445 context
= &acontext
;
2447 a
.a_desc
= &vnop_close_desc
;
2450 a
.a_context
= context
;
2451 thread_safe
= THREAD_SAFE_FS(vp
);
2454 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
2455 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2456 if ( (_err
= lock_fsnode(vp
, NULL
)) ) {
2457 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2462 _err
= (*vp
->v_op
[vnop_close_desc
.vdesc_offset
])(&a
);
2464 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2465 unlock_fsnode(vp
, NULL
);
2467 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2478 struct vnop_access_args
{
2479 struct vnodeop_desc
*a_desc
;
2482 vfs_context_t a_context
;
2486 VNOP_ACCESS(vnode_t vp
, int action
, vfs_context_t context
)
2489 struct vnop_access_args a
;
2491 int funnel_state
= 0;
2492 struct vfs_context acontext
;
2494 if (context
== NULL
) {
2495 acontext
.vc_proc
= current_proc();
2496 acontext
.vc_ucred
= kauth_cred_get();
2497 context
= &acontext
;
2499 a
.a_desc
= &vnop_access_desc
;
2501 a
.a_action
= action
;
2502 a
.a_context
= context
;
2503 thread_safe
= THREAD_SAFE_FS(vp
);
2506 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
2510 _err
= (*vp
->v_op
[vnop_access_desc
.vdesc_offset
])(&a
);
2512 unlock_fsnode(vp
, &funnel_state
);
2520 *#% getattr vp = = =
2523 struct vnop_getattr_args
{
2524 struct vnodeop_desc
*a_desc
;
2526 struct vnode_attr
*a_vap
;
2527 vfs_context_t a_context
;
2531 VNOP_GETATTR(vnode_t vp
, struct vnode_attr
* vap
, vfs_context_t context
)
2534 struct vnop_getattr_args a
;
2538 a
.a_desc
= &vnop_getattr_desc
;
2541 a
.a_context
= context
;
2542 thread_safe
= THREAD_SAFE_FS(vp
);
2545 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
2549 _err
= (*vp
->v_op
[vnop_getattr_desc
.vdesc_offset
])(&a
);
2551 unlock_fsnode(vp
, &funnel_state
);
2559 *#% setattr vp L L L
2562 struct vnop_setattr_args
{
2563 struct vnodeop_desc
*a_desc
;
2565 struct vnode_attr
*a_vap
;
2566 vfs_context_t a_context
;
2570 VNOP_SETATTR(vnode_t vp
, struct vnode_attr
* vap
, vfs_context_t context
)
2573 struct vnop_setattr_args a
;
2577 a
.a_desc
= &vnop_setattr_desc
;
2580 a
.a_context
= context
;
2581 thread_safe
= THREAD_SAFE_FS(vp
);
2584 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
2588 _err
= (*vp
->v_op
[vnop_setattr_desc
.vdesc_offset
])(&a
);
2591 * Shadow uid/gid/mod change to extended attibute file.
2593 if (_err
== 0 && !NATIVE_XATTR(vp
)) {
2594 struct vnode_attr va
;
2598 if (VATTR_IS_ACTIVE(vap
, va_uid
)) {
2599 VATTR_SET(&va
, va_uid
, vap
->va_uid
);
2602 if (VATTR_IS_ACTIVE(vap
, va_gid
)) {
2603 VATTR_SET(&va
, va_gid
, vap
->va_gid
);
2606 if (VATTR_IS_ACTIVE(vap
, va_mode
)) {
2607 VATTR_SET(&va
, va_mode
, vap
->va_mode
);
2614 dvp
= vnode_getparent(vp
);
2615 vname
= vnode_getname(vp
);
2617 xattrfile_setattr(dvp
, vname
, &va
, context
, thread_safe
);
2621 vnode_putname(vname
);
2625 unlock_fsnode(vp
, &funnel_state
);
2633 *#% getattrlist vp = = =
2636 struct vnop_getattrlist_args
{
2637 struct vnodeop_desc
*a_desc
;
2639 struct attrlist
*a_alist
;
2642 vfs_context_t a_context
;
2646 VNOP_GETATTRLIST(vnode_t vp
, struct attrlist
* alist
, struct uio
* uio
, int options
, vfs_context_t context
)
2649 struct vnop_getattrlist_args a
;
2651 int funnel_state
= 0;
2653 a
.a_desc
= &vnop_getattrlist_desc
;
2657 a
.a_options
= options
;
2658 a
.a_context
= context
;
2659 thread_safe
= THREAD_SAFE_FS(vp
);
2662 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
2666 _err
= (*vp
->v_op
[vnop_getattrlist_desc
.vdesc_offset
])(&a
);
2668 unlock_fsnode(vp
, &funnel_state
);
2676 *#% setattrlist vp L L L
2679 struct vnop_setattrlist_args
{
2680 struct vnodeop_desc
*a_desc
;
2682 struct attrlist
*a_alist
;
2685 vfs_context_t a_context
;
2689 VNOP_SETATTRLIST(vnode_t vp
, struct attrlist
* alist
, struct uio
* uio
, int options
, vfs_context_t context
)
2692 struct vnop_setattrlist_args a
;
2694 int funnel_state
= 0;
2696 a
.a_desc
= &vnop_setattrlist_desc
;
2700 a
.a_options
= options
;
2701 a
.a_context
= context
;
2702 thread_safe
= THREAD_SAFE_FS(vp
);
2705 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
2709 _err
= (*vp
->v_op
[vnop_setattrlist_desc
.vdesc_offset
])(&a
);
2711 vnode_uncache_credentials(vp
);
2714 unlock_fsnode(vp
, &funnel_state
);
2726 struct vnop_read_args
{
2727 struct vnodeop_desc
*a_desc
;
2731 vfs_context_t a_context
;
2735 VNOP_READ(vnode_t vp
, struct uio
* uio
, int ioflag
, vfs_context_t context
)
2738 struct vnop_read_args a
;
2740 int funnel_state
= 0;
2741 struct vfs_context acontext
;
2743 if (context
== NULL
) {
2744 acontext
.vc_proc
= current_proc();
2745 acontext
.vc_ucred
= kauth_cred_get();
2746 context
= &acontext
;
2749 a
.a_desc
= &vnop_read_desc
;
2752 a
.a_ioflag
= ioflag
;
2753 a
.a_context
= context
;
2754 thread_safe
= THREAD_SAFE_FS(vp
);
2757 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
2758 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2759 if ( (_err
= lock_fsnode(vp
, NULL
)) ) {
2760 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2765 _err
= (*vp
->v_op
[vnop_read_desc
.vdesc_offset
])(&a
);
2768 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2769 unlock_fsnode(vp
, NULL
);
2771 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2783 struct vnop_write_args
{
2784 struct vnodeop_desc
*a_desc
;
2788 vfs_context_t a_context
;
2792 VNOP_WRITE(vnode_t vp
, struct uio
* uio
, int ioflag
, vfs_context_t context
)
2794 struct vnop_write_args a
;
2797 int funnel_state
= 0;
2798 struct vfs_context acontext
;
2800 if (context
== NULL
) {
2801 acontext
.vc_proc
= current_proc();
2802 acontext
.vc_ucred
= kauth_cred_get();
2803 context
= &acontext
;
2806 a
.a_desc
= &vnop_write_desc
;
2809 a
.a_ioflag
= ioflag
;
2810 a
.a_context
= context
;
2811 thread_safe
= THREAD_SAFE_FS(vp
);
2814 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
2815 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2816 if ( (_err
= lock_fsnode(vp
, NULL
)) ) {
2817 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2822 _err
= (*vp
->v_op
[vnop_write_desc
.vdesc_offset
])(&a
);
2825 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2826 unlock_fsnode(vp
, NULL
);
2828 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2840 struct vnop_ioctl_args
{
2841 struct vnodeop_desc
*a_desc
;
2846 vfs_context_t a_context
;
2850 VNOP_IOCTL(vnode_t vp
, u_long command
, caddr_t data
, int fflag
, vfs_context_t context
)
2853 struct vnop_ioctl_args a
;
2855 int funnel_state
= 0;
2856 struct vfs_context acontext
;
2858 if (context
== NULL
) {
2859 acontext
.vc_proc
= current_proc();
2860 acontext
.vc_ucred
= kauth_cred_get();
2861 context
= &acontext
;
2864 if (vfs_context_is64bit(context
)) {
2865 if (!vnode_vfs64bitready(vp
)) {
2870 a
.a_desc
= &vnop_ioctl_desc
;
2872 a
.a_command
= command
;
2875 a
.a_context
= context
;
2876 thread_safe
= THREAD_SAFE_FS(vp
);
2879 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
2880 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2881 if ( (_err
= lock_fsnode(vp
, NULL
)) ) {
2882 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2887 _err
= (*vp
->v_op
[vnop_ioctl_desc
.vdesc_offset
])(&a
);
2889 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2890 unlock_fsnode(vp
, NULL
);
2892 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2904 struct vnop_select_args
{
2905 struct vnodeop_desc
*a_desc
;
2910 vfs_context_t a_context
;
2914 VNOP_SELECT(vnode_t vp
, int which
, int fflags
, void * wql
, vfs_context_t context
)
2917 struct vnop_select_args a
;
2919 int funnel_state
= 0;
2920 struct vfs_context acontext
;
2922 if (context
== NULL
) {
2923 acontext
.vc_proc
= current_proc();
2924 acontext
.vc_ucred
= kauth_cred_get();
2925 context
= &acontext
;
2927 a
.a_desc
= &vnop_select_desc
;
2930 a
.a_fflags
= fflags
;
2931 a
.a_context
= context
;
2933 thread_safe
= THREAD_SAFE_FS(vp
);
2936 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
2937 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2938 if ( (_err
= lock_fsnode(vp
, NULL
)) ) {
2939 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2944 _err
= (*vp
->v_op
[vnop_select_desc
.vdesc_offset
])(&a
);
2946 if (vp
->v_type
!= VCHR
&& vp
->v_type
!= VFIFO
&& vp
->v_type
!= VSOCK
) {
2947 unlock_fsnode(vp
, NULL
);
2949 (void) thread_funnel_set(kernel_flock
, funnel_state
);
2958 *#% exchange fvp L L L
2959 *#% exchange tvp L L L
2962 struct vnop_exchange_args
{
2963 struct vnodeop_desc
*a_desc
;
2967 vfs_context_t a_context
;
2971 VNOP_EXCHANGE(vnode_t fvp
, vnode_t tvp
, int options
, vfs_context_t context
)
2974 struct vnop_exchange_args a
;
2976 int funnel_state
= 0;
2977 vnode_t lock_first
= NULL
, lock_second
= NULL
;
2979 a
.a_desc
= &vnop_exchange_desc
;
2982 a
.a_options
= options
;
2983 a
.a_context
= context
;
2984 thread_safe
= THREAD_SAFE_FS(fvp
);
2988 * Lock in vnode address order to avoid deadlocks
2997 if ( (_err
= lock_fsnode(lock_first
, &funnel_state
)) ) {
3000 if ( (_err
= lock_fsnode(lock_second
, NULL
)) ) {
3001 unlock_fsnode(lock_first
, &funnel_state
);
3005 _err
= (*fvp
->v_op
[vnop_exchange_desc
.vdesc_offset
])(&a
);
3007 unlock_fsnode(lock_second
, NULL
);
3008 unlock_fsnode(lock_first
, &funnel_state
);
3020 struct vnop_revoke_args
{
3021 struct vnodeop_desc
*a_desc
;
3024 vfs_context_t a_context
;
3028 VNOP_REVOKE(vnode_t vp
, int flags
, vfs_context_t context
)
3030 struct vnop_revoke_args a
;
3033 int funnel_state
= 0;
3035 a
.a_desc
= &vnop_revoke_desc
;
3038 a
.a_context
= context
;
3039 thread_safe
= THREAD_SAFE_FS(vp
);
3042 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
3044 _err
= (*vp
->v_op
[vnop_revoke_desc
.vdesc_offset
])(&a
);
3046 (void) thread_funnel_set(kernel_flock
, funnel_state
);
3058 struct vnop_mmap_args
{
3059 struct vnodeop_desc
*a_desc
;
3062 vfs_context_t a_context
;
3066 VNOP_MMAP(vnode_t vp
, int fflags
, vfs_context_t context
)
3069 struct vnop_mmap_args a
;
3071 int funnel_state
= 0;
3073 a
.a_desc
= &vnop_mmap_desc
;
3075 a
.a_fflags
= fflags
;
3076 a
.a_context
= context
;
3077 thread_safe
= THREAD_SAFE_FS(vp
);
3080 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
3084 _err
= (*vp
->v_op
[vnop_mmap_desc
.vdesc_offset
])(&a
);
3086 unlock_fsnode(vp
, &funnel_state
);
3095 *# mnomap - vp U U U
3098 struct vnop_mnomap_args
{
3099 struct vnodeop_desc
*a_desc
;
3101 vfs_context_t a_context
;
3105 VNOP_MNOMAP(vnode_t vp
, vfs_context_t context
)
3108 struct vnop_mnomap_args a
;
3110 int funnel_state
= 0;
3112 a
.a_desc
= &vnop_mnomap_desc
;
3114 a
.a_context
= context
;
3115 thread_safe
= THREAD_SAFE_FS(vp
);
3118 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
3122 _err
= (*vp
->v_op
[vnop_mnomap_desc
.vdesc_offset
])(&a
);
3124 unlock_fsnode(vp
, &funnel_state
);
3136 struct vnop_fsync_args
{
3137 struct vnodeop_desc
*a_desc
;
3140 vfs_context_t a_context
;
3144 VNOP_FSYNC(vnode_t vp
, int waitfor
, vfs_context_t context
)
3146 struct vnop_fsync_args a
;
3149 int funnel_state
= 0;
3151 a
.a_desc
= &vnop_fsync_desc
;
3153 a
.a_waitfor
= waitfor
;
3154 a
.a_context
= context
;
3155 thread_safe
= THREAD_SAFE_FS(vp
);
3158 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
3162 _err
= (*vp
->v_op
[vnop_fsync_desc
.vdesc_offset
])(&a
);
3164 unlock_fsnode(vp
, &funnel_state
);
3173 *#% remove dvp L U U
3177 struct vnop_remove_args
{
3178 struct vnodeop_desc
*a_desc
;
3181 struct componentname
*a_cnp
;
3183 vfs_context_t a_context
;
3187 VNOP_REMOVE(vnode_t dvp
, vnode_t vp
, struct componentname
* cnp
, int flags
, vfs_context_t context
)
3190 struct vnop_remove_args a
;
3192 int funnel_state
= 0;
3194 a
.a_desc
= &vnop_remove_desc
;
3199 a
.a_context
= context
;
3200 thread_safe
= THREAD_SAFE_FS(dvp
);
3203 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
3207 _err
= (*dvp
->v_op
[vnop_remove_desc
.vdesc_offset
])(&a
);
3210 vnode_setneedinactive(vp
);
3212 if ( !(NATIVE_XATTR(dvp
)) ) {
3214 * Remove any associated extended attibute file (._ AppleDouble file).
3216 xattrfile_remove(dvp
, cnp
->cn_nameptr
, context
, thread_safe
, 1);
3220 unlock_fsnode(vp
, &funnel_state
);
3233 struct vnop_link_args
{
3234 struct vnodeop_desc
*a_desc
;
3237 struct componentname
*a_cnp
;
3238 vfs_context_t a_context
;
3242 VNOP_LINK(vnode_t vp
, vnode_t tdvp
, struct componentname
* cnp
, vfs_context_t context
)
3245 struct vnop_link_args a
;
3247 int funnel_state
= 0;
3250 * For file systems with non-native extended attributes,
3251 * disallow linking to an existing "._" Apple Double file.
3253 if ( !NATIVE_XATTR(tdvp
) && (vp
->v_type
== VREG
)) {
3256 vname
= vnode_getname(vp
);
3257 if (vname
!= NULL
) {
3259 if (vname
[0] == '.' && vname
[1] == '_' && vname
[2] != '\0') {
3262 vnode_putname(vname
);
3267 a
.a_desc
= &vnop_link_desc
;
3271 a
.a_context
= context
;
3272 thread_safe
= THREAD_SAFE_FS(vp
);
3275 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
3279 _err
= (*tdvp
->v_op
[vnop_link_desc
.vdesc_offset
])(&a
);
3281 unlock_fsnode(vp
, &funnel_state
);
3290 *#% rename fdvp U U U
3291 *#% rename fvp U U U
3292 *#% rename tdvp L U U
3293 *#% rename tvp X U U
3296 struct vnop_rename_args
{
3297 struct vnodeop_desc
*a_desc
;
3300 struct componentname
*a_fcnp
;
3303 struct componentname
*a_tcnp
;
3304 vfs_context_t a_context
;
3308 VNOP_RENAME(struct vnode
*fdvp
, struct vnode
*fvp
, struct componentname
*fcnp
,
3309 struct vnode
*tdvp
, struct vnode
*tvp
, struct componentname
*tcnp
,
3310 vfs_context_t context
)
3313 struct vnop_rename_args a
;
3314 int funnel_state
= 0;
3315 char smallname1
[48];
3316 char smallname2
[48];
3317 char *xfromname
= NULL
;
3318 char *xtoname
= NULL
;
3319 vnode_t lock_first
= NULL
, lock_second
= NULL
;
3320 vnode_t fdvp_unsafe
= NULLVP
;
3321 vnode_t tdvp_unsafe
= NULLVP
;
3323 a
.a_desc
= &vnop_rename_desc
;
3330 a
.a_context
= context
;
3332 if (!THREAD_SAFE_FS(fdvp
))
3334 if (!THREAD_SAFE_FS(tdvp
))
3337 if (fdvp_unsafe
!= NULLVP
) {
3339 * Lock parents in vnode address order to avoid deadlocks
3340 * note that it's possible for the fdvp to be unsafe,
3341 * but the tdvp to be safe because tvp could be a directory
3342 * in the root of a filesystem... in that case, tdvp is the
3343 * in the filesystem that this root is mounted on
3345 if (tdvp_unsafe
== NULL
|| fdvp_unsafe
== tdvp_unsafe
) {
3346 lock_first
= fdvp_unsafe
;
3348 } else if (fdvp_unsafe
< tdvp_unsafe
) {
3349 lock_first
= fdvp_unsafe
;
3350 lock_second
= tdvp_unsafe
;
3352 lock_first
= tdvp_unsafe
;
3353 lock_second
= fdvp_unsafe
;
3355 if ( (_err
= lock_fsnode(lock_first
, &funnel_state
)) )
3358 if (lock_second
!= NULL
&& (_err
= lock_fsnode(lock_second
, NULL
))) {
3359 unlock_fsnode(lock_first
, &funnel_state
);
3364 * Lock both children in vnode address order to avoid deadlocks
3366 if (tvp
== NULL
|| tvp
== fvp
) {
3369 } else if (fvp
< tvp
) {
3376 if ( (_err
= lock_fsnode(lock_first
, NULL
)) )
3379 if (lock_second
!= NULL
&& (_err
= lock_fsnode(lock_second
, NULL
))) {
3380 unlock_fsnode(lock_first
, NULL
);
3385 * Save source and destination names (._ AppleDouble files).
3386 * Skip if source already has a "._" prefix.
3388 if (!NATIVE_XATTR(fdvp
) &&
3389 !(fcnp
->cn_nameptr
[0] == '.' && fcnp
->cn_nameptr
[1] == '_')) {
3392 /* Get source attribute file name. */
3393 len
= fcnp
->cn_namelen
+ 3;
3394 if (len
> sizeof(smallname1
)) {
3395 MALLOC(xfromname
, char *, len
, M_TEMP
, M_WAITOK
);
3397 xfromname
= &smallname1
[0];
3399 strcpy(xfromname
, "._");
3400 strncat(xfromname
, fcnp
->cn_nameptr
, fcnp
->cn_namelen
);
3401 xfromname
[len
-1] = '\0';
3403 /* Get destination attribute file name. */
3404 len
= tcnp
->cn_namelen
+ 3;
3405 if (len
> sizeof(smallname2
)) {
3406 MALLOC(xtoname
, char *, len
, M_TEMP
, M_WAITOK
);
3408 xtoname
= &smallname2
[0];
3410 strcpy(xtoname
, "._");
3411 strncat(xtoname
, tcnp
->cn_nameptr
, tcnp
->cn_namelen
);
3412 xtoname
[len
-1] = '\0';
3415 _err
= (*fdvp
->v_op
[vnop_rename_desc
.vdesc_offset
])(&a
);
3417 if (fdvp_unsafe
!= NULLVP
) {
3418 if (lock_second
!= NULL
)
3419 unlock_fsnode(lock_second
, NULL
);
3420 unlock_fsnode(lock_first
, NULL
);
3423 if (tvp
&& tvp
!= fvp
)
3424 vnode_setneedinactive(tvp
);
3428 * Rename any associated extended attibute file (._ AppleDouble file).
3430 if (_err
== 0 && !NATIVE_XATTR(fdvp
) && xfromname
!= NULL
) {
3431 struct nameidata fromnd
, tond
;
3436 * Get source attribute file vnode.
3437 * Note that fdvp already has an iocount reference and
3438 * using DELETE will take an additional reference.
3440 NDINIT(&fromnd
, DELETE
, NOFOLLOW
| USEDVP
, UIO_SYSSPACE
,
3441 CAST_USER_ADDR_T(xfromname
), context
);
3442 fromnd
.ni_dvp
= fdvp
;
3443 error
= namei(&fromnd
);
3446 /* When source doesn't exist there still may be a destination. */
3447 if (error
== ENOENT
) {
3452 } else if (fromnd
.ni_vp
->v_type
!= VREG
) {
3453 vnode_put(fromnd
.ni_vp
);
3458 struct vnop_remove_args args
;
3461 * Get destination attribute file vnode.
3462 * Note that tdvp already has an iocount reference.
3464 NDINIT(&tond
, DELETE
, NOFOLLOW
| USEDVP
, UIO_SYSSPACE
,
3465 CAST_USER_ADDR_T(xtoname
), context
);
3467 error
= namei(&tond
);
3471 if (tond
.ni_vp
->v_type
!= VREG
) {
3472 vnode_put(tond
.ni_vp
);
3476 args
.a_desc
= &vnop_remove_desc
;
3478 args
.a_vp
= tond
.ni_vp
;
3479 args
.a_cnp
= &tond
.ni_cnd
;
3480 args
.a_context
= context
;
3482 if (fdvp_unsafe
!= NULLVP
)
3483 error
= lock_fsnode(tond
.ni_vp
, NULL
);
3485 error
= (*tdvp
->v_op
[vnop_remove_desc
.vdesc_offset
])(&args
);
3487 if (fdvp_unsafe
!= NULLVP
)
3488 unlock_fsnode(tond
.ni_vp
, NULL
);
3491 vnode_setneedinactive(tond
.ni_vp
);
3493 vnode_put(tond
.ni_vp
);
3499 * Get destination attribute file vnode.
3501 NDINIT(&tond
, RENAME
,
3502 NOCACHE
| NOFOLLOW
| USEDVP
, UIO_SYSSPACE
,
3503 CAST_USER_ADDR_T(xtoname
), context
);
3505 error
= namei(&tond
);
3508 vnode_put(fromnd
.ni_vp
);
3512 a
.a_desc
= &vnop_rename_desc
;
3514 a
.a_fvp
= fromnd
.ni_vp
;
3515 a
.a_fcnp
= &fromnd
.ni_cnd
;
3517 a
.a_tvp
= tond
.ni_vp
;
3518 a
.a_tcnp
= &tond
.ni_cnd
;
3519 a
.a_context
= context
;
3521 if (fdvp_unsafe
!= NULLVP
) {
3523 * Lock in vnode address order to avoid deadlocks
3525 if (tond
.ni_vp
== NULL
|| tond
.ni_vp
== fromnd
.ni_vp
) {
3526 lock_first
= fromnd
.ni_vp
;
3528 } else if (fromnd
.ni_vp
< tond
.ni_vp
) {
3529 lock_first
= fromnd
.ni_vp
;
3530 lock_second
= tond
.ni_vp
;
3532 lock_first
= tond
.ni_vp
;
3533 lock_second
= fromnd
.ni_vp
;
3535 if ( (error
= lock_fsnode(lock_first
, NULL
)) == 0) {
3536 if (lock_second
!= NULL
&& (error
= lock_fsnode(lock_second
, NULL
)) )
3537 unlock_fsnode(lock_first
, NULL
);
3541 error
= (*fdvp
->v_op
[vnop_rename_desc
.vdesc_offset
])(&a
);
3543 if (fdvp_unsafe
!= NULLVP
) {
3544 if (lock_second
!= NULL
)
3545 unlock_fsnode(lock_second
, NULL
);
3546 unlock_fsnode(lock_first
, NULL
);
3549 vnode_setneedinactive(fromnd
.ni_vp
);
3551 if (tond
.ni_vp
&& tond
.ni_vp
!= fromnd
.ni_vp
)
3552 vnode_setneedinactive(tond
.ni_vp
);
3555 vnode_put(fromnd
.ni_vp
);
3557 vnode_put(tond
.ni_vp
);
3563 if (xfromname
&& xfromname
!= &smallname1
[0]) {
3564 FREE(xfromname
, M_TEMP
);
3566 if (xtoname
&& xtoname
!= &smallname2
[0]) {
3567 FREE(xtoname
, M_TEMP
);
3570 if (fdvp_unsafe
!= NULLVP
) {
3571 if (tdvp_unsafe
!= NULLVP
)
3572 unlock_fsnode(tdvp_unsafe
, NULL
);
3573 unlock_fsnode(fdvp_unsafe
, &funnel_state
);
3585 struct vnop_mkdir_args
{
3586 struct vnodeop_desc
*a_desc
;
3589 struct componentname
*a_cnp
;
3590 struct vnode_attr
*a_vap
;
3591 vfs_context_t a_context
;
3595 VNOP_MKDIR(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
,
3596 struct vnode_attr
*vap
, vfs_context_t context
)
3599 struct vnop_mkdir_args a
;
3601 int funnel_state
= 0;
3603 a
.a_desc
= &vnop_mkdir_desc
;
3608 a
.a_context
= context
;
3609 thread_safe
= THREAD_SAFE_FS(dvp
);
3612 if ( (_err
= lock_fsnode(dvp
, &funnel_state
)) ) {
3616 _err
= (*dvp
->v_op
[vnop_mkdir_desc
.vdesc_offset
])(&a
);
3617 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
3619 * Remove stale Apple Double file (if any).
3621 xattrfile_remove(dvp
, cnp
->cn_nameptr
, context
, thread_safe
, 0);
3624 unlock_fsnode(dvp
, &funnel_state
);
3637 struct vnop_rmdir_args
{
3638 struct vnodeop_desc
*a_desc
;
3641 struct componentname
*a_cnp
;
3642 vfs_context_t a_context
;
3647 VNOP_RMDIR(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
*cnp
, vfs_context_t context
)
3650 struct vnop_rmdir_args a
;
3652 int funnel_state
= 0;
3654 a
.a_desc
= &vnop_rmdir_desc
;
3658 a
.a_context
= context
;
3659 thread_safe
= THREAD_SAFE_FS(dvp
);
3662 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
3666 _err
= (*vp
->v_op
[vnop_rmdir_desc
.vdesc_offset
])(&a
);
3669 vnode_setneedinactive(vp
);
3671 if ( !(NATIVE_XATTR(dvp
)) ) {
3673 * Remove any associated extended attibute file (._ AppleDouble file).
3675 xattrfile_remove(dvp
, cnp
->cn_nameptr
, context
, thread_safe
, 1);
3679 unlock_fsnode(vp
, &funnel_state
);
3685 * Remove a ._ AppleDouble file
3687 #define AD_STALE_SECS (180)
3689 xattrfile_remove(vnode_t dvp
, const char * basename
, vfs_context_t context
, int thread_safe
, int force
) {
3691 struct nameidata nd
;
3693 char *filename
= NULL
;
3696 if ((basename
== NULL
) || (basename
[0] == '\0') ||
3697 (basename
[0] == '.' && basename
[1] == '_')) {
3700 filename
= &smallname
[0];
3701 len
= snprintf(filename
, sizeof(smallname
), "._%s", basename
);
3702 if (len
>= sizeof(smallname
)) {
3703 len
++; /* snprintf result doesn't include '\0' */
3704 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
);
3705 len
= snprintf(filename
, len
, "._%s", basename
);
3707 NDINIT(&nd
, DELETE
, LOCKLEAF
| NOFOLLOW
| USEDVP
, UIO_SYSSPACE
,
3708 CAST_USER_ADDR_T(filename
), context
);
3710 if (namei(&nd
) != 0)
3715 if (xvp
->v_type
!= VREG
)
3719 * When creating a new object and a "._" file already
3720 * exists, check to see if its a stale "._" file.
3724 struct vnode_attr va
;
3727 VATTR_WANTED(&va
, va_data_size
);
3728 VATTR_WANTED(&va
, va_modify_time
);
3729 if (VNOP_GETATTR(xvp
, &va
, context
) == 0 &&
3730 VATTR_IS_SUPPORTED(&va
, va_data_size
) &&
3731 VATTR_IS_SUPPORTED(&va
, va_modify_time
) &&
3732 va
.va_data_size
!= 0) {
3736 if ((tv
.tv_sec
> va
.va_modify_time
.tv_sec
) &&
3737 (tv
.tv_sec
- va
.va_modify_time
.tv_sec
) > AD_STALE_SECS
) {
3738 force
= 1; /* must be stale */
3743 struct vnop_remove_args a
;
3746 a
.a_desc
= &vnop_remove_desc
;
3747 a
.a_dvp
= nd
.ni_dvp
;
3749 a
.a_cnp
= &nd
.ni_cnd
;
3750 a
.a_context
= context
;
3753 if ( (lock_fsnode(xvp
, NULL
)) )
3756 error
= (*dvp
->v_op
[vnop_remove_desc
.vdesc_offset
])(&a
);
3759 unlock_fsnode(xvp
, NULL
);
3762 vnode_setneedinactive(xvp
);
3765 /* Note: nd.ni_dvp's iocount is dropped by caller of VNOP_XXXX */
3768 if (filename
&& filename
!= &smallname
[0]) {
3769 FREE(filename
, M_TEMP
);
3774 * Shadow uid/gid/mod to a ._ AppleDouble file
3777 xattrfile_setattr(vnode_t dvp
, const char * basename
, struct vnode_attr
* vap
,
3778 vfs_context_t context
, int thread_safe
) {
3780 struct nameidata nd
;
3782 char *filename
= NULL
;
3785 if ((dvp
== NULLVP
) ||
3786 (basename
== NULL
) || (basename
[0] == '\0') ||
3787 (basename
[0] == '.' && basename
[1] == '_')) {
3790 filename
= &smallname
[0];
3791 len
= snprintf(filename
, sizeof(smallname
), "._%s", basename
);
3792 if (len
>= sizeof(smallname
)) {
3793 len
++; /* snprintf result doesn't include '\0' */
3794 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
);
3795 len
= snprintf(filename
, len
, "._%s", basename
);
3797 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| USEDVP
, UIO_SYSSPACE
,
3798 CAST_USER_ADDR_T(filename
), context
);
3800 if (namei(&nd
) != 0)
3806 if (xvp
->v_type
== VREG
) {
3807 struct vnop_setattr_args a
;
3809 a
.a_desc
= &vnop_setattr_desc
;
3812 a
.a_context
= context
;
3815 if ( (lock_fsnode(xvp
, NULL
)) )
3818 (void) (*xvp
->v_op
[vnop_setattr_desc
.vdesc_offset
])(&a
);
3820 unlock_fsnode(xvp
, NULL
);
3826 if (filename
&& filename
!= &smallname
[0]) {
3827 FREE(filename
, M_TEMP
);
3834 *#% symlink dvp L U U
3835 *#% symlink vpp - U -
3838 struct vnop_symlink_args
{
3839 struct vnodeop_desc
*a_desc
;
3842 struct componentname
*a_cnp
;
3843 struct vnode_attr
*a_vap
;
3845 vfs_context_t a_context
;
3850 VNOP_SYMLINK(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
,
3851 struct vnode_attr
*vap
, char *target
, vfs_context_t context
)
3854 struct vnop_symlink_args a
;
3856 int funnel_state
= 0;
3858 a
.a_desc
= &vnop_symlink_desc
;
3863 a
.a_target
= target
;
3864 a
.a_context
= context
;
3865 thread_safe
= THREAD_SAFE_FS(dvp
);
3868 if ( (_err
= lock_fsnode(dvp
, &funnel_state
)) ) {
3872 _err
= (*dvp
->v_op
[vnop_symlink_desc
.vdesc_offset
])(&a
);
3873 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
3875 * Remove stale Apple Double file (if any).
3877 xattrfile_remove(dvp
, cnp
->cn_nameptr
, context
, thread_safe
, 0);
3880 unlock_fsnode(dvp
, &funnel_state
);
3888 *#% readdir vp L L L
3891 struct vnop_readdir_args
{
3892 struct vnodeop_desc
*a_desc
;
3898 vfs_context_t a_context
;
3903 VNOP_READDIR(struct vnode
*vp
, struct uio
*uio
, int flags
, int *eofflag
,
3904 int *numdirent
, vfs_context_t context
)
3907 struct vnop_readdir_args a
;
3909 int funnel_state
= 0;
3911 a
.a_desc
= &vnop_readdir_desc
;
3915 a
.a_eofflag
= eofflag
;
3916 a
.a_numdirent
= numdirent
;
3917 a
.a_context
= context
;
3918 thread_safe
= THREAD_SAFE_FS(vp
);
3921 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
3925 _err
= (*vp
->v_op
[vnop_readdir_desc
.vdesc_offset
])(&a
);
3927 unlock_fsnode(vp
, &funnel_state
);
3935 *#% readdirattr vp L L L
3938 struct vnop_readdirattr_args
{
3939 struct vnodeop_desc
*a_desc
;
3941 struct attrlist
*a_alist
;
3947 u_long
*a_actualcount
;
3948 vfs_context_t a_context
;
3953 VNOP_READDIRATTR(struct vnode
*vp
, struct attrlist
*alist
, struct uio
*uio
, u_long maxcount
,
3954 u_long options
, u_long
*newstate
, int *eofflag
, u_long
*actualcount
, vfs_context_t context
)
3957 struct vnop_readdirattr_args a
;
3959 int funnel_state
= 0;
3961 a
.a_desc
= &vnop_readdirattr_desc
;
3965 a
.a_maxcount
= maxcount
;
3966 a
.a_options
= options
;
3967 a
.a_newstate
= newstate
;
3968 a
.a_eofflag
= eofflag
;
3969 a
.a_actualcount
= actualcount
;
3970 a
.a_context
= context
;
3971 thread_safe
= THREAD_SAFE_FS(vp
);
3974 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
3978 _err
= (*vp
->v_op
[vnop_readdirattr_desc
.vdesc_offset
])(&a
);
3980 unlock_fsnode(vp
, &funnel_state
);
3988 *#% readlink vp L L L
3991 struct vnop_readlink_args
{
3992 struct vnodeop_desc
*a_desc
;
3995 vfs_context_t a_context
;
4000 VNOP_READLINK(struct vnode
*vp
, struct uio
*uio
, vfs_context_t context
)
4003 struct vnop_readlink_args a
;
4005 int funnel_state
= 0;
4007 a
.a_desc
= &vnop_readlink_desc
;
4010 a
.a_context
= context
;
4011 thread_safe
= THREAD_SAFE_FS(vp
);
4014 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
4018 _err
= (*vp
->v_op
[vnop_readlink_desc
.vdesc_offset
])(&a
);
4020 unlock_fsnode(vp
, &funnel_state
);
4028 *#% inactive vp L U U
4031 struct vnop_inactive_args
{
4032 struct vnodeop_desc
*a_desc
;
4034 vfs_context_t a_context
;
4038 VNOP_INACTIVE(struct vnode
*vp
, vfs_context_t context
)
4041 struct vnop_inactive_args a
;
4043 int funnel_state
= 0;
4045 a
.a_desc
= &vnop_inactive_desc
;
4047 a
.a_context
= context
;
4048 thread_safe
= THREAD_SAFE_FS(vp
);
4051 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
4055 _err
= (*vp
->v_op
[vnop_inactive_desc
.vdesc_offset
])(&a
);
4057 unlock_fsnode(vp
, &funnel_state
);
4066 *#% reclaim vp U U U
4069 struct vnop_reclaim_args
{
4070 struct vnodeop_desc
*a_desc
;
4072 vfs_context_t a_context
;
4076 VNOP_RECLAIM(struct vnode
*vp
, vfs_context_t context
)
4079 struct vnop_reclaim_args a
;
4081 int funnel_state
= 0;
4083 a
.a_desc
= &vnop_reclaim_desc
;
4085 a
.a_context
= context
;
4086 thread_safe
= THREAD_SAFE_FS(vp
);
4089 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4091 _err
= (*vp
->v_op
[vnop_reclaim_desc
.vdesc_offset
])(&a
);
4093 (void) thread_funnel_set(kernel_flock
, funnel_state
);
4102 *#% pathconf vp L L L
4105 struct vnop_pathconf_args
{
4106 struct vnodeop_desc
*a_desc
;
4109 register_t
*a_retval
;
4110 vfs_context_t a_context
;
4114 VNOP_PATHCONF(struct vnode
*vp
, int name
, register_t
*retval
, vfs_context_t context
)
4117 struct vnop_pathconf_args a
;
4119 int funnel_state
= 0;
4121 a
.a_desc
= &vnop_pathconf_desc
;
4124 a
.a_retval
= retval
;
4125 a
.a_context
= context
;
4126 thread_safe
= THREAD_SAFE_FS(vp
);
4129 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
4133 _err
= (*vp
->v_op
[vnop_pathconf_desc
.vdesc_offset
])(&a
);
4135 unlock_fsnode(vp
, &funnel_state
);
4143 *#% advlock vp U U U
4146 struct vnop_advlock_args
{
4147 struct vnodeop_desc
*a_desc
;
4153 vfs_context_t a_context
;
4157 VNOP_ADVLOCK(struct vnode
*vp
, caddr_t id
, int op
, struct flock
*fl
, int flags
, vfs_context_t context
)
4160 struct vnop_advlock_args a
;
4162 int funnel_state
= 0;
4163 struct uthread
* uth
;
4165 a
.a_desc
= &vnop_advlock_desc
;
4171 a
.a_context
= context
;
4172 thread_safe
= THREAD_SAFE_FS(vp
);
4174 uth
= get_bsdthread_info(current_thread());
4176 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4178 /* Disallow advisory locking on non-seekable vnodes */
4179 if (vnode_isfifo(vp
)) {
4180 _err
= err_advlock(&a
);
4182 if ((vp
->v_flag
& VLOCKLOCAL
)) {
4183 /* Advisory locking done at this layer */
4184 _err
= lf_advlock(&a
);
4186 /* Advisory locking done by underlying filesystem */
4187 _err
= (*vp
->v_op
[vnop_advlock_desc
.vdesc_offset
])(&a
);
4191 (void) thread_funnel_set(kernel_flock
, funnel_state
);
4201 *#% allocate vp L L L
4204 struct vnop_allocate_args
{
4205 struct vnodeop_desc
*a_desc
;
4209 off_t
*a_bytesallocated
;
4211 vfs_context_t a_context
;
4216 VNOP_ALLOCATE(struct vnode
*vp
, off_t length
, u_int32_t flags
, off_t
*bytesallocated
, off_t offset
, vfs_context_t context
)
4219 struct vnop_allocate_args a
;
4221 int funnel_state
= 0;
4223 a
.a_desc
= &vnop_allocate_desc
;
4225 a
.a_length
= length
;
4227 a
.a_bytesallocated
= bytesallocated
;
4228 a
.a_offset
= offset
;
4229 a
.a_context
= context
;
4230 thread_safe
= THREAD_SAFE_FS(vp
);
4233 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
4237 _err
= (*vp
->v_op
[vnop_allocate_desc
.vdesc_offset
])(&a
);
4239 unlock_fsnode(vp
, &funnel_state
);
4250 struct vnop_pagein_args
{
4251 struct vnodeop_desc
*a_desc
;
4254 vm_offset_t a_pl_offset
;
4258 vfs_context_t a_context
;
4262 VNOP_PAGEIN(struct vnode
*vp
, upl_t pl
, vm_offset_t pl_offset
, off_t f_offset
, size_t size
, int flags
, vfs_context_t context
)
4265 struct vnop_pagein_args a
;
4267 int funnel_state
= 0;
4269 a
.a_desc
= &vnop_pagein_desc
;
4272 a
.a_pl_offset
= pl_offset
;
4273 a
.a_f_offset
= f_offset
;
4276 a
.a_context
= context
;
4277 thread_safe
= THREAD_SAFE_FS(vp
);
4280 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4282 _err
= (*vp
->v_op
[vnop_pagein_desc
.vdesc_offset
])(&a
);
4284 (void) thread_funnel_set(kernel_flock
, funnel_state
);
4292 *#% pageout vp = = =
4295 struct vnop_pageout_args
{
4296 struct vnodeop_desc
*a_desc
;
4299 vm_offset_t a_pl_offset
;
4303 vfs_context_t a_context
;
4308 VNOP_PAGEOUT(struct vnode
*vp
, upl_t pl
, vm_offset_t pl_offset
, off_t f_offset
, size_t size
, int flags
, vfs_context_t context
)
4311 struct vnop_pageout_args a
;
4313 int funnel_state
= 0;
4315 a
.a_desc
= &vnop_pageout_desc
;
4318 a
.a_pl_offset
= pl_offset
;
4319 a
.a_f_offset
= f_offset
;
4322 a
.a_context
= context
;
4323 thread_safe
= THREAD_SAFE_FS(vp
);
4326 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4328 _err
= (*vp
->v_op
[vnop_pageout_desc
.vdesc_offset
])(&a
);
4330 (void) thread_funnel_set(kernel_flock
, funnel_state
);
4339 *#% searchfs vp L L L
4342 struct vnop_searchfs_args
{
4343 struct vnodeop_desc
*a_desc
;
4345 void *a_searchparams1
;
4346 void *a_searchparams2
;
4347 struct attrlist
*a_searchattrs
;
4348 u_long a_maxmatches
;
4349 struct timeval
*a_timelimit
;
4350 struct attrlist
*a_returnattrs
;
4351 u_long
*a_nummatches
;
4352 u_long a_scriptcode
;
4355 struct searchstate
*a_searchstate
;
4356 vfs_context_t a_context
;
4361 VNOP_SEARCHFS(struct vnode
*vp
, void *searchparams1
, void *searchparams2
, struct attrlist
*searchattrs
, u_long maxmatches
, struct timeval
*timelimit
, struct attrlist
*returnattrs
, u_long
*nummatches
, u_long scriptcode
, u_long options
, struct uio
*uio
, struct searchstate
*searchstate
, vfs_context_t context
)
4364 struct vnop_searchfs_args a
;
4366 int funnel_state
= 0;
4368 a
.a_desc
= &vnop_searchfs_desc
;
4370 a
.a_searchparams1
= searchparams1
;
4371 a
.a_searchparams2
= searchparams2
;
4372 a
.a_searchattrs
= searchattrs
;
4373 a
.a_maxmatches
= maxmatches
;
4374 a
.a_timelimit
= timelimit
;
4375 a
.a_returnattrs
= returnattrs
;
4376 a
.a_nummatches
= nummatches
;
4377 a
.a_scriptcode
= scriptcode
;
4378 a
.a_options
= options
;
4380 a
.a_searchstate
= searchstate
;
4381 a
.a_context
= context
;
4382 thread_safe
= THREAD_SAFE_FS(vp
);
4385 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
4389 _err
= (*vp
->v_op
[vnop_searchfs_desc
.vdesc_offset
])(&a
);
4391 unlock_fsnode(vp
, &funnel_state
);
4399 *#% copyfile fvp U U U
4400 *#% copyfile tdvp L U U
4401 *#% copyfile tvp X U U
4404 struct vnop_copyfile_args
{
4405 struct vnodeop_desc
*a_desc
;
4409 struct componentname
*a_tcnp
;
4412 vfs_context_t a_context
;
4416 VNOP_COPYFILE(struct vnode
*fvp
, struct vnode
*tdvp
, struct vnode
*tvp
, struct componentname
*tcnp
,
4417 int mode
, int flags
, vfs_context_t context
)
4420 struct vnop_copyfile_args a
;
4421 a
.a_desc
= &vnop_copyfile_desc
;
4428 a
.a_context
= context
;
4429 _err
= (*fvp
->v_op
[vnop_copyfile_desc
.vdesc_offset
])(&a
);
4435 VNOP_GETXATTR(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
, int options
, vfs_context_t context
)
4437 struct vnop_getxattr_args a
;
4440 int funnel_state
= 0;
4442 a
.a_desc
= &vnop_getxattr_desc
;
4447 a
.a_options
= options
;
4448 a
.a_context
= context
;
4450 thread_safe
= THREAD_SAFE_FS(vp
);
4452 if ( (error
= lock_fsnode(vp
, &funnel_state
)) ) {
4456 error
= (*vp
->v_op
[vnop_getxattr_desc
.vdesc_offset
])(&a
);
4458 unlock_fsnode(vp
, &funnel_state
);
4464 VNOP_SETXATTR(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t context
)
4466 struct vnop_setxattr_args a
;
4469 int funnel_state
= 0;
4471 a
.a_desc
= &vnop_setxattr_desc
;
4475 a
.a_options
= options
;
4476 a
.a_context
= context
;
4478 thread_safe
= THREAD_SAFE_FS(vp
);
4480 if ( (error
= lock_fsnode(vp
, &funnel_state
)) ) {
4484 error
= (*vp
->v_op
[vnop_setxattr_desc
.vdesc_offset
])(&a
);
4486 unlock_fsnode(vp
, &funnel_state
);
4492 VNOP_REMOVEXATTR(vnode_t vp
, const char *name
, int options
, vfs_context_t context
)
4494 struct vnop_removexattr_args a
;
4497 int funnel_state
= 0;
4499 a
.a_desc
= &vnop_removexattr_desc
;
4502 a
.a_options
= options
;
4503 a
.a_context
= context
;
4505 thread_safe
= THREAD_SAFE_FS(vp
);
4507 if ( (error
= lock_fsnode(vp
, &funnel_state
)) ) {
4511 error
= (*vp
->v_op
[vnop_removexattr_desc
.vdesc_offset
])(&a
);
4513 unlock_fsnode(vp
, &funnel_state
);
4519 VNOP_LISTXATTR(vnode_t vp
, uio_t uio
, size_t *size
, int options
, vfs_context_t context
)
4521 struct vnop_listxattr_args a
;
4524 int funnel_state
= 0;
4526 a
.a_desc
= &vnop_listxattr_desc
;
4530 a
.a_options
= options
;
4531 a
.a_context
= context
;
4533 thread_safe
= THREAD_SAFE_FS(vp
);
4535 if ( (error
= lock_fsnode(vp
, &funnel_state
)) ) {
4539 error
= (*vp
->v_op
[vnop_listxattr_desc
.vdesc_offset
])(&a
);
4541 unlock_fsnode(vp
, &funnel_state
);
4550 *#% blktooff vp = = =
4553 struct vnop_blktooff_args
{
4554 struct vnodeop_desc
*a_desc
;
4561 VNOP_BLKTOOFF(struct vnode
*vp
, daddr64_t lblkno
, off_t
*offset
)
4564 struct vnop_blktooff_args a
;
4566 int funnel_state
= 0;
4568 a
.a_desc
= &vnop_blktooff_desc
;
4570 a
.a_lblkno
= lblkno
;
4571 a
.a_offset
= offset
;
4572 thread_safe
= THREAD_SAFE_FS(vp
);
4575 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4577 _err
= (*vp
->v_op
[vnop_blktooff_desc
.vdesc_offset
])(&a
);
4579 (void) thread_funnel_set(kernel_flock
, funnel_state
);
4587 *#% offtoblk vp = = =
4590 struct vnop_offtoblk_args
{
4591 struct vnodeop_desc
*a_desc
;
4594 daddr64_t
*a_lblkno
;
4598 VNOP_OFFTOBLK(struct vnode
*vp
, off_t offset
, daddr64_t
*lblkno
)
4601 struct vnop_offtoblk_args a
;
4603 int funnel_state
= 0;
4605 a
.a_desc
= &vnop_offtoblk_desc
;
4607 a
.a_offset
= offset
;
4608 a
.a_lblkno
= lblkno
;
4609 thread_safe
= THREAD_SAFE_FS(vp
);
4612 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4614 _err
= (*vp
->v_op
[vnop_offtoblk_desc
.vdesc_offset
])(&a
);
4616 (void) thread_funnel_set(kernel_flock
, funnel_state
);
4624 *#% blockmap vp L L L
4627 struct vnop_blockmap_args
{
4628 struct vnodeop_desc
*a_desc
;
4636 vfs_context_t a_context
;
4640 VNOP_BLOCKMAP(struct vnode
*vp
, off_t foffset
, size_t size
, daddr64_t
*bpn
, size_t *run
, void *poff
, int flags
, vfs_context_t context
)
4643 struct vnop_blockmap_args a
;
4645 int funnel_state
= 0;
4646 struct vfs_context acontext
;
4648 if (context
== NULL
) {
4649 acontext
.vc_proc
= current_proc();
4650 acontext
.vc_ucred
= kauth_cred_get();
4651 context
= &acontext
;
4653 a
.a_desc
= &vnop_blockmap_desc
;
4655 a
.a_foffset
= foffset
;
4661 a
.a_context
= context
;
4662 thread_safe
= THREAD_SAFE_FS(vp
);
4665 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4667 _err
= (*vp
->v_op
[vnop_blockmap_desc
.vdesc_offset
])(&a
);
4669 (void) thread_funnel_set(kernel_flock
, funnel_state
);
4675 struct vnop_strategy_args
{
4676 struct vnodeop_desc
*a_desc
;
4682 VNOP_STRATEGY(struct buf
*bp
)
4685 struct vnop_strategy_args a
;
4686 a
.a_desc
= &vnop_strategy_desc
;
4688 _err
= (*buf_vnode(bp
)->v_op
[vnop_strategy_desc
.vdesc_offset
])(&a
);
4693 struct vnop_bwrite_args
{
4694 struct vnodeop_desc
*a_desc
;
4699 VNOP_BWRITE(struct buf
*bp
)
4702 struct vnop_bwrite_args a
;
4703 a
.a_desc
= &vnop_bwrite_desc
;
4705 _err
= (*buf_vnode(bp
)->v_op
[vnop_bwrite_desc
.vdesc_offset
])(&a
);
4710 struct vnop_kqfilt_add_args
{
4711 struct vnodeop_desc
*a_desc
;
4714 vfs_context_t a_context
;
4718 VNOP_KQFILT_ADD(struct vnode
*vp
, struct knote
*kn
, vfs_context_t context
)
4721 struct vnop_kqfilt_add_args a
;
4723 int funnel_state
= 0;
4725 a
.a_desc
= VDESC(vnop_kqfilt_add
);
4728 a
.a_context
= context
;
4729 thread_safe
= THREAD_SAFE_FS(vp
);
4732 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
4736 _err
= (*vp
->v_op
[vnop_kqfilt_add_desc
.vdesc_offset
])(&a
);
4738 unlock_fsnode(vp
, &funnel_state
);
4744 struct vnop_kqfilt_remove_args
{
4745 struct vnodeop_desc
*a_desc
;
4748 vfs_context_t a_context
;
4752 VNOP_KQFILT_REMOVE(struct vnode
*vp
, uintptr_t ident
, vfs_context_t context
)
4755 struct vnop_kqfilt_remove_args a
;
4757 int funnel_state
= 0;
4759 a
.a_desc
= VDESC(vnop_kqfilt_remove
);
4762 a
.a_context
= context
;
4763 thread_safe
= THREAD_SAFE_FS(vp
);
4766 if ( (_err
= lock_fsnode(vp
, &funnel_state
)) ) {
4770 _err
= (*vp
->v_op
[vnop_kqfilt_remove_desc
.vdesc_offset
])(&a
);
4772 unlock_fsnode(vp
, &funnel_state
);