]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/vfs_vnops.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_vnops.c
index 7a1a2b21618b5aa00b2592c1b86042c64ba0d22a..fa8b10370cb6d0f86ea6c7e704372d1935e07849 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -22,7 +22,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
@@ -90,7 +90,7 @@
 #define ubc_setcred ubc_setcred_deprecated
 #include <sys/ubc.h>
 #undef ubc_setcred
-int    ubc_setcred(struct vnode *, struct proc *);
+int     ubc_setcred(struct vnode *, struct proc *);
 #include <sys/conf.h>
 #include <sys/disk.h>
 #include <sys/fsevents.h>
@@ -112,45 +112,43 @@ int       ubc_setcred(struct vnode *, struct proc *);
 #endif
 
 #include <IOKit/IOBSD.h>
+#include <libkern/section_keywords.h>
 
 static int vn_closefile(struct fileglob *fp, vfs_context_t ctx);
 static int vn_ioctl(struct fileproc *fp, u_long com, caddr_t data,
-                       vfs_context_t ctx);
+    vfs_context_t ctx);
 static int vn_read(struct fileproc *fp, struct uio *uio, int flags,
-                       vfs_context_t ctx);
+    vfs_context_t ctx);
 static int vn_write(struct fileproc *fp, struct uio *uio, int flags,
-                       vfs_context_t ctx);
+    vfs_context_t ctx);
 static int vn_select( struct fileproc *fp, int which, void * wql,
-                       vfs_context_t ctx);
-static int vn_kqfilt_add(struct fileproc *fp, struct knote *kn,
-                       vfs_context_t ctx);
+    vfs_context_t ctx);
+static int vn_kqfilter(struct fileproc *fp, struct knote *kn,
+    struct kevent_qos_s *kev);
 static void filt_vndetach(struct knote *kn);
 static int filt_vnode(struct knote *kn, long hint);
-static int filt_vnode_common(struct knote *kn, vnode_t vp, long hint);
+static int filt_vnode_common(struct knote *kn, struct kevent_qos_s *kev,
+    vnode_t vp, long hint);
 static int vn_open_auth_finish(vnode_t vp, int fmode, vfs_context_t ctx);
-#if 0
-static int vn_kqfilt_remove(struct vnode *vp, uintptr_t ident,
-                       vfs_context_t ctx);
-#endif
 
 const struct fileops vnops = {
-       .fo_type = DTYPE_VNODE,
-       .fo_read = vn_read,
-       .fo_write = vn_write,
-       .fo_ioctl = vn_ioctl,
-       .fo_select = vn_select,
-       .fo_close = vn_closefile,
-       .fo_kqfilter = vn_kqfilt_add,
-       .fo_drain = NULL,
+       .fo_type     = DTYPE_VNODE,
+       .fo_read     = vn_read,
+       .fo_write    = vn_write,
+       .fo_ioctl    = vn_ioctl,
+       .fo_select   = vn_select,
+       .fo_close    = vn_closefile,
+       .fo_drain    = fo_no_drain,
+       .fo_kqfilter = vn_kqfilter,
 };
 
-static int filt_vntouch(struct knote *kn, struct kevent_internal_s *kev);
-static int filt_vnprocess(struct knote *kn, struct filt_process_s *data, struct kevent_internal_s *kev);
+static int filt_vntouch(struct knote *kn, struct kevent_qos_s *kev);
+static int filt_vnprocess(struct knote *kn, struct kevent_qos_s*kev);
 
-struct  filterops vnode_filtops = { 
-       .f_isfd = 1, 
-       .f_attach = NULL, 
-       .f_detach = filt_vndetach, 
+SECURITY_READ_ONLY_EARLY(struct  filterops) vnode_filtops = {
+       .f_isfd = 1,
+       .f_attach = NULL,
+       .f_detach = filt_vndetach,
        .f_event = filt_vnode,
        .f_touch = filt_vntouch,
        .f_process = filt_vnprocess,
@@ -165,18 +163,25 @@ struct  filterops vnode_filtops = {
 int
 vn_open(struct nameidata *ndp, int fmode, int cmode)
 {
-       return(vn_open_modflags(ndp, &fmode, cmode));
+       return vn_open_modflags(ndp, &fmode, cmode);
 }
 
 int
 vn_open_modflags(struct nameidata *ndp, int *fmodep, int cmode)
 {
-       struct vnode_attr va;
+       int error;
+       struct vnode_attr *vap;
 
-       VATTR_INIT(&va);
-       VATTR_SET(&va, va_mode, cmode);
-       
-       return(vn_open_auth(ndp, fmodep, &va));
+       vap = kheap_alloc(KHEAP_TEMP, sizeof(struct vnode_attr), M_WAITOK);
+
+       VATTR_INIT(vap);
+       VATTR_SET(vap, va_mode, (mode_t)cmode);
+
+       error = vn_open_auth(ndp, fmodep, vap);
+
+       kheap_free(KHEAP_TEMP, vap, sizeof(struct vnode_attr));
+
+       return error;
 }
 
 static int
@@ -188,25 +193,24 @@ vn_open_auth_finish(vnode_t vp, int fmode, vfs_context_t ctx)
                goto bad;
        }
 
-       /* Call out to allow 3rd party notification of open. 
+       /* Call out to allow 3rd party notification of open.
         * Ignore result of kauth_authorize_fileop call.
         */
 #if CONFIG_MACF
        mac_vnode_notify_open(ctx, vp, fmode);
 #endif
-       kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_OPEN, 
-                                                  (uintptr_t)vp, 0);
+       kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_OPEN,
+           (uintptr_t)vp, 0);
 
        return 0;
 
 bad:
        return error;
-
 }
 
 /*
  * May do nameidone() to allow safely adding an FSEvent.  Cue off of ni_dvp to
- * determine whether that has happened.  
+ * determine whether that has happened.
  */
 static int
 vn_open_auth_do_create(struct nameidata *ndp, struct vnode_attr *vap, int fmode, boolean_t *did_create, boolean_t *did_open, vfs_context_t ctx)
