]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/kpi_vfs.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / bsd / vfs / kpi_vfs.c
index dff5f82d3ec9ff902137bed408c796b1b64ca83f..f4ef76113f593be558e8cc5a3ab76ac088ad9b8f 100644 (file)
 #include <sys/mount.h>
 #include <sys/mount_internal.h>
 #include <sys/time.h>
+#include <sys/disk.h>
 #include <sys/vnode_internal.h>
 #include <sys/stat.h>
 #include <sys/namei.h>
 #include <sys/ucred.h>
 #include <sys/buf.h>
 #include <sys/errno.h>
-#include <sys/malloc.h>
+#include <kern/kalloc.h>
 #include <sys/domain.h>
 #include <sys/mbuf.h>
 #include <sys/syslog.h>
 #include <sys/kdebug.h>
 
 #include <kern/assert.h>
-#include <kern/kalloc.h>
+#include <kern/zalloc.h>
 #include <kern/task.h>
 #include <kern/policy_internal.h>
 
@@ -144,8 +145,13 @@ static void xattrfile_setattr(vnode_t dvp, const char * basename,
     struct vnode_attr * vap, vfs_context_t ctx);
 #endif /* CONFIG_APPLEDOUBLE */
 
+extern lck_rw_t * rootvnode_rw_lock;
+
 static errno_t post_rename(vnode_t fdvp, vnode_t fvp, vnode_t tdvp, vnode_t tvp);
 
+static ZONE_VIEW_DEFINE(ZV_VFS_CONTEXT, "vfs_context",
+    KHEAP_ID_DEFAULT, sizeof(struct vfs_context));
+
 /*
  * vnode_setneedinactive
  *
@@ -444,6 +450,12 @@ vfs_mntlabel(mount_t mp)
        return (void*)mp->mnt_mntlabel;
 }
 
+uint64_t
+vfs_mount_id(mount_t mp)
+{
+       return mp->mnt_mount_id;
+}
+
 /* returns command modifier flags of mount_t ie. MNT_CMDFLAGS */
 uint64_t
 vfs_flags(mount_t mp)
@@ -642,6 +654,30 @@ vfs_setextendedsecurity(mount_t mp)
        mount_unlock(mp);
 }
 
+void
+vfs_setmntsystem(mount_t mp)
+{
+       mount_lock(mp);
+       mp->mnt_kern_flag |= MNTK_SYSTEM;
+       mount_unlock(mp);
+}
+
+void
+vfs_setmntsystemdata(mount_t mp)
+{
+       mount_lock(mp);
+       mp->mnt_kern_flag |= MNTK_SYSTEMDATA;
+       mount_unlock(mp);
+}
+
+void
+vfs_setmntswap(mount_t mp)
+{
+       mount_lock(mp);
+       mp->mnt_kern_flag |= (MNTK_SYSTEM | MNTK_SWAP_MOUNT);
+       mount_unlock(mp);
+}
+
 void
 vfs_clearextendedsecurity(mount_t mp)
 {
@@ -686,6 +722,12 @@ vfs_setmaxsymlen(mount_t mp, uint32_t symlen)
        mp->mnt_maxsymlinklen = symlen;
 }
 
+boolean_t
+vfs_is_basesystem(mount_t mp)
+{
+       return ((mp->mnt_supl_kern_flag & MNTK_SUPL_BASESYSTEM) == 0) ? false : true;
+}
+
 /* return a pointer to the RO vfs_statfs associated with mount_t */
 struct vfsstatfs *
 vfs_statfs(mount_t mp)
@@ -725,7 +767,7 @@ vfs_setattr(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx)
         * the volume name
         */
        if (vfs_isrdonly(mp) &&
-           !((mp->mnt_flag & MNT_ROOTFS) && (vfa->f_active == VFSATTR_f_vol_name))) {
+           !((strcmp(mp->mnt_vfsstat.f_fstypename, "apfs") == 0) && (vfa->f_active == VFSATTR_f_vol_name))) {
                return EROFS;
        }
 
@@ -899,9 +941,8 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t *handle)
                return EINVAL;
        }
 
