2 * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
70 * support for mandatory and extensible security protections. This notice
71 * is included in support of clause 2.2 (b) of the Apple Public License,
76 * External virtual filesystem routines
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/proc_internal.h>
83 #include <sys/kauth.h>
84 #include <sys/mount.h>
85 #include <sys/mount_internal.h>
87 #include <sys/vnode_internal.h>
89 #include <sys/namei.h>
90 #include <sys/ucred.h>
92 #include <sys/errno.h>
93 #include <sys/malloc.h>
94 #include <sys/domain.h>
96 #include <sys/syslog.h>
99 #include <sys/sysctl.h>
100 #include <sys/filedesc.h>
101 #include <sys/event.h>
102 #include <sys/fsevents.h>
103 #include <sys/user.h>
104 #include <sys/lockf.h>
105 #include <sys/xattr.h>
107 #include <kern/assert.h>
108 #include <kern/kalloc.h>
109 #include <kern/task.h>
111 #include <libkern/OSByteOrder.h>
113 #include <miscfs/specfs/specdev.h>
115 #include <mach/mach_types.h>
116 #include <mach/memory_object_types.h>
117 #include <mach/task.h>
120 #include <security/mac_framework.h>
131 #define NATIVE_XATTR(VP) \
132 ((VP)->v_mount ? (VP)->v_mount->mnt_kern_flag & MNTK_EXTENDED_ATTRS : 0)
134 #if CONFIG_APPLEDOUBLE
135 static void xattrfile_remove(vnode_t dvp
, const char *basename
,
136 vfs_context_t ctx
, int force
);
137 static void xattrfile_setattr(vnode_t dvp
, const char * basename
,
138 struct vnode_attr
* vap
, vfs_context_t ctx
);
139 #endif /* CONFIG_APPLEDOUBLE */
142 * vnode_setneedinactive
144 * Description: Indicate that when the last iocount on this vnode goes away,
145 * and the usecount is also zero, we should inform the filesystem
148 * Parameters: vnode_t vnode to mark
152 * Notes: Notably used when we're deleting a file--we need not have a
153 * usecount, so VNOP_INACTIVE may not get called by anyone. We
154 * want it called when we drop our iocount.
157 vnode_setneedinactive(vnode_t vp
)
162 vp
->v_lflag
|= VL_NEEDINACTIVE
;
167 /* ====================================================================== */
168 /* ************ EXTERNAL KERNEL APIS ********************************** */
169 /* ====================================================================== */
172 * implementations of exported VFS operations
175 VFS_MOUNT(mount_t mp
, vnode_t devvp
, user_addr_t data
, vfs_context_t ctx
)
179 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_mount
== 0))
182 if (vfs_context_is64bit(ctx
)) {
183 if (vfs_64bitready(mp
)) {
184 error
= (*mp
->mnt_op
->vfs_mount
)(mp
, devvp
, data
, ctx
);
191 error
= (*mp
->mnt_op
->vfs_mount
)(mp
, devvp
, data
, ctx
);
198 VFS_START(mount_t mp
, int flags
, vfs_context_t ctx
)
202 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_start
== 0))
205 error
= (*mp
->mnt_op
->vfs_start
)(mp
, flags
, ctx
);
211 VFS_UNMOUNT(mount_t mp
, int flags
, vfs_context_t ctx
)
215 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_unmount
== 0))
218 error
= (*mp
->mnt_op
->vfs_unmount
)(mp
, flags
, ctx
);
225 * ENOTSUP Not supported
229 * Note: The return codes from the underlying VFS's root routine can't
230 * be fully enumerated here, since third party VFS authors may not
231 * limit their error returns to the ones documented here, even
232 * though this may result in some programs functioning incorrectly.
234 * The return codes documented above are those which may currently
235 * be returned by HFS from hfs_vfs_root, which is a simple wrapper
236 * for a call to hfs_vget on the volume mount poit, not including
237 * additional error codes which may be propagated from underlying
238 * routines called by hfs_vget.
241 VFS_ROOT(mount_t mp
, struct vnode
** vpp
, vfs_context_t ctx
)
245 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_root
== 0))
249 ctx
= vfs_context_current();
252 error
= (*mp
->mnt_op
->vfs_root
)(mp
, vpp
, ctx
);
258 VFS_QUOTACTL(mount_t mp
, int cmd
, uid_t uid
, caddr_t datap
, vfs_context_t ctx
)
262 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_quotactl
== 0))
265 error
= (*mp
->mnt_op
->vfs_quotactl
)(mp
, cmd
, uid
, datap
, ctx
);
271 VFS_GETATTR(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
275 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_getattr
== 0))
279 ctx
= vfs_context_current();
282 error
= (*mp
->mnt_op
->vfs_getattr
)(mp
, vfa
, ctx
);
288 VFS_SETATTR(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
292 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_setattr
== 0))
296 ctx
= vfs_context_current();
299 error
= (*mp
->mnt_op
->vfs_setattr
)(mp
, vfa
, ctx
);
305 VFS_SYNC(mount_t mp
, int flags
, vfs_context_t ctx
)
309 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_sync
== 0))
313 ctx
= vfs_context_current();
316 error
= (*mp
->mnt_op
->vfs_sync
)(mp
, flags
, ctx
);
322 VFS_VGET(mount_t mp
, ino64_t ino
, struct vnode
**vpp
, vfs_context_t ctx
)
326 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_vget
== 0))
330 ctx
= vfs_context_current();
333 error
= (*mp
->mnt_op
->vfs_vget
)(mp
, ino
, vpp
, ctx
);
339 VFS_FHTOVP(mount_t mp
, int fhlen
, unsigned char * fhp
, vnode_t
* vpp
, vfs_context_t ctx
)
343 if ((mp
== dead_mountp
) || (mp
->mnt_op
->vfs_fhtovp
== 0))
347 ctx
= vfs_context_current();
350 error
= (*mp
->mnt_op
->vfs_fhtovp
)(mp
, fhlen
, fhp
, vpp
, ctx
);
356 VFS_VPTOFH(struct vnode
* vp
, int *fhlenp
, unsigned char * fhp
, vfs_context_t ctx
)
360 if ((vp
->v_mount
== dead_mountp
) || (vp
->v_mount
->mnt_op
->vfs_vptofh
== 0))
364 ctx
= vfs_context_current();
367 error
= (*vp
->v_mount
->mnt_op
->vfs_vptofh
)(vp
, fhlenp
, fhp
, ctx
);
373 /* returns the cached throttle mask for the mount_t */
375 vfs_throttle_mask(mount_t mp
)
377 return(mp
->mnt_throttle_mask
);
380 /* returns a copy of vfs type name for the mount_t */
382 vfs_name(mount_t mp
, char * buffer
)
384 strncpy(buffer
, mp
->mnt_vtable
->vfc_name
, MFSNAMELEN
);
387 /* returns vfs type number for the mount_t */
389 vfs_typenum(mount_t mp
)
391 return(mp
->mnt_vtable
->vfc_typenum
);
394 /* Safe to cast to "struct label*"; returns "void*" to limit dependence of mount.h on security headers. */
396 vfs_mntlabel(mount_t mp
)
398 return (void*)mp
->mnt_mntlabel
;
401 /* returns command modifier flags of mount_t ie. MNT_CMDFLAGS */
403 vfs_flags(mount_t mp
)
405 return((uint64_t)(mp
->mnt_flag
& (MNT_CMDFLAGS
| MNT_VISFLAGMASK
)));
408 /* set any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
410 vfs_setflags(mount_t mp
, uint64_t flags
)
412 uint32_t lflags
= (uint32_t)(flags
& (MNT_CMDFLAGS
| MNT_VISFLAGMASK
));
415 mp
->mnt_flag
|= lflags
;
419 /* clear any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
421 vfs_clearflags(mount_t mp
, uint64_t flags
)
423 uint32_t lflags
= (uint32_t)(flags
& (MNT_CMDFLAGS
| MNT_VISFLAGMASK
));
426 mp
->mnt_flag
&= ~lflags
;
430 /* Is the mount_t ronly and upgrade read/write requested? */
432 vfs_iswriteupgrade(mount_t mp
) /* ronly && MNTK_WANTRDWR */
434 return ((mp
->mnt_flag
& MNT_RDONLY
) && (mp
->mnt_kern_flag
& MNTK_WANTRDWR
));
438 /* Is the mount_t mounted ronly */
440 vfs_isrdonly(mount_t mp
)
442 return (mp
->mnt_flag
& MNT_RDONLY
);
445 /* Is the mount_t mounted for filesystem synchronous writes? */
447 vfs_issynchronous(mount_t mp
)
449 return (mp
->mnt_flag
& MNT_SYNCHRONOUS
);
452 /* Is the mount_t mounted read/write? */
454 vfs_isrdwr(mount_t mp
)
456 return ((mp
->mnt_flag
& MNT_RDONLY
) == 0);
460 /* Is mount_t marked for update (ie MNT_UPDATE) */
462 vfs_isupdate(mount_t mp
)
464 return (mp
->mnt_flag
& MNT_UPDATE
);
468 /* Is mount_t marked for reload (ie MNT_RELOAD) */
470 vfs_isreload(mount_t mp
)
472 return ((mp
->mnt_flag
& MNT_UPDATE
) && (mp
->mnt_flag
& MNT_RELOAD
));
475 /* Is mount_t marked for forced unmount (ie MNT_FORCE or MNTK_FRCUNMOUNT) */
477 vfs_isforce(mount_t mp
)
479 if (mp
->mnt_lflag
& MNT_LFORCE
)
486 vfs_isunmount(mount_t mp
)
488 if ((mp
->mnt_lflag
& MNT_LUNMOUNT
)) {
496 vfs_64bitready(mount_t mp
)
498 if ((mp
->mnt_vtable
->vfc_vfsflags
& VFC_VFS64BITREADY
))
506 vfs_authcache_ttl(mount_t mp
)
508 if ( (mp
->mnt_kern_flag
& (MNTK_AUTH_OPAQUE
| MNTK_AUTH_CACHE_TTL
)) )
509 return (mp
->mnt_authcache_ttl
);
511 return (CACHED_RIGHT_INFINITE_TTL
);
515 vfs_setauthcache_ttl(mount_t mp
, int ttl
)
518 mp
->mnt_kern_flag
|= MNTK_AUTH_CACHE_TTL
;
519 mp
->mnt_authcache_ttl
= ttl
;
524 vfs_clearauthcache_ttl(mount_t mp
)
527 mp
->mnt_kern_flag
&= ~MNTK_AUTH_CACHE_TTL
;
529 * back to the default TTL value in case
530 * MNTK_AUTH_OPAQUE is set on this mount
532 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
537 vfs_authopaque(mount_t mp
)
539 if ((mp
->mnt_kern_flag
& MNTK_AUTH_OPAQUE
))
546 vfs_authopaqueaccess(mount_t mp
)
548 if ((mp
->mnt_kern_flag
& MNTK_AUTH_OPAQUE_ACCESS
))
555 vfs_setauthopaque(mount_t mp
)
558 mp
->mnt_kern_flag
|= MNTK_AUTH_OPAQUE
;
563 vfs_setauthopaqueaccess(mount_t mp
)
566 mp
->mnt_kern_flag
|= MNTK_AUTH_OPAQUE_ACCESS
;
571 vfs_clearauthopaque(mount_t mp
)
574 mp
->mnt_kern_flag
&= ~MNTK_AUTH_OPAQUE
;
579 vfs_clearauthopaqueaccess(mount_t mp
)
582 mp
->mnt_kern_flag
&= ~MNTK_AUTH_OPAQUE_ACCESS
;
587 vfs_setextendedsecurity(mount_t mp
)
590 mp
->mnt_kern_flag
|= MNTK_EXTENDED_SECURITY
;
595 vfs_clearextendedsecurity(mount_t mp
)
598 mp
->mnt_kern_flag
&= ~MNTK_EXTENDED_SECURITY
;
603 vfs_extendedsecurity(mount_t mp
)
605 return(mp
->mnt_kern_flag
& MNTK_EXTENDED_SECURITY
);
608 /* returns the max size of short symlink in this mount_t */
610 vfs_maxsymlen(mount_t mp
)
612 return(mp
->mnt_maxsymlinklen
);
615 /* set max size of short symlink on mount_t */
617 vfs_setmaxsymlen(mount_t mp
, uint32_t symlen
)
619 mp
->mnt_maxsymlinklen
= symlen
;
622 /* return a pointer to the RO vfs_statfs associated with mount_t */
624 vfs_statfs(mount_t mp
)
626 return(&mp
->mnt_vfsstat
);
630 vfs_getattr(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
634 if ((error
= VFS_GETATTR(mp
, vfa
, ctx
)) != 0)
638 * If we have a filesystem create time, use it to default some others.
640 if (VFSATTR_IS_SUPPORTED(vfa
, f_create_time
)) {
641 if (VFSATTR_IS_ACTIVE(vfa
, f_modify_time
) && !VFSATTR_IS_SUPPORTED(vfa
, f_modify_time
))
642 VFSATTR_RETURN(vfa
, f_modify_time
, vfa
->f_create_time
);
649 vfs_setattr(mount_t mp
, struct vfs_attr
*vfa
, vfs_context_t ctx
)
653 if (vfs_isrdonly(mp
))
656 error
= VFS_SETATTR(mp
, vfa
, ctx
);
659 * If we had alternate ways of setting vfs attributes, we'd
666 /* return the private data handle stored in mount_t */
668 vfs_fsprivate(mount_t mp
)
670 return(mp
->mnt_data
);
673 /* set the private data handle in mount_t */
675 vfs_setfsprivate(mount_t mp
, void *mntdata
)
678 mp
->mnt_data
= mntdata
;
682 /* query whether the mount point supports native EAs */
684 vfs_nativexattrs(mount_t mp
) {
685 return (mp
->mnt_kern_flag
& MNTK_EXTENDED_ATTRS
);
689 * return the block size of the underlying
690 * device associated with mount_t
693 vfs_devblocksize(mount_t mp
) {
695 return(mp
->mnt_devblocksize
);
699 * Returns vnode with an iocount that must be released with vnode_put()
702 vfs_vnodecovered(mount_t mp
)
704 vnode_t vp
= mp
->mnt_vnodecovered
;
705 if ((vp
== NULL
) || (vnode_getwithref(vp
) != 0)) {
713 * Returns device vnode backing a mountpoint with an iocount (if valid vnode exists).
714 * The iocount must be released with vnode_put(). Note that this KPI is subtle
715 * with respect to the validity of using this device vnode for anything substantial
716 * (which is discouraged). If commands are sent to the device driver without
717 * taking proper steps to ensure that the device is still open, chaos may ensue.
718 * Similarly, this routine should only be called if there is some guarantee that
719 * the mount itself is still valid.
722 vfs_devvp(mount_t mp
)
724 vnode_t vp
= mp
->mnt_devvp
;
726 if ((vp
!= NULLVP
) && (vnode_get(vp
) == 0)) {
734 * return the io attributes associated with mount_t
737 vfs_ioattr(mount_t mp
, struct vfsioattr
*ioattrp
)
740 ioattrp
->io_maxreadcnt
= MAXPHYS
;
741 ioattrp
->io_maxwritecnt
= MAXPHYS
;
742 ioattrp
->io_segreadcnt
= 32;
743 ioattrp
->io_segwritecnt
= 32;
744 ioattrp
->io_maxsegreadsize
= MAXPHYS
;
745 ioattrp
->io_maxsegwritesize
= MAXPHYS
;
746 ioattrp
->io_devblocksize
= DEV_BSIZE
;
747 ioattrp
->io_flags
= 0;
749 ioattrp
->io_maxreadcnt
= mp
->mnt_maxreadcnt
;
750 ioattrp
->io_maxwritecnt
= mp
->mnt_maxwritecnt
;
751 ioattrp
->io_segreadcnt
= mp
->mnt_segreadcnt
;
752 ioattrp
->io_segwritecnt
= mp
->mnt_segwritecnt
;
753 ioattrp
->io_maxsegreadsize
= mp
->mnt_maxsegreadsize
;
754 ioattrp
->io_maxsegwritesize
= mp
->mnt_maxsegwritesize
;
755 ioattrp
->io_devblocksize
= mp
->mnt_devblocksize
;
756 ioattrp
->io_flags
= mp
->mnt_ioflags
;
758 ioattrp
->io_reserved
[0] = NULL
;
759 ioattrp
->io_reserved
[1] = NULL
;
764 * set the IO attributes associated with mount_t
767 vfs_setioattr(mount_t mp
, struct vfsioattr
* ioattrp
)
771 mp
->mnt_maxreadcnt
= ioattrp
->io_maxreadcnt
;
772 mp
->mnt_maxwritecnt
= ioattrp
->io_maxwritecnt
;
773 mp
->mnt_segreadcnt
= ioattrp
->io_segreadcnt
;
774 mp
->mnt_segwritecnt
= ioattrp
->io_segwritecnt
;
775 mp
->mnt_maxsegreadsize
= ioattrp
->io_maxsegreadsize
;
776 mp
->mnt_maxsegwritesize
= ioattrp
->io_maxsegwritesize
;
777 mp
->mnt_devblocksize
= ioattrp
->io_devblocksize
;
778 mp
->mnt_ioflags
= ioattrp
->io_flags
;
782 * Add a new filesystem into the kernel specified in passed in
783 * vfstable structure. It fills in the vnode
784 * dispatch vector that is to be passed to when vnodes are created.
785 * It returns a handle which is to be used to when the FS is to be removed
787 typedef int (*PFI
)(void *);
788 extern int vfs_opv_numops
;
790 vfs_fsadd(struct vfs_fsentry
*vfe
, vfstable_t
* handle
)
792 struct vfstable
*newvfstbl
= NULL
;
794 int (***opv_desc_vector_p
)(void *);
795 int (**opv_desc_vector
)(void *);
796 struct vnodeopv_entry_desc
*opve_descp
;
802 * This routine is responsible for all the initialization that would
803 * ordinarily be done as part of the system startup;
806 if (vfe
== (struct vfs_fsentry
*)0)
809 desccount
= vfe
->vfe_vopcnt
;
810 if ((desccount
<=0) || ((desccount
> 8)) || (vfe
->vfe_vfsops
== (struct vfsops
*)NULL
)
811 || (vfe
->vfe_opvdescs
== (struct vnodeopv_desc
**)NULL
))
814 /* Non-threadsafe filesystems are not supported */
815 if ((vfe
->vfe_flags
& (VFS_TBLTHREADSAFE
| VFS_TBLFSNODELOCK
)) == 0) {
819 MALLOC(newvfstbl
, void *, sizeof(struct vfstable
), M_TEMP
,
821 bzero(newvfstbl
, sizeof(struct vfstable
));
822 newvfstbl
->vfc_vfsops
= vfe
->vfe_vfsops
;
823 strncpy(&newvfstbl
->vfc_name
[0], vfe
->vfe_fsname
, MFSNAMELEN
);
824 if ((vfe
->vfe_flags
& VFS_TBLNOTYPENUM
))
825 newvfstbl
->vfc_typenum
= maxvfstypenum
++;
827 newvfstbl
->vfc_typenum
= vfe
->vfe_fstypenum
;
829 newvfstbl
->vfc_refcount
= 0;
830 newvfstbl
->vfc_flags
= 0;
831 newvfstbl
->vfc_mountroot
= NULL
;
832 newvfstbl
->vfc_next
= NULL
;
833 newvfstbl
->vfc_vfsflags
= 0;
834 if (vfe
->vfe_flags
& VFS_TBL64BITREADY
)
835 newvfstbl
->vfc_vfsflags
|= VFC_VFS64BITREADY
;
836 if (vfe
->vfe_flags
& VFS_TBLVNOP_PAGEINV2
)
837 newvfstbl
->vfc_vfsflags
|= VFC_VFSVNOP_PAGEINV2
;
838 if (vfe
->vfe_flags
& VFS_TBLVNOP_PAGEOUTV2
)
839 newvfstbl
->vfc_vfsflags
|= VFC_VFSVNOP_PAGEOUTV2
;
840 if ((vfe
->vfe_flags
& VFS_TBLLOCALVOL
) == VFS_TBLLOCALVOL
)
841 newvfstbl
->vfc_flags
|= MNT_LOCAL
;
842 if ((vfe
->vfe_flags
& VFS_TBLLOCALVOL
) && (vfe
->vfe_flags
& VFS_TBLGENERICMNTARGS
) == 0)
843 newvfstbl
->vfc_vfsflags
|= VFC_VFSLOCALARGS
;
845 newvfstbl
->vfc_vfsflags
|= VFC_VFSGENERICARGS
;
847 if (vfe
->vfe_flags
& VFS_TBLNATIVEXATTR
)
848 newvfstbl
->vfc_vfsflags
|= VFC_VFSNATIVEXATTR
;
849 if (vfe
->vfe_flags
& VFS_TBLUNMOUNT_PREFLIGHT
)
850 newvfstbl
->vfc_vfsflags
|= VFC_VFSPREFLIGHT
;
851 if (vfe
->vfe_flags
& VFS_TBLREADDIR_EXTENDED
)
852 newvfstbl
->vfc_vfsflags
|= VFC_VFSREADDIR_EXTENDED
;
853 if (vfe
->vfe_flags
& VFS_TBLNOMACLABEL
)
854 newvfstbl
->vfc_vfsflags
|= VFC_VFSNOMACLABEL
;
855 if (vfe
->vfe_flags
& VFS_TBLVNOP_NOUPDATEID_RENAME
)
856 newvfstbl
->vfc_vfsflags
|= VFC_VFSVNOP_NOUPDATEID_RENAME
;
859 * Allocate and init the vectors.
860 * Also handle backwards compatibility.
862 * We allocate one large block to hold all <desccount>
863 * vnode operation vectors stored contiguously.
865 /* XXX - shouldn't be M_TEMP */
867 descsize
= desccount
* vfs_opv_numops
* sizeof(PFI
);
868 MALLOC(descptr
, PFI
*, descsize
,
870 bzero(descptr
, descsize
);
872 newvfstbl
->vfc_descptr
= descptr
;
873 newvfstbl
->vfc_descsize
= descsize
;
875 newvfstbl
->vfc_sysctl
= NULL
;
877 for (i
= 0; i
< desccount
; i
++ ) {
878 opv_desc_vector_p
= vfe
->vfe_opvdescs
[i
]->opv_desc_vector_p
;
880 * Fill in the caller's pointer to the start of the i'th vector.
881 * They'll need to supply it when calling vnode_create.
883 opv_desc_vector
= descptr
+ i
* vfs_opv_numops
;
884 *opv_desc_vector_p
= opv_desc_vector
;
886 for (j
= 0; vfe
->vfe_opvdescs
[i
]->opv_desc_ops
[j
].opve_op
; j
++) {
887 opve_descp
= &(vfe
->vfe_opvdescs
[i
]->opv_desc_ops
[j
]);
890 * Sanity check: is this operation listed
891 * in the list of operations? We check this
892 * by seeing if its offset is zero. Since
893 * the default routine should always be listed
894 * first, it should be the only one with a zero
895 * offset. Any other operation with a zero
896 * offset is probably not listed in
897 * vfs_op_descs, and so is probably an error.
899 * A panic here means the layer programmer
900 * has committed the all-too common bug
901 * of adding a new operation to the layer's
902 * list of vnode operations but
903 * not adding the operation to the system-wide
904 * list of supported operations.
906 if (opve_descp
->opve_op
->vdesc_offset
== 0 &&
907 opve_descp
->opve_op
->vdesc_offset
!= VOFFSET(vnop_default
)) {
908 printf("vfs_fsadd: operation %s not listed in %s.\n",
909 opve_descp
->opve_op
->vdesc_name
,
911 panic("vfs_fsadd: bad operation");
914 * Fill in this entry.
916 opv_desc_vector
[opve_descp
->opve_op
->vdesc_offset
] =
917 opve_descp
->opve_impl
;
922 * Finally, go back and replace unfilled routines
923 * with their default. (Sigh, an O(n^3) algorithm. I
924 * could make it better, but that'd be work, and n is small.)
926 opv_desc_vector_p
= vfe
->vfe_opvdescs
[i
]->opv_desc_vector_p
;
929 * Force every operations vector to have a default routine.
931 opv_desc_vector
= *opv_desc_vector_p
;
932 if (opv_desc_vector
[VOFFSET(vnop_default
)] == NULL
)
933 panic("vfs_fsadd: operation vector without default routine.");
934 for (j
= 0; j
< vfs_opv_numops
; j
++)
935 if (opv_desc_vector
[j
] == NULL
)
937 opv_desc_vector
[VOFFSET(vnop_default
)];
939 } /* end of each vnodeopv_desc parsing */
943 *handle
= vfstable_add(newvfstbl
);
945 if (newvfstbl
->vfc_typenum
<= maxvfstypenum
)
946 maxvfstypenum
= newvfstbl
->vfc_typenum
+ 1;
948 if (newvfstbl
->vfc_vfsops
->vfs_init
) {
950 bzero(&vfsc
, sizeof(struct vfsconf
));
951 vfsc
.vfc_reserved1
= 0;
952 bcopy((*handle
)->vfc_name
, vfsc
.vfc_name
, sizeof(vfsc
.vfc_name
));
953 vfsc
.vfc_typenum
= (*handle
)->vfc_typenum
;
954 vfsc
.vfc_refcount
= (*handle
)->vfc_refcount
;
955 vfsc
.vfc_flags
= (*handle
)->vfc_flags
;
956 vfsc
.vfc_reserved2
= 0;
957 vfsc
.vfc_reserved3
= 0;
959 (*newvfstbl
->vfc_vfsops
->vfs_init
)(&vfsc
);
962 FREE(newvfstbl
, M_TEMP
);
968 * Removes the filesystem from kernel.
969 * The argument passed in is the handle that was given when
970 * file system was added
973 vfs_fsremove(vfstable_t handle
)
975 struct vfstable
* vfstbl
= (struct vfstable
*)handle
;
976 void *old_desc
= NULL
;
979 /* Preflight check for any mounts */
981 if ( vfstbl
->vfc_refcount
!= 0 ) {
987 * save the old descriptor; the free cannot occur unconditionally,
988 * since vfstable_del() may fail.
990 if (vfstbl
->vfc_descptr
&& vfstbl
->vfc_descsize
) {
991 old_desc
= vfstbl
->vfc_descptr
;
993 err
= vfstable_del(vfstbl
);
997 /* free the descriptor if the delete was successful */
998 if (err
== 0 && old_desc
) {
999 FREE(old_desc
, M_TEMP
);
1006 vfs_context_pid(vfs_context_t ctx
)
1008 return (proc_pid(vfs_context_proc(ctx
)));
1012 vfs_context_suser(vfs_context_t ctx
)
1014 return (suser(ctx
->vc_ucred
, NULL
));
1018 * Return bit field of signals posted to all threads in the context's process.
1020 * XXX Signals should be tied to threads, not processes, for most uses of this
1024 vfs_context_issignal(vfs_context_t ctx
, sigset_t mask
)
1026 proc_t p
= vfs_context_proc(ctx
);
1028 return(proc_pendingsignals(p
, mask
));
1033 vfs_context_is64bit(vfs_context_t ctx
)
1035 proc_t proc
= vfs_context_proc(ctx
);
1038 return(proc_is64bit(proc
));
1046 * Description: Given a vfs_context_t, return the proc_t associated with it.
1048 * Parameters: vfs_context_t The context to use
1050 * Returns: proc_t The process for this context
1052 * Notes: This function will return the current_proc() if any of the
1053 * following conditions are true:
1055 * o The supplied context pointer is NULL
1056 * o There is no Mach thread associated with the context
1057 * o There is no Mach task associated with the Mach thread
1058 * o There is no proc_t associated with the Mach task
1059 * o The proc_t has no per process open file table
1060 * o The proc_t is post-vfork()
1062 * This causes this function to return a value matching as
1063 * closely as possible the previous behaviour, while at the
1064 * same time avoiding the task lending that results from vfork()
1067 vfs_context_proc(vfs_context_t ctx
)
1071 if (ctx
!= NULL
&& ctx
->vc_thread
!= NULL
)
1072 proc
= (proc_t
)get_bsdthreadtask_info(ctx
->vc_thread
);
1073 if (proc
!= NULL
&& (proc
->p_fd
== NULL
|| (proc
->p_lflag
& P_LVFORK
)))
1076 return(proc
== NULL
? current_proc() : proc
);
1080 * vfs_context_get_special_port
1082 * Description: Return the requested special port from the task associated
1083 * with the given context.
1085 * Parameters: vfs_context_t The context to use
1086 * int Index of special port
1087 * ipc_port_t * Pointer to returned port
1089 * Returns: kern_return_t see task_get_special_port()
1092 vfs_context_get_special_port(vfs_context_t ctx
, int which
, ipc_port_t
*portp
)
1096 if (ctx
!= NULL
&& ctx
->vc_thread
!= NULL
)
1097 task
= get_threadtask(ctx
->vc_thread
);
1099 return task_get_special_port(task
, which
, portp
);
1103 * vfs_context_set_special_port
1105 * Description: Set the requested special port in the task associated
1106 * with the given context.
1108 * Parameters: vfs_context_t The context to use
1109 * int Index of special port
1110 * ipc_port_t New special port
1112 * Returns: kern_return_t see task_set_special_port()
1115 vfs_context_set_special_port(vfs_context_t ctx
, int which
, ipc_port_t port
)
1119 if (ctx
!= NULL
&& ctx
->vc_thread
!= NULL
)
1120 task
= get_threadtask(ctx
->vc_thread
);
1122 return task_set_special_port(task
, which
, port
);
1126 * vfs_context_thread
1128 * Description: Return the Mach thread associated with a vfs_context_t
1130 * Parameters: vfs_context_t The context to use
1132 * Returns: thread_t The thread for this context, or
1133 * NULL, if there is not one.
1135 * Notes: NULL thread_t's are legal, but discouraged. They occur only
1136 * as a result of a static vfs_context_t declaration in a function
1137 * and will result in this function returning NULL.
1139 * This is intentional; this function should NOT return the
1140 * current_thread() in this case.
1143 vfs_context_thread(vfs_context_t ctx
)
1145 return(ctx
->vc_thread
);
1152 * Description: Returns a reference on the vnode for the current working
1153 * directory for the supplied context
1155 * Parameters: vfs_context_t The context to use
1157 * Returns: vnode_t The current working directory
1160 * Notes: The function first attempts to obtain the current directory
1161 * from the thread, and if it is not present there, falls back
1162 * to obtaining it from the process instead. If it can't be
1163 * obtained from either place, we return NULLVP.
1166 vfs_context_cwd(vfs_context_t ctx
)
1168 vnode_t cwd
= NULLVP
;
1170 if(ctx
!= NULL
&& ctx
->vc_thread
!= NULL
) {
1171 uthread_t uth
= get_bsdthread_info(ctx
->vc_thread
);
1175 * Get the cwd from the thread; if there isn't one, get it
1176 * from the process, instead.
1178 if ((cwd
= uth
->uu_cdir
) == NULLVP
&&
1179 (proc
= (proc_t
)get_bsdthreadtask_info(ctx
->vc_thread
)) != NULL
&&
1181 cwd
= proc
->p_fd
->fd_cdir
;
1188 * vfs_context_create
1190 * Description: Allocate and initialize a new context.
1192 * Parameters: vfs_context_t: Context to copy, or NULL for new
1194 * Returns: Pointer to new context
1196 * Notes: Copy cred and thread from argument, if available; else
1197 * initialize with current thread and new cred. Returns
1198 * with a reference held on the credential.
1201 vfs_context_create(vfs_context_t ctx
)
1203 vfs_context_t newcontext
;
1205 newcontext
= (vfs_context_t
)kalloc(sizeof(struct vfs_context
));
1208 kauth_cred_t safecred
;
1210 newcontext
->vc_thread
= ctx
->vc_thread
;
1211 safecred
= ctx
->vc_ucred
;
1213 newcontext
->vc_thread
= current_thread();
1214 safecred
= kauth_cred_get();
1216 if (IS_VALID_CRED(safecred
))
1217 kauth_cred_ref(safecred
);
1218 newcontext
->vc_ucred
= safecred
;
1226 vfs_context_current(void)
1228 vfs_context_t ctx
= NULL
;
1229 volatile uthread_t ut
= (uthread_t
)get_bsdthread_info(current_thread());
1232 if (ut
->uu_context
.vc_ucred
!= NULL
) {
1233 ctx
= &ut
->uu_context
;
1237 return(ctx
== NULL
? vfs_context_kernel() : ctx
);
1244 * Dangerous hack - adopt the first kernel thread as the current thread, to
1245 * get to the vfs_context_t in the uthread associated with a kernel thread.
1246 * This is used by UDF to make the call into IOCDMediaBSDClient,
1247 * IOBDMediaBSDClient, and IODVDMediaBSDClient to determine whether the
1248 * ioctl() is being called from kernel or user space (and all this because
1249 * we do not pass threads into our ioctl()'s, instead of processes).
1251 * This is also used by imageboot_setup(), called early from bsd_init() after
1252 * kernproc has been given a credential.
1254 * Note: The use of proc_thread() here is a convenience to avoid inclusion
1255 * of many Mach headers to do the reference directly rather than indirectly;
1256 * we will need to forego this convenience when we reture proc_thread().
1258 static struct vfs_context kerncontext
;
1260 vfs_context_kernel(void)
1262 if (kerncontext
.vc_ucred
== NOCRED
)
1263 kerncontext
.vc_ucred
= kernproc
->p_ucred
;
1264 if (kerncontext
.vc_thread
== NULL
)
1265 kerncontext
.vc_thread
= proc_thread(kernproc
);
1267 return(&kerncontext
);
1272 vfs_context_rele(vfs_context_t ctx
)
1275 if (IS_VALID_CRED(ctx
->vc_ucred
))
1276 kauth_cred_unref(&ctx
->vc_ucred
);
1277 kfree(ctx
, sizeof(struct vfs_context
));
1284 vfs_context_ucred(vfs_context_t ctx
)
1286 return (ctx
->vc_ucred
);
1290 * Return true if the context is owned by the superuser.
1293 vfs_context_issuser(vfs_context_t ctx
)
1295 return(kauth_cred_issuser(vfs_context_ucred(ctx
)));
1299 * Given a context, for all fields of vfs_context_t which
1300 * are not held with a reference, set those fields to the
1301 * values for the current execution context. Currently, this
1302 * just means the vc_thread.
1304 * Returns: 0 for success, nonzero for failure
1306 * The intended use is:
1307 * 1. vfs_context_create() gets the caller a context
1308 * 2. vfs_context_bind() sets the unrefcounted data
1309 * 3. vfs_context_rele() releases the context
1313 vfs_context_bind(vfs_context_t ctx
)
1315 ctx
->vc_thread
= current_thread();
1319 /* XXXXXXXXXXXXXX VNODE KAPIS XXXXXXXXXXXXXXXXXXXXXXXXX */
1323 * Convert between vnode types and inode formats (since POSIX.1
1324 * defines mode word of stat structure in terms of inode formats).
1327 vnode_iftovt(int mode
)
1329 return(iftovt_tab
[((mode
) & S_IFMT
) >> 12]);
1333 vnode_vttoif(enum vtype indx
)
1335 return(vttoif_tab
[(int)(indx
)]);
1339 vnode_makeimode(int indx
, int mode
)
1341 return (int)(VTTOIF(indx
) | (mode
));
1346 * vnode manipulation functions.
1349 /* returns system root vnode iocount; It should be released using vnode_put() */
1355 error
= vnode_get(rootvnode
);
1357 return ((vnode_t
)0);
1364 vnode_vid(vnode_t vp
)
1366 return ((uint32_t)(vp
->v_id
));
1370 vnode_mount(vnode_t vp
)
1372 return (vp
->v_mount
);
1377 vnode_mountdevvp(vnode_t vp
)
1380 return (vp
->v_mount
->mnt_devvp
);
1382 return ((vnode_t
)0);
1387 vnode_mountedhere(vnode_t vp
)
1391 if ((vp
->v_type
== VDIR
) && ((mp
= vp
->v_mountedhere
) != NULL
) &&
1392 (mp
->mnt_vnodecovered
== vp
))
1395 return (mount_t
)NULL
;
1398 /* returns vnode type of vnode_t */
1400 vnode_vtype(vnode_t vp
)
1402 return (vp
->v_type
);
1405 /* returns FS specific node saved in vnode */
1407 vnode_fsnode(vnode_t vp
)
1409 return (vp
->v_data
);
1413 vnode_clearfsnode(vnode_t vp
)
1419 vnode_specrdev(vnode_t vp
)
1425 /* Accessor functions */
1426 /* is vnode_t a root vnode */
1428 vnode_isvroot(vnode_t vp
)
1430 return ((vp
->v_flag
& VROOT
)? 1 : 0);
1433 /* is vnode_t a system vnode */
1435 vnode_issystem(vnode_t vp
)
1437 return ((vp
->v_flag
& VSYSTEM
)? 1 : 0);
1440 /* is vnode_t a swap file vnode */
1442 vnode_isswap(vnode_t vp
)
1444 return ((vp
->v_flag
& VSWAP
)? 1 : 0);
1447 /* is vnode_t a tty */
1449 vnode_istty(vnode_t vp
)
1451 return ((vp
->v_flag
& VISTTY
) ? 1 : 0);
1454 /* if vnode_t mount operation in progress */
1456 vnode_ismount(vnode_t vp
)
1458 return ((vp
->v_flag
& VMOUNT
)? 1 : 0);
1461 /* is this vnode under recyle now */
1463 vnode_isrecycled(vnode_t vp
)
1467 vnode_lock_spin(vp
);
1468 ret
= (vp
->v_lflag
& (VL_TERMINATE
|VL_DEAD
))? 1 : 0;
1473 /* vnode was created by background task requesting rapid aging
1474 and has not since been referenced by a normal task */
1476 vnode_israge(vnode_t vp
)
1478 return ((vp
->v_flag
& VRAGE
)? 1 : 0);
1482 vnode_needssnapshots(vnode_t vp
)
1484 return ((vp
->v_flag
& VNEEDSSNAPSHOT
)? 1 : 0);
1488 /* Check the process/thread to see if we should skip atime updates */
1490 vfs_ctx_skipatime (vfs_context_t ctx
) {
1495 proc
= vfs_context_proc(ctx
);
1496 thr
= vfs_context_thread (ctx
);
1498 /* Validate pointers in case we were invoked via a kernel context */
1500 ut
= get_bsdthread_info (thr
);
1502 if (proc
->p_lflag
& P_LRAGE_VNODES
) {
1507 if (ut
->uu_flag
& UT_RAGE_VNODES
) {
1515 /* is vnode_t marked to not keep data cached once it's been consumed */
1517 vnode_isnocache(vnode_t vp
)
1519 return ((vp
->v_flag
& VNOCACHE_DATA
)? 1 : 0);
1523 * has sequential readahead been disabled on this vnode
1526 vnode_isnoreadahead(vnode_t vp
)
1528 return ((vp
->v_flag
& VRAOFF
)? 1 : 0);
1532 vnode_is_openevt(vnode_t vp
)
1534 return ((vp
->v_flag
& VOPENEVT
)? 1 : 0);
1537 /* is vnode_t a standard one? */
1539 vnode_isstandard(vnode_t vp
)
1541 return ((vp
->v_flag
& VSTANDARD
)? 1 : 0);
1544 /* don't vflush() if SKIPSYSTEM */
1546 vnode_isnoflush(vnode_t vp
)
1548 return ((vp
->v_flag
& VNOFLUSH
)? 1 : 0);
1551 /* is vnode_t a regular file */
1553 vnode_isreg(vnode_t vp
)
1555 return ((vp
->v_type
== VREG
)? 1 : 0);
1558 /* is vnode_t a directory? */
1560 vnode_isdir(vnode_t vp
)
1562 return ((vp
->v_type
== VDIR
)? 1 : 0);
1565 /* is vnode_t a symbolic link ? */
1567 vnode_islnk(vnode_t vp
)
1569 return ((vp
->v_type
== VLNK
)? 1 : 0);
1573 vnode_lookup_continue_needed(vnode_t vp
, struct componentname
*cnp
)
1575 struct nameidata
*ndp
= cnp
->cn_ndp
;
1578 panic("vnode_lookup_continue_needed(): cnp->cn_ndp is NULL\n");
1581 if (vnode_isdir(vp
)) {
1582 if (vp
->v_mountedhere
!= NULL
) {
1587 if (vp
->v_resolve
) {
1590 #endif /* CONFIG_TRIGGERS */
1595 if (vnode_islnk(vp
)) {
1596 /* From lookup(): || *ndp->ni_next == '/') No need for this, we know we're NULL-terminated here */
1597 if (cnp
->cn_flags
& FOLLOW
) {
1600 if (ndp
->ni_flag
& NAMEI_TRAILINGSLASH
) {
1608 ndp
->ni_flag
|= NAMEI_CONTLOOKUP
;
1609 return EKEEPLOOKING
;
1612 /* is vnode_t a fifo ? */
1614 vnode_isfifo(vnode_t vp
)
1616 return ((vp
->v_type
== VFIFO
)? 1 : 0);
1619 /* is vnode_t a block device? */
1621 vnode_isblk(vnode_t vp
)
1623 return ((vp
->v_type
== VBLK
)? 1 : 0);
1627 vnode_isspec(vnode_t vp
)
1629 return (((vp
->v_type
== VCHR
) || (vp
->v_type
== VBLK
)) ? 1 : 0);
1632 /* is vnode_t a char device? */
1634 vnode_ischr(vnode_t vp
)
1636 return ((vp
->v_type
== VCHR
)? 1 : 0);
1639 /* is vnode_t a socket? */
1641 vnode_issock(vnode_t vp
)
1643 return ((vp
->v_type
== VSOCK
)? 1 : 0);
1646 /* is vnode_t a device with multiple active vnodes referring to it? */
1648 vnode_isaliased(vnode_t vp
)
1650 enum vtype vt
= vp
->v_type
;
1651 if (!((vt
== VCHR
) || (vt
== VBLK
))) {
1654 return (vp
->v_specflags
& SI_ALIASED
);
1658 /* is vnode_t a named stream? */
1660 vnode_isnamedstream(
1669 return ((vp
->v_flag
& VISNAMEDSTREAM
) ? 1 : 0);
1685 return ((vp
->v_flag
& VISSHADOW
) ? 1 : 0);
1691 /* does vnode have associated named stream vnodes ? */
1693 vnode_hasnamedstreams(
1702 return ((vp
->v_lflag
& VL_HASSTREAMS
) ? 1 : 0);
1707 /* TBD: set vnode_t to not cache data after it is consumed once; used for quota */
1709 vnode_setnocache(vnode_t vp
)
1711 vnode_lock_spin(vp
);
1712 vp
->v_flag
|= VNOCACHE_DATA
;
1717 vnode_clearnocache(vnode_t vp
)
1719 vnode_lock_spin(vp
);
1720 vp
->v_flag
&= ~VNOCACHE_DATA
;
1725 vnode_set_openevt(vnode_t vp
)
1727 vnode_lock_spin(vp
);
1728 vp
->v_flag
|= VOPENEVT
;
1733 vnode_clear_openevt(vnode_t vp
)
1735 vnode_lock_spin(vp
);
1736 vp
->v_flag
&= ~VOPENEVT
;
1742 vnode_setnoreadahead(vnode_t vp
)
1744 vnode_lock_spin(vp
);
1745 vp
->v_flag
|= VRAOFF
;
1750 vnode_clearnoreadahead(vnode_t vp
)
1752 vnode_lock_spin(vp
);
1753 vp
->v_flag
&= ~VRAOFF
;
1758 /* mark vnode_t to skip vflush() is SKIPSYSTEM */
1760 vnode_setnoflush(vnode_t vp
)
1762 vnode_lock_spin(vp
);
1763 vp
->v_flag
|= VNOFLUSH
;
1768 vnode_clearnoflush(vnode_t vp
)
1770 vnode_lock_spin(vp
);
1771 vp
->v_flag
&= ~VNOFLUSH
;
1776 /* is vnode_t a blkdevice and has a FS mounted on it */
1778 vnode_ismountedon(vnode_t vp
)
1780 return ((vp
->v_specflags
& SI_MOUNTEDON
)? 1 : 0);
1784 vnode_setmountedon(vnode_t vp
)
1786 vnode_lock_spin(vp
);
1787 vp
->v_specflags
|= SI_MOUNTEDON
;
1792 vnode_clearmountedon(vnode_t vp
)
1794 vnode_lock_spin(vp
);
1795 vp
->v_specflags
&= ~SI_MOUNTEDON
;
1801 vnode_settag(vnode_t vp
, int tag
)
1808 vnode_tag(vnode_t vp
)
1814 vnode_parent(vnode_t vp
)
1817 return(vp
->v_parent
);
1821 vnode_setparent(vnode_t vp
, vnode_t dvp
)
1827 vnode_setname(vnode_t vp
, char * name
)
1832 /* return the registered FS name when adding the FS to kernel */
1834 vnode_vfsname(vnode_t vp
, char * buf
)
1836 strncpy(buf
, vp
->v_mount
->mnt_vtable
->vfc_name
, MFSNAMELEN
);
1839 /* return the FS type number */
1841 vnode_vfstypenum(vnode_t vp
)
1843 return(vp
->v_mount
->mnt_vtable
->vfc_typenum
);
1847 vnode_vfs64bitready(vnode_t vp
)
1851 * Checking for dead_mountp is a bit of a hack for SnowLeopard: <rdar://problem/6269051>
1853 if ((vp
->v_mount
!= dead_mountp
) && (vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFS64BITREADY
))
1861 /* return the visible flags on associated mount point of vnode_t */
1863 vnode_vfsvisflags(vnode_t vp
)
1865 return(vp
->v_mount
->mnt_flag
& MNT_VISFLAGMASK
);
1868 /* return the command modifier flags on associated mount point of vnode_t */
1870 vnode_vfscmdflags(vnode_t vp
)
1872 return(vp
->v_mount
->mnt_flag
& MNT_CMDFLAGS
);
1875 /* return the max symlink of short links of vnode_t */
1877 vnode_vfsmaxsymlen(vnode_t vp
)
1879 return(vp
->v_mount
->mnt_maxsymlinklen
);
1882 /* return a pointer to the RO vfs_statfs associated with vnode_t's mount point */
1884 vnode_vfsstatfs(vnode_t vp
)
1886 return(&vp
->v_mount
->mnt_vfsstat
);
1889 /* return a handle to the FSs specific private handle associated with vnode_t's mount point */
1891 vnode_vfsfsprivate(vnode_t vp
)
1893 return(vp
->v_mount
->mnt_data
);
1896 /* is vnode_t in a rdonly mounted FS */
1898 vnode_vfsisrdonly(vnode_t vp
)
1900 return ((vp
->v_mount
->mnt_flag
& MNT_RDONLY
)? 1 : 0);
1904 vnode_compound_rename_available(vnode_t vp
)
1906 return vnode_compound_op_available(vp
, COMPOUND_VNOP_RENAME
);
1909 vnode_compound_rmdir_available(vnode_t vp
)
1911 return vnode_compound_op_available(vp
, COMPOUND_VNOP_RMDIR
);
1914 vnode_compound_mkdir_available(vnode_t vp
)
1916 return vnode_compound_op_available(vp
, COMPOUND_VNOP_MKDIR
);
1919 vnode_compound_remove_available(vnode_t vp
)
1921 return vnode_compound_op_available(vp
, COMPOUND_VNOP_REMOVE
);
1924 vnode_compound_open_available(vnode_t vp
)
1926 return vnode_compound_op_available(vp
, COMPOUND_VNOP_OPEN
);
1930 vnode_compound_op_available(vnode_t vp
, compound_vnop_id_t opid
)
1932 return ((vp
->v_mount
->mnt_compound_ops
& opid
) != 0);
1936 * Returns vnode ref to current working directory; if a per-thread current
1937 * working directory is in effect, return that instead of the per process one.
1939 * XXX Published, but not used.
1942 current_workingdir(void)
1944 return vfs_context_cwd(vfs_context_current());
1947 /* returns vnode ref to current root(chroot) directory */
1949 current_rootdir(void)
1951 proc_t proc
= current_proc();
1954 if ( (vp
= proc
->p_fd
->fd_rdir
) ) {
1955 if ( (vnode_getwithref(vp
)) )
1962 * Get a filesec and optional acl contents from an extended attribute.
1963 * Function will attempt to retrive ACL, UUID, and GUID information using a
1964 * read of a named extended attribute (KAUTH_FILESEC_XATTR).
1966 * Parameters: vp The vnode on which to operate.
1967 * fsecp The filesec (and ACL, if any) being
1969 * ctx The vnode context in which the
1970 * operation is to be attempted.
1972 * Returns: 0 Success
1975 * Notes: The kauth_filesec_t in '*fsecp', if retrieved, will be in
1976 * host byte order, as will be the ACL contents, if any.
1977 * Internally, we will cannonize these values from network (PPC)
1978 * byte order after we retrieve them so that the on-disk contents
1979 * of the extended attribute are identical for both PPC and Intel
1980 * (if we were not being required to provide this service via
1981 * fallback, this would be the job of the filesystem
1982 * 'VNOP_GETATTR' call).
1984 * We use ntohl() because it has a transitive property on Intel
1985 * machines and no effect on PPC mancines. This guarantees us
1987 * XXX: Deleting rather than ignoreing a corrupt security structure is
1988 * probably the only way to reset it without assistance from an
1989 * file system integrity checking tool. Right now we ignore it.
1991 * XXX: We should enummerate the possible errno values here, and where
1992 * in the code they originated.
1995 vnode_get_filesec(vnode_t vp
, kauth_filesec_t
*fsecp
, vfs_context_t ctx
)
1997 kauth_filesec_t fsec
;
2000 size_t xsize
, rsize
;
2002 uint32_t host_fsec_magic
;
2003 uint32_t host_acl_entrycount
;
2009 /* find out how big the EA is */
2010 if (vn_getxattr(vp
, KAUTH_FILESEC_XATTR
, NULL
, &xsize
, XATTR_NOSECURITY
, ctx
) != 0) {
2011 /* no EA, no filesec */
2012 if ((error
== ENOATTR
) || (error
== ENOENT
) || (error
== EJUSTRETURN
))
2014 /* either way, we are done */
2019 * To be valid, a kauth_filesec_t must be large enough to hold a zero
2020 * ACE entrly ACL, and if it's larger than that, it must have the right
2021 * number of bytes such that it contains an atomic number of ACEs,
2022 * rather than partial entries. Otherwise, we ignore it.
2024 if (!KAUTH_FILESEC_VALID(xsize
)) {
2025 KAUTH_DEBUG(" ERROR - Bogus kauth_fiilesec_t: %ld bytes", xsize
);
2030 /* how many entries would fit? */
2031 fsec_size
= KAUTH_FILESEC_COUNT(xsize
);
2033 /* get buffer and uio */
2034 if (((fsec
= kauth_filesec_alloc(fsec_size
)) == NULL
) ||
2035 ((fsec_uio
= uio_create(1, 0, UIO_SYSSPACE
, UIO_READ
)) == NULL
) ||
2036 uio_addiov(fsec_uio
, CAST_USER_ADDR_T(fsec
), xsize
)) {
2037 KAUTH_DEBUG(" ERROR - could not allocate iov to read ACL");
2042 /* read security attribute */
2044 if ((error
= vn_getxattr(vp
,
2045 KAUTH_FILESEC_XATTR
,
2051 /* no attribute - no security data */
2052 if ((error
== ENOATTR
) || (error
== ENOENT
) || (error
== EJUSTRETURN
))
2054 /* either way, we are done */
2059 * Validate security structure; the validation must take place in host
2060 * byte order. If it's corrupt, we will just ignore it.
2063 /* Validate the size before trying to convert it */
2064 if (rsize
< KAUTH_FILESEC_SIZE(0)) {
2065 KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize
);
2069 /* Validate the magic number before trying to convert it */
2070 host_fsec_magic
= ntohl(KAUTH_FILESEC_MAGIC
);
2071 if (fsec
->fsec_magic
!= host_fsec_magic
) {
2072 KAUTH_DEBUG("ACL - BAD MAGIC %x", host_fsec_magic
);
2076 /* Validate the entry count before trying to convert it. */
2077 host_acl_entrycount
= ntohl(fsec
->fsec_acl
.acl_entrycount
);
2078 if (host_acl_entrycount
!= KAUTH_FILESEC_NOACL
) {
2079 if (host_acl_entrycount
> KAUTH_ACL_MAX_ENTRIES
) {
2080 KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", host_acl_entrycount
);
2083 if (KAUTH_FILESEC_SIZE(host_acl_entrycount
) > rsize
) {
2084 KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", host_acl_entrycount
, rsize
);
2089 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST
, fsec
, NULL
);
2096 kauth_filesec_free(fsec
);
2097 if (fsec_uio
!= NULL
)
2105 * Set a filesec and optional acl contents into an extended attribute.
2106 * function will attempt to store ACL, UUID, and GUID information using a
2107 * write to a named extended attribute (KAUTH_FILESEC_XATTR). The 'acl'
2108 * may or may not point to the `fsec->fsec_acl`, depending on whether the
2109 * original caller supplied an acl.
2111 * Parameters: vp The vnode on which to operate.
2112 * fsec The filesec being set.
2113 * acl The acl to be associated with 'fsec'.
2114 * ctx The vnode context in which the
2115 * operation is to be attempted.
2117 * Returns: 0 Success
2120 * Notes: Both the fsec and the acl are always valid.
2122 * The kauth_filesec_t in 'fsec', if any, is in host byte order,
2123 * as are the acl contents, if they are used. Internally, we will
2124 * cannonize these values into network (PPC) byte order before we
2125 * attempt to write them so that the on-disk contents of the
2126 * extended attribute are identical for both PPC and Intel (if we
2127 * were not being required to provide this service via fallback,
2128 * this would be the job of the filesystem 'VNOP_SETATTR' call).
2129 * We reverse this process on the way out, so we leave with the
2130 * same byte order we started with.
2132 * XXX: We should enummerate the possible errno values here, and where
2133 * in the code they originated.
2136 vnode_set_filesec(vnode_t vp
, kauth_filesec_t fsec
, kauth_acl_t acl
, vfs_context_t ctx
)
2140 uint32_t saved_acl_copysize
;
2144 if ((fsec_uio
= uio_create(2, 0, UIO_SYSSPACE
, UIO_WRITE
)) == NULL
) {
2145 KAUTH_DEBUG(" ERROR - could not allocate iov to write ACL");
2150 * Save the pre-converted ACL copysize, because it gets swapped too
2151 * if we are running with the wrong endianness.
2153 saved_acl_copysize
= KAUTH_ACL_COPYSIZE(acl
);
2155 kauth_filesec_acl_setendian(KAUTH_ENDIAN_DISK
, fsec
, acl
);
2157 uio_addiov(fsec_uio
, CAST_USER_ADDR_T(fsec
), KAUTH_FILESEC_SIZE(0) - KAUTH_ACL_SIZE(KAUTH_FILESEC_NOACL
));
2158 uio_addiov(fsec_uio
, CAST_USER_ADDR_T(acl
), saved_acl_copysize
);
2159 error
= vn_setxattr(vp
,
2160 KAUTH_FILESEC_XATTR
,
2162 XATTR_NOSECURITY
, /* we have auth'ed already */
2164 VFS_DEBUG(ctx
, vp
, "SETATTR - set ACL returning %d", error
);
2166 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST
, fsec
, acl
);
2169 if (fsec_uio
!= NULL
)
2176 * Returns: 0 Success
2177 * ENOMEM Not enough space [only if has filesec]
2179 * vnode_get_filesec: ???
2180 * kauth_cred_guid2uid: ???
2181 * kauth_cred_guid2gid: ???
2182 * vfs_update_vfsstat: ???
2185 vnode_getattr(vnode_t vp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
2187 kauth_filesec_t fsec
;
2193 /* don't ask for extended security data if the filesystem doesn't support it */
2194 if (!vfs_extendedsecurity(vnode_mount(vp
))) {
2195 VATTR_CLEAR_ACTIVE(vap
, va_acl
);
2196 VATTR_CLEAR_ACTIVE(vap
, va_uuuid
);
2197 VATTR_CLEAR_ACTIVE(vap
, va_guuid
);
2201 * If the caller wants size values we might have to synthesise, give the
2202 * filesystem the opportunity to supply better intermediate results.
2204 if (VATTR_IS_ACTIVE(vap
, va_data_alloc
) ||
2205 VATTR_IS_ACTIVE(vap
, va_total_size
) ||
2206 VATTR_IS_ACTIVE(vap
, va_total_alloc
)) {
2207 VATTR_SET_ACTIVE(vap
, va_data_size
);
2208 VATTR_SET_ACTIVE(vap
, va_data_alloc
);
2209 VATTR_SET_ACTIVE(vap
, va_total_size
);
2210 VATTR_SET_ACTIVE(vap
, va_total_alloc
);
2213 error
= VNOP_GETATTR(vp
, vap
, ctx
);
2215 KAUTH_DEBUG("ERROR - returning %d", error
);
2220 * If extended security data was requested but not returned, try the fallback
2223 if (VATTR_NOT_RETURNED(vap
, va_acl
) || VATTR_NOT_RETURNED(vap
, va_uuuid
) || VATTR_NOT_RETURNED(vap
, va_guuid
)) {
2226 if (XATTR_VNODE_SUPPORTED(vp
)) {
2227 /* try to get the filesec */
2228 if ((error
= vnode_get_filesec(vp
, &fsec
, ctx
)) != 0)
2231 /* if no filesec, no attributes */
2233 VATTR_RETURN(vap
, va_acl
, NULL
);
2234 VATTR_RETURN(vap
, va_uuuid
, kauth_null_guid
);
2235 VATTR_RETURN(vap
, va_guuid
, kauth_null_guid
);
2238 /* looks good, try to return what we were asked for */
2239 VATTR_RETURN(vap
, va_uuuid
, fsec
->fsec_owner
);
2240 VATTR_RETURN(vap
, va_guuid
, fsec
->fsec_group
);
2242 /* only return the ACL if we were actually asked for it */
2243 if (VATTR_IS_ACTIVE(vap
, va_acl
)) {
2244 if (fsec
->fsec_acl
.acl_entrycount
== KAUTH_FILESEC_NOACL
) {
2245 VATTR_RETURN(vap
, va_acl
, NULL
);
2247 facl
= kauth_acl_alloc(fsec
->fsec_acl
.acl_entrycount
);
2249 kauth_filesec_free(fsec
);
2253 bcopy(&fsec
->fsec_acl
, facl
, KAUTH_ACL_COPYSIZE(&fsec
->fsec_acl
));
2254 VATTR_RETURN(vap
, va_acl
, facl
);
2257 kauth_filesec_free(fsec
);
2261 * If someone gave us an unsolicited filesec, toss it. We promise that
2262 * we're OK with a filesystem giving us anything back, but our callers
2263 * only expect what they asked for.
2265 if (VATTR_IS_SUPPORTED(vap
, va_acl
) && !VATTR_IS_ACTIVE(vap
, va_acl
)) {
2266 if (vap
->va_acl
!= NULL
)
2267 kauth_acl_free(vap
->va_acl
);
2268 VATTR_CLEAR_SUPPORTED(vap
, va_acl
);
2271 #if 0 /* enable when we have a filesystem only supporting UUIDs */
2273 * Handle the case where we need a UID/GID, but only have extended
2274 * security information.
2276 if (VATTR_NOT_RETURNED(vap
, va_uid
) &&
2277 VATTR_IS_SUPPORTED(vap
, va_uuuid
) &&
2278 !kauth_guid_equal(&vap
->va_uuuid
, &kauth_null_guid
)) {
2279 if ((error
= kauth_cred_guid2uid(&vap
->va_uuuid
, &nuid
)) == 0)
2280 VATTR_RETURN(vap
, va_uid
, nuid
);
2282 if (VATTR_NOT_RETURNED(vap
, va_gid
) &&
2283 VATTR_IS_SUPPORTED(vap
, va_guuid
) &&
2284 !kauth_guid_equal(&vap
->va_guuid
, &kauth_null_guid
)) {
2285 if ((error
= kauth_cred_guid2gid(&vap
->va_guuid
, &ngid
)) == 0)
2286 VATTR_RETURN(vap
, va_gid
, ngid
);
2291 * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
2293 if (VATTR_IS_ACTIVE(vap
, va_uid
)) {
2294 if (vfs_context_issuser(ctx
) && VATTR_IS_SUPPORTED(vap
, va_uid
)) {
2296 } else if (vp
->v_mount
->mnt_flag
& MNT_IGNORE_OWNERSHIP
) {
2297 nuid
= vp
->v_mount
->mnt_fsowner
;
2298 if (nuid
== KAUTH_UID_NONE
)
2300 } else if (VATTR_IS_SUPPORTED(vap
, va_uid
)) {
2303 /* this will always be something sensible */
2304 nuid
= vp
->v_mount
->mnt_fsowner
;
2306 if ((nuid
== 99) && !vfs_context_issuser(ctx
))
2307 nuid
= kauth_cred_getuid(vfs_context_ucred(ctx
));
2308 VATTR_RETURN(vap
, va_uid
, nuid
);
2310 if (VATTR_IS_ACTIVE(vap
, va_gid
)) {
2311 if (vfs_context_issuser(ctx
) && VATTR_IS_SUPPORTED(vap
, va_gid
)) {
2313 } else if (vp
->v_mount
->mnt_flag
& MNT_IGNORE_OWNERSHIP
) {
2314 ngid
= vp
->v_mount
->mnt_fsgroup
;
2315 if (ngid
== KAUTH_GID_NONE
)
2317 } else if (VATTR_IS_SUPPORTED(vap
, va_gid
)) {
2320 /* this will always be something sensible */
2321 ngid
= vp
->v_mount
->mnt_fsgroup
;
2323 if ((ngid
== 99) && !vfs_context_issuser(ctx
))
2324 ngid
= kauth_cred_getgid(vfs_context_ucred(ctx
));
2325 VATTR_RETURN(vap
, va_gid
, ngid
);
2329 * Synthesise some values that can be reasonably guessed.
2331 if (!VATTR_IS_SUPPORTED(vap
, va_iosize
))
2332 VATTR_RETURN(vap
, va_iosize
, vp
->v_mount
->mnt_vfsstat
.f_iosize
);
2334 if (!VATTR_IS_SUPPORTED(vap
, va_flags
))
2335 VATTR_RETURN(vap
, va_flags
, 0);
2337 if (!VATTR_IS_SUPPORTED(vap
, va_filerev
))
2338 VATTR_RETURN(vap
, va_filerev
, 0);
2340 if (!VATTR_IS_SUPPORTED(vap
, va_gen
))
2341 VATTR_RETURN(vap
, va_gen
, 0);
2344 * Default sizes. Ordering here is important, as later defaults build on earlier ones.
2346 if (!VATTR_IS_SUPPORTED(vap
, va_data_size
))
2347 VATTR_RETURN(vap
, va_data_size
, 0);
2349 /* do we want any of the possibly-computed values? */
2350 if (VATTR_IS_ACTIVE(vap
, va_data_alloc
) ||
2351 VATTR_IS_ACTIVE(vap
, va_total_size
) ||
2352 VATTR_IS_ACTIVE(vap
, va_total_alloc
)) {
2353 /* make sure f_bsize is valid */
2354 if (vp
->v_mount
->mnt_vfsstat
.f_bsize
== 0) {
2355 if ((error
= vfs_update_vfsstat(vp
->v_mount
, ctx
, VFS_KERNEL_EVENT
)) != 0)
2359 /* default va_data_alloc from va_data_size */
2360 if (!VATTR_IS_SUPPORTED(vap
, va_data_alloc
))
2361 VATTR_RETURN(vap
, va_data_alloc
, roundup(vap
->va_data_size
, vp
->v_mount
->mnt_vfsstat
.f_bsize
));
2363 /* default va_total_size from va_data_size */
2364 if (!VATTR_IS_SUPPORTED(vap
, va_total_size
))
2365 VATTR_RETURN(vap
, va_total_size
, vap
->va_data_size
);
2367 /* default va_total_alloc from va_total_size which is guaranteed at this point */
2368 if (!VATTR_IS_SUPPORTED(vap
, va_total_alloc
))
2369 VATTR_RETURN(vap
, va_total_alloc
, roundup(vap
->va_total_size
, vp
->v_mount
->mnt_vfsstat
.f_bsize
));
2373 * If we don't have a change time, pull it from the modtime.
2375 if (!VATTR_IS_SUPPORTED(vap
, va_change_time
) && VATTR_IS_SUPPORTED(vap
, va_modify_time
))
2376 VATTR_RETURN(vap
, va_change_time
, vap
->va_modify_time
);
2379 * This is really only supported for the creation VNOPs, but since the field is there
2380 * we should populate it correctly.
2382 VATTR_RETURN(vap
, va_type
, vp
->v_type
);
2385 * The fsid can be obtained from the mountpoint directly.
2387 VATTR_RETURN(vap
, va_fsid
, vp
->v_mount
->mnt_vfsstat
.f_fsid
.val
[0]);
2395 * Set the attributes on a vnode in a vnode context.
2397 * Parameters: vp The vnode whose attributes to set.
2398 * vap A pointer to the attributes to set.
2399 * ctx The vnode context in which the
2400 * operation is to be attempted.
2402 * Returns: 0 Success
2405 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order.
2407 * The contents of the data area pointed to by 'vap' may be
2408 * modified if the vnode is on a filesystem which has been
2409 * mounted with ingore ownership flags, or by the underlyng
2410 * VFS itself, or by the fallback code, if the underlying VFS
2411 * does not support ACL, UUID, or GUUID attributes directly.
2413 * XXX: We should enummerate the possible errno values here, and where
2414 * in the code they originated.
2417 vnode_setattr(vnode_t vp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
2419 int error
, is_perm_change
=0;
2422 * Make sure the filesystem is mounted R/W.
2423 * If not, return an error.
2425 if (vfs_isrdonly(vp
->v_mount
)) {
2430 /* For streams, va_data_size is the only setable attribute. */
2431 if ((vp
->v_flag
& VISNAMEDSTREAM
) && (vap
->va_active
!= VNODE_ATTR_va_data_size
)) {
2438 * If ownership is being ignored on this volume, we silently discard
2439 * ownership changes.
2441 if (vp
->v_mount
->mnt_flag
& MNT_IGNORE_OWNERSHIP
) {
2442 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2443 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2446 if ( VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
)
2447 || VATTR_IS_ACTIVE(vap
, va_mode
) || VATTR_IS_ACTIVE(vap
, va_acl
)) {
2452 * Make sure that extended security is enabled if we're going to try
2455 if (!vfs_extendedsecurity(vnode_mount(vp
)) &&
2456 (VATTR_IS_ACTIVE(vap
, va_acl
) || VATTR_IS_ACTIVE(vap
, va_uuuid
) || VATTR_IS_ACTIVE(vap
, va_guuid
))) {
2457 KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security");
2462 error
= VNOP_SETATTR(vp
, vap
, ctx
);
2464 if ((error
== 0) && !VATTR_ALL_SUPPORTED(vap
))
2465 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
2468 // only send a stat_changed event if this is more than
2469 // just an access or backup time update
2470 if (error
== 0 && (vap
->va_active
!= VNODE_ATTR_BIT(va_access_time
)) && (vap
->va_active
!= VNODE_ATTR_BIT(va_backup_time
))) {
2471 if (is_perm_change
) {
2472 if (need_fsevent(FSE_CHOWN
, vp
)) {
2473 add_fsevent(FSE_CHOWN
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
2475 } else if(need_fsevent(FSE_STAT_CHANGED
, vp
)) {
2476 add_fsevent(FSE_STAT_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
2486 * Fallback for setting the attributes on a vnode in a vnode context. This
2487 * Function will attempt to store ACL, UUID, and GUID information utilizing
2488 * a read/modify/write operation against an EA used as a backing store for
2491 * Parameters: vp The vnode whose attributes to set.
2492 * vap A pointer to the attributes to set.
2493 * ctx The vnode context in which the
2494 * operation is to be attempted.
2496 * Returns: 0 Success
2499 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order,
2500 * as are the fsec and lfsec, if they are used.
2502 * The contents of the data area pointed to by 'vap' may be
2503 * modified to indicate that the attribute is supported for
2504 * any given requested attribute.
2506 * XXX: We should enummerate the possible errno values here, and where
2507 * in the code they originated.
2510 vnode_setattr_fallback(vnode_t vp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
2512 kauth_filesec_t fsec
;
2514 struct kauth_filesec lfsec
;
2520 * Extended security fallback via extended attributes.
2522 * Note that we do not free the filesec; the caller is expected to
2525 if (VATTR_NOT_RETURNED(vap
, va_acl
) ||
2526 VATTR_NOT_RETURNED(vap
, va_uuuid
) ||
2527 VATTR_NOT_RETURNED(vap
, va_guuid
)) {
2528 VFS_DEBUG(ctx
, vp
, "SETATTR - doing filesec fallback");
2531 * Fail for file types that we don't permit extended security
2534 if (!XATTR_VNODE_SUPPORTED(vp
)) {
2535 VFS_DEBUG(ctx
, vp
, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp
));
2541 * If we don't have all the extended security items, we need
2542 * to fetch the existing data to perform a read-modify-write
2546 if (!VATTR_IS_ACTIVE(vap
, va_acl
) ||
2547 !VATTR_IS_ACTIVE(vap
, va_uuuid
) ||
2548 !VATTR_IS_ACTIVE(vap
, va_guuid
)) {
2549 if ((error
= vnode_get_filesec(vp
, &fsec
, ctx
)) != 0) {
2550 KAUTH_DEBUG("SETATTR - ERROR %d fetching filesec for update", error
);
2554 /* if we didn't get a filesec, use our local one */
2556 KAUTH_DEBUG("SETATTR - using local filesec for new/full update");
2559 KAUTH_DEBUG("SETATTR - updating existing filesec");
2562 facl
= &fsec
->fsec_acl
;
2564 /* if we're using the local filesec, we need to initialise it */
2565 if (fsec
== &lfsec
) {
2566 fsec
->fsec_magic
= KAUTH_FILESEC_MAGIC
;
2567 fsec
->fsec_owner
= kauth_null_guid
;
2568 fsec
->fsec_group
= kauth_null_guid
;
2569 facl
->acl_entrycount
= KAUTH_FILESEC_NOACL
;
2570 facl
->acl_flags
= 0;
2574 * Update with the supplied attributes.
2576 if (VATTR_IS_ACTIVE(vap
, va_uuuid
)) {
2577 KAUTH_DEBUG("SETATTR - updating owner UUID");
2578 fsec
->fsec_owner
= vap
->va_uuuid
;
2579 VATTR_SET_SUPPORTED(vap
, va_uuuid
);
2581 if (VATTR_IS_ACTIVE(vap
, va_guuid
)) {
2582 KAUTH_DEBUG("SETATTR - updating group UUID");
2583 fsec
->fsec_group
= vap
->va_guuid
;
2584 VATTR_SET_SUPPORTED(vap
, va_guuid
);
2586 if (VATTR_IS_ACTIVE(vap
, va_acl
)) {
2587 if (vap
->va_acl
== NULL
) {
2588 KAUTH_DEBUG("SETATTR - removing ACL");
2589 facl
->acl_entrycount
= KAUTH_FILESEC_NOACL
;
2591 KAUTH_DEBUG("SETATTR - setting ACL with %d entries", vap
->va_acl
->acl_entrycount
);
2594 VATTR_SET_SUPPORTED(vap
, va_acl
);
2598 * If the filesec data is all invalid, we can just remove
2599 * the EA completely.
2601 if ((facl
->acl_entrycount
== KAUTH_FILESEC_NOACL
) &&
2602 kauth_guid_equal(&fsec
->fsec_owner
, &kauth_null_guid
) &&
2603 kauth_guid_equal(&fsec
->fsec_group
, &kauth_null_guid
)) {
2604 error
= vn_removexattr(vp
, KAUTH_FILESEC_XATTR
, XATTR_NOSECURITY
, ctx
);
2605 /* no attribute is ok, nothing to delete */
2606 if (error
== ENOATTR
)
2608 VFS_DEBUG(ctx
, vp
, "SETATTR - remove filesec returning %d", error
);
2611 error
= vnode_set_filesec(vp
, fsec
, facl
, ctx
);
2612 VFS_DEBUG(ctx
, vp
, "SETATTR - update filesec returning %d", error
);
2615 /* if we fetched a filesec, dispose of the buffer */
2617 kauth_filesec_free(fsec
);
2625 * Upcall for a filesystem to tell VFS about an EVFILT_VNODE-type
2629 vnode_notify(vnode_t vp
, uint32_t events
, struct vnode_attr
*vap
)
2631 /* These are the same as the corresponding knotes, at least for now. Cheating a little. */
2632 uint32_t knote_mask
= (VNODE_EVENT_WRITE
| VNODE_EVENT_DELETE
| VNODE_EVENT_RENAME
2633 | VNODE_EVENT_LINK
| VNODE_EVENT_EXTEND
| VNODE_EVENT_ATTRIB
);
2634 uint32_t dir_contents_mask
= (VNODE_EVENT_DIR_CREATED
| VNODE_EVENT_FILE_CREATED
2635 | VNODE_EVENT_DIR_REMOVED
| VNODE_EVENT_FILE_REMOVED
);
2636 uint32_t knote_events
= (events
& knote_mask
);
2638 /* Permissions are not explicitly part of the kqueue model */
2639 if (events
& VNODE_EVENT_PERMS
) {
2640 knote_events
|= NOTE_ATTRIB
;
2643 /* Directory contents information just becomes NOTE_WRITE */
2644 if ((vnode_isdir(vp
)) && (events
& dir_contents_mask
)) {
2645 knote_events
|= NOTE_WRITE
;
2649 lock_vnode_and_post(vp
, knote_events
);
2652 create_fsevent_from_kevent(vp
, events
, vap
);
2665 vnode_isdyldsharedcache(vnode_t vp
)
2667 return ((vp
->v_flag
& VSHARED_DYLD
) ? 1 : 0);
2672 * For a filesystem that isn't tracking its own vnode watchers:
2673 * check whether a vnode is being monitored.
2676 vnode_ismonitored(vnode_t vp
) {
2677 return (vp
->v_knotes
.slh_first
!= NULL
);
2681 * Initialize a struct vnode_attr and activate the attributes required
2682 * by the vnode_notify() call.
2685 vfs_get_notify_attributes(struct vnode_attr
*vap
)
2688 vap
->va_active
= VNODE_NOTIFY_ATTRS
;
2694 vfs_settriggercallback(fsid_t
*fsid
, vfs_trigger_callback_t vtc
, void *data
, uint32_t flags __unused
, vfs_context_t ctx
)
2699 mp
= mount_list_lookupby_fsid(fsid
, 0 /* locked */, 1 /* withref */);
2704 error
= vfs_busy(mp
, LK_NOWAIT
);
2712 if (mp
->mnt_triggercallback
!= NULL
) {
2718 mp
->mnt_triggercallback
= vtc
;
2719 mp
->mnt_triggerdata
= data
;
2722 mp
->mnt_triggercallback(mp
, VTC_REPLACE
, data
, ctx
);
2728 #endif /* CONFIG_TRIGGERS */
2731 * Definition of vnode operations.
2737 *#% lookup dvp L ? ?
2738 *#% lookup vpp - L -
2740 struct vnop_lookup_args
{
2741 struct vnodeop_desc
*a_desc
;
2744 struct componentname
*a_cnp
;
2745 vfs_context_t a_context
;
2750 * Returns: 0 Success
2751 * lock_fsnode:ENOENT No such file or directory [only for VFS
2752 * that is not thread safe & vnode is
2753 * currently being/has been terminated]
2754 * <vfs_lookup>:ENAMETOOLONG
2755 * <vfs_lookup>:ENOENT
2756 * <vfs_lookup>:EJUSTRETURN
2757 * <vfs_lookup>:EPERM
2758 * <vfs_lookup>:EISDIR
2759 * <vfs_lookup>:ENOTDIR
2762 * Note: The return codes from the underlying VFS's lookup routine can't
2763 * be fully enumerated here, since third party VFS authors may not
2764 * limit their error returns to the ones documented here, even
2765 * though this may result in some programs functioning incorrectly.
2767 * The return codes documented above are those which may currently
2768 * be returned by HFS from hfs_lookup, not including additional
2769 * error code which may be propagated from underlying routines.
2772 VNOP_LOOKUP(vnode_t dvp
, vnode_t
*vpp
, struct componentname
*cnp
, vfs_context_t ctx
)
2775 struct vnop_lookup_args a
;
2777 a
.a_desc
= &vnop_lookup_desc
;
2783 _err
= (*dvp
->v_op
[vnop_lookup_desc
.vdesc_offset
])(&a
);
2784 if (_err
== 0 && *vpp
) {
2785 DTRACE_FSINFO(lookup
, vnode_t
, *vpp
);
2792 struct vnop_compound_open_args
{
2793 struct vnodeop_desc
*a_desc
;
2796 struct componentname
*a_cnp
;
2799 struct vnode_attr
*a_vap
;
2800 vfs_context_t a_context
;
2806 VNOP_COMPOUND_OPEN(vnode_t dvp
, vnode_t
*vpp
, struct nameidata
*ndp
, int32_t flags
, int32_t fmode
, uint32_t *statusp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
2809 struct vnop_compound_open_args a
;
2812 uint32_t tmp_status
= 0;
2813 struct componentname
*cnp
= &ndp
->ni_cnd
;
2815 want_create
= (flags
& O_CREAT
);
2817 a
.a_desc
= &vnop_compound_open_desc
;
2819 a
.a_vpp
= vpp
; /* Could be NULL */
2823 a
.a_status
= (statusp
!= NULL
) ? statusp
: &tmp_status
;
2826 a
.a_open_create_authorizer
= vn_authorize_create
;
2827 a
.a_open_existing_authorizer
= vn_authorize_open_existing
;
2828 a
.a_reserved
= NULL
;
2830 if (dvp
== NULLVP
) {
2833 if (want_create
&& !vap
) {
2834 panic("Want create, but no vap?");
2836 if (!want_create
&& vap
) {
2837 panic("Don't want create, but have a vap?");
2840 _err
= (*dvp
->v_op
[vnop_compound_open_desc
.vdesc_offset
])(&a
);
2842 if (_err
== 0 && *vpp
) {
2843 DTRACE_FSINFO(compound_open
, vnode_t
, *vpp
);
2845 DTRACE_FSINFO(compound_open
, vnode_t
, dvp
);
2848 DTRACE_FSINFO(compound_open
, vnode_t
, *vpp
);
2851 did_create
= (*a
.a_status
& COMPOUND_OPEN_STATUS_DID_CREATE
);
2853 if (did_create
&& !want_create
) {
2854 panic("Filesystem did a create, even though none was requested?");
2858 #if CONFIG_APPLEDOUBLE
2859 if (!NATIVE_XATTR(dvp
)) {
2861 * Remove stale Apple Double file (if any).
2863 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 0);
2865 #endif /* CONFIG_APPLEDOUBLE */
2866 /* On create, provide kqueue notification */
2867 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
2870 lookup_compound_vnop_post_hook(_err
, dvp
, *vpp
, ndp
, did_create
);
2871 #if 0 /* FSEvents... */
2872 if (*vpp
&& _err
&& _err
!= EKEEPLOOKING
) {
2883 struct vnop_create_args
{
2884 struct vnodeop_desc
*a_desc
;
2887 struct componentname
*a_cnp
;
2888 struct vnode_attr
*a_vap
;
2889 vfs_context_t a_context
;
2893 VNOP_CREATE(vnode_t dvp
, vnode_t
* vpp
, struct componentname
* cnp
, struct vnode_attr
* vap
, vfs_context_t ctx
)
2896 struct vnop_create_args a
;
2898 a
.a_desc
= &vnop_create_desc
;
2905 _err
= (*dvp
->v_op
[vnop_create_desc
.vdesc_offset
])(&a
);
2906 if (_err
== 0 && *vpp
) {
2907 DTRACE_FSINFO(create
, vnode_t
, *vpp
);
2910 #if CONFIG_APPLEDOUBLE
2911 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
2913 * Remove stale Apple Double file (if any).
2915 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 0);
2917 #endif /* CONFIG_APPLEDOUBLE */
2919 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
2927 *#% whiteout dvp L L L
2928 *#% whiteout cnp - - -
2929 *#% whiteout flag - - -
2932 struct vnop_whiteout_args
{
2933 struct vnodeop_desc
*a_desc
;
2935 struct componentname
*a_cnp
;
2937 vfs_context_t a_context
;
2941 VNOP_WHITEOUT(__unused vnode_t dvp
, __unused
struct componentname
*cnp
,
2942 __unused
int flags
, __unused vfs_context_t ctx
)
2944 return (ENOTSUP
); // XXX OBSOLETE
2954 struct vnop_mknod_args
{
2955 struct vnodeop_desc
*a_desc
;
2958 struct componentname
*a_cnp
;
2959 struct vnode_attr
*a_vap
;
2960 vfs_context_t a_context
;
2964 VNOP_MKNOD(vnode_t dvp
, vnode_t
* vpp
, struct componentname
* cnp
, struct vnode_attr
* vap
, vfs_context_t ctx
)
2968 struct vnop_mknod_args a
;
2970 a
.a_desc
= &vnop_mknod_desc
;
2977 _err
= (*dvp
->v_op
[vnop_mknod_desc
.vdesc_offset
])(&a
);
2978 if (_err
== 0 && *vpp
) {
2979 DTRACE_FSINFO(mknod
, vnode_t
, *vpp
);
2982 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
2993 struct vnop_open_args
{
2994 struct vnodeop_desc
*a_desc
;
2997 vfs_context_t a_context
;
3001 VNOP_OPEN(vnode_t vp
, int mode
, vfs_context_t ctx
)
3004 struct vnop_open_args a
;
3007 ctx
= vfs_context_current();
3009 a
.a_desc
= &vnop_open_desc
;
3014 _err
= (*vp
->v_op
[vnop_open_desc
.vdesc_offset
])(&a
);
3015 DTRACE_FSINFO(open
, vnode_t
, vp
);
3026 struct vnop_close_args
{
3027 struct vnodeop_desc
*a_desc
;
3030 vfs_context_t a_context
;
3034 VNOP_CLOSE(vnode_t vp
, int fflag
, vfs_context_t ctx
)
3037 struct vnop_close_args a
;
3040 ctx
= vfs_context_current();
3042 a
.a_desc
= &vnop_close_desc
;
3047 _err
= (*vp
->v_op
[vnop_close_desc
.vdesc_offset
])(&a
);
3048 DTRACE_FSINFO(close
, vnode_t
, vp
);
3059 struct vnop_access_args
{
3060 struct vnodeop_desc
*a_desc
;
3063 vfs_context_t a_context
;
3067 VNOP_ACCESS(vnode_t vp
, int action
, vfs_context_t ctx
)
3070 struct vnop_access_args a
;
3073 ctx
= vfs_context_current();
3075 a
.a_desc
= &vnop_access_desc
;
3077 a
.a_action
= action
;
3080 _err
= (*vp
->v_op
[vnop_access_desc
.vdesc_offset
])(&a
);
3081 DTRACE_FSINFO(access
, vnode_t
, vp
);
3089 *#% getattr vp = = =
3092 struct vnop_getattr_args
{
3093 struct vnodeop_desc
*a_desc
;
3095 struct vnode_attr
*a_vap
;
3096 vfs_context_t a_context
;
3100 VNOP_GETATTR(vnode_t vp
, struct vnode_attr
* vap
, vfs_context_t ctx
)
3103 struct vnop_getattr_args a
;
3105 a
.a_desc
= &vnop_getattr_desc
;
3110 _err
= (*vp
->v_op
[vnop_getattr_desc
.vdesc_offset
])(&a
);
3111 DTRACE_FSINFO(getattr
, vnode_t
, vp
);
3119 *#% setattr vp L L L
3122 struct vnop_setattr_args
{
3123 struct vnodeop_desc
*a_desc
;
3125 struct vnode_attr
*a_vap
;
3126 vfs_context_t a_context
;
3130 VNOP_SETATTR(vnode_t vp
, struct vnode_attr
* vap
, vfs_context_t ctx
)
3133 struct vnop_setattr_args a
;
3135 a
.a_desc
= &vnop_setattr_desc
;
3140 _err
= (*vp
->v_op
[vnop_setattr_desc
.vdesc_offset
])(&a
);
3141 DTRACE_FSINFO(setattr
, vnode_t
, vp
);
3143 #if CONFIG_APPLEDOUBLE
3145 * Shadow uid/gid/mod change to extended attribute file.
3147 if (_err
== 0 && !NATIVE_XATTR(vp
)) {
3148 struct vnode_attr va
;
3152 if (VATTR_IS_ACTIVE(vap
, va_uid
)) {
3153 VATTR_SET(&va
, va_uid
, vap
->va_uid
);
3156 if (VATTR_IS_ACTIVE(vap
, va_gid
)) {
3157 VATTR_SET(&va
, va_gid
, vap
->va_gid
);
3160 if (VATTR_IS_ACTIVE(vap
, va_mode
)) {
3161 VATTR_SET(&va
, va_mode
, vap
->va_mode
);
3168 dvp
= vnode_getparent(vp
);
3169 vname
= vnode_getname(vp
);
3171 xattrfile_setattr(dvp
, vname
, &va
, ctx
);
3175 vnode_putname(vname
);
3178 #endif /* CONFIG_APPLEDOUBLE */
3181 * If we have changed any of the things about the file that are likely
3182 * to result in changes to authorization results, blow the vnode auth
3186 VATTR_IS_SUPPORTED(vap
, va_mode
) ||
3187 VATTR_IS_SUPPORTED(vap
, va_uid
) ||
3188 VATTR_IS_SUPPORTED(vap
, va_gid
) ||
3189 VATTR_IS_SUPPORTED(vap
, va_flags
) ||
3190 VATTR_IS_SUPPORTED(vap
, va_acl
) ||
3191 VATTR_IS_SUPPORTED(vap
, va_uuuid
) ||
3192 VATTR_IS_SUPPORTED(vap
, va_guuid
))) {
3193 vnode_uncache_authorized_action(vp
, KAUTH_INVALIDATE_CACHED_RIGHTS
);
3196 if (vfs_authopaque(vp
->v_mount
) && vnode_hasnamedstreams(vp
)) {
3198 if (vnode_getnamedstream(vp
, &svp
, XATTR_RESOURCEFORK_NAME
, NS_OPEN
, 0, ctx
) == 0) {
3199 vnode_uncache_authorized_action(svp
, KAUTH_INVALIDATE_CACHED_RIGHTS
);
3203 #endif /* NAMEDSTREAMS */
3207 post_event_if_success(vp
, _err
, NOTE_ATTRIB
);
3219 struct vnop_read_args
{
3220 struct vnodeop_desc
*a_desc
;
3224 vfs_context_t a_context
;
3228 VNOP_READ(vnode_t vp
, struct uio
* uio
, int ioflag
, vfs_context_t ctx
)
3231 struct vnop_read_args a
;
3233 user_ssize_t resid
= uio_resid(uio
);
3240 a
.a_desc
= &vnop_read_desc
;
3243 a
.a_ioflag
= ioflag
;
3246 _err
= (*vp
->v_op
[vnop_read_desc
.vdesc_offset
])(&a
);
3247 DTRACE_FSINFO_IO(read
,
3248 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
3260 struct vnop_write_args
{
3261 struct vnodeop_desc
*a_desc
;
3265 vfs_context_t a_context
;
3269 VNOP_WRITE(vnode_t vp
, struct uio
* uio
, int ioflag
, vfs_context_t ctx
)
3271 struct vnop_write_args a
;
3274 user_ssize_t resid
= uio_resid(uio
);
3281 a
.a_desc
= &vnop_write_desc
;
3284 a
.a_ioflag
= ioflag
;
3287 _err
= (*vp
->v_op
[vnop_write_desc
.vdesc_offset
])(&a
);
3288 DTRACE_FSINFO_IO(write
,
3289 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
3291 post_event_if_success(vp
, _err
, NOTE_WRITE
);
3303 struct vnop_ioctl_args
{
3304 struct vnodeop_desc
*a_desc
;
3309 vfs_context_t a_context
;
3313 VNOP_IOCTL(vnode_t vp
, u_long command
, caddr_t data
, int fflag
, vfs_context_t ctx
)
3316 struct vnop_ioctl_args a
;
3319 ctx
= vfs_context_current();
3323 * This check should probably have been put in the TTY code instead...
3325 * We have to be careful about what we assume during startup and shutdown.
3326 * We have to be able to use the root filesystem's device vnode even when
3327 * devfs isn't mounted (yet/anymore), so we can't go looking at its mount
3328 * structure. If there is no data pointer, it doesn't matter whether
3329 * the device is 64-bit ready. Any command (like DKIOCSYNCHRONIZECACHE)
3330 * which passes NULL for its data pointer can therefore be used during
3331 * mount or unmount of the root filesystem.
3333 * Depending on what root filesystems need to do during mount/unmount, we
3334 * may need to loosen this check again in the future.
3336 if (vfs_context_is64bit(ctx
) && !(vnode_ischr(vp
) || vnode_isblk(vp
))) {
3337 if (data
!= NULL
&& !vnode_vfs64bitready(vp
)) {
3342 a
.a_desc
= &vnop_ioctl_desc
;
3344 a
.a_command
= command
;
3349 _err
= (*vp
->v_op
[vnop_ioctl_desc
.vdesc_offset
])(&a
);
3350 DTRACE_FSINFO(ioctl
, vnode_t
, vp
);
3362 struct vnop_select_args
{
3363 struct vnodeop_desc
*a_desc
;
3368 vfs_context_t a_context
;
3372 VNOP_SELECT(vnode_t vp
, int which
, int fflags
, void * wql
, vfs_context_t ctx
)
3375 struct vnop_select_args a
;
3378 ctx
= vfs_context_current();
3380 a
.a_desc
= &vnop_select_desc
;
3383 a
.a_fflags
= fflags
;
3387 _err
= (*vp
->v_op
[vnop_select_desc
.vdesc_offset
])(&a
);
3388 DTRACE_FSINFO(select
, vnode_t
, vp
);
3397 *#% exchange fvp L L L
3398 *#% exchange tvp L L L
3401 struct vnop_exchange_args
{
3402 struct vnodeop_desc
*a_desc
;
3406 vfs_context_t a_context
;
3410 VNOP_EXCHANGE(vnode_t fvp
, vnode_t tvp
, int options
, vfs_context_t ctx
)
3413 struct vnop_exchange_args a
;
3415 a
.a_desc
= &vnop_exchange_desc
;
3418 a
.a_options
= options
;
3421 _err
= (*fvp
->v_op
[vnop_exchange_desc
.vdesc_offset
])(&a
);
3422 DTRACE_FSINFO(exchange
, vnode_t
, fvp
);
3424 /* Don't post NOTE_WRITE because file descriptors follow the data ... */
3425 post_event_if_success(fvp
, _err
, NOTE_ATTRIB
);
3426 post_event_if_success(tvp
, _err
, NOTE_ATTRIB
);
3438 struct vnop_revoke_args
{
3439 struct vnodeop_desc
*a_desc
;
3442 vfs_context_t a_context
;
3446 VNOP_REVOKE(vnode_t vp
, int flags
, vfs_context_t ctx
)
3448 struct vnop_revoke_args a
;
3451 a
.a_desc
= &vnop_revoke_desc
;
3456 _err
= (*vp
->v_op
[vnop_revoke_desc
.vdesc_offset
])(&a
);
3457 DTRACE_FSINFO(revoke
, vnode_t
, vp
);
3469 struct vnop_mmap_args
{
3470 struct vnodeop_desc
*a_desc
;
3473 vfs_context_t a_context
;
3477 VNOP_MMAP(vnode_t vp
, int fflags
, vfs_context_t ctx
)
3480 struct vnop_mmap_args a
;
3482 a
.a_desc
= &vnop_mmap_desc
;
3484 a
.a_fflags
= fflags
;
3487 _err
= (*vp
->v_op
[vnop_mmap_desc
.vdesc_offset
])(&a
);
3488 DTRACE_FSINFO(mmap
, vnode_t
, vp
);
3497 *# mnomap - vp U U U
3500 struct vnop_mnomap_args
{
3501 struct vnodeop_desc
*a_desc
;
3503 vfs_context_t a_context
;
3507 VNOP_MNOMAP(vnode_t vp
, vfs_context_t ctx
)
3510 struct vnop_mnomap_args a
;
3512 a
.a_desc
= &vnop_mnomap_desc
;
3516 _err
= (*vp
->v_op
[vnop_mnomap_desc
.vdesc_offset
])(&a
);
3517 DTRACE_FSINFO(mnomap
, vnode_t
, vp
);
3529 struct vnop_fsync_args
{
3530 struct vnodeop_desc
*a_desc
;
3533 vfs_context_t a_context
;
3537 VNOP_FSYNC(vnode_t vp
, int waitfor
, vfs_context_t ctx
)
3539 struct vnop_fsync_args a
;
3542 a
.a_desc
= &vnop_fsync_desc
;
3544 a
.a_waitfor
= waitfor
;
3547 _err
= (*vp
->v_op
[vnop_fsync_desc
.vdesc_offset
])(&a
);
3548 DTRACE_FSINFO(fsync
, vnode_t
, vp
);
3557 *#% remove dvp L U U
3561 struct vnop_remove_args
{
3562 struct vnodeop_desc
*a_desc
;
3565 struct componentname
*a_cnp
;
3567 vfs_context_t a_context
;
3571 VNOP_REMOVE(vnode_t dvp
, vnode_t vp
, struct componentname
* cnp
, int flags
, vfs_context_t ctx
)
3574 struct vnop_remove_args a
;
3576 a
.a_desc
= &vnop_remove_desc
;
3583 _err
= (*dvp
->v_op
[vnop_remove_desc
.vdesc_offset
])(&a
);
3584 DTRACE_FSINFO(remove
, vnode_t
, vp
);
3587 vnode_setneedinactive(vp
);
3588 #if CONFIG_APPLEDOUBLE
3589 if ( !(NATIVE_XATTR(dvp
)) ) {
3591 * Remove any associated extended attribute file (._ AppleDouble file).
3593 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 1);
3595 #endif /* CONFIG_APPLEDOUBLE */
3598 post_event_if_success(vp
, _err
, NOTE_DELETE
| NOTE_LINK
);
3599 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
3605 VNOP_COMPOUND_REMOVE(vnode_t dvp
, vnode_t
*vpp
, struct nameidata
*ndp
, int32_t flags
, struct vnode_attr
*vap
, vfs_context_t ctx
)
3608 struct vnop_compound_remove_args a
;
3609 int no_vp
= (*vpp
== NULLVP
);
3611 a
.a_desc
= &vnop_compound_remove_desc
;
3614 a
.a_cnp
= &ndp
->ni_cnd
;
3618 a
.a_remove_authorizer
= vn_authorize_unlink
;
3620 _err
= (*dvp
->v_op
[vnop_compound_remove_desc
.vdesc_offset
])(&a
);
3621 if (_err
== 0 && *vpp
) {
3622 DTRACE_FSINFO(compound_remove
, vnode_t
, *vpp
);
3624 DTRACE_FSINFO(compound_remove
, vnode_t
, dvp
);
3627 vnode_setneedinactive(*vpp
);
3628 #if CONFIG_APPLEDOUBLE
3629 if ( !(NATIVE_XATTR(dvp
)) ) {
3631 * Remove any associated extended attribute file (._ AppleDouble file).
3633 xattrfile_remove(dvp
, ndp
->ni_cnd
.cn_nameptr
, ctx
, 1);
3635 #endif /* CONFIG_APPLEDOUBLE */
3638 post_event_if_success(*vpp
, _err
, NOTE_DELETE
| NOTE_LINK
);
3639 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
3642 lookup_compound_vnop_post_hook(_err
, dvp
, *vpp
, ndp
, 0);
3643 if (*vpp
&& _err
&& _err
!= EKEEPLOOKING
) {
3649 //printf("VNOP_COMPOUND_REMOVE() returning %d\n", _err);
3661 struct vnop_link_args
{
3662 struct vnodeop_desc
*a_desc
;
3665 struct componentname
*a_cnp
;
3666 vfs_context_t a_context
;
3670 VNOP_LINK(vnode_t vp
, vnode_t tdvp
, struct componentname
* cnp
, vfs_context_t ctx
)
3673 struct vnop_link_args a
;
3675 #if CONFIG_APPLEDOUBLE
3677 * For file systems with non-native extended attributes,
3678 * disallow linking to an existing "._" Apple Double file.
3680 if ( !NATIVE_XATTR(tdvp
) && (vp
->v_type
== VREG
)) {
3683 vname
= vnode_getname(vp
);
3684 if (vname
!= NULL
) {
3686 if (vname
[0] == '.' && vname
[1] == '_' && vname
[2] != '\0') {
3689 vnode_putname(vname
);
3694 #endif /* CONFIG_APPLEDOUBLE */
3696 a
.a_desc
= &vnop_link_desc
;
3702 _err
= (*tdvp
->v_op
[vnop_link_desc
.vdesc_offset
])(&a
);
3703 DTRACE_FSINFO(link
, vnode_t
, vp
);
3705 post_event_if_success(vp
, _err
, NOTE_LINK
);
3706 post_event_if_success(tdvp
, _err
, NOTE_WRITE
);
3712 vn_rename(struct vnode
*fdvp
, struct vnode
**fvpp
, struct componentname
*fcnp
, struct vnode_attr
*fvap
,
3713 struct vnode
*tdvp
, struct vnode
**tvpp
, struct componentname
*tcnp
, struct vnode_attr
*tvap
,
3714 uint32_t flags
, vfs_context_t ctx
)
3717 struct nameidata
*fromnd
= NULL
;
3718 struct nameidata
*tond
= NULL
;
3719 #if CONFIG_APPLEDOUBLE
3720 vnode_t src_attr_vp
= NULLVP
;
3721 vnode_t dst_attr_vp
= NULLVP
;
3722 char smallname1
[48];
3723 char smallname2
[48];
3724 char *xfromname
= NULL
;
3725 char *xtoname
= NULL
;
3726 #endif /* CONFIG_APPLEDOUBLE */
3728 uint32_t tdfflags
; // Target directory file flags
3730 batched
= vnode_compound_rename_available(fdvp
);
3733 if (*fvpp
== NULLVP
)
3734 panic("Not batched, and no fvp?");
3737 #if CONFIG_SECLUDED_RENAME
3738 if ((fcnp
->cn_flags
& CN_SECLUDE_RENAME
) &&
3739 (((*fvpp
)->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSVNOP_SECLUDE_RENAME
) == 0)) {
3744 #if CONFIG_APPLEDOUBLE
3746 * We need to preflight any potential AppleDouble file for the source file
3747 * before doing the rename operation, since we could potentially be doing
3748 * this operation on a network filesystem, and would end up duplicating
3749 * the work. Also, save the source and destination names. Skip it if the
3750 * source has a "._" prefix.
3753 if (!NATIVE_XATTR(fdvp
) &&
3754 !(fcnp
->cn_nameptr
[0] == '.' && fcnp
->cn_nameptr
[1] == '_')) {
3758 /* Get source attribute file name. */
3759 len
= fcnp
->cn_namelen
+ 3;
3760 if (len
> sizeof(smallname1
)) {
3761 MALLOC(xfromname
, char *, len
, M_TEMP
, M_WAITOK
);
3763 xfromname
= &smallname1
[0];
3765 strlcpy(xfromname
, "._", min(sizeof smallname1
, len
));
3766 strncat(xfromname
, fcnp
->cn_nameptr
, fcnp
->cn_namelen
);
3767 xfromname
[len
-1] = '\0';
3769 /* Get destination attribute file name. */
3770 len
= tcnp
->cn_namelen
+ 3;
3771 if (len
> sizeof(smallname2
)) {
3772 MALLOC(xtoname
, char *, len
, M_TEMP
, M_WAITOK
);
3774 xtoname
= &smallname2
[0];
3776 strlcpy(xtoname
, "._", min(sizeof smallname2
, len
));
3777 strncat(xtoname
, tcnp
->cn_nameptr
, tcnp
->cn_namelen
);
3778 xtoname
[len
-1] = '\0';
3781 * Look up source attribute file, keep reference on it if exists.
3782 * Note that we do the namei with the nameiop of RENAME, which is different than
3783 * in the rename syscall. It's OK if the source file does not exist, since this
3784 * is only for AppleDouble files.
3786 if (xfromname
!= NULL
) {
3787 MALLOC(fromnd
, struct nameidata
*, sizeof (struct nameidata
), M_TEMP
, M_WAITOK
);
3788 NDINIT(fromnd
, RENAME
, OP_RENAME
, NOFOLLOW
| USEDVP
| CN_NBMOUNTLOOK
,
3789 UIO_SYSSPACE
, CAST_USER_ADDR_T(xfromname
), ctx
);
3790 fromnd
->ni_dvp
= fdvp
;
3791 error
= namei(fromnd
);
3794 * If there was an error looking up source attribute file,
3795 * we'll behave as if it didn't exist.
3799 if (fromnd
->ni_vp
) {
3800 /* src_attr_vp indicates need to call vnode_put / nameidone later */
3801 src_attr_vp
= fromnd
->ni_vp
;
3803 if (fromnd
->ni_vp
->v_type
!= VREG
) {
3804 src_attr_vp
= NULLVP
;
3805 vnode_put(fromnd
->ni_vp
);
3809 * Either we got an invalid vnode type (not a regular file) or the namei lookup
3810 * suppressed ENOENT as a valid error since we're renaming. Either way, we don't
3811 * have a vnode here, so we drop our namei buffer for the source attribute file
3813 if (src_attr_vp
== NULLVP
) {
3819 #endif /* CONFIG_APPLEDOUBLE */
3822 _err
= VNOP_COMPOUND_RENAME(fdvp
, fvpp
, fcnp
, fvap
, tdvp
, tvpp
, tcnp
, tvap
, flags
, ctx
);
3824 printf("VNOP_COMPOUND_RENAME() returned %d\n", _err
);
3827 _err
= VNOP_RENAME(fdvp
, *fvpp
, fcnp
, tdvp
, *tvpp
, tcnp
, ctx
);
3831 mac_vnode_notify_rename(ctx
, *fvpp
, tdvp
, tcnp
);
3836 * If moved to a new directory that is restricted,
3837 * set the restricted flag on the item moved.
3840 _err
= vnode_flags(tdvp
, &tdfflags
, ctx
);
3841 if (_err
== 0 && (tdfflags
& SF_RESTRICTED
)) {
3843 _err
= vnode_flags(*fvpp
, &fflags
, ctx
);
3844 if (_err
== 0 && !(fflags
& SF_RESTRICTED
)) {
3845 struct vnode_attr va
;
3847 VATTR_SET(&va
, va_flags
, fflags
| SF_RESTRICTED
);
3848 _err
= vnode_setattr(*fvpp
, &va
, ctx
);
3853 #if CONFIG_APPLEDOUBLE
3855 * Rename any associated extended attribute file (._ AppleDouble file).
3857 if (_err
== 0 && !NATIVE_XATTR(fdvp
) && xfromname
!= NULL
) {
3861 * Get destination attribute file vnode.
3862 * Note that tdvp already has an iocount reference. Make sure to check that we
3863 * get a valid vnode from namei.
3865 MALLOC(tond
, struct nameidata
*, sizeof(struct nameidata
), M_TEMP
, M_WAITOK
);
3866 NDINIT(tond
, RENAME
, OP_RENAME
,
3867 NOCACHE
| NOFOLLOW
| USEDVP
| CN_NBMOUNTLOOK
, UIO_SYSSPACE
,
3868 CAST_USER_ADDR_T(xtoname
), ctx
);
3869 tond
->ni_dvp
= tdvp
;
3870 error
= namei(tond
);
3876 dst_attr_vp
= tond
->ni_vp
;
3880 const char *old_name
= src_attr_vp
->v_name
;
3881 vnode_t old_parent
= src_attr_vp
->v_parent
;
3884 error
= VNOP_COMPOUND_RENAME(fdvp
, &src_attr_vp
, &fromnd
->ni_cnd
, NULL
,
3885 tdvp
, &dst_attr_vp
, &tond
->ni_cnd
, NULL
,
3888 error
= VNOP_RENAME(fdvp
, src_attr_vp
, &fromnd
->ni_cnd
,
3889 tdvp
, dst_attr_vp
, &tond
->ni_cnd
, ctx
);
3892 if (error
== 0 && old_name
== src_attr_vp
->v_name
&&
3893 old_parent
== src_attr_vp
->v_parent
) {
3894 int update_flags
= VNODE_UPDATE_NAME
;
3897 update_flags
|= VNODE_UPDATE_PARENT
;
3899 if ((src_attr_vp
->v_mount
->mnt_vtable
->vfc_vfsflags
& VFC_VFSVNOP_NOUPDATEID_RENAME
) == 0) {
3900 vnode_update_identity(src_attr_vp
, tdvp
,
3901 tond
->ni_cnd
.cn_nameptr
,
3902 tond
->ni_cnd
.cn_namelen
,
3903 tond
->ni_cnd
.cn_hash
,
3908 /* kevent notifications for moving resource files
3909 * _err is zero if we're here, so no need to notify directories, code
3910 * below will do that. only need to post the rename on the source and
3911 * possibly a delete on the dest
3913 post_event_if_success(src_attr_vp
, error
, NOTE_RENAME
);
3915 post_event_if_success(dst_attr_vp
, error
, NOTE_DELETE
);
3918 } else if (dst_attr_vp
) {
3920 * Just delete destination attribute file vnode if it exists, since
3921 * we didn't have a source attribute file.
3922 * Note that tdvp already has an iocount reference.
3925 struct vnop_remove_args args
;
3927 args
.a_desc
= &vnop_remove_desc
;
3929 args
.a_vp
= dst_attr_vp
;
3930 args
.a_cnp
= &tond
->ni_cnd
;
3931 args
.a_context
= ctx
;
3934 error
= (*tdvp
->v_op
[vnop_remove_desc
.vdesc_offset
])(&args
);
3937 vnode_setneedinactive(dst_attr_vp
);
3940 /* kevent notification for deleting the destination's attribute file
3941 * if it existed. Only need to post the delete on the destination, since
3942 * the code below will handle the directories.
3944 post_event_if_success(dst_attr_vp
, error
, NOTE_DELETE
);
3949 vnode_put(src_attr_vp
);
3953 vnode_put(dst_attr_vp
);
3956 if (xfromname
&& xfromname
!= &smallname1
[0]) {
3957 FREE(xfromname
, M_TEMP
);
3959 if (xtoname
&& xtoname
!= &smallname2
[0]) {
3960 FREE(xtoname
, M_TEMP
);
3962 #endif /* CONFIG_APPLEDOUBLE */
3964 FREE(fromnd
, M_TEMP
);
3976 *#% rename fdvp U U U
3977 *#% rename fvp U U U
3978 *#% rename tdvp L U U
3979 *#% rename tvp X U U
3982 struct vnop_rename_args
{
3983 struct vnodeop_desc
*a_desc
;
3986 struct componentname
*a_fcnp
;
3989 struct componentname
*a_tcnp
;
3990 vfs_context_t a_context
;
3994 VNOP_RENAME(struct vnode
*fdvp
, struct vnode
*fvp
, struct componentname
*fcnp
,
3995 struct vnode
*tdvp
, struct vnode
*tvp
, struct componentname
*tcnp
,
4000 struct vnop_rename_args a
;
4002 a
.a_desc
= &vnop_rename_desc
;
4011 /* do the rename of the main file. */
4012 _err
= (*fdvp
->v_op
[vnop_rename_desc
.vdesc_offset
])(&a
);
4013 DTRACE_FSINFO(rename
, vnode_t
, fdvp
);
4016 if (tvp
&& tvp
!= fvp
)
4017 vnode_setneedinactive(tvp
);
4020 /* Wrote at least one directory. If transplanted a dir, also changed link counts */
4022 events
= NOTE_WRITE
;
4023 if (vnode_isdir(fvp
)) {
4024 /* Link count on dir changed only if we are moving a dir and...
4025 * --Moved to new dir, not overwriting there
4026 * --Kept in same dir and DID overwrite
4028 if (((fdvp
!= tdvp
) && (!tvp
)) || ((fdvp
== tdvp
) && (tvp
))) {
4029 events
|= NOTE_LINK
;
4033 lock_vnode_and_post(fdvp
, events
);
4035 lock_vnode_and_post(tdvp
, events
);
4038 /* If you're replacing the target, post a deletion for it */
4041 lock_vnode_and_post(tvp
, NOTE_DELETE
);
4044 lock_vnode_and_post(fvp
, NOTE_RENAME
);
4051 VNOP_COMPOUND_RENAME(
4052 struct vnode
*fdvp
, struct vnode
**fvpp
, struct componentname
*fcnp
, struct vnode_attr
*fvap
,
4053 struct vnode
*tdvp
, struct vnode
**tvpp
, struct componentname
*tcnp
, struct vnode_attr
*tvap
,
4054 uint32_t flags
, vfs_context_t ctx
)
4058 struct vnop_compound_rename_args a
;
4061 no_fvp
= (*fvpp
) == NULLVP
;
4062 no_tvp
= (*tvpp
) == NULLVP
;
4064 a
.a_desc
= &vnop_compound_rename_desc
;
4078 a
.a_rename_authorizer
= vn_authorize_rename
;
4079 a
.a_reserved
= NULL
;
4081 /* do the rename of the main file. */
4082 _err
= (*fdvp
->v_op
[vnop_compound_rename_desc
.vdesc_offset
])(&a
);
4083 DTRACE_FSINFO(compound_rename
, vnode_t
, fdvp
);
4086 if (*tvpp
&& *tvpp
!= *fvpp
)
4087 vnode_setneedinactive(*tvpp
);
4090 /* Wrote at least one directory. If transplanted a dir, also changed link counts */
4091 if (_err
== 0 && *fvpp
!= *tvpp
) {
4093 panic("No fvpp after compound rename?");
4096 events
= NOTE_WRITE
;
4097 if (vnode_isdir(*fvpp
)) {
4098 /* Link count on dir changed only if we are moving a dir and...
4099 * --Moved to new dir, not overwriting there
4100 * --Kept in same dir and DID overwrite
4102 if (((fdvp
!= tdvp
) && (!*tvpp
)) || ((fdvp
== tdvp
) && (*tvpp
))) {
4103 events
|= NOTE_LINK
;
4107 lock_vnode_and_post(fdvp
, events
);
4109 lock_vnode_and_post(tdvp
, events
);
4112 /* If you're replacing the target, post a deletion for it */
4115 lock_vnode_and_post(*tvpp
, NOTE_DELETE
);
4118 lock_vnode_and_post(*fvpp
, NOTE_RENAME
);
4122 lookup_compound_vnop_post_hook(_err
, fdvp
, *fvpp
, fcnp
->cn_ndp
, 0);
4124 if (no_tvp
&& *tvpp
!= NULLVP
) {
4125 lookup_compound_vnop_post_hook(_err
, tdvp
, *tvpp
, tcnp
->cn_ndp
, 0);
4128 if (_err
&& _err
!= EKEEPLOOKING
) {
4143 vn_mkdir(struct vnode
*dvp
, struct vnode
**vpp
, struct nameidata
*ndp
,
4144 struct vnode_attr
*vap
, vfs_context_t ctx
)
4146 if (ndp
->ni_cnd
.cn_nameiop
!= CREATE
) {
4147 panic("Non-CREATE nameiop in vn_mkdir()?");
4150 if (vnode_compound_mkdir_available(dvp
)) {
4151 return VNOP_COMPOUND_MKDIR(dvp
, vpp
, ndp
, vap
, ctx
);
4153 return VNOP_MKDIR(dvp
, vpp
, &ndp
->ni_cnd
, vap
, ctx
);
4164 struct vnop_mkdir_args
{
4165 struct vnodeop_desc
*a_desc
;
4168 struct componentname
*a_cnp
;
4169 struct vnode_attr
*a_vap
;
4170 vfs_context_t a_context
;
4174 VNOP_MKDIR(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
,
4175 struct vnode_attr
*vap
, vfs_context_t ctx
)
4178 struct vnop_mkdir_args a
;
4180 a
.a_desc
= &vnop_mkdir_desc
;
4187 _err
= (*dvp
->v_op
[vnop_mkdir_desc
.vdesc_offset
])(&a
);
4188 if (_err
== 0 && *vpp
) {
4189 DTRACE_FSINFO(mkdir
, vnode_t
, *vpp
);
4191 #if CONFIG_APPLEDOUBLE
4192 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
4194 * Remove stale Apple Double file (if any).
4196 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 0);
4198 #endif /* CONFIG_APPLEDOUBLE */
4200 post_event_if_success(dvp
, _err
, NOTE_LINK
| NOTE_WRITE
);
4206 VNOP_COMPOUND_MKDIR(struct vnode
*dvp
, struct vnode
**vpp
, struct nameidata
*ndp
,
4207 struct vnode_attr
*vap
, vfs_context_t ctx
)
4210 struct vnop_compound_mkdir_args a
;
4212 a
.a_desc
= &vnop_compound_mkdir_desc
;
4215 a
.a_cnp
= &ndp
->ni_cnd
;
4220 a
.a_mkdir_authorizer
= vn_authorize_mkdir
;
4222 a
.a_reserved
= NULL
;
4224 _err
= (*dvp
->v_op
[vnop_compound_mkdir_desc
.vdesc_offset
])(&a
);
4225 if (_err
== 0 && *vpp
) {
4226 DTRACE_FSINFO(compound_mkdir
, vnode_t
, *vpp
);
4228 #if CONFIG_APPLEDOUBLE
4229 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
4231 * Remove stale Apple Double file (if any).
4233 xattrfile_remove(dvp
, ndp
->ni_cnd
.cn_nameptr
, ctx
, 0);
4235 #endif /* CONFIG_APPLEDOUBLE */
4237 post_event_if_success(dvp
, _err
, NOTE_LINK
| NOTE_WRITE
);
4239 lookup_compound_vnop_post_hook(_err
, dvp
, *vpp
, ndp
, (_err
== 0));
4240 if (*vpp
&& _err
&& _err
!= EKEEPLOOKING
) {
4249 vn_rmdir(vnode_t dvp
, vnode_t
*vpp
, struct nameidata
*ndp
, struct vnode_attr
*vap
, vfs_context_t ctx
)
4251 if (vnode_compound_rmdir_available(dvp
)) {
4252 return VNOP_COMPOUND_RMDIR(dvp
, vpp
, ndp
, vap
, ctx
);
4254 if (*vpp
== NULLVP
) {
4255 panic("NULL vp, but not a compound VNOP?");
4258 panic("Non-NULL vap, but not a compound VNOP?");
4260 return VNOP_RMDIR(dvp
, *vpp
, &ndp
->ni_cnd
, ctx
);
4271 struct vnop_rmdir_args
{
4272 struct vnodeop_desc
*a_desc
;
4275 struct componentname
*a_cnp
;
4276 vfs_context_t a_context
;
4281 VNOP_RMDIR(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
*cnp
, vfs_context_t ctx
)
4284 struct vnop_rmdir_args a
;
4286 a
.a_desc
= &vnop_rmdir_desc
;
4292 _err
= (*vp
->v_op
[vnop_rmdir_desc
.vdesc_offset
])(&a
);
4293 DTRACE_FSINFO(rmdir
, vnode_t
, vp
);
4296 vnode_setneedinactive(vp
);
4297 #if CONFIG_APPLEDOUBLE
4298 if ( !(NATIVE_XATTR(dvp
)) ) {
4300 * Remove any associated extended attribute file (._ AppleDouble file).
4302 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 1);
4307 /* If you delete a dir, it loses its "." reference --> NOTE_LINK */
4308 post_event_if_success(vp
, _err
, NOTE_DELETE
| NOTE_LINK
);
4309 post_event_if_success(dvp
, _err
, NOTE_LINK
| NOTE_WRITE
);
4315 VNOP_COMPOUND_RMDIR(struct vnode
*dvp
, struct vnode
**vpp
, struct nameidata
*ndp
,
4316 struct vnode_attr
*vap
, vfs_context_t ctx
)
4319 struct vnop_compound_rmdir_args a
;
4322 a
.a_desc
= &vnop_mkdir_desc
;
4325 a
.a_cnp
= &ndp
->ni_cnd
;
4329 a
.a_rmdir_authorizer
= vn_authorize_rmdir
;
4330 a
.a_reserved
= NULL
;
4332 no_vp
= (*vpp
== NULLVP
);
4334 _err
= (*dvp
->v_op
[vnop_compound_rmdir_desc
.vdesc_offset
])(&a
);
4335 if (_err
== 0 && *vpp
) {
4336 DTRACE_FSINFO(compound_rmdir
, vnode_t
, *vpp
);
4338 #if CONFIG_APPLEDOUBLE
4339 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
4341 * Remove stale Apple Double file (if any).
4343 xattrfile_remove(dvp
, ndp
->ni_cnd
.cn_nameptr
, ctx
, 0);
4348 post_event_if_success(*vpp
, _err
, NOTE_DELETE
| NOTE_LINK
);
4350 post_event_if_success(dvp
, _err
, NOTE_LINK
| NOTE_WRITE
);
4353 lookup_compound_vnop_post_hook(_err
, dvp
, *vpp
, ndp
, 0);
4355 #if 0 /* Removing orphaned ._ files requires a vp.... */
4356 if (*vpp
&& _err
&& _err
!= EKEEPLOOKING
) {
4366 #if CONFIG_APPLEDOUBLE
4368 * Remove a ._ AppleDouble file
4370 #define AD_STALE_SECS (180)
4372 xattrfile_remove(vnode_t dvp
, const char * basename
, vfs_context_t ctx
, int force
)
4375 struct nameidata nd
;
4377 char *filename
= NULL
;
4380 if ((basename
== NULL
) || (basename
[0] == '\0') ||
4381 (basename
[0] == '.' && basename
[1] == '_')) {
4384 filename
= &smallname
[0];
4385 len
= snprintf(filename
, sizeof(smallname
), "._%s", basename
);
4386 if (len
>= sizeof(smallname
)) {
4387 len
++; /* snprintf result doesn't include '\0' */
4388 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
);
4389 len
= snprintf(filename
, len
, "._%s", basename
);
4391 NDINIT(&nd
, DELETE
, OP_UNLINK
, WANTPARENT
| LOCKLEAF
| NOFOLLOW
| USEDVP
, UIO_SYSSPACE
,
4392 CAST_USER_ADDR_T(filename
), ctx
);
4394 if (namei(&nd
) != 0)
4399 if (xvp
->v_type
!= VREG
)
4403 * When creating a new object and a "._" file already
4404 * exists, check to see if its a stale "._" file.
4408 struct vnode_attr va
;
4411 VATTR_WANTED(&va
, va_data_size
);
4412 VATTR_WANTED(&va
, va_modify_time
);
4413 if (VNOP_GETATTR(xvp
, &va
, ctx
) == 0 &&
4414 VATTR_IS_SUPPORTED(&va
, va_data_size
) &&
4415 VATTR_IS_SUPPORTED(&va
, va_modify_time
) &&
4416 va
.va_data_size
!= 0) {
4420 if ((tv
.tv_sec
> va
.va_modify_time
.tv_sec
) &&
4421 (tv
.tv_sec
- va
.va_modify_time
.tv_sec
) > AD_STALE_SECS
) {
4422 force
= 1; /* must be stale */
4429 error
= VNOP_REMOVE(dvp
, xvp
, &nd
.ni_cnd
, 0, ctx
);
4431 vnode_setneedinactive(xvp
);
4433 post_event_if_success(xvp
, error
, NOTE_DELETE
);
4434 post_event_if_success(dvp
, error
, NOTE_WRITE
);
4441 if (filename
&& filename
!= &smallname
[0]) {
4442 FREE(filename
, M_TEMP
);
4447 * Shadow uid/gid/mod to a ._ AppleDouble file
4450 xattrfile_setattr(vnode_t dvp
, const char * basename
, struct vnode_attr
* vap
,
4454 struct nameidata nd
;
4456 char *filename
= NULL
;
4459 if ((dvp
== NULLVP
) ||
4460 (basename
== NULL
) || (basename
[0] == '\0') ||
4461 (basename
[0] == '.' && basename
[1] == '_')) {
4464 filename
= &smallname
[0];
4465 len
= snprintf(filename
, sizeof(smallname
), "._%s", basename
);
4466 if (len
>= sizeof(smallname
)) {
4467 len
++; /* snprintf result doesn't include '\0' */
4468 MALLOC(filename
, char *, len
, M_TEMP
, M_WAITOK
);
4469 len
= snprintf(filename
, len
, "._%s", basename
);
4471 NDINIT(&nd
, LOOKUP
, OP_SETATTR
, NOFOLLOW
| USEDVP
, UIO_SYSSPACE
,
4472 CAST_USER_ADDR_T(filename
), ctx
);
4474 if (namei(&nd
) != 0)
4480 if (xvp
->v_type
== VREG
) {
4481 struct vnop_setattr_args a
;
4483 a
.a_desc
= &vnop_setattr_desc
;
4488 (void) (*xvp
->v_op
[vnop_setattr_desc
.vdesc_offset
])(&a
);
4493 if (filename
&& filename
!= &smallname
[0]) {
4494 FREE(filename
, M_TEMP
);
4497 #endif /* CONFIG_APPLEDOUBLE */
4502 *#% symlink dvp L U U
4503 *#% symlink vpp - U -
4506 struct vnop_symlink_args
{
4507 struct vnodeop_desc
*a_desc
;
4510 struct componentname
*a_cnp
;
4511 struct vnode_attr
*a_vap
;
4513 vfs_context_t a_context
;
4518 VNOP_SYMLINK(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
,
4519 struct vnode_attr
*vap
, char *target
, vfs_context_t ctx
)
4522 struct vnop_symlink_args a
;
4524 a
.a_desc
= &vnop_symlink_desc
;
4529 a
.a_target
= target
;
4532 _err
= (*dvp
->v_op
[vnop_symlink_desc
.vdesc_offset
])(&a
);
4533 DTRACE_FSINFO(symlink
, vnode_t
, dvp
);
4534 #if CONFIG_APPLEDOUBLE
4535 if (_err
== 0 && !NATIVE_XATTR(dvp
)) {
4537 * Remove stale Apple Double file (if any). Posts its own knotes
4539 xattrfile_remove(dvp
, cnp
->cn_nameptr
, ctx
, 0);
4541 #endif /* CONFIG_APPLEDOUBLE */
4543 post_event_if_success(dvp
, _err
, NOTE_WRITE
);
4551 *#% readdir vp L L L
4554 struct vnop_readdir_args
{
4555 struct vnodeop_desc
*a_desc
;
4561 vfs_context_t a_context
;
4566 VNOP_READDIR(struct vnode
*vp
, struct uio
*uio
, int flags
, int *eofflag
,
4567 int *numdirent
, vfs_context_t ctx
)
4570 struct vnop_readdir_args a
;
4572 user_ssize_t resid
= uio_resid(uio
);
4575 a
.a_desc
= &vnop_readdir_desc
;
4579 a
.a_eofflag
= eofflag
;
4580 a
.a_numdirent
= numdirent
;
4583 _err
= (*vp
->v_op
[vnop_readdir_desc
.vdesc_offset
])(&a
);
4584 DTRACE_FSINFO_IO(readdir
,
4585 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
4593 *#% readdirattr vp L L L
4596 struct vnop_readdirattr_args
{
4597 struct vnodeop_desc
*a_desc
;
4599 struct attrlist
*a_alist
;
4601 uint32_t a_maxcount
;
4603 uint32_t *a_newstate
;
4605 uint32_t *a_actualcount
;
4606 vfs_context_t a_context
;
4611 VNOP_READDIRATTR(struct vnode
*vp
, struct attrlist
*alist
, struct uio
*uio
, uint32_t maxcount
,
4612 uint32_t options
, uint32_t *newstate
, int *eofflag
, uint32_t *actualcount
, vfs_context_t ctx
)
4615 struct vnop_readdirattr_args a
;
4617 user_ssize_t resid
= uio_resid(uio
);
4620 a
.a_desc
= &vnop_readdirattr_desc
;
4624 a
.a_maxcount
= maxcount
;
4625 a
.a_options
= options
;
4626 a
.a_newstate
= newstate
;
4627 a
.a_eofflag
= eofflag
;
4628 a
.a_actualcount
= actualcount
;
4631 _err
= (*vp
->v_op
[vnop_readdirattr_desc
.vdesc_offset
])(&a
);
4632 DTRACE_FSINFO_IO(readdirattr
,
4633 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
4639 struct vnop_getttrlistbulk_args
{
4640 struct vnodeop_desc
*a_desc
;
4642 struct attrlist
*a_alist
;
4643 struct vnode_attr
*a_vap
;
4648 uint32_t *a_actualcount
;
4649 vfs_context_t a_context
;
4653 VNOP_GETATTRLISTBULK(struct vnode
*vp
, struct attrlist
*alist
,
4654 struct vnode_attr
*vap
, struct uio
*uio
, void *private, uint64_t options
,
4655 int32_t *eofflag
, int32_t *actualcount
, vfs_context_t ctx
)
4658 struct vnop_getattrlistbulk_args a
;
4660 user_ssize_t resid
= uio_resid(uio
);
4663 a
.a_desc
= &vnop_getattrlistbulk_desc
;
4668 a
.a_private
= private;
4669 a
.a_options
= options
;
4670 a
.a_eofflag
= eofflag
;
4671 a
.a_actualcount
= actualcount
;
4674 _err
= (*vp
->v_op
[vnop_getattrlistbulk_desc
.vdesc_offset
])(&a
);
4675 DTRACE_FSINFO_IO(getattrlistbulk
,
4676 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
4684 *#% readlink vp L L L
4687 struct vnop_readlink_args
{
4688 struct vnodeop_desc
*a_desc
;
4691 vfs_context_t a_context
;
4696 * Returns: 0 Success
4697 * lock_fsnode:ENOENT No such file or directory [only for VFS
4698 * that is not thread safe & vnode is
4699 * currently being/has been terminated]
4700 * <vfs_readlink>:EINVAL
4701 * <vfs_readlink>:???
4703 * Note: The return codes from the underlying VFS's readlink routine
4704 * can't be fully enumerated here, since third party VFS authors
4705 * may not limit their error returns to the ones documented here,
4706 * even though this may result in some programs functioning
4709 * The return codes documented above are those which may currently
4710 * be returned by HFS from hfs_vnop_readlink, not including
4711 * additional error code which may be propagated from underlying
4715 VNOP_READLINK(struct vnode
*vp
, struct uio
*uio
, vfs_context_t ctx
)
4718 struct vnop_readlink_args a
;
4720 user_ssize_t resid
= uio_resid(uio
);
4722 a
.a_desc
= &vnop_readlink_desc
;
4727 _err
= (*vp
->v_op
[vnop_readlink_desc
.vdesc_offset
])(&a
);
4728 DTRACE_FSINFO_IO(readlink
,
4729 vnode_t
, vp
, user_ssize_t
, (resid
- uio_resid(uio
)));
4737 *#% inactive vp L U U
4740 struct vnop_inactive_args
{
4741 struct vnodeop_desc
*a_desc
;
4743 vfs_context_t a_context
;
4747 VNOP_INACTIVE(struct vnode
*vp
, vfs_context_t ctx
)
4750 struct vnop_inactive_args a
;
4752 a
.a_desc
= &vnop_inactive_desc
;
4756 _err
= (*vp
->v_op
[vnop_inactive_desc
.vdesc_offset
])(&a
);
4757 DTRACE_FSINFO(inactive
, vnode_t
, vp
);
4760 /* For file systems that do not support namedstream natively, mark
4761 * the shadow stream file vnode to be recycled as soon as the last
4762 * reference goes away. To avoid re-entering reclaim code, do not
4763 * call recycle on terminating namedstream vnodes.
4765 if (vnode_isnamedstream(vp
) &&
4766 (vp
->v_parent
!= NULLVP
) &&
4767 vnode_isshadow(vp
) &&
4768 ((vp
->v_lflag
& VL_TERMINATE
) == 0)) {
4780 *#% reclaim vp U U U
4783 struct vnop_reclaim_args
{
4784 struct vnodeop_desc
*a_desc
;
4786 vfs_context_t a_context
;
4790 VNOP_RECLAIM(struct vnode
*vp
, vfs_context_t ctx
)
4793 struct vnop_reclaim_args a
;
4795 a
.a_desc
= &vnop_reclaim_desc
;
4799 _err
= (*vp
->v_op
[vnop_reclaim_desc
.vdesc_offset
])(&a
);
4800 DTRACE_FSINFO(reclaim
, vnode_t
, vp
);
4807 * Returns: 0 Success
4808 * lock_fsnode:ENOENT No such file or directory [only for VFS
4809 * that is not thread safe & vnode is
4810 * currently being/has been terminated]
4811 * <vnop_pathconf_desc>:??? [per FS implementation specific]
4816 *#% pathconf vp L L L
4819 struct vnop_pathconf_args
{
4820 struct vnodeop_desc
*a_desc
;
4824 vfs_context_t a_context
;
4828 VNOP_PATHCONF(struct vnode
*vp
, int name
, int32_t *retval
, vfs_context_t ctx
)
4831 struct vnop_pathconf_args a
;
4833 a
.a_desc
= &vnop_pathconf_desc
;
4836 a
.a_retval
= retval
;
4839 _err
= (*vp
->v_op
[vnop_pathconf_desc
.vdesc_offset
])(&a
);
4840 DTRACE_FSINFO(pathconf
, vnode_t
, vp
);
4846 * Returns: 0 Success
4847 * err_advlock:ENOTSUP
4849 * <vnop_advlock_desc>:???
4851 * Notes: VFS implementations of advisory locking using calls through
4852 * <vnop_advlock_desc> because lock enforcement does not occur
4853 * locally should try to limit themselves to the return codes
4854 * documented above for lf_advlock and err_advlock.
4859 *#% advlock vp U U U
4862 struct vnop_advlock_args
{
4863 struct vnodeop_desc
*a_desc
;
4869 vfs_context_t a_context
;
4873 VNOP_ADVLOCK(struct vnode
*vp
, caddr_t id
, int op
, struct flock
*fl
, int flags
, vfs_context_t ctx
, struct timespec
*timeout
)
4876 struct vnop_advlock_args a
;
4878 a
.a_desc
= &vnop_advlock_desc
;
4885 a
.a_timeout
= timeout
;
4887 /* Disallow advisory locking on non-seekable vnodes */
4888 if (vnode_isfifo(vp
)) {
4889 _err
= err_advlock(&a
);
4891 if ((vp
->v_flag
& VLOCKLOCAL
)) {
4892 /* Advisory locking done at this layer */
4893 _err
= lf_advlock(&a
);
4895 /* Advisory locking done by underlying filesystem */
4896 _err
= (*vp
->v_op
[vnop_advlock_desc
.vdesc_offset
])(&a
);
4898 DTRACE_FSINFO(advlock
, vnode_t
, vp
);
4909 *#% allocate vp L L L
4912 struct vnop_allocate_args
{
4913 struct vnodeop_desc
*a_desc
;
4917 off_t
*a_bytesallocated
;
4919 vfs_context_t a_context
;
4924 VNOP_ALLOCATE(struct vnode
*vp
, off_t length
, u_int32_t flags
, off_t
*bytesallocated
, off_t offset
, vfs_context_t ctx
)
4927 struct vnop_allocate_args a
;
4929 a
.a_desc
= &vnop_allocate_desc
;
4931 a
.a_length
= length
;
4933 a
.a_bytesallocated
= bytesallocated
;
4934 a
.a_offset
= offset
;
4937 _err
= (*vp
->v_op
[vnop_allocate_desc
.vdesc_offset
])(&a
);
4938 DTRACE_FSINFO(allocate
, vnode_t
, vp
);
4941 add_fsevent(FSE_STAT_CHANGED
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
4954 struct vnop_pagein_args
{
4955 struct vnodeop_desc
*a_desc
;
4958 upl_offset_t a_pl_offset
;
4962 vfs_context_t a_context
;
4966 VNOP_PAGEIN(struct vnode
*vp
, upl_t pl
, upl_offset_t pl_offset
, off_t f_offset
, size_t size
, int flags
, vfs_context_t ctx
)
4969 struct vnop_pagein_args a
;
4971 a
.a_desc
= &vnop_pagein_desc
;
4974 a
.a_pl_offset
= pl_offset
;
4975 a
.a_f_offset
= f_offset
;
4980 _err
= (*vp
->v_op
[vnop_pagein_desc
.vdesc_offset
])(&a
);
4981 DTRACE_FSINFO(pagein
, vnode_t
, vp
);
4989 *#% pageout vp = = =
4992 struct vnop_pageout_args
{
4993 struct vnodeop_desc
*a_desc
;
4996 upl_offset_t a_pl_offset
;
5000 vfs_context_t a_context
;
5005 VNOP_PAGEOUT(struct vnode
*vp
, upl_t pl
, upl_offset_t pl_offset
, off_t f_offset
, size_t size
, int flags
, vfs_context_t ctx
)
5008 struct vnop_pageout_args a
;
5010 a
.a_desc
= &vnop_pageout_desc
;
5013 a
.a_pl_offset
= pl_offset
;
5014 a
.a_f_offset
= f_offset
;
5019 _err
= (*vp
->v_op
[vnop_pageout_desc
.vdesc_offset
])(&a
);
5020 DTRACE_FSINFO(pageout
, vnode_t
, vp
);
5022 post_event_if_success(vp
, _err
, NOTE_WRITE
);
5028 vn_remove(vnode_t dvp
, vnode_t
*vpp
, struct nameidata
*ndp
, int32_t flags
, struct vnode_attr
*vap
, vfs_context_t ctx
)
5030 if (vnode_compound_remove_available(dvp
)) {
5031 return VNOP_COMPOUND_REMOVE(dvp
, vpp
, ndp
, flags
, vap
, ctx
);
5033 return VNOP_REMOVE(dvp
, *vpp
, &ndp
->ni_cnd
, flags
, ctx
);
5042 *#% searchfs vp L L L
5045 struct vnop_searchfs_args
{
5046 struct vnodeop_desc
*a_desc
;
5048 void *a_searchparams1
;
5049 void *a_searchparams2
;
5050 struct attrlist
*a_searchattrs
;
5051 uint32_t a_maxmatches
;
5052 struct timeval
*a_timelimit
;
5053 struct attrlist
*a_returnattrs
;
5054 uint32_t *a_nummatches
;
5055 uint32_t a_scriptcode
;
5058 struct searchstate
*a_searchstate
;
5059 vfs_context_t a_context
;
5064 VNOP_SEARCHFS(struct vnode
*vp
, void *searchparams1
, void *searchparams2
, struct attrlist
*searchattrs
, uint32_t maxmatches
, struct timeval
*timelimit
, struct attrlist
*returnattrs
, uint32_t *nummatches
, uint32_t scriptcode
, uint32_t options
, struct uio
*uio
, struct searchstate
*searchstate
, vfs_context_t ctx
)
5067 struct vnop_searchfs_args a
;
5069 a
.a_desc
= &vnop_searchfs_desc
;
5071 a
.a_searchparams1
= searchparams1
;
5072 a
.a_searchparams2
= searchparams2
;
5073 a
.a_searchattrs
= searchattrs
;
5074 a
.a_maxmatches
= maxmatches
;
5075 a
.a_timelimit
= timelimit
;
5076 a
.a_returnattrs
= returnattrs
;
5077 a
.a_nummatches
= nummatches
;
5078 a
.a_scriptcode
= scriptcode
;
5079 a
.a_options
= options
;
5081 a
.a_searchstate
= searchstate
;
5084 _err
= (*vp
->v_op
[vnop_searchfs_desc
.vdesc_offset
])(&a
);
5085 DTRACE_FSINFO(searchfs
, vnode_t
, vp
);
5089 #endif /* CONFIG_SEARCHFS */
5094 *#% copyfile fvp U U U
5095 *#% copyfile tdvp L U U
5096 *#% copyfile tvp X U U
5099 struct vnop_copyfile_args
{
5100 struct vnodeop_desc
*a_desc
;
5104 struct componentname
*a_tcnp
;
5107 vfs_context_t a_context
;
5111 VNOP_COPYFILE(struct vnode
*fvp
, struct vnode
*tdvp
, struct vnode
*tvp
, struct componentname
*tcnp
,
5112 int mode
, int flags
, vfs_context_t ctx
)
5115 struct vnop_copyfile_args a
;
5116 a
.a_desc
= &vnop_copyfile_desc
;
5124 _err
= (*fvp
->v_op
[vnop_copyfile_desc
.vdesc_offset
])(&a
);
5125 DTRACE_FSINFO(copyfile
, vnode_t
, fvp
);
5130 VNOP_GETXATTR(vnode_t vp
, const char *name
, uio_t uio
, size_t *size
, int options
, vfs_context_t ctx
)
5132 struct vnop_getxattr_args a
;
5135 a
.a_desc
= &vnop_getxattr_desc
;
5140 a
.a_options
= options
;
5143 error
= (*vp
->v_op
[vnop_getxattr_desc
.vdesc_offset
])(&a
);
5144 DTRACE_FSINFO(getxattr
, vnode_t
, vp
);
5150 VNOP_SETXATTR(vnode_t vp
, const char *name
, uio_t uio
, int options
, vfs_context_t ctx
)
5152 struct vnop_setxattr_args a
;
5155 a
.a_desc
= &vnop_setxattr_desc
;
5159 a
.a_options
= options
;
5162 error
= (*vp
->v_op
[vnop_setxattr_desc
.vdesc_offset
])(&a
);
5163 DTRACE_FSINFO(setxattr
, vnode_t
, vp
);
5166 vnode_uncache_authorized_action(vp
, KAUTH_INVALIDATE_CACHED_RIGHTS
);
5168 post_event_if_success(vp
, error
, NOTE_ATTRIB
);
5174 VNOP_REMOVEXATTR(vnode_t vp
, const char *name
, int options
, vfs_context_t ctx
)
5176 struct vnop_removexattr_args a
;
5179 a
.a_desc
= &vnop_removexattr_desc
;
5182 a
.a_options
= options
;
5185 error
= (*vp
->v_op
[vnop_removexattr_desc
.vdesc_offset
])(&a
);
5186 DTRACE_FSINFO(removexattr
, vnode_t
, vp
);
5188 post_event_if_success(vp
, error
, NOTE_ATTRIB
);
5194 VNOP_LISTXATTR(vnode_t vp
, uio_t uio
, size_t *size
, int options
, vfs_context_t ctx
)
5196 struct vnop_listxattr_args a
;
5199 a
.a_desc
= &vnop_listxattr_desc
;
5203 a
.a_options
= options
;
5206 error
= (*vp
->v_op
[vnop_listxattr_desc
.vdesc_offset
])(&a
);
5207 DTRACE_FSINFO(listxattr
, vnode_t
, vp
);
5216 *#% blktooff vp = = =
5219 struct vnop_blktooff_args
{
5220 struct vnodeop_desc
*a_desc
;
5227 VNOP_BLKTOOFF(struct vnode
*vp
, daddr64_t lblkno
, off_t
*offset
)
5230 struct vnop_blktooff_args a
;
5232 a
.a_desc
= &vnop_blktooff_desc
;
5234 a
.a_lblkno
= lblkno
;
5235 a
.a_offset
= offset
;
5237 _err
= (*vp
->v_op
[vnop_blktooff_desc
.vdesc_offset
])(&a
);
5238 DTRACE_FSINFO(blktooff
, vnode_t
, vp
);
5246 *#% offtoblk vp = = =
5249 struct vnop_offtoblk_args
{
5250 struct vnodeop_desc
*a_desc
;
5253 daddr64_t
*a_lblkno
;
5257 VNOP_OFFTOBLK(struct vnode
*vp
, off_t offset
, daddr64_t
*lblkno
)
5260 struct vnop_offtoblk_args a
;
5262 a
.a_desc
= &vnop_offtoblk_desc
;
5264 a
.a_offset
= offset
;
5265 a
.a_lblkno
= lblkno
;
5267 _err
= (*vp
->v_op
[vnop_offtoblk_desc
.vdesc_offset
])(&a
);
5268 DTRACE_FSINFO(offtoblk
, vnode_t
, vp
);
5276 *#% blockmap vp L L L
5279 struct vnop_blockmap_args
{
5280 struct vnodeop_desc
*a_desc
;
5288 vfs_context_t a_context
;
5292 VNOP_BLOCKMAP(struct vnode
*vp
, off_t foffset
, size_t size
, daddr64_t
*bpn
, size_t *run
, void *poff
, int flags
, vfs_context_t ctx
)
5295 struct vnop_blockmap_args a
;
5296 size_t localrun
= 0;
5299 ctx
= vfs_context_current();
5301 a
.a_desc
= &vnop_blockmap_desc
;
5303 a
.a_foffset
= foffset
;
5306 a
.a_run
= &localrun
;
5311 _err
= (*vp
->v_op
[vnop_blockmap_desc
.vdesc_offset
])(&a
);
5312 DTRACE_FSINFO(blockmap
, vnode_t
, vp
);
5315 * We used a local variable to request information from the underlying
5316 * filesystem about the length of the I/O run in question. If
5317 * we get malformed output from the filesystem, we cap it to the length
5318 * requested, at most. Update 'run' on the way out.
5321 if (localrun
> size
) {
5334 struct vnop_strategy_args
{
5335 struct vnodeop_desc
*a_desc
;
5341 VNOP_STRATEGY(struct buf
*bp
)
5344 struct vnop_strategy_args a
;
5345 vnode_t vp
= buf_vnode(bp
);
5346 a
.a_desc
= &vnop_strategy_desc
;
5348 _err
= (*vp
->v_op
[vnop_strategy_desc
.vdesc_offset
])(&a
);
5349 DTRACE_FSINFO(strategy
, vnode_t
, vp
);
5354 struct vnop_bwrite_args
{
5355 struct vnodeop_desc
*a_desc
;
5360 VNOP_BWRITE(struct buf
*bp
)
5363 struct vnop_bwrite_args a
;
5364 vnode_t vp
= buf_vnode(bp
);
5365 a
.a_desc
= &vnop_bwrite_desc
;
5367 _err
= (*vp
->v_op
[vnop_bwrite_desc
.vdesc_offset
])(&a
);
5368 DTRACE_FSINFO(bwrite
, vnode_t
, vp
);
5373 struct vnop_kqfilt_add_args
{
5374 struct vnodeop_desc
*a_desc
;
5377 vfs_context_t a_context
;
5381 VNOP_KQFILT_ADD(struct vnode
*vp
, struct knote
*kn
, vfs_context_t ctx
)
5384 struct vnop_kqfilt_add_args a
;
5386 a
.a_desc
= VDESC(vnop_kqfilt_add
);
5391 _err
= (*vp
->v_op
[vnop_kqfilt_add_desc
.vdesc_offset
])(&a
);
5392 DTRACE_FSINFO(kqfilt_add
, vnode_t
, vp
);
5398 struct vnop_kqfilt_remove_args
{
5399 struct vnodeop_desc
*a_desc
;
5402 vfs_context_t a_context
;
5406 VNOP_KQFILT_REMOVE(struct vnode
*vp
, uintptr_t ident
, vfs_context_t ctx
)
5409 struct vnop_kqfilt_remove_args a
;
5411 a
.a_desc
= VDESC(vnop_kqfilt_remove
);
5416 _err
= (*vp
->v_op
[vnop_kqfilt_remove_desc
.vdesc_offset
])(&a
);
5417 DTRACE_FSINFO(kqfilt_remove
, vnode_t
, vp
);
5423 VNOP_MONITOR(vnode_t vp
, uint32_t events
, uint32_t flags
, void *handle
, vfs_context_t ctx
)
5426 struct vnop_monitor_args a
;
5428 a
.a_desc
= VDESC(vnop_monitor
);
5430 a
.a_events
= events
;
5432 a
.a_handle
= handle
;
5435 _err
= (*vp
->v_op
[vnop_monitor_desc
.vdesc_offset
])(&a
);
5436 DTRACE_FSINFO(monitor
, vnode_t
, vp
);
5442 struct vnop_setlabel_args
{
5443 struct vnodeop_desc
*a_desc
;
5446 vfs_context_t a_context
;
5450 VNOP_SETLABEL(struct vnode
*vp
, struct label
*label
, vfs_context_t ctx
)
5453 struct vnop_setlabel_args a
;
5455 a
.a_desc
= VDESC(vnop_setlabel
);
5460 _err
= (*vp
->v_op
[vnop_setlabel_desc
.vdesc_offset
])(&a
);
5461 DTRACE_FSINFO(setlabel
, vnode_t
, vp
);
5469 * Get a named streamed
5472 VNOP_GETNAMEDSTREAM(vnode_t vp
, vnode_t
*svpp
, const char *name
, enum nsoperation operation
, int flags
, vfs_context_t ctx
)
5475 struct vnop_getnamedstream_args a
;
5477 a
.a_desc
= &vnop_getnamedstream_desc
;
5481 a
.a_operation
= operation
;
5485 _err
= (*vp
->v_op
[vnop_getnamedstream_desc
.vdesc_offset
])(&a
);
5486 DTRACE_FSINFO(getnamedstream
, vnode_t
, vp
);
5491 * Create a named streamed
5494 VNOP_MAKENAMEDSTREAM(vnode_t vp
, vnode_t
*svpp
, const char *name
, int flags
, vfs_context_t ctx
)
5497 struct vnop_makenamedstream_args a
;
5499 a
.a_desc
= &vnop_makenamedstream_desc
;
5506 _err
= (*vp
->v_op
[vnop_makenamedstream_desc
.vdesc_offset
])(&a
);
5507 DTRACE_FSINFO(makenamedstream
, vnode_t
, vp
);
5513 * Remove a named streamed
5516 VNOP_REMOVENAMEDSTREAM(vnode_t vp
, vnode_t svp
, const char *name
, int flags
, vfs_context_t ctx
)
5519 struct vnop_removenamedstream_args a
;
5521 a
.a_desc
= &vnop_removenamedstream_desc
;
5528 _err
= (*vp
->v_op
[vnop_removenamedstream_desc
.vdesc_offset
])(&a
);
5529 DTRACE_FSINFO(removenamedstream
, vnode_t
, vp
);