@@ -221,72 +225,79 @@ vn_open_auth_do_create(struct nameidata *ndp, struct vnode_attr *vap, int fmode,
        *did_open = FALSE;
 
        VATTR_SET(vap, va_type, VREG);
-       if (fmode & O_EXCL)
+       if (fmode & O_EXCL) {
                vap->va_vaflags |= VA_EXCLUSIVE;
+       }
 
 #if NAMEDRSRCFORK
        if (ndp->ni_cnd.cn_flags & CN_WANTSRSRCFORK) {
-               if ((error = vn_authorize_create(dvp, &ndp->ni_cnd, vap, ctx, NULL)) != 0) 
+               if ((error = vn_authorize_create(dvp, &ndp->ni_cnd, vap, ctx, NULL)) != 0) {
                        goto out;
-               if ((error = vnode_makenamedstream(dvp, &ndp->ni_vp, XATTR_RESOURCEFORK_NAME, 0, ctx)) != 0)
+               }
+               if ((error = vnode_makenamedstream(dvp, &ndp->ni_vp, XATTR_RESOURCEFORK_NAME, 0, ctx)) != 0) {
                        goto out;
+               }
                *did_create = TRUE;
        } else {
 #endif
-               if (!batched) {
-                       if ((error = vn_authorize_create(dvp, &ndp->ni_cnd, vap, ctx, NULL)) != 0)
-                               goto out;
+       if (!batched) {
+               if ((error = vn_authorize_create(dvp, &ndp->ni_cnd, vap, ctx, NULL)) != 0) {
+                       goto out;
                }
+       }
 
-               error = vn_create(dvp, &ndp->ni_vp, ndp, vap, VN_CREATE_DOOPEN, fmode, &status, ctx);
-               if (error != 0) {
-                       if (batched) {
-                               *did_create = (status & COMPOUND_OPEN_STATUS_DID_CREATE) ? TRUE : FALSE;
-                       } else {
-                               *did_create = FALSE;
-                       }
-
-                       if (error == EKEEPLOOKING) {
-                               if (*did_create) {
-                                       panic("EKEEPLOOKING, but we did a create?");
-                               }
-                               if (!batched) {
-                                       panic("EKEEPLOOKING from filesystem that doesn't support compound vnops?");
-                               }
-                               if ((ndp->ni_flag & NAMEI_CONTLOOKUP) == 0) {
-                                       panic("EKEEPLOOKING, but continue flag not set?");
-                               }
+       error = vn_create(dvp, &ndp->ni_vp, ndp, vap, VN_CREATE_DOOPEN, fmode, &status, ctx);
+       if (error != 0) {
+               if (batched) {
+                       *did_create = (status & COMPOUND_OPEN_STATUS_DID_CREATE) ? TRUE : FALSE;
+               } else {
+                       *did_create = FALSE;
+               }
 
-                               /* 
-                                * Do NOT drop the dvp: we need everything to continue the lookup.
-                                */
-                               return error;
+               if (error == EKEEPLOOKING) {
+                       if (*did_create) {
+                               panic("EKEEPLOOKING, but we did a create?");
                        }
-               } else {
-                       if (batched) {
-                               *did_create = (status & COMPOUND_OPEN_STATUS_DID_CREATE) ? 1 : 0;
-                               *did_open = TRUE;
-                       } else {
-                               *did_create = TRUE;
+                       if (!batched) {
+                               panic("EKEEPLOOKING from filesystem that doesn't support compound vnops?");
+                       }
+                       if ((ndp->ni_flag & NAMEI_CONTLOOKUP) == 0) {
+                               panic("EKEEPLOOKING, but continue flag not set?");
                        }
+
+                       /*
+                        * Do NOT drop the dvp: we need everything to continue the lookup.
+                        */
+                       return error;
+               }
+       } else {
+               if (batched) {
+                       *did_create = (status & COMPOUND_OPEN_STATUS_DID_CREATE) ? 1 : 0;
+                       *did_open = TRUE;
+               } else {
+                       *did_create = TRUE;
                }
-#if NAMEDRSRCFORK
        }
+#if NAMEDRSRCFORK
+}
 #endif
 
        vp = ndp->ni_vp;
 
        if (*did_create) {
-               int     update_flags = 0;
+               int     update_flags = 0;
 
                // Make sure the name & parent pointers are hooked up
-               if (vp->v_name == NULL)
+               if (vp->v_name == NULL) {
                        update_flags |= VNODE_UPDATE_NAME;
-               if (vp->v_parent == NULLVP)
+               }
+               if (vp->v_parent == NULLVP) {
                        update_flags |= VNODE_UPDATE_PARENT;
+               }
 
-               if (update_flags)
+               if (update_flags) {
                        vnode_update_identity(vp, dvp, ndp->ni_cnd.cn_nameptr, ndp->ni_cnd.cn_namelen, ndp->ni_cnd.cn_hash, update_flags);
+               }
 
                vnode_put(dvp);
                ndp->ni_dvp = NULLVP;
@@ -294,8 +305,8 @@ vn_open_auth_do_create(struct nameidata *ndp, struct vnode_attr *vap, int fmode,
 #if CONFIG_FSE
                if (need_fsevent(FSE_CREATE_FILE, vp)) {
                        add_fsevent(FSE_CREATE_FILE, ctx,
-                                       FSE_ARG_VNODE, vp,
-                                       FSE_ARG_DONE);
+                           FSE_ARG_VNODE, vp,
+                           FSE_ARG_DONE);
                }
 #endif
        }
@@ -312,7 +323,7 @@ out:
  * This is the number of times we'll loop in vn_open_auth without explicitly
  * yielding the CPU when we determine we have to retry.
  */
-#define RETRY_NO_YIELD_COUNT   5
+#define RETRY_NO_YIELD_COUNT    5
 
 /*
  * Open a file with authorization, updating the contents of the structures
@@ -386,17 +397,22 @@ again:
        origcnflags = ndp->ni_cnd.cn_flags;
 
        // If raw encrypted mode is requested, handle that here
-       if (VATTR_IS_ACTIVE (vap, va_dataprotect_flags)
-               && ISSET(vap->va_dataprotect_flags, VA_DP_RAWENCRYPTED)) {
+       if (VATTR_IS_ACTIVE(vap, va_dataprotect_flags)
+           && ISSET(vap->va_dataprotect_flags, VA_DP_RAWENCRYPTED)) {
                fmode |= FENCRYPTED;
        }
 
+       if ((fmode & O_NOFOLLOW_ANY) && (fmode & (O_SYMLINK | O_NOFOLLOW))) {
+               error = EINVAL;
+               goto out;
+       }
+
        /*
         * O_CREAT
         */
        if (fmode & O_CREAT) {
-               if ( (fmode & O_DIRECTORY) ) {
-                       error = EINVAL;
+               if ((fmode & O_DIRECTORY)) {
+                       error = EINVAL;
                        goto out;
                }
                ndp->ni_cnd.cn_nameiop = CREATE;
@@ -411,12 +427,18 @@ again:
                /* open calls are allowed for resource forks. */
                ndp->ni_cnd.cn_flags |= CN_ALLOWRSRCFORK;
 #endif
-               if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0 && (origcnflags & FOLLOW) != 0)
+               if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0 && (origcnflags & FOLLOW) != 0) {
                        ndp->ni_cnd.cn_flags |= FOLLOW;
+               }
+               if (fmode & O_NOFOLLOW_ANY) {
+                       /* will return ELOOP on the first symlink to be hit */
+                       ndp->ni_flag |= NAMEI_NOFOLLOW_ANY;
+               }
 
 continue_create_lookup:
-               if ( (error = namei(ndp)) )
+               if ((error = namei(ndp))) {
                        goto out;
+               }
 
                dvp = ndp->ni_dvp;
                vp = ndp->ni_vp;
@@ -441,7 +463,7 @@ continue_create_lookup:
                        dvp = ndp->ni_dvp;
                        vp = ndp->ni_vp;
 
-                       /* 
+                       /*
                         * Detected a node that the filesystem couldn't handle.  Don't call
                         * nameidone() yet, because we need that path buffer.
                         */
@@ -461,22 +483,23 @@ continue_create_lookup:
                                /*
                                 * Check for a create race.
                                 */
-                               if ((error == EEXIST) && !(fmode & O_EXCL)){
-                                       if (vp) 
+                               if ((error == EEXIST) && !(fmode & O_EXCL)) {
+                                       if (vp) {
                                                vnode_put(vp);
+                                       }
                                        goto again;
                                }
                                goto bad;
                        }
 
                        need_vnop_open = !did_open;
-               } 
-               else {
-                       if (fmode & O_EXCL)
+               } else {
+                       if (fmode & O_EXCL) {
                                error = EEXIST;
+                       }
 
-                       /* 
-                        * We have a vnode.  Use compound open if available 
+                       /*
+                        * We have a vnode.  Use compound open if available
                         * or else fall through to "traditional" path.  Note: can't
                         * do a compound open for root, because the parent belongs
                         * to a different FS.
@@ -492,7 +515,7 @@ continue_create_lookup:
                                                panic("EKEEPLOOKING, but continue flag not set?");
                                        }
                                        goto continue_create_lookup;
-                               } 
+                               }
                        }
                        nameidone(ndp);
                        vnode_put(dvp);
@@ -506,8 +529,7 @@ continue_create_lookup:
 
                        /* Fall through */
                }
-       }
-    else {
+       } else {
                /*
                 * Not O_CREAT
                 */
@@ -519,19 +541,25 @@ continue_create_lookup:
                /* open calls are allowed for resource forks. */
                ndp->ni_cnd.cn_flags |= CN_ALLOWRSRCFORK;
 #endif
-               if (fmode & FENCRYPTED)
+               if (fmode & FENCRYPTED) {
                        ndp->ni_cnd.cn_flags |= CN_RAW_ENCRYPTED | CN_SKIPNAMECACHE;
+               }
                ndp->ni_flag = NAMEI_COMPOUNDOPEN;
 
                /* preserve NOFOLLOW from vnode_open() */
                if (fmode & O_NOFOLLOW || fmode & O_SYMLINK || (origcnflags & FOLLOW) == 0) {
                        ndp->ni_cnd.cn_flags &= ~FOLLOW;
                }
+               if (fmode & O_NOFOLLOW_ANY) {
+                       /* will return ELOOP on the first symlink to be hit */
+                       ndp->ni_flag |= NAMEI_NOFOLLOW_ANY;
+               }
 
                /* Do a lookup, possibly going directly to filesystem for compound operation */
                do {
-                       if ( (error = namei(ndp)) )
+                       if ((error = namei(ndp))) {
                                goto out;
+                       }
                        vp = ndp->ni_vp;
                        dvp = ndp->ni_dvp;
 
@@ -559,7 +587,7 @@ continue_create_lookup:
                }
        }
 
-       /* 
+       /*
         * By this point, nameidone() is called, dvp iocount is dropped,
         * and dvp pointer is cleared.
         */
@@ -567,21 +595,8 @@ continue_create_lookup:
                panic("Haven't cleaned up adequately in vn_open_auth()");
        }
 
-#if DEVELOPMENT || DEBUG
        /*
-        * XXX VSWAP: Check for entitlements or special flag here
-        * so we can restrict access appropriately.
-        */
-#else /* DEVELOPMENT || DEBUG */
-
-       if (vnode_isswap(vp) && (fmode & (FWRITE | O_TRUNC)) && (ctx != vfs_context_kernel())) {
-               error = EPERM;
-               goto bad;
-       }
-#endif /* DEVELOPMENT || DEBUG */
-
-       /*
-        * Expect to use this code for filesystems without compound VNOPs, for the root 
+        * Expect to use this code for filesystems without compound VNOPs, for the root
         * of a filesystem, which can't be "looked up" in the sense of VNOP_LOOKUP(),
         * and for shadow files, which do not live on the same filesystems as their "parents."
         */
@@ -597,8 +612,8 @@ continue_create_lookup:
                        }
                }
 
-               if (VATTR_IS_ACTIVE (vap, va_dataprotect_flags)
-                       && ISSET(vap->va_dataprotect_flags, VA_DP_RAWUNENCRYPTED)) {
+               if (VATTR_IS_ACTIVE(vap, va_dataprotect_flags)
+                   && ISSET(vap->va_dataprotect_flags, VA_DP_RAWUNENCRYPTED)) {
                        /* Don't allow unencrypted io request from user space unless entitled */
                        boolean_t entitled = FALSE;
 #if !SECURE_KERNEL
@@ -640,11 +655,12 @@ continue_create_lookup:
        }
 
        /* Compound VNOP open is responsible for doing the truncate */
-       if (batched || did_create) 
+       if (batched || did_create) {
                fmode &= ~O_TRUNC;
+       }
 
        *fmodep = fmode;
-       return (0);
+       return 0;
 
 bad:
        /* Opened either explicitly or by a batched create */
@@ -657,9 +673,9 @@ bad:
 #if NAMEDRSRCFORK
                /* Aggressively recycle shadow files if we error'd out during open() */
                if ((vnode_isnamedstream(vp)) &&
-                       (vp->v_parent != NULLVP) && 
-                       (vnode_isshadow(vp))) {
-                               vnode_recycle(vp);
+                   (vp->v_parent != NULLVP) &&
+                   (vnode_isshadow(vp))) {
+                       vnode_recycle(vp);
                }
 #endif
                vnode_put(vp);
@@ -690,14 +706,14 @@ bad:
                        if (nretries > RETRY_NO_YIELD_COUNT) {
                                /* Every hz/100 secs is 10 msecs ... */
                                tsleep(&nretries, PVFS, "vn_open_auth_retry",
-                                   MIN((nretries * (hz/100)), hz));
+                                   MIN((nretries * (hz / 100)), hz));
                        }
                        goto again;
                }
        }
 
 out:
-       return (error);
+       return error;
 }
 
 #if vn_access_DEPRECATED
@@ -713,19 +729,22 @@ out:
 int
 vn_access(vnode_t vp, int mode, vfs_context_t context)
 {
-       kauth_action_t  action;
-  
-       action = 0;
-       if (mode & VREAD)
-               action |= KAUTH_VNODE_READ_DATA;
-       if (mode & VWRITE)
+       kauth_action_t  action;
+
+       action = 0;
+       if (mode & VREAD) {
+               action |= KAUTH_VNODE_READ_DATA;
+       }
+       if (mode & VWRITE) {
                action |= KAUTH_VNODE_WRITE_DATA;
-       if (mode & VEXEC)
-               action |= KAUTH_VNODE_EXECUTE;
-  
-       return(vnode_authorize(vp, NULL, action, context));
+       }
+       if (mode & VEXEC) {
+               action |= KAUTH_VNODE_EXECUTE;
+       }
+
+       return vnode_authorize(vp, NULL, action, context);
 }
-#endif /* vn_access_DEPRECATED */
+#endif  /* vn_access_DEPRECATED */
 
 /*
  * Vnode close call
@@ -738,7 +757,7 @@ vn_close(struct vnode *vp, int flags, vfs_context_t ctx)
 
 #if NAMEDRSRCFORK
        /* Sync data from resource fork shadow file if needed. */
-       if ((vp->v_flag & VISNAMEDSTREAM) && 
+       if ((vp->v_flag & VISNAMEDSTREAM) &&
            (vp->v_parent != NULLVP) &&
            vnode_isshadow(vp)) {
                if (flags & FWASWRITTEN) {
@@ -746,10 +765,18 @@ vn_close(struct vnode *vp, int flags, vfs_context_t ctx)
                }
        }
 #endif
-       
-       /* work around for foxhound */
-       if (vnode_isspec(vp))
+       /*
+        * If vnode @vp belongs to a chardev or a blkdev then it is handled
+        * specially.  We first drop its user reference count @vp->v_usecount
+        * before calling VNOP_CLOSE().  This was done historically to ensure
+        * that the last close of a special device vnode performed some
+        * conditional cleanups.  Now we still need to drop this reference here
+        * to ensure that devfsspec_close() can check if the vnode is still in
+        * use.
+        */
+       if (vnode_isspec(vp)) {
                (void)vnode_rele_ext(vp, flags, 0);
+       }
 
        /*
         * On HFS, we flush when the last writer closes.  We do this
@@ -760,40 +787,42 @@ vn_close(struct vnode *vp, int flags, vfs_context_t ctx)
         * Note that it's OK to access v_writecount without the lock
         * in this context.
         */
-       if (vp->v_tag == VT_HFS && (flags & FWRITE) && vp->v_writecount == 1)
+       if (vp->v_tag == VT_HFS && (flags & FWRITE) && vp->v_writecount == 1) {
                VNOP_FSYNC(vp, MNT_NOWAIT, ctx);
+       }
 
        error = VNOP_CLOSE(vp, flags, ctx);
 
 #if CONFIG_FSE
        if (flags & FWASWRITTEN) {
-               if (need_fsevent(FSE_CONTENT_MODIFIED, vp)) {
-                       add_fsevent(FSE_CONTENT_MODIFIED, ctx,
-                                   FSE_ARG_VNODE, vp,
-                                   FSE_ARG_DONE);
+               if (need_fsevent(FSE_CONTENT_MODIFIED, vp)) {
+                       add_fsevent(FSE_CONTENT_MODIFIED, ctx,
+                           FSE_ARG_VNODE, vp,
+                           FSE_ARG_DONE);
                }
        }
 #endif
 
-       if (!vnode_isspec(vp))
+       if (!vnode_isspec(vp)) {
                (void)vnode_rele_ext(vp, flags, 0);
-       
+       }
+
        if (flusherror) {
                error = flusherror;
        }
-       return (error);
+       return error;
 }
 
 static int
 vn_read_swapfile(
-       struct vnode    *vp,
-       uio_t           uio)
+       struct vnode    *vp,
+       uio_t           uio)
 {
-       int     error;
-       off_t   swap_count, this_count;
-       off_t   file_end, read_end;
-       off_t   prev_resid;
-       char    *my_swap_page;
+       int     error;
+       off_t   swap_count, this_count;
+       off_t   file_end, read_end;
+       off_t   prev_resid;
+       char    *my_swap_page;
 
        /*
         * Reading from a swap file will get you zeroes.
@@ -815,11 +844,9 @@ vn_read_swapfile(
 
        while (swap_count > 0) {
                if (my_swap_page == NULL) {
-                       MALLOC(my_swap_page, char *, PAGE_SIZE,
-                              M_TEMP, M_WAITOK);
-                       memset(my_swap_page, '\0', PAGE_SIZE);
+                       my_swap_page = kheap_alloc(KHEAP_TEMP, PAGE_SIZE, Z_WAITOK | Z_ZERO);
                        /* add an end-of-line to keep line counters happy */
-                       my_swap_page[PAGE_SIZE-1] = '\n';
+                       my_swap_page[PAGE_SIZE - 1] = '\n';
                }
                this_count = swap_count;
                if (this_count > PAGE_SIZE) {
@@ -828,17 +855,14 @@ vn_read_swapfile(
 
                prev_resid = uio_resid(uio);
                error = uiomove((caddr_t) my_swap_page,
-                               this_count,
-                               uio);
+                   (int)this_count,
+                   uio);
                if (error) {
                        break;
                }
                swap_count -= (prev_resid - uio_resid(uio));
        }
-       if (my_swap_page != NULL) {
-               FREE(my_swap_page, M_TEMP);
-               my_swap_page = NULL;
-       }
+       kheap_free(KHEAP_TEMP, my_swap_page, PAGE_SIZE);
 
        return error;
 }
@@ -860,21 +884,25 @@ vn_rdwr(
 {
        int64_t resid;
        int result;
-       
+
+       if (len < 0) {
+               return EINVAL;
+       }
+
        result = vn_rdwr_64(rw,
-                       vp,
-                       (uint64_t)(uintptr_t)base,
-                       (int64_t)len,
-                       offset,
-                       segflg,
-                       ioflg,
-                       cred,
-                       &resid,
-                       p);
+           vp,
+           (uint64_t)(uintptr_t)base,
+           (int64_t)len,
+           offset,
+           segflg,
+           ioflg,
+           cred,
+           &resid,
+           p);
 
        /* "resid" should be bounded above by "len," which is an int */
        if (aresid != NULL) {
-               *aresid = resid;
+               *aresid = (int)resid;
        }
 
        return result;
@@ -897,33 +925,38 @@ vn_rdwr_64(
        uio_t auio;
        int spacetype;
        struct vfs_context context;
-       int error=0;
-       char uio_buf[ UIO_SIZEOF(1) ];
+       int error = 0;
+       char uio_buf[UIO_SIZEOF(1)];
 
        context.vc_thread = current_thread();
        context.vc_ucred = cred;
 
        if (UIO_SEG_IS_USER_SPACE(segflg)) {
                spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
-       }
-       else {
+       } else {
                spacetype = UIO_SYSSPACE;
        }
-       auio = uio_createwithbuffer(1, offset, spacetype, rw, 
-                                                                 &uio_buf[0], sizeof(uio_buf));
-       uio_addiov(auio, base, len);
+
+       if (len < 0) {
+               return EINVAL;
+       }
+
+       auio = uio_createwithbuffer(1, offset, spacetype, rw,
+           &uio_buf[0], sizeof(uio_buf));
+       uio_addiov(auio, CAST_USER_ADDR_T(base), (user_size_t)len);
 
 #if CONFIG_MACF
        /* XXXMAC
-        *      IO_NOAUTH should be re-examined.
-        *      Likely that mediation should be performed in caller.
+        *      IO_NOAUTH should be re-examined.
+        *      Likely that mediation should be performed in caller.
         */
        if ((ioflg & IO_NOAUTH) == 0) {
-       /* passed cred is fp->f_cred */
-               if (rw == UIO_READ)
+               /* passed cred is fp->f_cred */
+               if (rw == UIO_READ) {
                        error = mac_vnode_check_read(&context, cred, vp);
-               else
+               } else {
                        error = mac_vnode_check_write(&context, cred, vp);
+               }
        }
 #endif
 
@@ -935,30 +968,17 @@ vn_rdwr_64(
                                error = VNOP_READ(vp, auio, ioflg, &context);
                        }
                } else {
-
-#if DEVELOPMENT || DEBUG
-                       /*
-                        * XXX VSWAP: Check for entitlements or special flag here
-                        * so we can restrict access appropriately.
-                        */
                        error = VNOP_WRITE(vp, auio, ioflg, &context);
-#else /* DEVELOPMENT || DEBUG */
-
-                       if (vnode_isswap(vp) && ((ioflg & (IO_SWAP_DISPATCH | IO_SKIP_ENCRYPTION)) == 0)) {
-                               error = EPERM;
-                       } else {
-                               error = VNOP_WRITE(vp, auio, ioflg, &context);
-                       }
-#endif /* DEVELOPMENT || DEBUG */
                }
        }
 