-       MALLOC(newvfstbl, void *, sizeof(struct vfstable), M_TEMP,
-           M_WAITOK);
-       bzero(newvfstbl, sizeof(struct vfstable));
+       newvfstbl = kheap_alloc(KHEAP_TEMP, sizeof(struct vfstable),
+           Z_WAITOK | Z_ZERO);
        newvfstbl->vfc_vfsops = vfe->vfe_vfsops;
        strncpy(&newvfstbl->vfc_name[0], vfe->vfe_fsname, MFSNAMELEN);
        if ((vfe->vfe_flags & VFS_TBLNOTYPENUM)) {
@@ -965,9 +1006,7 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t *handle)
        /* XXX - shouldn't be M_TEMP */
 
        descsize = desccount * vfs_opv_numops * sizeof(PFI);
-       MALLOC(descptr, PFI *, descsize,
-           M_TEMP, M_WAITOK);
-       bzero(descptr, descsize);
+       descptr = kheap_alloc(KHEAP_DEFAULT, descsize, Z_WAITOK | Z_ZERO);
 
        newvfstbl->vfc_descptr = descptr;
        newvfstbl->vfc_descsize = descsize;
@@ -1069,7 +1108,7 @@ vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t *handle)
                (*newvfstbl->vfc_vfsops->vfs_init)(&vfsc);
        }
 
-       FREE(newvfstbl, M_TEMP);
+       kheap_free(KHEAP_TEMP, newvfstbl, sizeof(struct vfstable));
 
        return 0;
 }
@@ -1084,6 +1123,7 @@ vfs_fsremove(vfstable_t handle)
 {
        struct vfstable * vfstbl =  (struct vfstable *)handle;
        void *old_desc = NULL;
+       size_t descsize = 0;
        errno_t err;
 
        /* Preflight check for any mounts */
@@ -1099,14 +1139,15 @@ vfs_fsremove(vfstable_t handle)
         */
        if (vfstbl->vfc_descptr && vfstbl->vfc_descsize) {
                old_desc = vfstbl->vfc_descptr;
+               descsize = vfstbl->vfc_descsize;
        }
        err = vfstable_del(vfstbl);
 
        mount_list_unlock();
 
        /* free the descriptor if the delete was successful */
-       if (err == 0 && old_desc) {
-               FREE(old_desc, M_TEMP);
+       if (err == 0) {
+               kheap_free(KHEAP_DEFAULT, old_desc, descsize);
        }
 
        return err;
@@ -1180,6 +1221,20 @@ vfs_context_is64bit(vfs_context_t ctx)
        return 0;
 }
 
+boolean_t
+vfs_context_can_resolve_triggers(vfs_context_t ctx)
+{
+       proc_t proc = vfs_context_proc(ctx);
+
+       if (proc) {
+               if (proc->p_vfs_iopolicy &
+                   P_VFS_IOPOLICY_TRIGGER_RESOLVE_DISABLE) {
+                       return false;
+               }
+               return true;
+       }
+       return false;
+}
 
 /*
  * vfs_context_proc
@@ -1348,7 +1403,7 @@ vfs_context_create(vfs_context_t ctx)
 {
        vfs_context_t newcontext;
 
-       newcontext = (vfs_context_t)kalloc(sizeof(struct vfs_context));
+       newcontext = zalloc_flags(ZV_VFS_CONTEXT, Z_WAITOK | Z_ZERO);
 
        if (newcontext) {
                kauth_cred_t safecred;
@@ -1373,7 +1428,7 @@ vfs_context_t
 vfs_context_current(void)
 {
        vfs_context_t ctx = NULL;
-       volatile uthread_t ut = (uthread_t)get_bsdthread_info(current_thread());
+       uthread_t ut = (uthread_t)get_bsdthread_info(current_thread());
 
        if (ut != NULL) {
                if (ut->uu_context.vc_ucred != NULL) {
@@ -1398,24 +1453,22 @@ vfs_context_current(void)
  * This is also used by imageboot_setup(), called early from bsd_init() after
  * kernproc has been given a credential.
  *
- * Note: The use of proc_thread() here is a convenience to avoid inclusion
- * of many Mach headers to do the reference directly rather than indirectly;
- * we will need to forego this convenience when we reture proc_thread().
  */
 static struct vfs_context kerncontext;
 vfs_context_t
 vfs_context_kernel(void)
 {
-       if (kerncontext.vc_ucred == NOCRED) {
-               kerncontext.vc_ucred = kernproc->p_ucred;
-       }
-       if (kerncontext.vc_thread == NULL) {
-               kerncontext.vc_thread = proc_thread(kernproc);
-       }
-
        return &kerncontext;
 }
 
+/*
+ * Called early in bsd_init() when kernproc sets its thread and cred context.
+ */
+void
+vfs_set_context_kernel(vfs_context_t ctx)
+{
+       kerncontext = *ctx;
+}
 
 int
 vfs_context_rele(vfs_context_t ctx)
@@ -1424,7 +1477,7 @@ vfs_context_rele(vfs_context_t ctx)
                if (IS_VALID_CRED(ctx->vc_ucred)) {
                        kauth_cred_unref(&ctx->vc_ucred);
                }
-               kfree(ctx, sizeof(struct vfs_context));
+               zfree(ZV_VFS_CONTEXT, ctx);
        }
        return 0;
 }
@@ -1514,7 +1567,9 @@ vfs_rootvnode(void)
 {
        int error;
 
+       lck_rw_lock_shared(rootvnode_rw_lock);
        error = vnode_get(rootvnode);
+       lck_rw_unlock_shared(rootvnode_rw_lock);
        if (error) {
                return (vnode_t)0;
        } else {
@@ -2028,7 +2083,12 @@ vnode_clearmountedon(vnode_t vp)
 void
 vnode_settag(vnode_t vp, int tag)
 {
-       vp->v_tag = tag;
+       /*
+        * We only assign enum values to v_tag, but add an assert to make sure we
+        * catch it in dev/debug builds if this ever change.
+        */
+       assert(tag >= SHRT_MIN && tag <= SHRT_MAX);
+       vp->v_tag = (uint16_t)tag;
 }
 
 int
@@ -2170,21 +2230,6 @@ current_workingdir(void)
        return vfs_context_cwd(vfs_context_current());
 }
 
-/* returns vnode ref to current root(chroot) directory */
-vnode_t
-current_rootdir(void)
-{
-       proc_t proc = current_proc();
-       struct vnode * vp;
-
-       if ((vp = proc->p_fd->fd_rdir)) {
-               if ((vnode_getwithref(vp))) {
-                       return NULL;
-               }
-       }
-       return vp;
-}
-
 /*
  * Get a filesec and optional acl contents from an extended attribute.
  * Function will attempt to retrive ACL, UUID, and GUID information using a
@@ -2264,7 +2309,7 @@ vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
        }
 
        /* get buffer and uio */
-       if (((fsec = kauth_filesec_alloc(fsec_size)) == NULL) ||
+       if (((fsec = kauth_filesec_alloc((int)fsec_size)) == NULL) ||
            ((fsec_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ)) == NULL) ||
            uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), xsize)) {
                KAUTH_DEBUG("    ERROR - could not allocate iov to read ACL");
@@ -2408,6 +2453,54 @@ out:
        return error;
 }
 