-       if (aresid)
+       if (aresid) {
                *aresid = uio_resid(auio);
-       else
-               if (uio_resid(auio) && error == 0)
-                       error = EIO;
-       return (error);
+               assert(*aresid <= len);
+       } else if (uio_resid(auio) && error == 0) {
+               error = EIO;
+       }
+       return error;
 }
 
 static inline void
@@ -999,68 +1019,119 @@ vn_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
        struct vnode *vp;
        int error;
        int ioflag;
-       off_t count;
-       int offset_locked = 0;
+       off_t read_offset;
+       user_ssize_t  read_len;
+       user_ssize_t  adjusted_read_len;
+       user_ssize_t  clippedsize;
+       bool offset_locked;
+
+       read_len = uio_resid(uio);
+       if (read_len < 0 || read_len > INT_MAX) {
+               return EINVAL;
+       }
+       adjusted_read_len = read_len;
+       clippedsize = 0;
+       offset_locked = false;
 
-       vp = (struct vnode *)fp->f_fglob->fg_data;
-       if ( (error = vnode_getwithref(vp)) ) {
-               return(error);
+       vp = (struct vnode *)fp->fp_glob->fg_data;
+       if ((error = vnode_getwithref(vp))) {
+               return error;
        }
 
 #if CONFIG_MACF
        error = mac_vnode_check_read(ctx, vfs_context_ucred(ctx), vp);
        if (error) {
                (void)vnode_put(vp);
-               return (error);
+               return error;
        }
 #endif
 
        /* This signals to VNOP handlers that this read came from a file table read */
        ioflag = IO_SYSCALL_DISPATCH;
 
-       if (fp->f_fglob->fg_flag & FNONBLOCK)
+       if (fp->fp_glob->fg_flag & FNONBLOCK) {
                ioflag |= IO_NDELAY;
-       if ((fp->f_fglob->fg_flag & FNOCACHE) || vnode_isnocache(vp))
-           ioflag |= IO_NOCACHE;
-       if (fp->f_fglob->fg_flag & FENCRYPTED) {
+       }
+       if ((fp->fp_glob->fg_flag & FNOCACHE) || vnode_isnocache(vp)) {
+               ioflag |= IO_NOCACHE;
+       }
+       if (fp->fp_glob->fg_flag & FENCRYPTED) {
                ioflag |= IO_ENCRYPTED;
        }
-       if (fp->f_fglob->fg_flag & FUNENCRYPTED) {
+       if (fp->fp_glob->fg_flag & FUNENCRYPTED) {
                ioflag |= IO_SKIP_ENCRYPTION;
        }
-       if (fp->f_fglob->fg_flag & O_EVTONLY) {
+       if (fp->fp_glob->fg_flag & O_EVTONLY) {
                ioflag |= IO_EVTONLY;
        }
-       if (fp->f_fglob->fg_flag & FNORDAHEAD)
-           ioflag |= IO_RAOFF;
+       if (fp->fp_glob->fg_flag & FNORDAHEAD) {
+               ioflag |= IO_RAOFF;
+       }
 
        if ((flags & FOF_OFFSET) == 0) {
                if ((vnode_vtype(vp) == VREG) && !vnode_isswap(vp)) {
-                       vn_offset_lock(fp->f_fglob);
-                       offset_locked = 1;
+                       vn_offset_lock(fp->fp_glob);
+                       offset_locked = true;
+               }
+               read_offset = fp->fp_glob->fg_offset;
+               uio_setoffset(uio, read_offset);
+       } else {
+               read_offset = uio_offset(uio);
+               /* POSIX allows negative offsets for character devices. */
+               if ((read_offset < 0) && (vnode_vtype(vp) != VCHR)) {
+                       error = EINVAL;
+                       goto error_out;
                }
-               uio->uio_offset = fp->f_fglob->fg_offset;
        }
-       count = uio_resid(uio);
 
-       if (vnode_isswap(vp) && !(IO_SKIP_ENCRYPTION & ioflag)) {
+       if (read_offset == INT64_MAX) {
+               /* can't read any more */
+               error = 0;
+               goto error_out;
+       }
 
+       /*
+        * If offset + len will cause overflow, reduce the len to a value
+        * (adjusted_read_len) where it won't
+        */
+       if ((read_offset >= 0) && (INT64_MAX - read_offset) < read_len) {
+               /*
+                * 0                                          read_offset  INT64_MAX
+                * |-----------------------------------------------|----------|~~~
+                *                                                 <--read_len-->
+                *                                                 <-adjusted->
+                */
+               adjusted_read_len = (user_ssize_t)(INT64_MAX - read_offset);
+       }
+
+       if (adjusted_read_len < read_len) {
+               uio_setresid(uio, adjusted_read_len);
+               clippedsize = read_len - adjusted_read_len;
+       }
+
+       if (vnode_isswap(vp) && !(IO_SKIP_ENCRYPTION & ioflag)) {
                /* special case for swap files */
                error = vn_read_swapfile(vp, uio);
        } else {
                error = VNOP_READ(vp, uio, ioflag, ctx);
        }
 
+       if (clippedsize) {
+               uio_setresid(uio, (uio_resid(uio) + clippedsize));
+       }
+
        if ((flags & FOF_OFFSET) == 0) {
-               fp->f_fglob->fg_offset += count - uio_resid(uio);
-               if (offset_locked) {
-                       vn_offset_unlock(fp->f_fglob);
-                       offset_locked = 0;
-               }
+               fp->fp_glob->fg_offset += read_len - uio_resid(uio);
+       }
+
+error_out:
+       if (offset_locked) {
+               vn_offset_unlock(fp->fp_glob);
+               offset_locked = false;
        }
 
        (void)vnode_put(vp);
-       return (error);
+       return error;
 }
 
 
@@ -1072,39 +1143,33 @@ vn_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
 {
        struct vnode *vp;
        int error, ioflag;
-       off_t count;
-       int clippedsize = 0;
-       int partialwrite=0;
-       int residcount, oldcount;
-       int offset_locked = 0;
+       off_t write_offset;
+       off_t write_end_offset;
+       user_ssize_t write_len;
+       user_ssize_t adjusted_write_len;
+       user_ssize_t clippedsize;
+       bool offset_locked;
        proc_t p = vfs_context_proc(ctx);
+       rlim_t rlim_cur_fsize = p ? proc_limitgetcur(p, RLIMIT_FSIZE, TRUE) : 0;
 
-       count = 0;
-       vp = (struct vnode *)fp->f_fglob->fg_data;
-       if ( (error = vnode_getwithref(vp)) ) {
-               return(error);
+       write_len = uio_resid(uio);
+       if (write_len < 0 || write_len > INT_MAX) {
+               return EINVAL;
        }
+       adjusted_write_len = write_len;
+       clippedsize = 0;
+       offset_locked = false;
 
-#if DEVELOPMENT || DEBUG
-       /*
-        * XXX VSWAP: Check for entitlements or special flag here
-        * so we can restrict access appropriately.
-        */
-#else /* DEVELOPMENT || DEBUG */
-
-       if (vnode_isswap(vp)) {
-               (void)vnode_put(vp);
-               error = EPERM;
-               return (error);
+       vp = (struct vnode *)fp->fp_glob->fg_data;
+       if ((error = vnode_getwithref(vp))) {
+               return error;
        }
-#endif /* DEVELOPMENT || DEBUG */
-
 
 #if CONFIG_MACF
        error = mac_vnode_check_write(ctx, vfs_context_ucred(ctx), vp);
        if (error) {
                (void)vnode_put(vp);
-               return (error);
+               return error;
        }
 #endif
 
@@ -1114,18 +1179,24 @@ vn_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
         */
        ioflag = (IO_UNIT | IO_SYSCALL_DISPATCH);
 
-       if (vp->v_type == VREG && (fp->f_fglob->fg_flag & O_APPEND))
+       if (vp->v_type == VREG && (fp->fp_glob->fg_flag & O_APPEND)) {
                ioflag |= IO_APPEND;
-       if (fp->f_fglob->fg_flag & FNONBLOCK)
+       }
+       if (fp->fp_glob->fg_flag & FNONBLOCK) {
                ioflag |= IO_NDELAY;
-       if ((fp->f_fglob->fg_flag & FNOCACHE) || vnode_isnocache(vp))
-               ioflag |= IO_NOCACHE;
-       if (fp->f_fglob->fg_flag & FNODIRECT)
+       }
+       if ((fp->fp_glob->fg_flag & FNOCACHE) || vnode_isnocache(vp)) {
+               ioflag |= IO_NOCACHE;
+       }
+       if (fp->fp_glob->fg_flag & FNODIRECT) {
                ioflag |= IO_NODIRECT;
-       if (fp->f_fglob->fg_flag & FSINGLE_WRITER)
+       }
+       if (fp->fp_glob->fg_flag & FSINGLE_WRITER) {
                ioflag |= IO_SINGLE_WRITER;
-       if (fp->f_fglob->fg_flag & O_EVTONLY)
+       }
+       if (fp->fp_glob->fg_flag & O_EVTONLY) {
                ioflag |= IO_EVTONLY;
+       }
 
        /*
         * Treat synchronous mounts and O_FSYNC on the fd as equivalent.
@@ -1134,78 +1205,125 @@ vn_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
         * XXX the non-essential metadata without some additional VFS work;
         * XXX the intent at this point is to plumb the interface for it.
         */
-       if ((fp->f_fglob->fg_flag & (O_FSYNC|O_DSYNC)) ||
-               (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS))) {
+       if ((fp->fp_glob->fg_flag & (O_FSYNC | O_DSYNC)) ||
+           (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS))) {
                ioflag |= IO_SYNC;
        }
 
        if ((flags & FOF_OFFSET) == 0) {
                if ((vnode_vtype(vp) == VREG) && !vnode_isswap(vp)) {
-                       vn_offset_lock(fp->f_fglob);
-                       offset_locked = 1;
+                       vn_offset_lock(fp->fp_glob);
+                       offset_locked = true;
                }
-               uio->uio_offset = fp->f_fglob->fg_offset;
-               count = uio_resid(uio);
-       }
-       if (((flags & FOF_OFFSET) == 0) &&
-               vfs_context_proc(ctx) && (vp->v_type == VREG) &&
-            (((rlim_t)(uio->uio_offset + uio_resid(uio)) > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) ||
-             ((rlim_t)uio_resid(uio) > (p->p_rlimit[RLIMIT_FSIZE].rlim_cur - uio->uio_offset)))) {
-               /*
+               write_offset = fp->fp_glob->fg_offset;
+               uio_setoffset(uio, write_offset);
+       } else {
+               /* for pwrite, append should  be ignored */
+               ioflag &= ~IO_APPEND;
+               write_offset = uio_offset(uio);
+               /* POSIX allows negative offsets for character devices. */
+               if ((write_offset < 0) && (vnode_vtype(vp) != VCHR)) {
+                       error = EINVAL;
+                       goto error_out;
+               }
+       }
+
+       if (write_offset == INT64_MAX) {
+               /* writes are not possible */
+               error = EFBIG;
+               goto error_out;
+       }
+
+       /*
+        * write_len is the original write length that was requested.
+        * We may however need to reduce that becasue of two reasons
+        *
+        * 1) If write_offset + write_len will exceed OFF_T_MAX (i.e. INT64_MAX)
+        *    and/or
+        * 2) If write_offset + write_len will exceed the administrative
+        *    limit for the maximum file size.
+        *
+        * In both cases the write will be denied if we can't write even a single
+        * byte otherwise it will be "clipped" (i.e. a short write).
+        */
+
+       /*
+        * If offset + len will cause overflow, reduce the len
+        * to a value (adjusted_write_len) where it won't
+        */
+       if ((write_offset >= 0) && (INT64_MAX - write_offset) < write_len) {
+               /*
+                * 0                                          write_offset  INT64_MAX
+                * |-----------------------------------------------|----------|~~~
+                *                                                 <--write_len-->
+                *                                                 <-adjusted->
+                */
+               adjusted_write_len = (user_ssize_t)(INT64_MAX - write_offset);
+       }
+
+       /* write_end_offset will always be [0, INT64_MAX] */
+       write_end_offset = write_offset + adjusted_write_len;
+
+       if (p && (vp->v_type == VREG) &&
+           (rlim_cur_fsize != RLIM_INFINITY) &&
+           (rlim_cur_fsize <= INT64_MAX) &&
+           (write_end_offset > (off_t)rlim_cur_fsize)) {
+               /*
                 * If the requested residual would cause us to go past the
                 * administrative limit, then we need to adjust the residual
                 * down to cause fewer bytes than requested to be written.  If
                 * we can't do that (e.g. the residual is already 1 byte),
                 * then we fail the write with EFBIG.
                 */
-               residcount = uio_resid(uio);
-               if ((rlim_t)(uio->uio_offset + uio_resid(uio)) > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
-                       clippedsize =  (uio->uio_offset + uio_resid(uio)) - p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
-               } else if ((rlim_t)uio_resid(uio) > (p->p_rlimit[RLIMIT_FSIZE].rlim_cur - uio->uio_offset)) {
-                       clippedsize = (p->p_rlimit[RLIMIT_FSIZE].rlim_cur - uio->uio_offset);
-               }
-               if (clippedsize >= residcount) {
+               if (write_offset >= (off_t)rlim_cur_fsize) {
+                       /*
+                        * 0                  rlim_fsize  write_offset  write_end  INT64_MAX
+                        * |------------------------|----------|-------------|--------|
+                        *                                     <--write_len-->
+                        *
+                        *                write not permitted
+                        */
                        psignal(p, SIGXFSZ);
                        error = EFBIG;
                        goto error_out;
                }
-               partialwrite = 1;
-               uio_setresid(uio, residcount-clippedsize);
-       }
-       if ((flags & FOF_OFFSET) != 0) {
-               /* for pwrite, append should  be ignored */
-               ioflag &= ~IO_APPEND;
-               if (p && (vp->v_type == VREG) &&
-               ((rlim_t)uio->uio_offset  >= p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
-               psignal(p, SIGXFSZ);
-               error = EFBIG;
-               goto error_out;
+
+               /*
+                * 0                  write_offset rlim_fsize  write_end  INT64_MAX
+                * |------------------------|-----------|---------|------------|
+                *                          <------write_len------>
+                *                          <-adjusted-->
+                */
+               adjusted_write_len =  (user_ssize_t)((off_t)rlim_cur_fsize - write_offset);
+               assert((adjusted_write_len > 0) && (adjusted_write_len < write_len));
        }
-               if (p && (vp->v_type == VREG) &&
-                       ((rlim_t)(uio->uio_offset + uio_resid(uio)) > p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
-                       //Debugger("vn_bwrite:overstepping the bounds");
-                       residcount = uio_resid(uio);
-                       clippedsize =  (uio->uio_offset + uio_resid(uio)) - p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
-                       partialwrite = 1;
-                       uio_setresid(uio, residcount-clippedsize);
-               }
+
+       if (adjusted_write_len < write_len) {
+               uio_setresid(uio, adjusted_write_len);
+               clippedsize = write_len - adjusted_write_len;
        }
 
        error = VNOP_WRITE(vp, uio, ioflag, ctx);
 
-       if (partialwrite) {
-               oldcount = uio_resid(uio);
-               uio_setresid(uio, oldcount + clippedsize);
+       /*
+        * If we had to reduce the size of write requested either because
+        * of rlimit or because it would have exceeded
+        * maximum file size, we have to add that back to the residual so
+        * it correctly reflects what we did in this function.
+        */
+       if (clippedsize) {
+               uio_setresid(uio, (uio_resid(uio) + clippedsize));
        }
 
        if ((flags & FOF_OFFSET) == 0) {
-               if (ioflag & IO_APPEND)
-                       fp->f_fglob->fg_offset = uio->uio_offset;
-               else
-                       fp->f_fglob->fg_offset += count - uio_resid(uio);
+               if (ioflag & IO_APPEND) {
+                       fp->fp_glob->fg_offset = uio_offset(uio);
+               } else {
+                       fp->fp_glob->fg_offset += (write_len - uio_resid(uio));
+               }
                if (offset_locked) {
-                       vn_offset_unlock(fp->f_fglob);
-                       offset_locked = 0;
+                       vn_offset_unlock(fp->fp_glob);
+                       offset_locked = false;
                }
        }
 
@@ -1213,7 +1331,7 @@ vn_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
         * Set the credentials on successful writes
         */
        if ((error == 0) && (vp->v_tag == VT_NFS) && (UBCINFOEXISTS(vp))) {
-               /* 
+               /*
                 * When called from aio subsystem, we only have the proc from
                 * which to get the credential, at this point, so use that
                 * instead.  This means aio functions are incompatible with
@@ -1228,14 +1346,14 @@ vn_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
                }
        }
        (void)vnode_put(vp);
-       return (error);
+       return error;
 
 error_out:
        if (offset_locked) {
-               vn_offset_unlock(fp->f_fglob);
+               vn_offset_unlock(fp->fp_glob);
        }
        (void)vnode_put(vp);
-       return (error);
+       return error;
 }
 
 /*
@@ -1248,19 +1366,20 @@ error_out:
  */
 int
 vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat64,
-              vfs_context_t ctx, struct ucred *file_cred)
+    int needsrealdev, vfs_context_t ctx, struct ucred *file_cred)
 {
        struct vnode_attr va;
        int error;
        u_short mode;
        kauth_filesec_t fsec;
-       struct stat *sb = (struct stat *)0;     /* warning avoidance ; protected by isstat64 */
+       struct stat *sb = (struct stat *)0;     /* warning avoidance ; protected by isstat64 */
        struct stat64 * sb64 = (struct stat64 *)0;  /* warning avoidance ; protected by isstat64 */
 
-       if (isstat64 != 0)
+       if (isstat64 != 0) {
                sb64 = (struct stat64 *)sbptr;
-       else
+       } else {
                sb = (struct stat *)sbptr;
+       }
        memset(&va, 0, sizeof(va));
        VATTR_INIT(&va);
        VATTR_WANTED(&va, va_fsid);
@@ -1286,9 +1405,13 @@ vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat6
                VATTR_WANTED(&va, va_guuid);
                VATTR_WANTED(&va, va_acl);
        }
+       if (needsrealdev) {
+               va.va_vaflags = VA_REALFSID;
+       }
        error = vnode_getattr(vp, &va, ctx);
-       if (error)
+       if (error) {
                goto out;
+       }
 #if CONFIG_MACF
        /*
         * Give MAC polices a chance to reject or filter the attributes
@@ -1299,8 +1422,9 @@ vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat6
         * to change the values of attributes retrieved.
         */
        error = mac_vnode_check_getattr(ctx, file_cred, vp, &va);
-       if (error)
+       if (error) {
                goto out;
+       }
 #endif
        /*
         * Copy from vattr table
@@ -1308,7 +1432,6 @@ vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat6
        if (isstat64 != 0) {
                sb64->st_dev = va.va_fsid;
                sb64->st_ino = (ino64_t)va.va_fileid;
-
        } else {
                sb->st_dev = va.va_fsid;
                sb->st_ino = (ino_t)va.va_fileid;
@@ -1339,10 +1462,11 @@ vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat6
        default:
                error = EBADF;
                goto out;
-       };
+       }
+       ;
        if (isstat64 != 0) {
                sb64->st_mode = mode;
-               sb64->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? (u_int16_t)va.va_nlink : 1;
+               sb64->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? va.va_nlink > UINT16_MAX ? UINT16_MAX : (u_int16_t)va.va_nlink : 1;
                sb64->st_uid = va.va_uid;
                sb64->st_gid = va.va_gid;
                sb64->st_rdev = va.va_rdev;
@@ -1360,7 +1484,7 @@ vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat6
                sb64->st_blocks = roundup(va.va_total_alloc, 512) / 512;
        } else {
                sb->st_mode = mode;
-               sb->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? (u_int16_t)va.va_nlink : 1;
+               sb->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? va.va_nlink > UINT16_MAX ? UINT16_MAX : (u_int16_t)va.va_nlink : 1;
                sb->st_uid = va.va_uid;
                sb->st_gid = va.va_gid;
                sb->st_rdev = va.va_rdev;
@@ -1380,7 +1504,6 @@ vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat6
                    !VATTR_IS_SUPPORTED(&va, va_guuid)) {
                        *xsec = KAUTH_FILESEC_NONE;
                } else {
-               
                        if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) {
                                fsec = kauth_filesec_alloc(va.va_acl->acl_entrycount);
                        } else {
@@ -1402,51 +1525,56 @@ vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat6
                                fsec->fsec_group = kauth_null_guid;
                        }
                        if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) {
-                               bcopy(va.va_acl, &(fsec->fsec_acl), KAUTH_ACL_COPYSIZE(va.va_acl));
+                               __nochk_bcopy(va.va_acl, &(fsec->fsec_acl), KAUTH_ACL_COPYSIZE(va.va_acl));
                        } else {
                                fsec->fsec_acl.acl_entrycount = KAUTH_FILESEC_NOACL;
                        }
                        *xsec = fsec;
                }
        }
-       
+
        /* Do not give the generation number out to unpriviledged users */
        if (va.va_gen && !vfs_context_issuser(ctx)) {
-               if (isstat64 != 0)
-                       sb64->st_gen = 0; 
-               else
-                       sb->st_gen = 0; 
+               if (isstat64 != 0) {
+                       sb64->st_gen = 0;
+               } else {
+                       sb->st_gen = 0;
+               }
        } else {
-               if (isstat64 != 0)
-                       sb64->st_gen = va.va_gen; 
-               else
+               if (isstat64 != 0) {
+                       sb64->st_gen = va.va_gen;
+               } else {
                        sb->st_gen = va.va_gen;
+               }
        }
 
        error = 0;
 out:
-       if (VATTR_IS_SUPPORTED(&va, va_acl) && va.va_acl != NULL)
+       if (VATTR_IS_SUPPORTED(&va, va_acl) && va.va_acl != NULL) {
                kauth_acl_free(va.va_acl);
-       return (error);
+       }
+       return error;
 }
 
 int
-vn_stat(struct vnode *vp, void *sb, kauth_filesec_t *xsec, int isstat64, vfs_context_t ctx)
+vn_stat(struct vnode *vp, void *sb, kauth_filesec_t *xsec, int isstat64, int needsrealdev, vfs_context_t ctx)
 {
        int error;
 
 #if CONFIG_MACF
        error = mac_vnode_check_stat(ctx, NOCRED, vp);
-       if (error)
-               return (error);
+       if (error) {
+               return error;
+       }
 #endif
 
        /* authorize */
-       if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_ATTRIBUTES | KAUTH_VNODE_READ_SECURITY, ctx)) != 0)
-               return(error);
+       if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_ATTRIBUTES | KAUTH_VNODE_READ_SECURITY, ctx)) != 0) {
+               return error;
+       }
 
        /* actual stat */
-       return(vn_stat_noauth(vp, sb, xsec, isstat64, ctx, NOCRED));
+       return vn_stat_noauth(vp, sb, xsec, isstat64, needsrealdev, ctx, NOCRED);
 }
 
 
@@ -1456,35 +1584,45 @@ vn_stat(struct vnode *vp, void *sb, kauth_filesec_t *xsec, int isstat64, vfs_con
 static int
 vn_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
 {
-       struct vnode *vp = ((struct vnode *)fp->f_fglob->fg_data);
+       struct vnode *vp = ((struct vnode *)fp->fp_glob->fg_data);
        off_t file_size;
        int error;
        struct vnode *ttyvp;
        struct session * sessp;
-       
-       if ( (error = vnode_getwithref(vp)) ) {
-               return(error);
+
+       if ((error = vnode_getwithref(vp))) {
+               return error;
        }
 
 #if CONFIG_MACF
        error = mac_vnode_check_ioctl(ctx, vp, com);
-       if (error)
+       if (error) {
                goto out;
+       }
 #endif
 
        switch (vp->v_type) {
        case VREG:
        case VDIR:
                if (com == FIONREAD) {
-                       if ((error = vnode_size(vp, &file_size, ctx)) != 0)
+                       off_t temp_nbytes;
+                       if ((error = vnode_size(vp, &file_size, ctx)) != 0) {
                                goto out;
-                       *(int *)data = file_size - fp->f_fglob->fg_offset;
+                       }
+                       temp_nbytes = file_size - fp->fp_glob->fg_offset;
+                       if (temp_nbytes > INT_MAX) {
+                               *(int *)data = INT_MAX;
+                       } else if (temp_nbytes < 0) {
+                               *(int *)data = 0;
+                       } else {
+                               *(int *)data = (int)temp_nbytes;
+                       }
                        goto out;
                }
-               if (com == FIONBIO || com == FIOASYNC) {        /* XXX */
+               if (com == FIONBIO || com == FIOASYNC) {        /* XXX */
                        goto out;
                }
-               /* fall into ... */
+               OS_FALLTHROUGH;
 
        default:
                error = ENOTTY;
@@ -1494,6 +1632,11 @@ vn_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
        case VCHR:
        case VBLK:
 
+               if (com == TIOCREVOKE || com == TIOCREVOKECLEAR) {
+                       error = ENOTTY;
+                       goto out;
+               }
+
                /* Should not be able to set block size from user space */
                if (com == DKIOCSETBLOCKSIZE) {
                        error = EPERM;
@@ -1507,7 +1650,6 @@ vn_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
                                        goto out;
                                }
                                *(int *)data = bdevsw[major(vp->v_rdev)].d_type;
-
                        } else if (vp->v_type == VCHR) {
                                if (major(vp->v_rdev) >= nchrdev) {
                                        error = ENXIO;
@@ -1520,7 +1662,7 @@ vn_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
                        }
                        goto out;
                }
-               error = VNOP_IOCTL(vp, com, data, fp->f_fglob->fg_flag, ctx);
+               error = VNOP_IOCTL(vp, com, data, fp->fp_glob->fg_flag, ctx);
 
                if (error == 0 && com == TIOCSCTTY) {
                        sessp = proc_session(vfs_context_proc(ctx));
@@ -1535,7 +1677,7 @@ vn_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
        }
 out:
        (void)vnode_put(vp);
-       return(error);
+       return error;
 }
 
 /*
@@ -1545,12 +1687,12 @@ static int
 vn_select(struct fileproc *fp, int which, void *wql, __unused vfs_context_t ctx)
 {
        int error;
-       struct vnode * vp = (struct vnode *)fp->f_fglob->fg_data;
+       struct vnode * vp = (struct vnode *)fp->fp_glob->fg_data;
        struct vfs_context context;
 
-       if ( (error = vnode_getwithref(vp)) == 0 ) {
+       if ((error = vnode_getwithref(vp)) == 0) {
                context.vc_thread = current_thread();
-               context.vc_ucred = fp->f_fglob->fg_cred;
+               context.vc_ucred = fp->fp_glob->fg_cred;
 
 #if CONFIG_MACF
                /*
@@ -1561,12 +1703,11 @@ vn_select(struct fileproc *fp, int which, void *wql, __unused vfs_context_t ctx)
                error = mac_vnode_check_select(ctx, vp, which);
                if (error == 0)
 #endif
-               error = VNOP_SELECT(vp, which, fp->f_fglob->fg_flag, wql, ctx);
+               error = VNOP_SELECT(vp, which, fp->fp_glob->fg_flag, wql, ctx);
 
                (void)vnode_put(vp);
        }
-       return(error);
-       
+       return error;
 }
 
 /*
@@ -1578,9 +1719,9 @@ vn_closefile(struct fileglob *fg, vfs_context_t ctx)
        struct vnode *vp = fg->fg_data;
        int error;
 
-       if ( (error = vnode_getwithref(vp)) == 0 ) {
+       if ((error = vnode_getwithref(vp)) == 0) {
                if (FILEGLOB_DTYPE(fg) == DTYPE_VNODE &&
-                   ((fg->fg_flag & FHASLOCK) != 0 || 
+                   ((fg->fg_flag & FWASLOCKED) != 0 ||
                    (fg->fg_lflags & FG_HAS_OFDLOCK) != 0)) {
                        struct flock lf = {
                                .l_whence = SEEK_SET,
@@ -1589,18 +1730,20 @@ vn_closefile(struct fileglob *fg, vfs_context_t ctx)
                                .l_type = F_UNLCK
                        };
 
-                       if ((fg->fg_flag & FHASLOCK) != 0)
+                       if ((fg->fg_flag & FWASLOCKED) != 0) {
                                (void) VNOP_ADVLOCK(vp, (caddr_t)fg,
                                    F_UNLCK, &lf, F_FLOCK, ctx, NULL);
+                       }
 
-                       if ((fg->fg_lflags & FG_HAS_OFDLOCK) != 0)
+                       if ((fg->fg_lflags & FG_HAS_OFDLOCK) != 0) {
                                (void) VNOP_ADVLOCK(vp, (caddr_t)fg,
                                    F_UNLCK, &lf, F_OFD_LOCK, ctx, NULL);
+                       }
                }
-               error = vn_close(vp, fg->fg_flag, ctx);
+               error = vn_close(vp, fg->fg_flag, ctx);
                (void) vnode_put(vp);
        }
-       return (error);
+       return error;
 }
 
 /*
@@ -1610,10 +1753,10 @@ vn_closefile(struct fileglob *fg, vfs_context_t ctx)
 int
 vn_pathconf(vnode_t vp, int name, int32_t *retval, vfs_context_t ctx)
 {
-       int     error = 0;
+       int     error = 0;
        struct vfs_attr vfa;
 
-       switch(name) {
+       switch (name) {
        case _PC_EXTENDED_SECURITY_NP:
                *retval = vfs_extendedsecurity(vnode_mount(vp)) ? 1 : 0;
                break;
@@ -1621,57 +1764,57 @@ vn_pathconf(vnode_t vp, int name, int32_t *retval, vfs_context_t ctx)
                *retval = vfs_authopaque(vnode_mount(vp));
                break;
        case _PC_2_SYMLINKS:
-               *retval = 1;    /* XXX NOTSUP on MSDOS, etc. */
+               *retval = 1;    /* XXX NOTSUP on MSDOS, etc. */
                break;
        case _PC_ALLOC_SIZE_MIN:
-               *retval = 1;    /* XXX lie: 1 byte */
+               *retval = 1;    /* XXX lie: 1 byte */
                break;
-       case _PC_ASYNC_IO:      /* unistd.h: _POSIX_ASYNCHRONUS_IO */
-               *retval = 1;    /* [AIO] option is supported */
+       case _PC_ASYNC_IO:      /* unistd.h: _POSIX_ASYNCHRONUS_IO */
+               *retval = 1;    /* [AIO] option is supported */
                break;
-       case _PC_PRIO_IO:       /* unistd.h: _POSIX_PRIORITIZED_IO */
-               *retval = 0;    /* [PIO] option is not supported */
+       case _PC_PRIO_IO:       /* unistd.h: _POSIX_PRIORITIZED_IO */
+               *retval = 0;    /* [PIO] option is not supported */
                break;
        case _PC_REC_INCR_XFER_SIZE:
-               *retval = 4096; /* XXX go from MIN to MAX 4K at a time */
+               *retval = 4096; /* XXX go from MIN to MAX 4K at a time */
                break;
        case _PC_REC_MIN_XFER_SIZE:
-               *retval = 4096; /* XXX recommend 4K minimum reads/writes */
+               *retval = 4096; /* XXX recommend 4K minimum reads/writes */
                break;
        case _PC_REC_MAX_XFER_SIZE:
                *retval = 65536; /* XXX recommend 64K maximum reads/writes */
                break;
        case _PC_REC_XFER_ALIGN:
-               *retval = 4096; /* XXX recommend page aligned buffers */
+               *retval = 4096; /* XXX recommend page aligned buffers */
                break;
        case _PC_SYMLINK_MAX:
-               *retval = 255;  /* Minimum acceptable POSIX value */
+               *retval = 255;  /* Minimum acceptable POSIX value */
                break;
-       case _PC_SYNC_IO:       /* unistd.h: _POSIX_SYNCHRONIZED_IO */
-               *retval = 0;    /* [SIO] option is not supported */
+       case _PC_SYNC_IO:       /* unistd.h: _POSIX_SYNCHRONIZED_IO */
+               *retval = 0;    /* [SIO] option is not supported */
                break;
        case _PC_XATTR_SIZE_BITS:
-               /* The number of bits used to store maximum extended 
-                * attribute size in bytes.  For example, if the maximum 
-                * attribute size supported by a file system is 128K, the 
-                * value returned will be 18.  However a value 18 can mean 
-                * that the maximum attribute size can be anywhere from 
-                * (256KB - 1) to 128KB.  As a special case, the resource 
-                * fork can have much larger size, and some file system 
-                * specific extended attributes can have smaller and preset 
+               /* The number of bits used to store maximum extended
+                * attribute size in bytes.  For example, if the maximum
+                * attribute size supported by a file system is 128K, the
+                * value returned will be 18.  However a value 18 can mean
+                * that the maximum attribute size can be anywhere from
+                * (256KB - 1) to 128KB.  As a special case, the resource
+                * fork can have much larger size, and some file system
+                * specific extended attributes can have smaller and preset
                 * size; for example, Finder Info is always 32 bytes.
                 */
                memset(&vfa, 0, sizeof(vfa));
                VFSATTR_INIT(&vfa);
                VFSATTR_WANTED(&vfa, f_capabilities);
                if (vfs_getattr(vnode_mount(vp), &vfa, ctx) == 0 &&
-                   (VFSATTR_IS_SUPPORTED(&vfa, f_capabilities)) && 
-                   (vfa.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_EXTENDED_ATTR) && 
+                   (VFSATTR_IS_SUPPORTED(&vfa, f_capabilities)) &&
+                   (vfa.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_EXTENDED_ATTR) &&
                    (vfa.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_EXTENDED_ATTR)) {
                        /* Supports native extended attributes */
                        error = VNOP_PATHCONF(vp, name, retval, ctx);
                } else {
-                       /* Number of bits used to represent the maximum size of 
+                       /* Number of bits used to represent the maximum size of
                         * extended attribute stored in an Apple Double file.
                         */
                        *retval = AD_XATTR_SIZE_BITS;
@@ -1682,53 +1825,52 @@ vn_pathconf(vnode_t vp, int name, int32_t *retval, vfs_context_t ctx)
                break;
        }
 
-       return (error);
+       return error;
 }
 
 static int
-vn_kqfilt_add(struct fileproc *fp, struct knote *kn, vfs_context_t ctx)
+vn_kqfilter(struct fileproc *fp, struct knote *kn, struct kevent_qos_s *kev)
 {
+       vfs_context_t ctx = vfs_context_current();
        struct vnode *vp;
        int error = 0;
        int result = 0;
-       
-       vp = (struct vnode *)fp->f_fglob->fg_data;
+
+       vp = (struct vnode *)fp->fp_glob->fg_data;
 
        /*
         * Don't attach a knote to a dead vnode.
         */
        if ((error = vget_internal(vp, 0, VNODE_NODEAD)) == 0) {
                switch (kn->kn_filter) {
-                       case EVFILT_READ:
-                       case EVFILT_WRITE:
-                               if (vnode_isfifo(vp)) {
-                                       /* We'll only watch FIFOs that use our fifofs */
-                                       if (!(vp->v_fifoinfo && vp->v_fifoinfo->fi_readsock)) {
-                                               error = ENOTSUP;
-                                       }
-
-                               } else if (!vnode_isreg(vp)) {
-                                       if (vnode_ischr(vp)) {
-                                               result = spec_kqfilter(vp, kn);
-                                               if ((kn->kn_flags & EV_ERROR) == 0) {
-                                                       /* claimed by a special device */
-                                                       vnode_put(vp);
-                                                       return result;
-                                               }
+               case EVFILT_READ:
+               case EVFILT_WRITE:
+                       if (vnode_isfifo(vp)) {
+                               /* We'll only watch FIFOs that use our fifofs */
+                               if (!(vp->v_fifoinfo && vp->v_fifoinfo->fi_readsock)) {
+                                       error = ENOTSUP;
+                               }
+                       } else if (!vnode_isreg(vp)) {
+                               if (vnode_ischr(vp)) {
+                                       result = spec_kqfilter(vp, kn, kev);
+                                       if ((kn->kn_flags & EV_ERROR) == 0) {
+                                               /* claimed by a special device */
+                                               vnode_put(vp);
+                                               return result;
                                        }
-                                       error = EINVAL;
                                }
-                               break;
-                       case EVFILT_VNODE:
-                               break;
-                       default:
                                error = EINVAL;
+                       }
+                       break;
+               case EVFILT_VNODE:
+                       break;
+               default:
+                       error = EINVAL;
                }
 
                if (error == 0) {
-
 #if CONFIG_MACF
-                       error = mac_vnode_check_kqfilter(ctx, fp->f_fglob->fg_cred, kn, vp);
+                       error = mac_vnode_check_kqfilter(ctx, fp->fp_glob->fg_cred, kn, vp);
                        if (error) {
                                vnode_put(vp);
                                goto out;
@@ -1736,28 +1878,26 @@ vn_kqfilt_add(struct fileproc *fp, struct knote *kn, vfs_context_t ctx)
 #endif
 
                        kn->kn_hook = (void*)vp;
-                       kn->kn_hookid = vnode_vid(vp);
                        kn->kn_filtid = EVFILTID_VN;
 
                        vnode_lock(vp);
                        KNOTE_ATTACH(&vp->v_knotes, kn);
-                       result = filt_vnode_common(kn, vp, 0);
+                       result = filt_vnode_common(kn, NULL, vp, 0);
                        vnode_unlock(vp);
 
                        /*
                         * Ask the filesystem to provide remove notifications,
                         * but ignore failure
                         */
-                       VNOP_MONITOR(vp, 0, VNODE_MONITOR_BEGIN, (void*) kn,  ctx);
+                       VNOP_MONITOR(vp, 0, VNODE_MONITOR_BEGIN, (void*) kn, ctx);
                }
 
                vnode_put(vp);
        }
 
- out:
+out:
        if (error) {
-               kn->kn_flags = EV_ERROR;
-               kn->kn_data = error;
+               knote_set_error(kn, error);
        }
 
        return result;
@@ -1767,17 +1907,18 @@ static void
 filt_vndetach(struct knote *kn)
 {
        vfs_context_t ctx = vfs_context_current();
-       struct vnode *vp
-       vp = (struct vnode *)kn->kn_hook;
-       if (vnode_getwithvid(vp, kn->kn_hookid))
+       struct vnode *vp = (struct vnode *)kn->kn_hook;
+       uint32_t vid = vnode_vid(vp);
+       if (vnode_getwithvid(vp, vid)) {
                return;
+       }
 
        vnode_lock(vp);
        KNOTE_DETACH(&vp->v_knotes, kn);
        vnode_unlock(vp);
-       
-       /* 
-        * Tell a (generally networked) filesystem that we're no longer watching 
+
+       /*
+        * Tell a (generally networked) filesystem that we're no longer watching
         * If the FS wants to track contexts, it should still be using the one from
         * the VNODE_MONITOR_BEGIN.
         */
@@ -1793,7 +1934,7 @@ filt_vndetach(struct knote *kn)
  * differently than the regular case for VREG files.  If not in poll(),
  * then we need to know current fileproc offset for VREG.
  */
-static intptr_t
+static int64_t
 vnode_readable_data_count(vnode_t vp, off_t current_offset, int ispoll)
 {
        if (vnode_isfifo(vp)) {
@@ -1801,26 +1942,26 @@ vnode_readable_data_count(vnode_t vp, off_t current_offset, int ispoll)
                int cnt;
                int err = fifo_charcount(vp, &cnt);
                if (err == 0) {
-                       return (intptr_t)cnt;
-               } else 
+                       return (int64_t)cnt;
+               } else
 #endif
                {
-                       return (intptr_t)0;
+                       return 0;
                }
        } else if (vnode_isreg(vp)) {
                if (ispoll) {
-                       return (intptr_t)1;
+                       return 1;
                }
 
                off_t amount;
                amount = vp->v_un.vu_ubcinfo->ui_size - current_offset;
-               if (amount > (off_t)INTPTR_MAX) {
-                       return INTPTR_MAX;
-               } else if (amount < (off_t)INTPTR_MIN) {
-                       return INTPTR_MIN;
+               if (amount > INT64_MAX) {
+                       return INT64_MAX;
+               } else if (amount < INT64_MIN) {
+                       return INT64_MIN;
                } else {
-                       return (intptr_t)amount;
-               } 
+                       return (int64_t)amount;
+               }
        } else {
                panic("Should never have an EVFILT_READ except for reg or fifo.");
                return 0;
@@ -1828,13 +1969,13 @@ vnode_readable_data_count(vnode_t vp, off_t current_offset, int ispoll)
 }
 
 /*
- * Used for EVFILT_WRITE.  
+ * Used for EVFILT_WRITE.
  *
  * For regular vnodes, we can always write (1).  For named pipes,
  * see how much space there is in the buffer.  Nothing else is covered.
  */
 static intptr_t
-vnode_writable_space_count(vnode_t vp) 
+vnode_writable_space_count(vnode_t vp)
 {
        if (vnode_isfifo(vp)) {
 #if FIFO
@@ -1842,7 +1983,7 @@ vnode_writable_space_count(vnode_t vp)
                int err = fifo_freespace(vp, &spc);
                if (err == 0) {
                        return (intptr_t)spc;
-               } else 
+               } else
 #endif
                {
                        return (intptr_t)0;
@@ -1855,19 +1996,20 @@ vnode_writable_space_count(vnode_t vp)
        }
 }
 
-/* 
+/*
  * Determine whether this knote should be active
- * 
- * This is kind of subtle.  
- *     --First, notice if the vnode has been revoked: in so, override hint
- *     --EVFILT_READ knotes are checked no matter what the hint is
- *     --Other knotes activate based on hint.  
- *     --If hint is revoke, set special flags and activate
+ *
+ * This is kind of subtle.
+ *      --First, notice if the vnode has been revoked: in so, override hint
+ *      --EVFILT_READ knotes are checked no matter what the hint is
+ *      --Other knotes activate based on hint.
+ *      --If hint is revoke, set special flags and activate
  */
 static int
-filt_vnode_common(struct knote *kn, vnode_t vp, long hint)
+filt_vnode_common(struct knote *kn, struct kevent_qos_s *kev, vnode_t vp, long hint)
 {
        int activate = 0;
+       int64_t data = 0;
 
        lck_mtx_assert(&vp->v_lock, LCK_MTX_ASSERT_OWNED);
 
@@ -1880,35 +2022,32 @@ filt_vnode_common(struct knote *kn, vnode_t vp, long hint)
                        kn->kn_fflags |= NOTE_REVOKE;
                }
        } else {
-               switch(kn->kn_filter) {
-                       case EVFILT_READ:
-                               kn->kn_data = vnode_readable_data_count(vp, kn->kn_fp->f_fglob->fg_offset, (kn->kn_flags & EV_POLL));
-
-                               if (kn->kn_data != 0) {
-                                       activate = 1;
-                               }
-                               break;
-                       case EVFILT_WRITE: 
-                               kn->kn_data = vnode_writable_space_count(vp);
-
-                               if (kn->kn_data != 0) {
-                                       activate = 1;
-                               }
-                               break;
-                       case EVFILT_VNODE:
-                               /* Check events this note matches against the hint */
-                               if (kn->kn_sfflags & hint) {
-                                       kn->kn_fflags |= hint; /* Set which event occurred */
-                               }
-                               if (kn->kn_fflags != 0) {
-                                       activate = 1;
-                               }
-                               break;
-                       default:
-                               panic("Invalid knote filter on a vnode!\n");
+               switch (kn->kn_filter) {
+               case EVFILT_READ:
+                       data = vnode_readable_data_count(vp, kn->kn_fp->fp_glob->fg_offset, (kn->kn_flags & EV_POLL));
+                       activate = (data != 0);
+                       break;
+               case EVFILT_WRITE:
+                       data = vnode_writable_space_count(vp);
+                       activate = (data != 0);
+                       break;
+               case EVFILT_VNODE:
+                       /* Check events this note matches against the hint */
+                       if (kn->kn_sfflags & hint) {
+                               kn->kn_fflags |= hint;         /* Set which event occurred */
+                       }
+                       activate = (kn->kn_fflags != 0);
+                       break;
+               default:
+                       panic("Invalid knote filter on a vnode!\n");
                }
        }
-       return (activate);
+
+       if (kev && activate) {
+               knote_fill_kevent(kn, kev, data);
+       }
+
+       return activate;
 }
 
 static int
@@ -1916,63 +2055,56 @@ filt_vnode(struct knote *kn, long hint)
 {
        vnode_t vp = (struct vnode *)kn->kn_hook;
 
-       return filt_vnode_common(kn, vp, hint);
+       return filt_vnode_common(kn, NULL, vp, hint);
 }
 
 static int
-filt_vntouch(struct knote *kn, struct kevent_internal_s *kev)
+filt_vntouch(struct knote *kn, struct kevent_qos_s *kev)
 {
        vnode_t vp = (struct vnode *)kn->kn_hook;
+       uint32_t vid = vnode_vid(vp);
        int activate;
        int hint = 0;
 
        vnode_lock(vp);
-       if (vnode_getiocount(vp, kn->kn_hookid, VNODE_NODEAD | VNODE_WITHID) != 0) {
+       if (vnode_getiocount(vp, vid, VNODE_NODEAD | VNODE_WITHID) != 0) {
                /* is recycled */
                hint = NOTE_REVOKE;
        }
 
        /* accept new input fflags mask */
        kn->kn_sfflags = kev->fflags;
-       if ((kn->kn_status & KN_UDATA_SPECIFIC) == 0)
-               kn->kn_udata = kev->udata;
 
-       activate = filt_vnode_common(kn, vp, hint);
+       activate = filt_vnode_common(kn, NULL, vp, hint);
 
-       if (hint == 0)
+       if (hint == 0) {
                vnode_put_locked(vp);
+       }
        vnode_unlock(vp);
 
        return activate;
 }
 
 static int
-filt_vnprocess(struct knote *kn, struct filt_process_s *data, struct kevent_internal_s *kev)
+filt_vnprocess(struct knote *kn, struct kevent_qos_s *kev)
 {
-#pragma unused(data)
        vnode_t vp = (struct vnode *)kn->kn_hook;
+       uint32_t vid = vnode_vid(vp);
        int activate;
        int hint = 0;
 
        vnode_lock(vp);
-       if (vnode_getiocount(vp, kn->kn_hookid, VNODE_NODEAD | VNODE_WITHID) != 0) {
+       if (vnode_getiocount(vp, vid, VNODE_NODEAD | VNODE_WITHID) != 0) {
                /* Is recycled */
                hint = NOTE_REVOKE;
-       } 
-       activate = filt_vnode_common(kn, vp, hint);
-       if (activate) {
-               *kev = kn->kn_kevent;
-               if (kn->kn_flags & EV_CLEAR) {
-                       kn->kn_data = 0;
-                       kn->kn_fflags = 0;
-               }
        }
+       activate = filt_vnode_common(kn, kev, vp, hint);
 
        /* Definitely need to unlock, may need to put */
-       if (hint == 0)
+       if (hint == 0) {
                vnode_put_locked(vp);
+       }
        vnode_unlock(vp);
 
        return activate;
 }
-