+/*
+ * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
+ */
+void
+vnode_attr_handle_mnt_ignore_ownership(struct vnode_attr *vap, mount_t mp, vfs_context_t ctx)
+{
+       uid_t   nuid;
+       gid_t   ngid;
+
+       if (VATTR_IS_ACTIVE(vap, va_uid)) {
+               if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_uid)) {
+                       nuid = vap->va_uid;
+               } else if (mp->mnt_flag & MNT_IGNORE_OWNERSHIP) {
+                       nuid = mp->mnt_fsowner;
+                       if (nuid == KAUTH_UID_NONE) {
+                               nuid = 99;
+                       }
+               } else if (VATTR_IS_SUPPORTED(vap, va_uid)) {
+                       nuid = vap->va_uid;
+               } else {
+                       /* this will always be something sensible */
+                       nuid = mp->mnt_fsowner;
+               }
+               if ((nuid == 99) && !vfs_context_issuser(ctx)) {
+                       nuid = kauth_cred_getuid(vfs_context_ucred(ctx));
+               }
+               VATTR_RETURN(vap, va_uid, nuid);
+       }
+       if (VATTR_IS_ACTIVE(vap, va_gid)) {
+               if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_gid)) {
+                       ngid = vap->va_gid;
+               } else if (mp->mnt_flag & MNT_IGNORE_OWNERSHIP) {
+                       ngid = mp->mnt_fsgroup;
+                       if (ngid == KAUTH_GID_NONE) {
+                               ngid = 99;
+                       }
+               } else if (VATTR_IS_SUPPORTED(vap, va_gid)) {
+                       ngid = vap->va_gid;
+               } else {
+                       /* this will always be something sensible */
+                       ngid = mp->mnt_fsgroup;
+               }
+               if ((ngid == 99) && !vfs_context_issuser(ctx)) {
+                       ngid = kauth_cred_getgid(vfs_context_ucred(ctx));
+               }
+               VATTR_RETURN(vap, va_gid, ngid);
+       }
+}
 
 /*
  * Returns:    0                       Success
@@ -2425,8 +2518,6 @@ vnode_getattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
        kauth_filesec_t fsec;
        kauth_acl_t facl;
        int     error;
-       uid_t   nuid;
-       gid_t   ngid;
 
        /*
         * Reject attempts to fetch unknown attributes.
@@ -2537,53 +2628,14 @@ vnode_getattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
        }
 #endif
 
-       /*
-        * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
-        */
-       if (VATTR_IS_ACTIVE(vap, va_uid)) {
-               if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_uid)) {
-                       nuid = vap->va_uid;
-               } else if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) {
-                       nuid = vp->v_mount->mnt_fsowner;
-                       if (nuid == KAUTH_UID_NONE) {
-                               nuid = 99;
-                       }
-               } else if (VATTR_IS_SUPPORTED(vap, va_uid)) {
-                       nuid = vap->va_uid;
-               } else {
-                       /* this will always be something sensible */
-                       nuid = vp->v_mount->mnt_fsowner;
-               }
-               if ((nuid == 99) && !vfs_context_issuser(ctx)) {
-                       nuid = kauth_cred_getuid(vfs_context_ucred(ctx));
-               }
-               VATTR_RETURN(vap, va_uid, nuid);
-       }
-       if (VATTR_IS_ACTIVE(vap, va_gid)) {
-               if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_gid)) {
-                       ngid = vap->va_gid;
-               } else if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) {
-                       ngid = vp->v_mount->mnt_fsgroup;
-                       if (ngid == KAUTH_GID_NONE) {
-                               ngid = 99;
-                       }
-               } else if (VATTR_IS_SUPPORTED(vap, va_gid)) {
-                       ngid = vap->va_gid;
-               } else {
-                       /* this will always be something sensible */
-                       ngid = vp->v_mount->mnt_fsgroup;
-               }
-               if ((ngid == 99) && !vfs_context_issuser(ctx)) {
-                       ngid = kauth_cred_getgid(vfs_context_ucred(ctx));
-               }
-               VATTR_RETURN(vap, va_gid, ngid);
-       }
+       vnode_attr_handle_mnt_ignore_ownership(vap, vp->v_mount, ctx);
 
        /*
         * Synthesise some values that can be reasonably guessed.
         */
        if (!VATTR_IS_SUPPORTED(vap, va_iosize)) {
-               VATTR_RETURN(vap, va_iosize, vp->v_mount->mnt_vfsstat.f_iosize);
+               assert(vp->v_mount->mnt_vfsstat.f_iosize <= UINT32_MAX);
+               VATTR_RETURN(vap, va_iosize, (uint32_t)vp->v_mount->mnt_vfsstat.f_iosize);
        }
 
        if (!VATTR_IS_SUPPORTED(vap, va_flags)) {
@@ -3717,6 +3769,11 @@ VNOP_IOCTL(vnode_t vp, u_long command, caddr_t data, int fflag, vfs_context_t ct
                }
        }
 
+       if ((command == DKIOCISSOLIDSTATE) && (vp == rootvp) && rootvp_is_ssd && data) {
+               *data = 1;
+               return 0;
+       }
+
        a.a_desc = &vnop_ioctl_desc;
        a.a_vp = vp;
        a.a_command = command;
@@ -4156,30 +4213,31 @@ vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, s
         * source has a "._" prefix.
         */
 
+       size_t xfromname_len = 0;
+       size_t xtoname_len = 0;
        if (!NATIVE_XATTR(fdvp) &&
            !(fcnp->cn_nameptr[0] == '.' && fcnp->cn_nameptr[1] == '_')) {
-               size_t len;
                int error;
 
                /* Get source attribute file name. */
-               len = fcnp->cn_namelen + 3;
-               if (len > sizeof(smallname1)) {
-                       MALLOC(xfromname, char *, len, M_TEMP, M_WAITOK);
+               xfromname_len = fcnp->cn_namelen + 3;
+               if (xfromname_len > sizeof(smallname1)) {
+                       xfromname = kheap_alloc(KHEAP_TEMP, xfromname_len, Z_WAITOK);
                } else {
                        xfromname = &smallname1[0];
                }
-               strlcpy(xfromname, "._", len);
-               strlcat(xfromname, fcnp->cn_nameptr, len);
+               strlcpy(xfromname, "._", xfromname_len);
+               strlcat(xfromname, fcnp->cn_nameptr, xfromname_len);
 
                /* Get destination attribute file name. */
-               len = tcnp->cn_namelen + 3;
-               if (len > sizeof(smallname2)) {
-                       MALLOC(xtoname, char *, len, M_TEMP, M_WAITOK);
+               xtoname_len = tcnp->cn_namelen + 3;
+               if (xtoname_len > sizeof(smallname2)) {
+                       xtoname = kheap_alloc(KHEAP_TEMP, xtoname_len, Z_WAITOK);
                } else {
                        xtoname = &smallname2[0];
                }
-               strlcpy(xtoname, "._", len);
-               strlcat(xtoname, tcnp->cn_nameptr, len);
+               strlcpy(xtoname, "._", xtoname_len);
+               strlcat(xtoname, tcnp->cn_nameptr, xtoname_len);
 
                /*
                 * Look up source attribute file, keep reference on it if exists.
@@ -4187,7 +4245,7 @@ vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, s
                 * in the rename syscall. It's OK if the source file does not exist, since this
                 * is only for AppleDouble files.
                 */
-               MALLOC(fromnd, struct nameidata *, sizeof(struct nameidata), M_TEMP, M_WAITOK);
+               fromnd = kheap_alloc(KHEAP_TEMP, sizeof(struct nameidata), Z_WAITOK);
                NDINIT(fromnd, RENAME, OP_RENAME, NOFOLLOW | USEDVP | CN_NBMOUNTLOOK,
                    UIO_SYSSPACE, CAST_USER_ADDR_T(xfromname), ctx);
                fromnd->ni_dvp = fdvp;
@@ -4282,7 +4340,7 @@ vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, s
                 * Note that tdvp already has an iocount reference. Make sure to check that we
                 * get a valid vnode from namei.
                 */
-               MALLOC(tond, struct nameidata *, sizeof(struct nameidata), M_TEMP, M_WAITOK);
+               tond = kheap_alloc(KHEAP_TEMP, sizeof(struct nameidata), Z_WAITOK);
                NDINIT(tond, RENAME, OP_RENAME,
                    NOCACHE | NOFOLLOW | USEDVP | CN_NBMOUNTLOOK, UIO_SYSSPACE,
                    CAST_USER_ADDR_T(xtoname), ctx);
@@ -4376,18 +4434,14 @@ ad_error:
                nameidone(tond);
        }
        if (xfromname && xfromname != &smallname1[0]) {
-               FREE(xfromname, M_TEMP);
+               kheap_free(KHEAP_TEMP, xfromname, xfromname_len);
        }
        if (xtoname && xtoname != &smallname2[0]) {
-               FREE(xtoname, M_TEMP);
+               kheap_free(KHEAP_TEMP, xtoname, xtoname_len);
        }
 #endif /* CONFIG_APPLEDOUBLE */
-       if (fromnd) {
-               FREE(fromnd, M_TEMP);
-       }
-       if (tond) {
-               FREE(tond, M_TEMP);
-       }
+       kheap_free(KHEAP_TEMP, fromnd, sizeof(struct nameidata));
+       kheap_free(KHEAP_TEMP, tond, sizeof(struct nameidata));
        return _err;
 }
 
@@ -4853,18 +4907,19 @@ xattrfile_remove(vnode_t dvp, const char * basename, vfs_context_t ctx, int forc
        struct nameidata nd;
        char smallname[64];
        char *filename = NULL;
-       size_t len;
+       size_t alloc_len;
+       size_t copy_len;
 
        if ((basename == NULL) || (basename[0] == '\0') ||
            (basename[0] == '.' && basename[1] == '_')) {
                return;
        }
        filename = &smallname[0];
-       len = snprintf(filename, sizeof(smallname), "._%s", basename);
-       if (len >= sizeof(smallname)) {
-               len++;  /* snprintf result doesn't include '\0' */
-               MALLOC(filename, char *, len, M_TEMP, M_WAITOK);
-               len = snprintf(filename, len, "._%s", basename);
+       alloc_len = snprintf(filename, sizeof(smallname), "._%s", basename);
+       if (alloc_len >= sizeof(smallname)) {
+               alloc_len++;  /* snprintf result doesn't include '\0' */
+               filename = kheap_alloc(KHEAP_TEMP, alloc_len, Z_WAITOK);
+               copy_len = snprintf(filename, alloc_len, "._%s", basename);
        }
        NDINIT(&nd, DELETE, OP_UNLINK, WANTPARENT | LOCKLEAF | NOFOLLOW | USEDVP, UIO_SYSSPACE,
            CAST_USER_ADDR_T(filename), ctx);
@@ -4920,7 +4975,7 @@ out1:
        vnode_put(xvp);
 out2:
        if (filename && filename != &smallname[0]) {
-               FREE(filename, M_TEMP);
+               kheap_free(KHEAP_TEMP, filename, alloc_len);
        }
 }
 
@@ -4946,7 +5001,7 @@ xattrfile_setattr(vnode_t dvp, const char * basename, struct vnode_attr * vap,
        len = snprintf(filename, sizeof(smallname), "._%s", basename);
        if (len >= sizeof(smallname)) {
                len++;  /* snprintf result doesn't include '\0' */
-               MALLOC(filename, char *, len, M_TEMP, M_WAITOK);
+               filename = kheap_alloc(KHEAP_TEMP, len, Z_WAITOK);
                len = snprintf(filename, len, "._%s", basename);
        }
        NDINIT(&nd, LOOKUP, OP_SETATTR, NOFOLLOW | USEDVP, UIO_SYSSPACE,
@@ -4973,7 +5028,7 @@ xattrfile_setattr(vnode_t dvp, const char * basename, struct vnode_attr * vap,
        vnode_put(xvp);
 out2:
        if (filename && filename != &smallname[0]) {
-               FREE(filename, M_TEMP);
+               kheap_free(KHEAP_TEMP, filename, len);
        }
 }
 #endif /* CONFIG_APPLEDOUBLE */
@@ -5819,6 +5874,58 @@ VNOP_OFFTOBLK(struct vnode *vp, off_t offset, daddr64_t *lblkno)
        return _err;
 }
 
+#if 0
+/*
+*#
+*#% ap vp L L L
+*#
+*/
+struct vnop_verify_args {
+       struct vnodeop_desc *a_desc;
+       vnode_t a_vp;
+       off_t a_foffset;
+       char *a_buf;
+       size_t a_bufsize;
+       size_t *a_verifyblksize;
+       int a_flags;
+       vfs_context_t a_context;
+};
+#endif
+
+errno_t
+VNOP_VERIFY(struct vnode *vp, off_t foffset, uint8_t *buf, size_t bufsize,
+    size_t *verify_block_size, vnode_verify_flags_t flags, vfs_context_t ctx)
+{
+       int _err;
+       struct vnop_verify_args a;
+
+       if (ctx == NULL) {
+               ctx = vfs_context_current();
+       }
+       a.a_desc = &vnop_verify_desc;
+       a.a_vp = vp;
+       a.a_foffset = foffset;
+       a.a_buf = buf;
+       a.a_bufsize = bufsize;
+       a.a_verifyblksize = verify_block_size;
+       a.a_flags = flags;
+       a.a_context = ctx;
+
+       _err = (*vp->v_op[vnop_verify_desc.vdesc_offset])(&a);
+       DTRACE_FSINFO(verify, vnode_t, vp);
+
+       /* It is not an error for a filesystem to not support this VNOP */
+       if (_err == ENOTSUP) {
+               if (!buf && verify_block_size) {
+                       *verify_block_size = 0;
+               }
+
+               _err = 0;
+       }
+
+       return _err;
+}
+
 #if 0
 /*
 *#