]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_vnops.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_vnops.c
index 0991a5373ff166f549c6def6f7a999034c6d21cc..b03463b43b07dd51c4b72c14687de27effd85bb9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -65,6 +65,8 @@
  * FreeBSD-Id: nfs_vnops.c,v 1.72 1997/11/07 09:20:48 phk Exp $
  */
 
+#include <nfs/nfs_conf.h>
+#if CONFIG_NFS_CLIENT
 
 /*
  * vnode op calls for Sun NFS version 2 and 3
@@ -87,6 +89,7 @@
 #include <sys/attr.h>
 #include <sys/signalvar.h>
 #include <sys/uio_internal.h>
+#include <sys/xattr.h>
 
 #include <vfs/vfs_support.h>
 
@@ -157,110 +160,116 @@ int     nfs3_vnop_mkdir(struct vnop_mkdir_args *);
 int     nfs3_vnop_rmdir(struct vnop_rmdir_args *);
 int     nfs3_vnop_symlink(struct vnop_symlink_args *);
 
+
 vnop_t **nfsv2_vnodeop_p;
-static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
-       { &vnop_default_desc, (vnop_t *)vn_default_error },
-       { &vnop_lookup_desc, (vnop_t *)nfs_vnop_lookup },       /* lookup */
-       { &vnop_create_desc, (vnop_t *)nfs3_vnop_create },      /* create */
-       { &vnop_mknod_desc, (vnop_t *)nfs3_vnop_mknod },        /* mknod */
-       { &vnop_open_desc, (vnop_t *)nfs_vnop_open },           /* open */
-       { &vnop_close_desc, (vnop_t *)nfs_vnop_close },         /* close */
-       { &vnop_access_desc, (vnop_t *)nfs_vnop_access },       /* access */
-       { &vnop_getattr_desc, (vnop_t *)nfs3_vnop_getattr },    /* getattr */
-       { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr },     /* setattr */
-       { &vnop_read_desc, (vnop_t *)nfs_vnop_read },           /* read */
-       { &vnop_write_desc, (vnop_t *)nfs_vnop_write },         /* write */
-       { &vnop_ioctl_desc, (vnop_t *)nfs_vnop_ioctl },         /* ioctl */
-       { &vnop_select_desc, (vnop_t *)nfs_vnop_select },       /* select */
-       { &vnop_revoke_desc, (vnop_t *)nfs_vnop_revoke },       /* revoke */
-       { &vnop_mmap_desc, (vnop_t *)nfs_vnop_mmap },           /* mmap */
-       { &vnop_mnomap_desc, (vnop_t *)nfs_vnop_mnomap },       /* mnomap */
-       { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync },         /* fsync */
-       { &vnop_remove_desc, (vnop_t *)nfs_vnop_remove },       /* remove */
-       { &vnop_link_desc, (vnop_t *)nfs3_vnop_link },          /* link */
-       { &vnop_rename_desc, (vnop_t *)nfs_vnop_rename },       /* rename */
-       { &vnop_mkdir_desc, (vnop_t *)nfs3_vnop_mkdir },        /* mkdir */
-       { &vnop_rmdir_desc, (vnop_t *)nfs3_vnop_rmdir },        /* rmdir */
-       { &vnop_symlink_desc, (vnop_t *)nfs3_vnop_symlink },    /* symlink */
-       { &vnop_readdir_desc, (vnop_t *)nfs_vnop_readdir },     /* readdir */
-       { &vnop_readlink_desc, (vnop_t *)nfs_vnop_readlink },   /* readlink */
-       { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive },   /* inactive */
-       { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim },     /* reclaim */
-       { &vnop_strategy_desc, (vnop_t *)err_strategy },        /* strategy */
-       { &vnop_pathconf_desc, (vnop_t *)nfs_vnop_pathconf },   /* pathconf */
-       { &vnop_advlock_desc, (vnop_t *)nfs_vnop_advlock },     /* advlock */
-       { &vnop_bwrite_desc, (vnop_t *)err_bwrite },            /* bwrite */
-       { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein },       /* Pagein */
-       { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout },     /* Pageout */
-       { &vnop_copyfile_desc, (vnop_t *)err_copyfile },        /* Copyfile */
-       { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff },   /* blktooff */
-       { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk },   /* offtoblk */
-       { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap },   /* blockmap */
-       { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor },     /* monitor */
-       { NULL, NULL }
+static const struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
+       { .opve_op = &vnop_default_desc, .opve_impl = (vnop_t *)vn_default_error },
+       { .opve_op = &vnop_lookup_desc, .opve_impl = (vnop_t *)nfs_vnop_lookup },         /* lookup */
+       { .opve_op = &vnop_create_desc, .opve_impl = (vnop_t *)nfs3_vnop_create },        /* create */
+       { .opve_op = &vnop_mknod_desc, .opve_impl = (vnop_t *)nfs3_vnop_mknod },          /* mknod */
+       { .opve_op = &vnop_open_desc, .opve_impl = (vnop_t *)nfs_vnop_open },             /* open */
+       { .opve_op = &vnop_close_desc, .opve_impl = (vnop_t *)nfs_vnop_close },           /* close */
+       { .opve_op = &vnop_access_desc, .opve_impl = (vnop_t *)nfs_vnop_access },         /* access */
+       { .opve_op = &vnop_getattr_desc, .opve_impl = (vnop_t *)nfs3_vnop_getattr },      /* getattr */
+       { .opve_op = &vnop_setattr_desc, .opve_impl = (vnop_t *)nfs_vnop_setattr },       /* setattr */
+       { .opve_op = &vnop_read_desc, .opve_impl = (vnop_t *)nfs_vnop_read },             /* read */
+       { .opve_op = &vnop_write_desc, .opve_impl = (vnop_t *)nfs_vnop_write },           /* write */
+       { .opve_op = &vnop_ioctl_desc, .opve_impl = (vnop_t *)nfs_vnop_ioctl },           /* ioctl */
+       { .opve_op = &vnop_select_desc, .opve_impl = (vnop_t *)nfs_vnop_select },         /* select */
+       { .opve_op = &vnop_revoke_desc, .opve_impl = (vnop_t *)nfs_vnop_revoke },         /* revoke */
+       { .opve_op = &vnop_mmap_desc, .opve_impl = (vnop_t *)nfs_vnop_mmap },             /* mmap */
+       { .opve_op = &vnop_mmap_check_desc, .opve_impl = (vnop_t *)nfs_vnop_mmap_check }, /* mmap_check */
+       { .opve_op = &vnop_mnomap_desc, .opve_impl = (vnop_t *)nfs_vnop_mnomap },         /* mnomap */
+       { .opve_op = &vnop_fsync_desc, .opve_impl = (vnop_t *)nfs_vnop_fsync },           /* fsync */
+       { .opve_op = &vnop_remove_desc, .opve_impl = (vnop_t *)nfs_vnop_remove },         /* remove */
+       { .opve_op = &vnop_link_desc, .opve_impl = (vnop_t *)nfs3_vnop_link },            /* link */
+       { .opve_op = &vnop_rename_desc, .opve_impl = (vnop_t *)nfs_vnop_rename },         /* rename */
+       { .opve_op = &vnop_mkdir_desc, .opve_impl = (vnop_t *)nfs3_vnop_mkdir },          /* mkdir */
+       { .opve_op = &vnop_rmdir_desc, .opve_impl = (vnop_t *)nfs3_vnop_rmdir },          /* rmdir */
+       { .opve_op = &vnop_symlink_desc, .opve_impl = (vnop_t *)nfs3_vnop_symlink },      /* symlink */
+       { .opve_op = &vnop_readdir_desc, .opve_impl = (vnop_t *)nfs_vnop_readdir },       /* readdir */
+       { .opve_op = &vnop_readlink_desc, .opve_impl = (vnop_t *)nfs_vnop_readlink },     /* readlink */
+       { .opve_op = &vnop_inactive_desc, .opve_impl = (vnop_t *)nfs_vnop_inactive },     /* inactive */
+       { .opve_op = &vnop_reclaim_desc, .opve_impl = (vnop_t *)nfs_vnop_reclaim },       /* reclaim */
+       { .opve_op = &vnop_strategy_desc, .opve_impl = (vnop_t *)err_strategy },          /* strategy */
+       { .opve_op = &vnop_pathconf_desc, .opve_impl = (vnop_t *)nfs_vnop_pathconf },     /* pathconf */
+       { .opve_op = &vnop_advlock_desc, .opve_impl = (vnop_t *)nfs_vnop_advlock },       /* advlock */
+       { .opve_op = &vnop_bwrite_desc, .opve_impl = (vnop_t *)err_bwrite },              /* bwrite */
+       { .opve_op = &vnop_pagein_desc, .opve_impl = (vnop_t *)nfs_vnop_pagein },         /* Pagein */
+       { .opve_op = &vnop_pageout_desc, .opve_impl = (vnop_t *)nfs_vnop_pageout },       /* Pageout */
+       { .opve_op = &vnop_copyfile_desc, .opve_impl = (vnop_t *)err_copyfile },          /* Copyfile */
+       { .opve_op = &vnop_blktooff_desc, .opve_impl = (vnop_t *)nfs_vnop_blktooff },     /* blktooff */
+       { .opve_op = &vnop_offtoblk_desc, .opve_impl = (vnop_t *)nfs_vnop_offtoblk },     /* offtoblk */
+       { .opve_op = &vnop_blockmap_desc, .opve_impl = (vnop_t *)nfs_vnop_blockmap },     /* blockmap */
+       { .opve_op = &vnop_monitor_desc, .opve_impl = (vnop_t *)nfs_vnop_monitor },       /* monitor */
+       { .opve_op = NULL, .opve_impl = NULL }
 };
-struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
+const struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
 { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
 
+
+#if CONFIG_NFS4
 vnop_t **nfsv4_vnodeop_p;
-static struct vnodeopv_entry_desc nfsv4_vnodeop_entries[] = {
+static const struct vnodeopv_entry_desc nfsv4_vnodeop_entries[] = {
        { &vnop_default_desc, (vnop_t *)vn_default_error },
-       { &vnop_lookup_desc, (vnop_t *)nfs_vnop_lookup },       /* lookup */
-       { &vnop_create_desc, (vnop_t *)nfs4_vnop_create },      /* create */
-       { &vnop_mknod_desc, (vnop_t *)nfs4_vnop_mknod },        /* mknod */
-       { &vnop_open_desc, (vnop_t *)nfs_vnop_open },           /* open */
-       { &vnop_close_desc, (vnop_t *)nfs_vnop_close },         /* close */
-       { &vnop_access_desc, (vnop_t *)nfs_vnop_access },       /* access */
-       { &vnop_getattr_desc, (vnop_t *)nfs4_vnop_getattr },    /* getattr */
-       { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr },     /* setattr */
-       { &vnop_read_desc, (vnop_t *)nfs_vnop_read },           /* read */
-       { &vnop_write_desc, (vnop_t *)nfs_vnop_write },         /* write */
-       { &vnop_ioctl_desc, (vnop_t *)nfs_vnop_ioctl },         /* ioctl */
-       { &vnop_select_desc, (vnop_t *)nfs_vnop_select },       /* select */
-       { &vnop_revoke_desc, (vnop_t *)nfs_vnop_revoke },       /* revoke */
-       { &vnop_mmap_desc, (vnop_t *)nfs_vnop_mmap },           /* mmap */
-       { &vnop_mnomap_desc, (vnop_t *)nfs_vnop_mnomap },       /* mnomap */
-       { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync },         /* fsync */
-       { &vnop_remove_desc, (vnop_t *)nfs_vnop_remove },       /* remove */
-       { &vnop_link_desc, (vnop_t *)nfs4_vnop_link },          /* link */
-       { &vnop_rename_desc, (vnop_t *)nfs_vnop_rename },       /* rename */
-       { &vnop_mkdir_desc, (vnop_t *)nfs4_vnop_mkdir },        /* mkdir */
-       { &vnop_rmdir_desc, (vnop_t *)nfs4_vnop_rmdir },        /* rmdir */
-       { &vnop_symlink_desc, (vnop_t *)nfs4_vnop_symlink },    /* symlink */
-       { &vnop_readdir_desc, (vnop_t *)nfs_vnop_readdir },     /* readdir */
-       { &vnop_readlink_desc, (vnop_t *)nfs_vnop_readlink },   /* readlink */
-       { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive },   /* inactive */
-       { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim },     /* reclaim */
-       { &vnop_strategy_desc, (vnop_t *)err_strategy },        /* strategy */
-       { &vnop_pathconf_desc, (vnop_t *)nfs_vnop_pathconf },   /* pathconf */
-       { &vnop_advlock_desc, (vnop_t *)nfs_vnop_advlock },     /* advlock */
-       { &vnop_bwrite_desc, (vnop_t *)err_bwrite },            /* bwrite */
-       { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein },       /* Pagein */
-       { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout },     /* Pageout */
-       { &vnop_copyfile_desc, (vnop_t *)err_copyfile },        /* Copyfile */
-       { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff },   /* blktooff */
-       { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk },   /* offtoblk */
-       { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap },   /* blockmap */
-       { &vnop_getxattr_desc, (vnop_t *)nfs4_vnop_getxattr },  /* getxattr */
-       { &vnop_setxattr_desc, (vnop_t *)nfs4_vnop_setxattr },  /* setxattr */
-       { &vnop_removexattr_desc, (vnop_t *)nfs4_vnop_removexattr },/* removexattr */
-       { &vnop_listxattr_desc, (vnop_t *)nfs4_vnop_listxattr },/* listxattr */
+       { &vnop_lookup_desc, (vnop_t *)nfs_vnop_lookup },                        /* lookup */
+       { &vnop_create_desc, (vnop_t *)nfs4_vnop_create },                       /* create */
+       { &vnop_mknod_desc, (vnop_t *)nfs4_vnop_mknod },                         /* mknod */
+       { &vnop_open_desc, (vnop_t *)nfs_vnop_open },                            /* open */
+       { &vnop_close_desc, (vnop_t *)nfs_vnop_close },                          /* close */
+       { &vnop_access_desc, (vnop_t *)nfs_vnop_access },                        /* access */
+       { &vnop_getattr_desc, (vnop_t *)nfs4_vnop_getattr },                     /* getattr */
+       { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr },                      /* setattr */
+       { &vnop_read_desc, (vnop_t *)nfs_vnop_read },                            /* read */
+       { &vnop_write_desc, (vnop_t *)nfs_vnop_write },                          /* write */
+       { &vnop_ioctl_desc, (vnop_t *)nfs_vnop_ioctl },                          /* ioctl */
+       { &vnop_select_desc, (vnop_t *)nfs_vnop_select },                        /* select */
+       { &vnop_revoke_desc, (vnop_t *)nfs_vnop_revoke },                        /* revoke */
+       { &vnop_mmap_desc, (vnop_t *)nfs_vnop_mmap },                            /* mmap */
+       { &vnop_mmap_check_desc, (vnop_t *)nfs_vnop_mmap_check },                /* mmap_check */
+       { &vnop_mnomap_desc, (vnop_t *)nfs_vnop_mnomap },                        /* mnomap */
+       { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync },                          /* fsync */
+       { &vnop_remove_desc, (vnop_t *)nfs_vnop_remove },                        /* remove */
+       { &vnop_link_desc, (vnop_t *)nfs4_vnop_link },                           /* link */
+       { &vnop_rename_desc, (vnop_t *)nfs_vnop_rename },                        /* rename */
+       { &vnop_mkdir_desc, (vnop_t *)nfs4_vnop_mkdir },                         /* mkdir */
+       { &vnop_rmdir_desc, (vnop_t *)nfs4_vnop_rmdir },                         /* rmdir */
+       { &vnop_symlink_desc, (vnop_t *)nfs4_vnop_symlink },                     /* symlink */
+       { &vnop_readdir_desc, (vnop_t *)nfs_vnop_readdir },                      /* readdir */
+       { &vnop_readlink_desc, (vnop_t *)nfs_vnop_readlink },                    /* readlink */
+       { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive },                    /* inactive */
+       { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim },                      /* reclaim */
+       { &vnop_strategy_desc, (vnop_t *)err_strategy },                         /* strategy */
+       { &vnop_pathconf_desc, (vnop_t *)nfs_vnop_pathconf },                    /* pathconf */
+       { &vnop_advlock_desc, (vnop_t *)nfs_vnop_advlock },                      /* advlock */
+       { &vnop_bwrite_desc, (vnop_t *)err_bwrite },                             /* bwrite */
+       { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein },                        /* Pagein */
+       { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout },                      /* Pageout */
+       { &vnop_copyfile_desc, (vnop_t *)err_copyfile },                         /* Copyfile */
+       { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff },                    /* blktooff */
+       { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk },                    /* offtoblk */
+       { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap },                    /* blockmap */
+       { &vnop_getxattr_desc, (vnop_t *)nfs4_vnop_getxattr },                   /* getxattr */
+       { &vnop_setxattr_desc, (vnop_t *)nfs4_vnop_setxattr },                   /* setxattr */
+       { &vnop_removexattr_desc, (vnop_t *)nfs4_vnop_removexattr },             /* removexattr */
+       { &vnop_listxattr_desc, (vnop_t *)nfs4_vnop_listxattr },                 /* listxattr */
 #if NAMEDSTREAMS
-       { &vnop_getnamedstream_desc, (vnop_t *)nfs4_vnop_getnamedstream },      /* getnamedstream */
-       { &vnop_makenamedstream_desc, (vnop_t *)nfs4_vnop_makenamedstream },    /* makenamedstream */
-       { &vnop_removenamedstream_desc, (vnop_t *)nfs4_vnop_removenamedstream },/* removenamedstream */
+       { &vnop_getnamedstream_desc, (vnop_t *)nfs4_vnop_getnamedstream },       /* getnamedstream */
+       { &vnop_makenamedstream_desc, (vnop_t *)nfs4_vnop_makenamedstream },     /* makenamedstream */
+       { &vnop_removenamedstream_desc, (vnop_t *)nfs4_vnop_removenamedstream }, /* removenamedstream */
 #endif
-       { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor },     /* monitor */
+       { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor },                      /* monitor */
        { NULL, NULL }
 };
-struct vnodeopv_desc nfsv4_vnodeop_opv_desc =
+const struct vnodeopv_desc nfsv4_vnodeop_opv_desc =
 { &nfsv4_vnodeop_p, nfsv4_vnodeop_entries };
+#endif
 
 /*
  * Special device vnode ops
  */
 vnop_t **spec_nfsv2nodeop_p;
-static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
+static const struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
        { &vnop_default_desc, (vnop_t *)vn_default_error },
        { &vnop_lookup_desc, (vnop_t *)spec_lookup },           /* lookup */
        { &vnop_create_desc, (vnop_t *)spec_create },           /* create */
@@ -298,10 +307,11 @@ static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
        { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor },     /* monitor */
        { NULL, NULL }
 };
-struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
+const struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
 { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
+#if CONFIG_NFS4
 vnop_t **spec_nfsv4nodeop_p;
-static struct vnodeopv_entry_desc spec_nfsv4nodeop_entries[] = {
+static const struct vnodeopv_entry_desc spec_nfsv4nodeop_entries[] = {
        { &vnop_default_desc, (vnop_t *)vn_default_error },
        { &vnop_lookup_desc, (vnop_t *)spec_lookup },           /* lookup */
        { &vnop_create_desc, (vnop_t *)spec_create },           /* create */
@@ -348,12 +358,13 @@ static struct vnodeopv_entry_desc spec_nfsv4nodeop_entries[] = {
        { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor },     /* monitor */
        { NULL, NULL }
 };
-struct vnodeopv_desc spec_nfsv4nodeop_opv_desc =
+const struct vnodeopv_desc spec_nfsv4nodeop_opv_desc =
 { &spec_nfsv4nodeop_p, spec_nfsv4nodeop_entries };
+#endif /* CONFIG_NFS4 */
 
 #if FIFO
 vnop_t **fifo_nfsv2nodeop_p;
-static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
+static const struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
        { &vnop_default_desc, (vnop_t *)vn_default_error },
        { &vnop_lookup_desc, (vnop_t *)fifo_lookup },           /* lookup */
        { &vnop_create_desc, (vnop_t *)fifo_create },           /* create */
@@ -391,11 +402,14 @@ static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
        { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor },     /* monitor */
        { NULL, NULL }
 };
-struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
+const struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
 { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
+#endif
 
+#if CONFIG_NFS4
+#if FIFO
 vnop_t **fifo_nfsv4nodeop_p;
-static struct vnodeopv_entry_desc fifo_nfsv4nodeop_entries[] = {
+static const struct vnodeopv_entry_desc fifo_nfsv4nodeop_entries[] = {
        { &vnop_default_desc, (vnop_t *)vn_default_error },
        { &vnop_lookup_desc, (vnop_t *)fifo_lookup },           /* lookup */
        { &vnop_create_desc, (vnop_t *)fifo_create },           /* create */
@@ -442,14 +456,72 @@ static struct vnodeopv_entry_desc fifo_nfsv4nodeop_entries[] = {
        { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor },     /* monitor */
        { NULL, NULL }
 };
-struct vnodeopv_desc fifo_nfsv4nodeop_opv_desc =
+const struct vnodeopv_desc fifo_nfsv4nodeop_opv_desc =
 { &fifo_nfsv4nodeop_p, fifo_nfsv4nodeop_entries };
 #endif /* FIFO */
+#endif /* CONFIG_NFS4 */
 
 int     nfs_sillyrename(nfsnode_t, nfsnode_t, struct componentname *, vfs_context_t);
 int     nfs_getattr_internal(nfsnode_t, struct nfs_vattr *, vfs_context_t, int);
 int     nfs_refresh_fh(nfsnode_t, vfs_context_t);
 
+
+ZONE_VIEW_DEFINE(ZV_NFSDIROFF, "NFSV3 diroff",
+    KHEAP_ID_DATA_BUFFERS, sizeof(struct nfsdmap));
+
+static void
+nfs_dir_buf_cache_lookup_boundaries(struct nfsbuf *bp, int *sof, int *eof)
+{
+       if (bp) {
+               struct nfs_dir_buf_header *ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
+               if (sof && bp->nb_lblkno == 0) {
+                       *sof = 1;
+               }
+               if (eof && ISSET(ndbhp->ndbh_flags, NDB_EOF)) {
+                       *eof = 1;
+               }
+       }
+}
+
+/*
+ * Update nfsnode attributes to avoid extra getattr calls for each direntry.
+ * This function should be called only if RDIRPLUS flag is enabled.
+ */
+void
+nfs_rdirplus_update_node_attrs(nfsnode_t dnp, struct direntry *dp, fhandle_t *fhp, struct nfs_vattr *nvattrp, uint64_t *savedxidp)
+{
+       nfsnode_t np;
+       struct componentname cn;
+       int isdot = (dp->d_namlen == 1) && (dp->d_name[0] == '.');
+       int isdotdot = (dp->d_namlen == 2) && (dp->d_name[0] == '.') && (dp->d_name[1] == '.');
+       int should_update_fileid = nvattrp->nva_flags & NFS_FFLAG_FILEID_CONTAINS_XID;
+       uint64_t xid = 0;
+
+       if (isdot || isdotdot) {
+               return;
+       }
+
+       np = NULL;
+       bzero(&cn, sizeof(cn));
+       cn.cn_nameptr = dp->d_name;
+       cn.cn_namelen = dp->d_namlen;
+       cn.cn_nameiop = LOOKUP;
+
+       /* xid might be stashed in nva_fileid is rdirplus is enabled */
+       if (should_update_fileid) {
+               xid = nvattrp->nva_fileid;
+               nvattrp->nva_fileid = dp->d_fileno;
+       }
+       nfs_nget(NFSTOMP(dnp), dnp, &cn, fhp->fh_data, fhp->fh_len, nvattrp, savedxidp, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
+       if (should_update_fileid) {
+               nvattrp->nva_fileid = xid;
+       }
+       if (np) {
+               nfs_node_unlock(np);
+               vnode_put(NFSTOV(np));
+       }
+}
+
 /*
  * Find the slot in the access cache for this UID.
  * If adding and no existing slot is found, reuse slots in FIFO order.
@@ -478,7 +550,7 @@ nfs_node_access_slot(nfsnode_t np, uid_t uid, int add)
 int
 nfs3_access_rpc(nfsnode_t np, u_int32_t *access, int rpcflags, vfs_context_t ctx)
 {
-       int error = 0, lockerror = ENOENT, status, slot;
+       int error = 0, lockerror = ENOENT, status = 0, slot;
        uint32_t access_result = 0;
        u_int64_t xid;
        struct nfsm_chain nmreq, nmrep;
@@ -514,11 +586,15 @@ nfs3_access_rpc(nfsnode_t np, u_int32_t *access, int rpcflags, vfs_context_t ctx
        }
        nfsmout_if(error);
 
+#if CONFIG_NFS_GSS
        if (auth_is_kerberized(np->n_auth) || auth_is_kerberized(nmp->nm_auth)) {
                uid = nfs_cred_getasid2uid(vfs_context_ucred(ctx));
        } else {
                uid = kauth_cred_getuid(vfs_context_ucred(ctx));
        }
+#else
+       uid = kauth_cred_getuid(vfs_context_ucred(ctx));
+#endif /* CONFIG_NFS_GSS */
        slot = nfs_node_access_slot(np, uid, 1);
        np->n_accessuid[slot] = uid;
        microuptime(&now);
@@ -551,6 +627,7 @@ nfsmout:
        return error;
 }
 
+
 /*
  * NFS access vnode op.
  * For NFS version 2, just return ok. File accesses may fail later.
@@ -582,7 +659,8 @@ nfs_vnop_access(
        }
        nfsvers = nmp->nm_vers;
 
-       if (nfsvers == NFS_VER2) {
+
+       if (nfsvers == NFS_VER2 || NMFLAG(nmp, NOOPAQUE_AUTH)) {
                if ((ap->a_action & KAUTH_VNODE_WRITE_RIGHTS) &&
                    vfs_isrdonly(vnode_mount(vp))) {
                        return EROFS;
@@ -670,11 +748,15 @@ nfs_vnop_access(
         * Does our cached result allow us to give a definite yes to
         * this request?
         */
+#if CONFIG_NFS_GSS
        if (auth_is_kerberized(np->n_auth) || auth_is_kerberized(nmp->nm_auth)) {
                uid = nfs_cred_getasid2uid(vfs_context_ucred(ctx));
        } else {
                uid = kauth_cred_getuid(vfs_context_ucred(ctx));
        }
+#else
+       uid = kauth_cred_getuid(vfs_context_ucred(ctx));
+#endif /* CONFIG_NFS_GSS */
        slot = nfs_node_access_slot(np, uid, 0);
        dorpc = 1;
        if (access == 0) {
@@ -851,14 +933,16 @@ restart:
                NP(np, "nfs_vnop_open: LOST %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
                error = EIO;
        }
+#if CONFIG_NFS4
        if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
-               nfs_mount_state_in_use_end(nmp, 0);
                error = nfs4_reopen(nofp, vfs_context_thread(ctx));
                nofp = NULL;
                if (!error) {
+                       nfs_mount_state_in_use_end(nmp, 0);
                        goto restart;
                }
        }
+#endif
        if (!error) {
                error = nfs_open_file_set_busy(nofp, vfs_context_thread(ctx));
        }
@@ -886,9 +970,11 @@ restart:
                nofp->nof_flags &= ~NFS_OPEN_FILE_CREATE;
                nofp->nof_creator = NULL;
        } else {
+#if CONFIG_NFS4
                if (!opened) {
                        error = nfs4_open(np, nofp, accessMode, denyMode, ctx);
                }
+#endif
                if ((error == EACCES) && (nofp->nof_flags & NFS_OPEN_FILE_CREATE) &&
                    (nofp->nof_creator == current_thread())) {
                        /*
@@ -1069,7 +1155,7 @@ nfs_vnop_close(
        }
        error1 = error;
 
-       /* fflag should contain some combination of: FREAD, FWRITE, FHASLOCK */
+       /* fflag should contain some combination of: FREAD, FWRITE */
        accessMode = 0;
        if (fflag & FREAD) {
                accessMode |= NFS_OPEN_SHARE_ACCESS_READ;
@@ -1084,24 +1170,8 @@ nfs_vnop_close(
 //             denyMode = NFS_OPEN_SHARE_DENY_WRITE;
 //     else
 //             denyMode = NFS_OPEN_SHARE_DENY_NONE;
-#if 0  // Not yet
-       if (fflag & FHASLOCK) {
-               /* XXX assume FHASLOCK is for the deny mode and not flock */
-               /* FHASLOCK flock will be unlocked in the close path, but the flag is not cleared. */
-               if (nofp->nof_deny & NFS_OPEN_SHARE_DENY_READ) {
-                       denyMode = NFS_OPEN_SHARE_DENY_BOTH;
-               } else if (nofp->nof_deny & NFS_OPEN_SHARE_DENY_WRITE) {
-                       denyMode = NFS_OPEN_SHARE_DENY_WRITE;
-               } else {
-                       denyMode = NFS_OPEN_SHARE_DENY_NONE;
-               }
-       } else {
-               denyMode = NFS_OPEN_SHARE_DENY_NONE;
-       }
-#else
        // XXX don't do deny modes just yet (and never do it for !v4)
        denyMode = NFS_OPEN_SHARE_DENY_NONE;
-#endif
 
        if (!accessMode) {
                /*
@@ -1154,14 +1224,16 @@ restart:
        }
 
        error = nfs_open_file_find(np, noop, &nofp, 0, 0, 0);
+#if CONFIG_NFS4
        if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
-               nfs_mount_state_in_use_end(nmp, 0);
                error = nfs4_reopen(nofp, NULL);
                nofp = NULL;
                if (!error) {
+                       nfs_mount_state_in_use_end(nmp, 0);
                        goto restart;
                }
        }
+#endif
        if (error) {
                NP(np, "nfs_vnop_close: no open file for owner, error %d, %d", error, kauth_cred_getuid(noop->noo_cred));
                error = EBADF;
@@ -1210,11 +1282,13 @@ nfs_close(
        struct nfs_open_file *nofp,
        uint32_t accessMode,
        uint32_t denyMode,
-       vfs_context_t ctx)
+       __unused vfs_context_t ctx)
 {
+#if CONFIG_NFS4
        struct nfs_lock_owner *nlop;
+#endif
        int error = 0, changed = 0, delegated = 0, closed = 0, downgrade = 0;
-       uint32_t newAccessMode, newDenyMode;
+       uint8_t newAccessMode, newDenyMode;
 
        /* warn if modes don't match current state */
        if (((accessMode & nofp->nof_access) != accessMode) || ((denyMode & nofp->nof_deny) != denyMode)) {
@@ -1254,10 +1328,11 @@ nfs_close(
                changed = 0;
        }
 
-       if (NFSTONMP(np)->nm_vers < NFS_VER4) { /* NFS v2/v3 closes simply need to remove the open. */
+       if (NFSTONMP(np)->nm_vers < NFS_VER4) {
+               /* NFS v2/v3 closes simply need to remove the open. */
                goto v3close;
        }
-
+#if CONFIG_NFS4
        if ((newAccessMode == 0) || (nofp->nof_opencnt == 1)) {
                /*
                 * No more access after this close, so clean up and close it.
@@ -1305,13 +1380,13 @@ nfs_close(
                        }
                }
        }
-
+#endif
+v3close:
        if (error) {
                NP(np, "nfs_close: error %d, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
                return error;
        }
 
-v3close:
        if (!downgrade) {
                nfs_open_file_remove_open(nofp, accessMode, denyMode);
        }
@@ -1369,7 +1444,7 @@ nfs3_getattr_rpc(
        u_int64_t *xidp)
 {
        struct nfsmount *nmp = mp ? VFSTONFS(mp) : NFSTONMP(np);
-       int error = 0, status, nfsvers, rpcflags = 0;
+       int error = 0, status = 0, nfsvers, rpcflags = 0;
        struct nfsm_chain nmreq, nmrep;
 
        if (nfs_mount_gone(nmp)) {
@@ -1402,7 +1477,7 @@ nfs3_getattr_rpc(
                error = status;
        }
        nfsmout_if(error);
-       error = nfs_parsefattr(&nmrep, nfsvers, nvap);
+       error = nfs_parsefattr(nmp, &nmrep, nfsvers, nvap);
 nfsmout:
        nfsm_chain_cleanup(&nmreq);
        nfsm_chain_cleanup(&nmrep);
@@ -1423,10 +1498,11 @@ nfs_refresh_fh(nfsnode_t np, vfs_context_t ctx)
        nfsnode_t dnp;
        const char *v_name = vnode_getname(vp);
        char *name;
-       int namelen, fhsize, refreshed;
+       int namelen, refreshed;
+       uint32_t fhsize;
        int error, wanted = 0;
        uint8_t *fhp;
-       struct timespec ts = {2, 0};
+       struct timespec ts = {.tv_sec = 2, .tv_nsec = 0};
 
        NFS_VNOP_DBG("vnode is %d\n", vnode_vtype(vp));
 
@@ -1440,7 +1516,7 @@ nfs_refresh_fh(nfsnode_t np, vfs_context_t ctx)
        }
        dnp = VTONFS(dvp);
 
-       namelen = strlen(v_name);
+       namelen = NFS_STRLEN_INT(v_name);
        MALLOC(name, char *, namelen + 1, M_TEMP, M_WAITOK);
        if (name == NULL) {
                vnode_putname(v_name);
@@ -1451,7 +1527,7 @@ nfs_refresh_fh(nfsnode_t np, vfs_context_t ctx)
        vnode_putname(v_name);
 
        /* Allocate the maximum size file handle */
-       MALLOC(fhp, uint8_t *, NFS4_FHSIZE, M_TEMP, M_WAITOK);
+       MALLOC(fhp, uint8_t *, NFS4_FHSIZE, M_FHANDLE, M_WAITOK);
        if (fhp == NULL) {
                FREE(name, M_TEMP);
                return ESTALE;
@@ -1459,7 +1535,7 @@ nfs_refresh_fh(nfsnode_t np, vfs_context_t ctx)
 
        if ((error = nfs_node_lock(np))) {
                FREE(name, M_TEMP);
-               FREE(fhp, M_TEMP);
+               FREE(fhp, M_FHANDLE);
                return ESTALE;
        }
 
@@ -1547,7 +1623,7 @@ nfsmout:
        }
 
        FREE(name, M_TEMP);
-       FREE(fhp, M_TEMP);
+       FREE(fhp, M_FHANDLE);
 
        return error ? ESTALE : 0;
 }
@@ -1572,10 +1648,10 @@ int
 nfs_getattr_internal(nfsnode_t np, struct nfs_vattr *nvap, vfs_context_t ctx, int flags)
 {
        struct nfsmount *nmp;
-       int error = 0, nfsvers, inprogset = 0, wanted = 0, avoidfloods;
-       struct nfs_vattr nvattr;
-       struct timespec ts = { 2, 0 };
-       u_int64_t xid;
+       int error = 0, nfsvers, inprogset = 0, wanted = 0, avoidfloods = 0;
+       struct nfs_vattr *nvattr = NULL;
+       struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
+       u_int64_t xid = 0;
 
        FSDBG_TOP(513, np->n_size, np, np->n_vattr.nva_size, np->n_flag);
 
@@ -1587,7 +1663,8 @@ nfs_getattr_internal(nfsnode_t np, struct nfs_vattr *nvap, vfs_context_t ctx, in
        nfsvers = nmp->nm_vers;
 
        if (!nvap) {
-               nvap = &nvattr;
+               MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+               nvap = nvattr;
        }
        NVATTR_INIT(nvap);
 
@@ -1782,8 +1859,9 @@ nfsmout:
                }
        }
 
-       if (nvap == &nvattr) {
+       if (nvattr != NULL) {
                NVATTR_CLEANUP(nvap);
+               FREE(nvattr, M_TEMP);
        } else if (!(flags & NGA_ACL)) {
                /* make sure we don't return an ACL if it wasn't asked for */
                NFS_BITMAP_CLR(nvap->nva_bitmap, NFS_FATTR_ACL);
@@ -1796,6 +1874,7 @@ nfsmout:
        return error;
 }
 
+
 /*
  * NFS getattr call from vfs.
  */
@@ -1821,6 +1900,7 @@ nfsmout:
         VNODE_ATTR_va_fileid |         \
         VNODE_ATTR_va_type)
 
+
 int
 nfs3_vnop_getattr(
        struct vnop_getattr_args /* {
@@ -1831,18 +1911,25 @@ nfs3_vnop_getattr(
                                   *  } */*ap)
 {
        int error;
-       struct nfs_vattr nva;
+       nfsnode_t np;
+       uint64_t supported_attrs;
+       struct nfs_vattr *nva;
        struct vnode_attr *vap = ap->a_vap;
        struct nfsmount *nmp;
        dev_t rdev;
 
+       nmp = VTONMP(ap->a_vp);
+
        /*
         * Lets don't go over the wire if we don't support any of the attributes.
         * Just fall through at the VFS layer and let it cons up what it needs.
         */
        /* Return the io size no matter what, since we don't go over the wire for this */
        VATTR_RETURN(vap, va_iosize, nfs_iosize);
-       if ((vap->va_active & NFS3_SUPPORTED_VATTRS) == 0) {
+
+       supported_attrs = NFS3_SUPPORTED_VATTRS;
+
+       if ((vap->va_active & supported_attrs) == 0) {
                return 0;
        }
 
@@ -1851,34 +1938,49 @@ nfs3_vnop_getattr(
                    (uint64_t)VM_KERNEL_ADDRPERM(ap->a_vp),
                    ap->a_vp->v_name ? ap->a_vp->v_name : "empty");
        }
-       error = nfs_getattr(VTONFS(ap->a_vp), &nva, ap->a_context, NGA_CACHED);
+
+       /*
+        * We should not go over the wire if only fileid was requested and has ever been populated.
+        */
+       if ((vap->va_active & supported_attrs) == VNODE_ATTR_va_fileid) {
+               np = VTONFS(ap->a_vp);
+               if (np->n_attrstamp) {
+                       VATTR_RETURN(vap, va_fileid, np->n_vattr.nva_fileid);
+                       return 0;
+               }
+       }
+
+       MALLOC(nva, struct nfs_vattr *, sizeof(*nva), M_TEMP, M_WAITOK);
+       error = nfs_getattr(VTONFS(ap->a_vp), nva, ap->a_context, NGA_CACHED);
        if (error) {
-               return error;
+               goto out;
        }
 
        /* copy nva to *a_vap */
-       nmp = VTONMP(ap->a_vp);
-       VATTR_RETURN(vap, va_type, nva.nva_type);
-       VATTR_RETURN(vap, va_mode, nva.nva_mode);
-       rdev = makedev(nva.nva_rawdev.specdata1, nva.nva_rawdev.specdata2);
+       VATTR_RETURN(vap, va_type, nva->nva_type);
+       VATTR_RETURN(vap, va_mode, nva->nva_mode);
+       rdev = makedev(nva->nva_rawdev.specdata1, nva->nva_rawdev.specdata2);
        VATTR_RETURN(vap, va_rdev, rdev);
-       VATTR_RETURN(vap, va_uid, nva.nva_uid);
-       VATTR_RETURN(vap, va_gid, nva.nva_gid);
-       VATTR_RETURN(vap, va_nlink, nva.nva_nlink);
-       VATTR_RETURN(vap, va_fileid, nva.nva_fileid);
-       VATTR_RETURN(vap, va_data_size, nva.nva_size);
-       VATTR_RETURN(vap, va_data_alloc, nva.nva_bytes);
-       vap->va_access_time.tv_sec = nva.nva_timesec[NFSTIME_ACCESS];
-       vap->va_access_time.tv_nsec = nva.nva_timensec[NFSTIME_ACCESS];
+       VATTR_RETURN(vap, va_uid, nva->nva_uid);
+       VATTR_RETURN(vap, va_gid, nva->nva_gid);
+       VATTR_RETURN(vap, va_nlink, nva->nva_nlink);
+       VATTR_RETURN(vap, va_fileid, nva->nva_fileid);
+       VATTR_RETURN(vap, va_data_size, nva->nva_size);
+       VATTR_RETURN(vap, va_data_alloc, nva->nva_bytes);
+       vap->va_access_time.tv_sec = nva->nva_timesec[NFSTIME_ACCESS];
+       vap->va_access_time.tv_nsec = nva->nva_timensec[NFSTIME_ACCESS];
        VATTR_SET_SUPPORTED(vap, va_access_time);
-       vap->va_modify_time.tv_sec = nva.nva_timesec[NFSTIME_MODIFY];
-       vap->va_modify_time.tv_nsec = nva.nva_timensec[NFSTIME_MODIFY];
+       vap->va_modify_time.tv_sec = nva->nva_timesec[NFSTIME_MODIFY];
+       vap->va_modify_time.tv_nsec = nva->nva_timensec[NFSTIME_MODIFY];
        VATTR_SET_SUPPORTED(vap, va_modify_time);
-       vap->va_change_time.tv_sec = nva.nva_timesec[NFSTIME_CHANGE];
-       vap->va_change_time.tv_nsec = nva.nva_timensec[NFSTIME_CHANGE];
+       vap->va_change_time.tv_sec = nva->nva_timesec[NFSTIME_CHANGE];
+       vap->va_change_time.tv_nsec = nva->nva_timensec[NFSTIME_CHANGE];
        VATTR_SET_SUPPORTED(vap, va_change_time);
 
+
        // VATTR_RETURN(vap, va_encoding, 0xffff /* kTextEncodingUnknown */);
+out:
+       FREE(nva, M_TEMP);
        return error;
 }
 
@@ -1902,14 +2004,15 @@ nfs_vnop_setattr(
        int error = 0;
        int biosize, nfsvers, namedattrs;
        u_quad_t origsize, vapsize;
-       struct nfs_dulookup dul;
+       struct nfs_dulookup *dul;
        nfsnode_t dnp = NULL;
        int dul_in_progress = 0;
        vnode_t dvp = NULL;
        const char *vname = NULL;
+#if CONFIG_NFS4
        struct nfs_open_owner *noop = NULL;
        struct nfs_open_file *nofp = NULL;
-
+#endif
        nmp = VTONMP(vp);
        if (nfs_mount_gone(nmp)) {
                return ENXIO;
@@ -1966,6 +2069,7 @@ nfs_vnop_setattr(
                                FSDBG_BOT(512, np->n_size, vap->va_data_size, np->n_vattr.nva_size, -1);
                                return error;
                        }
+#if CONFIG_NFS4
                        if (nfsvers >= NFS_VER4) {
                                /* setting file size requires having the file open for write access */
                                if (np->n_flag & NREVOKE) {
@@ -1989,10 +2093,10 @@ restart:
                                        error = EIO;
                                }
                                if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
-                                       nfs_mount_state_in_use_end(nmp, 0);
                                        error = nfs4_reopen(nofp, vfs_context_thread(ctx));
                                        nofp = NULL;
                                        if (!error) {
+                                               nfs_mount_state_in_use_end(nmp, 0);
                                                goto restart;
                                        }
                                }
@@ -2000,6 +2104,7 @@ restart:
                                        error = nfs_open_file_set_busy(nofp, vfs_context_thread(ctx));
                                }
                                if (error) {
+                                       nfs_mount_state_in_use_end(nmp, 0);
                                        nfs_open_owner_rele(noop);
                                        return error;
                                }
@@ -2012,17 +2117,19 @@ restart:
                                        if (nfs_mount_state_error_should_restart(error)) {
                                                nfs_open_file_clear_busy(nofp);
                                                nofp = NULL;
-                                               if (nfs_mount_state_in_use_end(nmp, error)) {
-                                                       goto restart;
-                                               }
+                                               nfs_mount_state_in_use_end(nmp, error);
+                                               goto restart;
                                        }
                                }
                        }
+#endif
                        nfs_data_lock(np, NFS_DATA_LOCK_EXCLUSIVE);
                        if (np->n_size > vap->va_data_size) { /* shrinking? */
                                daddr64_t obn, bn;
-                               int neweofoff, mustwrite;
+                               int mustwrite;
+                               off_t neweofoff;
                                struct nfsbuf *bp;
+                               nfsbufpgs pagemask;
 
                                obn = (np->n_size - 1) / biosize;
                                bn = vap->va_data_size / biosize;
@@ -2055,8 +2162,9 @@ restart:
                                                        mustwrite++;
                                                }
                                        }
-                                       bp->nb_dirty &= (1 << round_page_32(neweofoff) / PAGE_SIZE) - 1;
-                                       if (bp->nb_dirty) {
+                                       nfs_buf_pgs_get_page_mask(&pagemask, round_page_64(neweofoff) / PAGE_SIZE);
+                                       nfs_buf_pgs_bit_and(&bp->nb_dirty, &pagemask, &bp->nb_dirty);
+                                       if (nfs_buf_pgs_is_set(&bp->nb_dirty)) {
                                                mustwrite++;
                                        }
                                        if (!mustwrite) {
@@ -2112,18 +2220,31 @@ restart:
            VATTR_IS_ACTIVE(vap, va_access_time) ||
            (vap->va_vaflags & VA_UTIMES_NULL)) {
                if ((error = nfs_node_lock(np))) {
+#if CONFIG_NFS4
+                       if (nfsvers >= NFS_VER4) {
+                               nfs_mount_state_in_use_end(nmp, 0);
+                       }
+#endif
                        return error;
                }
                if ((np->n_flag & NMODIFIED) && (vnode_vtype(vp) == VREG)) {
                        nfs_node_unlock(np);
                        error = nfs_vinvalbuf(vp, V_SAVE, ctx, 1);
                        if (error == EINTR) {
+#if CONFIG_NFS4
+                               if (nfsvers >= NFS_VER4) {
+                                       nfs_mount_state_in_use_end(nmp, 0);
+                               }
+#endif
                                return error;
                        }
                } else {
                        nfs_node_unlock(np);
                }
        }
+
+       MALLOC(dul, struct nfs_dulookup *, sizeof(*dul), M_TEMP, M_WAITOK);
+
        if ((VATTR_IS_ACTIVE(vap, va_mode) || VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid) ||
            VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid)) &&
            !(error = nfs_node_lock(np))) {
@@ -2138,8 +2259,8 @@ restart:
                                        vnode_put(dvp);
                                        vnode_putname(vname);
                                } else {
-                                       nfs_dulookup_init(&dul, dnp, vname, strlen(vname), ctx);
-                                       nfs_dulookup_start(&dul, dnp, ctx);
+                                       nfs_dulookup_init(dul, dnp, vname, NFS_STRLEN_INT(vname), ctx);
+                                       nfs_dulookup_start(dul, dnp, ctx);
                                        dul_in_progress = 1;
                                }
                        } else {
@@ -2158,12 +2279,13 @@ restart:
        }
 
        if (dul_in_progress) {
-               nfs_dulookup_finish(&dul, dnp, ctx);
+               nfs_dulookup_finish(dul, dnp, ctx);
                nfs_node_clear_busy(dnp);
                vnode_put(dvp);
                vnode_putname(vname);
        }
 
+       FREE(dul, M_TEMP);
        FSDBG_BOT(512, np->n_size, vap->va_data_size, np->n_vattr.nva_size, error);
        if (VATTR_IS_ACTIVE(vap, va_data_size)) {
                if (error && (origsize != np->n_size) &&
@@ -2201,6 +2323,7 @@ restart:
                        nfs_node_unlock(np);
                }
                nfs_data_unlock(np);
+#if CONFIG_NFS4
                if (nfsvers >= NFS_VER4) {
                        if (nofp) {
                                /* don't close our setattr open if we'll be restarting... */
@@ -2220,6 +2343,7 @@ restart:
                        }
                        nfs_open_owner_rele(noop);
                }
+#endif
        }
        return error;
 }
@@ -2234,7 +2358,7 @@ nfs3_setattr_rpc(
        vfs_context_t ctx)
 {
        struct nfsmount *nmp = NFSTONMP(np);
-       int error = 0, lockerror = ENOENT, status, wccpostattr = 0, nfsvers;
+       int error = 0, lockerror = ENOENT, status = 0, wccpostattr = 0, nfsvers;
        u_int64_t xid, nextxid;
        struct nfsm_chain nmreq, nmrep;
 
@@ -2250,7 +2374,9 @@ nfs3_setattr_rpc(
        VATTR_SET_SUPPORTED(vap, va_access_time);
        VATTR_SET_SUPPORTED(vap, va_modify_time);
 
-       if (VATTR_IS_ACTIVE(vap, va_flags)) {
+
+       if (VATTR_IS_ACTIVE(vap, va_flags)
+           ) {
                if (vap->va_flags) {    /* we don't support setting flags */
                        if (vap->va_active & ~VNODE_ATTR_va_flags) {
                                return EINVAL;        /* return EINVAL if other attributes also set */
@@ -2348,7 +2474,7 @@ nfs3_setattr_rpc(
                error = lockerror;
        }
        if (nfsvers == NFS_VER3) {
-               struct timespec premtime = { 0, 0 };
+               struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
                nfsm_chain_get_wcc_data(error, &nmrep, np, &premtime, &wccpostattr, &xid);
                nfsmout_if(error);
                /* if file hadn't changed, update cached mtime */
@@ -2419,17 +2545,21 @@ nfs_vnop_lookup(
        struct nfsmount *nmp;
        mount_t mp;
        int nfsvers, error, busyerror = ENOENT, isdot, isdotdot, negnamecache;
-       u_int64_t xid;
-       struct nfs_vattr nvattr;
-       int ngflags;
+       u_int64_t xid = 0;
+       struct nfs_vattr *nvattr;
+       int ngflags, skipdu = 0;
        struct vnop_access_args naa;
-       fhandle_t fh;
-       struct nfsreq rq, *req = &rq;
+       fhandle_t *fh;
+       struct nfsreq *req;
 
        *vpp = NULLVP;
 
        dnp = VTONFS(dvp);
-       NVATTR_INIT(&nvattr);
+
+       fh = zalloc(nfs_fhandle_zone);
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+       NVATTR_INIT(nvattr);
 
        mp = vnode_mount(dvp);
        nmp = VFSTONFS(mp);
@@ -2457,17 +2587,21 @@ nfs_vnop_lookup(
                /* cache miss */
                if ((nfsvers > NFS_VER2) && NMFLAG(nmp, RDIRPLUS)) {
                        /* if rdirplus, try dir buf cache lookup */
-                       error = nfs_dir_buf_cache_lookup(dnp, &np, cnp, ctx, 0);
+                       error = nfs_dir_buf_cache_lookup(dnp, &np, cnp, ctx, 0, &skipdu);
                        if (!error && np) {
                                /* dir buf cache hit */
                                *vpp = NFSTOV(np);
                                error = -1;
+                       } else if (skipdu) {
+                               /* Skip lookup for du files */
+                               error = ENOENT;
+                               goto error_return;
                        }
                }
                if (error != -1) { /* cache miss */
                        break;
                }
-       /* FALLTHROUGH */
+               OS_FALLTHROUGH;
        case -1:
                /* cache hit, not really an error */
                OSAddAtomic64(1, &nfsstats.lookupcache_hits);
@@ -2483,7 +2617,7 @@ nfs_vnop_lookup(
 
                /* compute actual success/failure based on accessibility */
                error = nfs_vnop_access(&naa);
-       /* FALLTHROUGH */
+               OS_FALLTHROUGH;
        default:
                /* unexpected error from cache_lookup */
                goto error_return;
@@ -2500,14 +2634,16 @@ nfs_vnop_lookup(
                }
        }
        if (isdotdot || isdot) {
-               fh.fh_len = 0;
+               fh->fh_len = 0;
                goto found;
        }
+#if CONFIG_NFS4
        if ((nfsvers >= NFS_VER4) && (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER)) {
                /* we should never be looking things up in a trigger directory, return nothing */
                error = ENOENT;
                goto error_return;
        }
+#endif
 
        /* do we know this name is too long? */
        nmp = VTONMP(dvp);
@@ -2516,7 +2652,7 @@ nfs_vnop_lookup(
                goto error_return;
        }
        if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXNAME) &&
-           (cnp->cn_namelen > (int)nmp->nm_fsattr.nfsa_maxname)) {
+           (cnp->cn_namelen > nmp->nm_fsattr.nfsa_maxname)) {
                error = ENAMETOOLONG;
                goto error_return;
        }
@@ -2528,11 +2664,11 @@ nfs_vnop_lookup(
 
        error = nmp->nm_funcs->nf_lookup_rpc_async(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &req);
        nfsmout_if(error);
-       error = nmp->nm_funcs->nf_lookup_rpc_async_finish(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, req, &xid, &fh, &nvattr);
+       error = nmp->nm_funcs->nf_lookup_rpc_async_finish(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, req, &xid, fh, nvattr);
        nfsmout_if(error);
 
        /* is the file handle the same as this directory's file handle? */
-       isdot = NFS_CMPFH(dnp, fh.fh_data, fh.fh_len);
+       isdot = NFS_CMPFH(dnp, fh->fh_data, fh->fh_len);
 
 found:
        if (flags & ISLASTCN) {
@@ -2563,13 +2699,13 @@ found:
                }
                newvp = dvp;
                nfs_node_lock_force(dnp);
-               if (fh.fh_len && (dnp->n_xid <= xid)) {
-                       nfs_loadattrcache(dnp, &nvattr, &xid, 0);
+               if (fh->fh_len && (dnp->n_xid <= xid)) {
+                       nfs_loadattrcache(dnp, nvattr, &xid, 0);
                }
                nfs_node_unlock(dnp);
        } else {
                ngflags = (cnp->cn_flags & MAKEENTRY) ? NG_MAKEENTRY : 0;
-               error = nfs_nget(mp, dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, ngflags, &np);
+               error = nfs_nget(mp, dnp, cnp, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, ngflags, &np);
                if (error) {
                        goto error_return;
                }
@@ -2598,7 +2734,10 @@ nfsmout:
                nfs_node_unlock(dnp);
        }
 error_return:
-       NVATTR_CLEANUP(&nvattr);
+       NVATTR_CLEANUP(nvattr);
+       NFS_ZFREE(nfs_fhandle_zone, fh);
+       NFS_ZFREE(nfs_req_zone, req);
+       FREE(nvattr, M_TEMP);
        if (!busyerror) {
                nfs_node_clear_busy(dnp);
        }
@@ -2627,11 +2766,11 @@ nfs_vnop_readlink(
        nfsnode_t np = VTONFS(ap->a_vp);
        struct nfsmount *nmp;
        int error = 0, nfsvers;
-       uint32_t buflen;
+       size_t buflen;
        uio_t uio = ap->a_uio;
        struct nfsbuf *bp = NULL;
-       struct timespec ts;
-       int timeo;
+       struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
+       long timeo = 0;
 
        if (vnode_vtype(ap->a_vp) != VLNK) {
                return EPERM;
@@ -2671,7 +2810,7 @@ retry:
        }
 
        if (nfs_readlink_nocache) {
-               NFS_VNOP_DBG("timeo = %d ts.tv_sec = %ld need refresh = %d cached = %d\n", timeo, ts.tv_sec,
+               NFS_VNOP_DBG("timeo = %ld ts.tv_sec = %ld need refresh = %d cached = %d\n", timeo, ts.tv_sec,
                    (np->n_rltim.tv_sec + timeo) < ts.tv_sec || nfs_readlink_nocache > 1,
                    ISSET(bp->nb_flags, NB_CACHE) == NB_CACHE);
                /* n_rltim is synchronized by the associated nfs buf */
@@ -2701,14 +2840,18 @@ readagain:
                        bp->nb_validoff = 0;
                        bp->nb_validend = buflen;
                        np->n_rltim = ts;
-                       NFS_VNOP_DBG("readlink of %.*s\n", bp->nb_validend, (char *)bp->nb_data);
+                       NFS_VNOP_DBG("readlink of %.*s\n", (int32_t)bp->nb_validend, (char *)bp->nb_data);
                }
        } else {
-               NFS_VNOP_DBG("got cached link of %.*s\n", bp->nb_validend, (char *)bp->nb_data);
+               NFS_VNOP_DBG("got cached link of %.*s\n", (int32_t)bp->nb_validend, (char *)bp->nb_data);
        }
 
        if (!error && (bp->nb_validend > 0)) {
-               error = uiomove(bp->nb_data, bp->nb_validend, uio);
+               int validend32 = bp->nb_validend > INT_MAX ? INT_MAX : (int)bp->nb_validend;
+               error = uiomove(bp->nb_data, validend32, uio);
+               if (!error && bp->nb_validend > validend32) {
+                       error = uiomove(bp->nb_data + validend32, (int)(bp->nb_validend - validend32), uio);
+               }
        }
        FSDBG(531, np, bp->nb_validend, 0, error);
        nfs_buf_release(bp, 1);
@@ -2719,11 +2862,11 @@ readagain:
  * Do a readlink RPC.
  */
 int
-nfs3_readlink_rpc(nfsnode_t np, char *buf, uint32_t *buflenp, vfs_context_t ctx)
+nfs3_readlink_rpc(nfsnode_t np, char *buf, size_t *buflenp, vfs_context_t ctx)
 {
        struct nfsmount *nmp;
        int error = 0, lockerror = ENOENT, nfsvers, status;
-       uint32_t len;
+       size_t len;
        u_int64_t xid;
        struct nfsm_chain nmreq, nmrep;
 
@@ -2757,7 +2900,7 @@ nfs3_readlink_rpc(nfsnode_t np, char *buf, uint32_t *buflenp, vfs_context_t ctx)
        }
        if (len >= *buflenp) {
                if (np->n_size && (np->n_size < *buflenp)) {
-                       len = np->n_size;
+                       len = (size_t)np->n_size;
                } else {
                        len = *buflenp - 1;
                }
@@ -2787,9 +2930,10 @@ nfs_read_rpc(nfsnode_t np, uio_t uio, vfs_context_t ctx)
        size_t nmrsize, len, retlen;
        user_ssize_t tsiz;
        off_t txoffset;
-       struct nfsreq rq, *req = &rq;
+       struct nfsreq *req;
+#if CONFIG_NFS4
        uint32_t stategenid = 0, restart = 0;
-
+#endif
        FSDBG_TOP(536, np, uio_offset(uio), uio_resid(uio), 0);
        nmp = NFSTONMP(np);
        if (nfs_mount_gone(nmp)) {
@@ -2805,6 +2949,7 @@ nfs_read_rpc(nfsnode_t np, uio_t uio, vfs_context_t ctx)
                return EFBIG;
        }
 
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
        while (tsiz > 0) {
                len = retlen = (tsiz > (user_ssize_t)nmrsize) ? nmrsize : (size_t)tsiz;
                FSDBG(536, np, txoffset, len, 0);
@@ -2812,14 +2957,17 @@ nfs_read_rpc(nfsnode_t np, uio_t uio, vfs_context_t ctx)
                        error = EIO;
                        break;
                }
+#if CONFIG_NFS4
                if (nmp->nm_vers >= NFS_VER4) {
                        stategenid = nmp->nm_stategenid;
                }
+#endif
                error = nmp->nm_funcs->nf_read_rpc_async(np, txoffset, len,
                    vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, &req);
                if (!error) {
                        error = nmp->nm_funcs->nf_read_rpc_async_finish(np, req, uio, &retlen, &eof);
                }
+#if CONFIG_NFS4
                if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error) &&
                    (++restart <= nfs_mount_state_max_restarts(nmp))) { /* guard against no progress */
                        lck_mtx_lock(&nmp->nm_lock);
@@ -2839,6 +2987,7 @@ nfs_read_rpc(nfsnode_t np, uio_t uio, vfs_context_t ctx)
                                }
                        }
                }
+#endif
                if (error) {
                        break;
                }
@@ -2853,6 +3002,7 @@ nfs_read_rpc(nfsnode_t np, uio_t uio, vfs_context_t ctx)
                }
        }
 
+       NFS_ZFREE(nfs_req_zone, req);
        FSDBG_BOT(536, np, eof, uio_resid(uio), error);
        return error;
 }
@@ -2904,8 +3054,8 @@ nfs3_read_rpc_async_finish(
        size_t *lenp,
        int *eofp)
 {
-       int error = 0, lockerror, nfsvers, status, eof = 0;
-       size_t retlen = 0;
+       int error = 0, lockerror, nfsvers, status = 0, eof = 0;
+       uint32_t retlen = 0;
        uint64_t xid;
        struct nfsmount *nmp;
        struct nfsm_chain nmrep;
@@ -2985,8 +3135,10 @@ nfs_vnop_write(
        struct nfsbuf *bp;
        struct nfsmount *nmp = VTONMP(vp);
        daddr64_t lbn;
-       int biosize;
-       int n, on, error = 0;
+       uint32_t biosize;
+       int error = 0;
+       off_t n, on;
+       int n32;
        off_t boff, start, end;
        uio_t auio;
        char auio_buf[UIO_SIZEOF(1)];
@@ -3081,7 +3233,7 @@ nfs_vnop_write(
                 */
                struct nfsbuf *eofbp = NULL;
                daddr64_t eofbn = np->n_size / biosize;
-               int eofoff = np->n_size % biosize;
+               uint32_t eofoff = np->n_size % biosize;
                lbn = uio_offset(uio) / biosize;
 
                if (eofoff && (eofbn < lbn)) {
@@ -3171,7 +3323,7 @@ again:
                 * that's just masquerading as new written data.)
                 */
                if (bp->nb_dirtyend > 0) {
-                       if (on > bp->nb_dirtyend || (on + n) < bp->nb_dirtyoff || bp->nb_dirty) {
+                       if (on > bp->nb_dirtyend || (on + n) < bp->nb_dirtyoff || nfs_buf_pgs_is_set(&bp->nb_dirty)) {
                                FSDBG(515, np, uio_offset(uio), bp, 0xd15c001);
                                /* write/commit buffer "synchronously" */
                                /* (NB_STABLE indicates that data writes should be FILESYNC) */
@@ -3183,15 +3335,21 @@ again:
                                }
                                goto again;
                        }
-               } else if (bp->nb_dirty) {
-                       int firstpg, lastpg;
-                       u_int32_t pagemask;
+               } else if (nfs_buf_pgs_is_set(&bp->nb_dirty)) {
+                       off_t firstpg = 0, lastpg = 0;
+                       nfsbufpgs pagemask, pagemaskand;
                        /* calculate write range pagemask */
-                       firstpg = on / PAGE_SIZE;
-                       lastpg = (on + n - 1) / PAGE_SIZE;
-                       pagemask = ((1 << (lastpg + 1)) - 1) & ~((1 << firstpg) - 1);
+                       if (n > 0) {
+                               firstpg = on / PAGE_SIZE;
+                               lastpg = (on + n - 1) / PAGE_SIZE;
+                               nfs_buf_pgs_set_pages_between(&pagemask, firstpg, lastpg + 1);
+                       } else {
+                               NBPGS_ERASE(&pagemask);
+                       }
                        /* check if there are dirty pages outside the write range */
-                       if (bp->nb_dirty & ~pagemask) {
+                       nfs_buf_pgs_bit_not(&pagemask);
+                       nfs_buf_pgs_bit_and(&bp->nb_dirty, &pagemask, &pagemaskand);
+                       if (nfs_buf_pgs_is_set(&pagemaskand)) {
                                FSDBG(515, np, uio_offset(uio), bp, 0xd15c002);
                                /* write/commit buffer "synchronously" */
                                /* (NB_STABLE indicates that data writes should be FILESYNC) */
@@ -3207,7 +3365,7 @@ again:
                        /* make sure that the dirty range encompasses those pages */
                        if (NBPGDIRTY(bp, firstpg) || NBPGDIRTY(bp, lastpg)) {
                                FSDBG(515, np, uio_offset(uio), bp, 0xd15c003);
-                               bp->nb_dirtyoff = min(on, firstpg * PAGE_SIZE);
+                               bp->nb_dirtyoff = MIN(on, firstpg * PAGE_SIZE);
                                if (NBPGDIRTY(bp, lastpg)) {
                                        bp->nb_dirtyend = (lastpg + 1) * PAGE_SIZE;
                                        /* clip to EOF */
@@ -3240,21 +3398,20 @@ again:
                        if ((lbn == eofbn) && ISSET(bp->nb_flags, NB_CACHE)) {
                                /* ...check that all pages in buffer are valid */
                                int endpg = ((neweofoff ? neweofoff : biosize) - 1) / PAGE_SIZE;
-                               u_int32_t pagemask;
+                               nfsbufpgs pagemask, pagemaskand;
                                /* pagemask only has to extend to last page being written to */
-                               pagemask = (1 << (endpg + 1)) - 1;
+                               nfs_buf_pgs_get_page_mask(&pagemask, endpg + 1);
                                FSDBG(515, 0xb1ffa001, bp->nb_valid, pagemask, 0);
-                               if ((bp->nb_valid & pagemask) != pagemask) {
+                               nfs_buf_pgs_bit_and(&bp->nb_valid, &pagemask, &pagemaskand);
+                               if (!NBPGS_IS_EQUAL(&pagemaskand, &pagemask)) {
                                        /* zerofill any hole */
                                        if (on > bp->nb_validend) {
-                                               int i;
-                                               for (i = bp->nb_validend / PAGE_SIZE; i <= (on - 1) / PAGE_SIZE; i++) {
+                                               for (off_t i = bp->nb_validend / PAGE_SIZE; i <= (on - 1) / PAGE_SIZE; i++) {
                                                        NBPGVALID_SET(bp, i);
                                                }
                                                NFS_BUF_MAP(bp);
                                                FSDBG(516, bp, bp->nb_validend, on - bp->nb_validend, 0xf01e);
-                                               bzero((char *)bp->nb_data + bp->nb_validend,
-                                                   on - bp->nb_validend);
+                                               NFS_BZERO((char *)bp->nb_data + bp->nb_validend, on - bp->nb_validend);
                                        }
                                        /* zerofill any trailing data in the last page */
                                        if (neweofoff) {
@@ -3307,8 +3464,7 @@ again:
                 *   page cache.
                 */
                if (!ISSET(bp->nb_flags, NB_CACHE) && (n < biosize)) {
-                       int firstpg, lastpg, dirtypg;
-                       int firstpgoff, lastpgoff;
+                       off_t firstpgoff, lastpgoff, firstpg, lastpg, dirtypg;
                        start = end = -1;
                        firstpg = on / PAGE_SIZE;
                        firstpgoff = on & PAGE_MASK;
@@ -3376,7 +3532,7 @@ again:
                                        /* there's a dirty page in the way, so just do two reads */
                                        /* we'll read the preceding data here */
                                        uio_reset(auio, boff + start, UIO_SYSSPACE, UIO_READ);
-                                       uio_addiov(auio, CAST_USER_ADDR_T(bp->nb_data + start), on - start);
+                                       NFS_UIO_ADDIOV(auio, CAST_USER_ADDR_T(bp->nb_data + start), on - start);
                                        error = nfs_read_rpc(np, auio, ctx);
                                        if (error) {
                                                /* couldn't read the data, so treat buffer as synchronous NOCACHE */
@@ -3396,7 +3552,7 @@ again:
                                                        bp->nb_validend = on;
                                                }
                                                if ((off_t)np->n_size > boff + bp->nb_validend) {
-                                                       bp->nb_validend = min(np->n_size - (boff + start), biosize);
+                                                       bp->nb_validend = MIN(np->n_size - (boff + start), biosize);
                                                }
                                                /* validate any pages before the write offset */
                                                for (; start < on / PAGE_SIZE; start += PAGE_SIZE) {
@@ -3428,12 +3584,12 @@ again:
                                         * read nothing.  So, just zero the buffer instead.
                                         */
                                        FSDBG(516, bp, start, end - start, 0xd00dee00);
-                                       bzero(bp->nb_data + start, end - start);
+                                       NFS_BZERO(bp->nb_data + start, end - start);
                                        error = 0;
                                } else {
                                        /* now we'll read the (rest of the) data */
                                        uio_reset(auio, boff + start, UIO_SYSSPACE, UIO_READ);
-                                       uio_addiov(auio, CAST_USER_ADDR_T(bp->nb_data + start), end - start);
+                                       NFS_UIO_ADDIOV(auio, CAST_USER_ADDR_T(bp->nb_data + start), end - start);
                                        error = nfs_read_rpc(np, auio, ctx);
                                        if (error) {
                                                /* couldn't read the data, so treat buffer as synchronous NOCACHE */
@@ -3454,14 +3610,14 @@ again:
                                                bp->nb_validend = end;
                                        }
                                        if ((off_t)np->n_size > boff + bp->nb_validend) {
-                                               bp->nb_validend = min(np->n_size - (boff + start), biosize);
+                                               bp->nb_validend = MIN(np->n_size - (boff + start), biosize);
                                        }
                                        /* validate any pages before the write offset's page */
-                                       for (; start < (off_t)trunc_page_32(on); start += PAGE_SIZE) {
+                                       for (; start < (off_t)trunc_page_64(on); start += PAGE_SIZE) {
                                                NBPGVALID_SET(bp, start / PAGE_SIZE);
                                        }
                                        /* validate any pages after the range of pages being written to */
-                                       for (; (end - 1) > (off_t)round_page_32(on + n - 1); end -= PAGE_SIZE) {
+                                       for (; (end - 1) > (off_t)round_page_64(on + n - 1); end -= PAGE_SIZE) {
                                                NBPGVALID_SET(bp, (end - 1) / PAGE_SIZE);
                                        }
                                }
@@ -3481,7 +3637,15 @@ skipread:
                nfs_node_unlock(np);
 
                NFS_BUF_MAP(bp);
-               error = uiomove((char *)bp->nb_data + on, n, uio);
+               if (n < 0) {
+                       error = EINVAL;
+               } else {
+                       n32 = n > INT_MAX ? INT_MAX : (int)n;
+                       error = uiomove(bp->nb_data + on, n32, uio);
+                       if (!error && n > n32) {
+                               error = uiomove(bp->nb_data + on + n32, (int)(n - n32), uio);
+                       }
+               }
                if (error) {
                        SET(bp->nb_flags, NB_ERROR);
                        nfs_buf_release(bp, 1);
@@ -3503,8 +3667,8 @@ skipread:
                         */
                }
                if (bp->nb_dirtyend > 0) {
-                       bp->nb_dirtyoff = min(on, bp->nb_dirtyoff);
-                       bp->nb_dirtyend = max((on + n), bp->nb_dirtyend);
+                       bp->nb_dirtyoff = MIN(on, bp->nb_dirtyoff);
+                       bp->nb_dirtyend = MAX((on + n), bp->nb_dirtyend);
                } else {
                        bp->nb_dirtyoff = on;
                        bp->nb_dirtyend = on + n;
@@ -3514,8 +3678,8 @@ skipread:
                        bp->nb_validoff = bp->nb_dirtyoff;
                        bp->nb_validend = bp->nb_dirtyend;
                } else {
-                       bp->nb_validoff = min(bp->nb_validoff, bp->nb_dirtyoff);
-                       bp->nb_validend = max(bp->nb_validend, bp->nb_dirtyend);
+                       bp->nb_validoff = MIN(bp->nb_validoff, bp->nb_dirtyoff);
+                       bp->nb_validend = MAX(bp->nb_validend, bp->nb_dirtyend);
                }
                if (!ISSET(bp->nb_flags, NB_CACHE)) {
                        nfs_buf_normalize_valid_range(np, bp);
@@ -3540,6 +3704,9 @@ skipread:
                        if (error) {
                                goto out;
                        }
+                       if (np->n_needcommitcnt >= NFS_A_LOT_OF_NEEDCOMMITS) {
+                               nfs_flushcommits(np, 1);
+                       }
                } else if (((n + on) == biosize) || (ioflag & IO_APPEND) ||
                    (ioflag & IO_NOCACHE) || ISSET(bp->nb_flags, NB_NOCACHE)) {
                        SET(bp->nb_flags, NB_ASYNC);
@@ -3557,14 +3724,15 @@ skipread:
                        }
                        nfs_buf_write_delayed(bp);
                }
-               if (np->n_needcommitcnt >= NFS_A_LOT_OF_NEEDCOMMITS) {
-                       nfs_flushcommits(np, 1);
-               }
+
        } while (uio_resid(uio) > 0 && n > 0);
 
 out:
        nfs_node_lock_force(np);
        np->n_wrbusy--;
+       if ((ioflag & IO_SYNC) && !np->n_wrbusy && !np->n_numoutput) {
+               np->n_flag &= ~NMODIFIED;
+       }
        nfs_node_unlock(np);
        nfs_data_unlock(np);
        FSDBG_BOT(515, np, uio_offset(uio), uio_resid(uio), error);
@@ -3597,11 +3765,14 @@ nfs_write_rpc2(
 {
        struct nfsmount *nmp;
        int error = 0, nfsvers;
-       int wverfset, commit, committed;
-       uint64_t wverf = 0, wverf2;
-       size_t nmwsize, totalsize, tsiz, len, rlen;
-       struct nfsreq rq, *req = &rq;
-       uint32_t stategenid = 0, vrestart = 0, restart = 0;
+       int wverfset, commit = 0, committed;
+       uint64_t wverf = 0, wverf2 = 0;
+       size_t nmwsize, totalsize, tsiz, len, rlen = 0;
+       struct nfsreq *req;
+#if CONFIG_NFS4
+       uint32_t stategenid = 0, restart = 0;
+#endif
+       uint32_t vrestart = 0;
        uio_t uio_save = NULL;
 
 #if DIAGNOSTIC
@@ -3632,6 +3803,7 @@ nfs_write_rpc2(
                return EIO;
        }
 
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
        while (tsiz > 0) {
                len = (tsiz > nmwsize) ? nmwsize : tsiz;
                FSDBG(537, np, uio_offset(uio), len, 0);
@@ -3639,9 +3811,11 @@ nfs_write_rpc2(
                        error = EIO;
                        break;
                }
+#if CONFIG_NFS4
                if (nmp->nm_vers >= NFS_VER4) {
                        stategenid = nmp->nm_stategenid;
                }
+#endif
                error = nmp->nm_funcs->nf_write_rpc_async(np, uio, len, thd, cred, *iomodep, NULL, &req);
                if (!error) {
                        error = nmp->nm_funcs->nf_write_rpc_async_finish(np, req, &commit, &rlen, &wverf2);
@@ -3650,6 +3824,7 @@ nfs_write_rpc2(
                if (nfs_mount_gone(nmp)) {
                        error = ENXIO;
                }
+#if CONFIG_NFS4
                if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error) &&
                    (++restart <= nfs_mount_state_max_restarts(nmp))) { /* guard against no progress */
                        lck_mtx_lock(&nmp->nm_lock);
@@ -3669,6 +3844,7 @@ nfs_write_rpc2(
                                }
                        }
                }
+#endif
                if (error) {
                        break;
                }
@@ -3719,6 +3895,7 @@ nfs_write_rpc2(
        if (error) {
                uio_setresid(uio, tsiz);
        }
+       NFS_ZFREE(nfs_req_zone, req);
        FSDBG_BOT(537, np, committed, uio_resid(uio), error);
        return error;
 }
@@ -3811,7 +3988,7 @@ nfs3_write_rpc_async_finish(
                error = lockerror;
        }
        if (nfsvers == NFS_VER3) {
-               struct timespec premtime = { 0, 0 };
+               struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
                nfsm_chain_get_wcc_data(error, &nmrep, np, &premtime, &wccpostattr, &xid);
                if (nfstimespeccmp(&np->n_mtime, &premtime, ==)) {
                        updatemtime = 1;
@@ -3888,15 +4065,15 @@ nfs3_vnop_mknod(
        nfsnode_t np = NULL;
        struct nfsmount *nmp;
        nfsnode_t dnp = VTONFS(dvp);
-       struct nfs_vattr nvattr;
-       fhandle_t fh;
-       int error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0;
-       struct timespec premtime = { 0, 0 };
+       struct nfs_vattr *nvattr;
+       fhandle_t *fh;
+       int error = 0, lockerror = ENOENT, busyerror = ENOENT, status = 0, wccpostattr = 0;
+       struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
        u_int32_t rdev;
        u_int64_t xid = 0, dxid;
        int nfsvers, gotuid, gotgid;
        struct nfsm_chain nmreq, nmrep;
-       struct nfsreq rq, *req = &rq;
+       struct nfsreq *req;
 
        nmp = VTONMP(dvp);
        if (nfs_mount_gone(nmp)) {
@@ -3935,6 +4112,10 @@ nfs3_vnop_mknod(
        nfsm_chain_null(&nmreq);
        nfsm_chain_null(&nmrep);
 
+       fh = zalloc(nfs_fhandle_zone);
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+
        nfsm_chain_build_alloc_init(error, &nmreq,
            NFSX_FH(nfsvers) + 4 * NFSX_UNSIGNED +
            nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(nfsvers));
@@ -3942,7 +4123,7 @@ nfs3_vnop_mknod(
        nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
        if (nfsvers == NFS_VER3) {
                nfsm_chain_add_32(error, &nmreq, vtonfs_type(vap->va_type, nfsvers));
-               nfsm_chain_add_v3sattr(error, &nmreq, vap);
+               nfsm_chain_add_v3sattr(nmp, error, &nmreq, vap);
                if (vap->va_type == VCHR || vap->va_type == VBLK) {
                        nfsm_chain_add_32(error, &nmreq, major(vap->va_rdev));
                        nfsm_chain_add_32(error, &nmreq, minor(vap->va_rdev));
@@ -3972,7 +4153,7 @@ nfs3_vnop_mknod(
                        dnp->n_flag &= ~NNEGNCENTRIES;
                        cache_purge_negatives(dvp);
                }
-               error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr);
+               error = nfsm_chain_get_fh_attr(nmp, &nmrep, dnp, ctx, nfsvers, &xid, fh, nvattr);
        }
        if (nfsvers == NFS_VER3) {
                nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid);
@@ -3995,8 +4176,8 @@ nfsmout:
                nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
        }
 
-       if (!error && fh.fh_len) {
-               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
+       if (!error && fh->fh_len) {
+               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, NG_MAKEENTRY, &np);
        }
        if (!error && !np) {
                error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
@@ -4009,9 +4190,9 @@ nfsmout:
        }
 
        if (!error && (gotuid || gotgid) &&
-           (!newvp || nfs_getattrcache(np, &nvattr, 0) ||
-           (gotuid && (nvattr.nva_uid != vap->va_uid)) ||
-           (gotgid && (nvattr.nva_gid != vap->va_gid)))) {
+           (!newvp || nfs_getattrcache(np, nvattr, 0) ||
+           (gotuid && (nvattr->nva_uid != vap->va_uid)) ||
+           (gotgid && (nvattr->nva_gid != vap->va_gid)))) {
                /* clear ID bits if server didn't use them (or we can't tell) */
                VATTR_CLEAR_SUPPORTED(vap, va_uid);
                VATTR_CLEAR_SUPPORTED(vap, va_gid);
@@ -4025,6 +4206,9 @@ nfsmout:
                *vpp = newvp;
                nfs_node_unlock(np);
        }
+       NFS_ZFREE(nfs_fhandle_zone, fh);
+       NFS_ZFREE(nfs_req_zone, req);
+       FREE(nvattr, M_TEMP);
        return error;
 }
 
@@ -4047,26 +4231,29 @@ nfs3_vnop_create(
        vnode_t dvp = ap->a_dvp;
        struct vnode_attr *vap = ap->a_vap;
        struct componentname *cnp = ap->a_cnp;
-       struct nfs_vattr nvattr;
-       fhandle_t fh;
+       struct nfs_vattr *nvattr;
+       fhandle_t *fh;
        nfsnode_t np = NULL;
        struct nfsmount *nmp;
        nfsnode_t dnp = VTONFS(dvp);
        vnode_t newvp = NULL;
-       int error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0, fmode = 0;
-       struct timespec premtime = { 0, 0 };
+       int error = 0, lockerror = ENOENT, busyerror = ENOENT, status = 0, wccpostattr = 0, fmode = 0;
+       struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
        int nfsvers, gotuid, gotgid;
-       u_int64_t xid, dxid;
+       u_int64_t xid = 0, dxid;
        uint32_t val;
        struct nfsm_chain nmreq, nmrep;
-       struct nfsreq rq, *req = &rq;
-       struct nfs_dulookup dul;
+       struct nfsreq *req;
+       struct nfs_dulookup *dul;
+       int dul_in_progress = 0;
+       int namedattrs;
 
        nmp = VTONMP(dvp);
        if (nfs_mount_gone(nmp)) {
                return ENXIO;
        }
        nfsvers = nmp->nm_vers;
+       namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
 
        if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN)) {
                return ENAMETOOLONG;
@@ -4083,16 +4270,24 @@ nfs3_vnop_create(
        gotuid = VATTR_IS_ACTIVE(vap, va_uid);
        gotgid = VATTR_IS_ACTIVE(vap, va_gid);
 
-       if (vap->va_vaflags & VA_EXCLUSIVE) {
+       if ((vap->va_vaflags & VA_EXCLUSIVE)
+           ) {
                fmode |= O_EXCL;
                if (!VATTR_IS_ACTIVE(vap, va_access_time) || !VATTR_IS_ACTIVE(vap, va_modify_time)) {
                        vap->va_vaflags |= VA_UTIMES_NULL;
                }
        }
 
+       fh = zalloc(nfs_fhandle_zone);
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
+       MALLOC(dul, struct nfs_dulookup *, sizeof(*dul), M_TEMP, M_WAITOK);
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+
 again:
        error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx));
-       nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
+       if (!namedattrs) {
+               nfs_dulookup_init(dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
+       }
 
        nfsm_chain_null(&nmreq);
        nfsm_chain_null(&nmrep);
@@ -4117,7 +4312,7 @@ again:
                        nfsm_chain_add_32(error, &nmreq, create_verf);
                } else {
                        nfsm_chain_add_32(error, &nmreq, NFS_CREATE_UNCHECKED);
-                       nfsm_chain_add_v3sattr(error, &nmreq, vap);
+                       nfsm_chain_add_v3sattr(nmp, error, &nmreq, vap);
                }
        } else {
                nfsm_chain_add_v2sattr(error, &nmreq, vap, 0);
@@ -4128,7 +4323,10 @@ again:
        error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_CREATE,
            vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req);
        if (!error) {
-               nfs_dulookup_start(&dul, dnp, ctx);
+               if (!namedattrs) {
+                       nfs_dulookup_start(dul, dnp, ctx);
+                       dul_in_progress = 1;
+               }
                error = nfs_request_async_finish(req, &nmrep, &xid, &status);
        }
 
@@ -4141,7 +4339,7 @@ again:
                        dnp->n_flag &= ~NNEGNCENTRIES;
                        cache_purge_negatives(dvp);
                }
-               error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr);
+               error = nfsm_chain_get_fh_attr(nmp, &nmrep, dnp, ctx, nfsvers, &xid, fh, nvattr);
        }
        if (nfsvers == NFS_VER3) {
                nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid);
@@ -4164,8 +4362,8 @@ nfsmout:
                nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
        }
 
-       if (!error && fh.fh_len) {
-               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
+       if (!error && fh->fh_len) {
+               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, NG_MAKEENTRY, &np);
        }
        if (!error && !np) {
                error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
@@ -4174,7 +4372,9 @@ nfsmout:
                newvp = NFSTOV(np);
        }
 
-       nfs_dulookup_finish(&dul, dnp, ctx);
+       if (dul_in_progress) {
+               nfs_dulookup_finish(dul, dnp, ctx);
+       }
        if (!busyerror) {
                nfs_node_clear_busy(dnp);
        }
@@ -4208,9 +4408,9 @@ nfsmout:
                *ap->a_vpp = newvp;
        }
        if (!error && (gotuid || gotgid) &&
-           (!newvp || nfs_getattrcache(np, &nvattr, 0) ||
-           (gotuid && (nvattr.nva_uid != vap->va_uid)) ||
-           (gotgid && (nvattr.nva_gid != vap->va_gid)))) {
+           (!newvp || nfs_getattrcache(np, nvattr, 0) ||
+           (gotuid && (nvattr->nva_uid != vap->va_uid)) ||
+           (gotgid && (nvattr->nva_gid != vap->va_gid)))) {
                /* clear ID bits if server didn't use them (or we can't tell) */
                VATTR_CLEAR_SUPPORTED(vap, va_uid);
                VATTR_CLEAR_SUPPORTED(vap, va_gid);
@@ -4218,6 +4418,10 @@ nfsmout:
        if (!error) {
                nfs_node_unlock(np);
        }
+       NFS_ZFREE(nfs_fhandle_zone, fh);
+       NFS_ZFREE(nfs_req_zone, req);
+       FREE(dul, M_TEMP);
+       FREE(nvattr, M_TEMP);
        return error;
 }
 
@@ -4250,9 +4454,9 @@ nfs_vnop_remove(
        nfsnode_t dnp = VTONFS(dvp);
        nfsnode_t np = VTONFS(vp);
        int error = 0, nfsvers, namedattrs, inuse, gotattr = 0, flushed = 0, setsize = 0;
-       struct nfs_vattr nvattr;
+       struct nfs_vattr *nvattr;
        struct nfsmount *nmp;
-       struct nfs_dulookup dul;
+       struct nfs_dulookup *dul;
 
        /* XXX prevent removing a sillyrenamed file? */
 
@@ -4260,13 +4464,20 @@ nfs_vnop_remove(
        if (nfs_mount_gone(nmp)) {
                return ENXIO;
        }
+
+       if (vnode_isdir(vp)) {
+               return EPERM;
+       }
+
        nfsvers = nmp->nm_vers;
        namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
+       MALLOC(dul, struct nfs_dulookup *, sizeof(*dul), M_TEMP, M_WAITOK);
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
 
 again_relock:
        error = nfs_node_set_busy2(dnp, np, vfs_context_thread(ctx));
        if (error) {
-               return error;
+               goto out_free;
        }
 
        /* lock the node while we remove the file */
@@ -4279,8 +4490,9 @@ again_relock:
        lck_mtx_unlock(nfs_node_hash_mutex);
 
        if (!namedattrs) {
-               nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
+               nfs_dulookup_init(dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
        }
+
 again:
        inuse = vnode_isinuse(vp, 0);
        if ((ap->a_flags & VNODE_REMOVE_NODELETEBUSY) && inuse) {
@@ -4289,13 +4501,13 @@ again:
                goto out;
        }
        if (inuse && !gotattr) {
-               if (nfs_getattr(np, &nvattr, ctx, NGA_CACHED)) {
-                       nvattr.nva_nlink = 1;
+               if (nfs_getattr(np, nvattr, ctx, NGA_CACHED)) {
+                       nvattr->nva_nlink = 1;
                }
                gotattr = 1;
                goto again;
        }
-       if (!inuse || (np->n_sillyrename && (nvattr.nva_nlink > 1))) {
+       if (!inuse || (np->n_sillyrename && (nvattr->nva_nlink > 1))) {
                if (!inuse && !flushed) { /* flush all the buffers first */
                        /* unlock the node */
                        lck_mtx_lock(nfs_node_hash_mutex);
@@ -4313,18 +4525,18 @@ again:
                                nfs_node_lock_force(np);
                                NATTRINVALIDATE(np);
                                nfs_node_unlock(np);
-                               return error;
+                               goto out_free;
                        }
                        if (!namedattrs) {
-                               nfs_dulookup_finish(&dul, dnp, ctx);
+                               nfs_dulookup_finish(dul, dnp, ctx);
                        }
                        goto again_relock;
                }
-
+#if CONFIG_NFS4
                if ((nmp->nm_vers >= NFS_VER4) && (np->n_openflags & N_DELEG_MASK)) {
                        nfs4_delegation_return(np, 0, vfs_context_thread(ctx), vfs_context_ucred(ctx));
                }
-
+#endif
                /*
                 * Purge the name cache so that the chance of a lookup for
                 * the name succeeding while the remove is in progress is
@@ -4333,7 +4545,7 @@ again:
                nfs_name_cache_purge(dnp, np, cnp, ctx);
 
                if (!namedattrs) {
-                       nfs_dulookup_start(&dul, dnp, ctx);
+                       nfs_dulookup_start(dul, dnp, ctx);
                }
 
                /* Do the rpc */
@@ -4379,7 +4591,7 @@ again:
                }
        } else if (!np->n_sillyrename) {
                if (!namedattrs) {
-                       nfs_dulookup_start(&dul, dnp, ctx);
+                       nfs_dulookup_start(dul, dnp, ctx);
                }
                error = nfs_sillyrename(dnp, np, cnp, ctx);
                nfs_node_lock_force(np);
@@ -4390,14 +4602,14 @@ again:
                NATTRINVALIDATE(np);
                nfs_node_unlock(np);
                if (!namedattrs) {
-                       nfs_dulookup_start(&dul, dnp, ctx);
+                       nfs_dulookup_start(dul, dnp, ctx);
                }
        }
 
        /* nfs_getattr() will check changed and purge caches */
        nfs_getattr(dnp, NULL, ctx, NGA_CACHED);
        if (!namedattrs) {
-               nfs_dulookup_finish(&dul, dnp, ctx);
+               nfs_dulookup_finish(dul, dnp, ctx);
        }
 out:
        /* unlock the node */
@@ -4412,6 +4624,9 @@ out:
        if (setsize) {
                ubc_setsize(vp, 0);
        }
+out_free:
+       FREE(dul, M_TEMP);
+       FREE(nvattr, M_TEMP);
        return error;
 }
 
@@ -4439,8 +4654,8 @@ nfs3_remove_rpc(
        thread_t thd,
        kauth_cred_t cred)
 {
-       int error = 0, lockerror = ENOENT, status, wccpostattr = 0;
-       struct timespec premtime = { 0, 0 };
+       int error = 0, lockerror = ENOENT, status = 0, wccpostattr = 0;
+       struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
        struct nfsmount *nmp;
        int nfsvers;
        u_int64_t xid;
@@ -4520,7 +4735,7 @@ nfs_vnop_rename(
        struct componentname *fcnp = ap->a_fcnp;
        int error, nfsvers, inuse = 0, tvprecycle = 0, locked = 0;
        mount_t fmp, tdmp, tmp;
-       struct nfs_vattr nvattr;
+       struct nfs_vattr *nvattr;
        struct nfsmount *nmp;
 
        fdnp = VTONFS(fdvp);
@@ -4539,6 +4754,8 @@ nfs_vnop_rename(
                return error;
        }
 
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+
        if (tvp && (tvp != fvp)) {
                /* lock the node while we rename over the existing file */
                lck_mtx_lock(nfs_node_hash_mutex);
@@ -4581,10 +4798,12 @@ nfs_vnop_rename(
                        /* sillyrename succeeded.*/
                        tvp = NULL;
                }
-       } else if (tvp && (nmp->nm_vers >= NFS_VER4) && (tnp->n_openflags & N_DELEG_MASK)) {
+       }
+#if CONFIG_NFS4
+       else if (tvp && (nmp->nm_vers >= NFS_VER4) && (tnp->n_openflags & N_DELEG_MASK)) {
                nfs4_delegation_return(tnp, 0, vfs_context_thread(ctx), vfs_context_ucred(ctx));
        }
-
+#endif
        error = nmp->nm_funcs->nf_rename_rpc(fdnp, fcnp->cn_nameptr, fcnp->cn_namelen,
            tdnp, tcnp->cn_nameptr, tcnp->cn_namelen, ctx);
 
@@ -4598,7 +4817,7 @@ nfs_vnop_rename(
        if (tvp && (tvp != fvp) && !tnp->n_sillyrename) {
                nfs_node_lock_force(tnp);
                tvprecycle = (!error && !vnode_isinuse(tvp, 0) &&
-                   (nfs_getattrcache(tnp, &nvattr, 0) || (nvattr.nva_nlink == 1)));
+                   (nfs_getattrcache(tnp, nvattr, 0) || (nvattr->nva_nlink == 1)));
                nfs_node_unlock(tnp);
                lck_mtx_lock(nfs_node_hash_mutex);
                if (tvprecycle && (tnp->n_hflag & NHHASHED)) {
@@ -4668,6 +4887,7 @@ out:
                lck_mtx_unlock(nfs_node_hash_mutex);
        }
        nfs_node_clear_busy4(fdnp, fnp, tdnp, tnp);
+       FREE(nvattr, M_TEMP);
        return error;
 }
 
@@ -4684,8 +4904,8 @@ nfs3_rename_rpc(
        int tnamelen,
        vfs_context_t ctx)
 {
-       int error = 0, lockerror = ENOENT, status, fwccpostattr = 0, twccpostattr = 0;
-       struct timespec fpremtime = { 0, 0 }, tpremtime = { 0, 0 };
+       int error = 0, lockerror = ENOENT, status = 0, fwccpostattr = 0, twccpostattr = 0;
+       struct timespec fpremtime = { .tv_sec = 0, .tv_nsec = 0 }, tpremtime = { .tv_sec = 0, .tv_nsec = 0 };
        struct nfsmount *nmp;
        int nfsvers;
        u_int64_t xid, txid;
@@ -4769,8 +4989,8 @@ nfs3_vnop_link(
        vnode_t vp = ap->a_vp;
        vnode_t tdvp = ap->a_tdvp;
        struct componentname *cnp = ap->a_cnp;
-       int error = 0, lockerror = ENOENT, status, wccpostattr = 0, attrflag = 0;
-       struct timespec premtime = { 0, 0 };
+       int error = 0, lockerror = ENOENT, status = 0, wccpostattr = 0, attrflag = 0;
+       struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
        struct nfsmount *nmp;
        nfsnode_t np = VTONFS(vp);
        nfsnode_t tdnp = VTONFS(tdvp);
@@ -4877,10 +5097,11 @@ nfs3_vnop_symlink(
        vnode_t dvp = ap->a_dvp;
        struct vnode_attr *vap = ap->a_vap;
        struct componentname *cnp = ap->a_cnp;
-       struct nfs_vattr nvattr;
-       fhandle_t fh;
-       int slen, error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0;
-       struct timespec premtime = { 0, 0 };
+       struct nfs_vattr *nvattr;
+       fhandle_t *fh;
+       int error = 0, lockerror = ENOENT, busyerror = ENOENT, status = 0, wccpostattr = 0;
+       size_t slen;
+       struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
        vnode_t newvp = NULL;
        int nfsvers, gotuid, gotgid;
        u_int64_t xid = 0, dxid;
@@ -4888,14 +5109,17 @@ nfs3_vnop_symlink(
        nfsnode_t dnp = VTONFS(dvp);
        struct nfsmount *nmp;
        struct nfsm_chain nmreq, nmrep;
-       struct nfsreq rq, *req = &rq;
-       struct nfs_dulookup dul;
+       struct nfsreq *req;
+       struct nfs_dulookup *dul;
+       int namedattrs;
+       int dul_in_progress = 0;
 
        nmp = VTONMP(dvp);
        if (nfs_mount_gone(nmp)) {
                return ENXIO;
        }
        nfsvers = nmp->nm_vers;
+       namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
 
        slen = strlen(ap->a_target);
        if ((nfsvers == NFS_VER2) &&
@@ -4914,8 +5138,15 @@ nfs3_vnop_symlink(
        gotuid = VATTR_IS_ACTIVE(vap, va_uid);
        gotgid = VATTR_IS_ACTIVE(vap, va_gid);
 
+       fh = zalloc(nfs_fhandle_zone);
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
+       MALLOC(dul, struct nfs_dulookup *, sizeof(*dul), M_TEMP, M_WAITOK);
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+
        error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx));
-       nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
+       if (!namedattrs) {
+               nfs_dulookup_init(dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
+       }
 
        nfsm_chain_null(&nmreq);
        nfsm_chain_null(&nmrep);
@@ -4926,7 +5157,7 @@ nfs3_vnop_symlink(
        nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
        nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
        if (nfsvers == NFS_VER3) {
-               nfsm_chain_add_v3sattr(error, &nmreq, vap);
+               nfsm_chain_add_v3sattr(nmp, error, &nmreq, vap);
        }
        nfsm_chain_add_name(error, &nmreq, ap->a_target, slen, nmp);
        if (nfsvers == NFS_VER2) {
@@ -4938,7 +5169,10 @@ nfs3_vnop_symlink(
        error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_SYMLINK,
            vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req);
        if (!error) {
-               nfs_dulookup_start(&dul, dnp, ctx);
+               if (!namedattrs) {
+                       nfs_dulookup_start(dul, dnp, ctx);
+                       dul_in_progress = 1;
+               }
                error = nfs_request_async_finish(req, &nmrep, &xid, &status);
        }
 
@@ -4952,9 +5186,9 @@ nfs3_vnop_symlink(
                        cache_purge_negatives(dvp);
                }
                if (nfsvers == NFS_VER3) {
-                       error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr);
+                       error = nfsm_chain_get_fh_attr(nmp, &nmrep, dnp, ctx, nfsvers, &xid, fh, nvattr);
                } else {
-                       fh.fh_len = 0;
+                       fh->fh_len = 0;
                }
        }
        if (nfsvers == NFS_VER3) {
@@ -4978,14 +5212,16 @@ nfsmout:
                nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
        }
 
-       if (!error && fh.fh_len) {
-               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
+       if (!error && fh->fh_len) {
+               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, NG_MAKEENTRY, &np);
        }
        if (!error && np) {
                newvp = NFSTOV(np);
        }
 
-       nfs_dulookup_finish(&dul, dnp, ctx);
+       if (dul_in_progress) {
+               nfs_dulookup_finish(dul, dnp, ctx);
+       }
 
        /*
         * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
@@ -5009,9 +5245,9 @@ nfsmout:
                nfs_node_clear_busy(dnp);
        }
        if (!error && (gotuid || gotgid) &&
-           (!newvp || nfs_getattrcache(np, &nvattr, 0) ||
-           (gotuid && (nvattr.nva_uid != vap->va_uid)) ||
-           (gotgid && (nvattr.nva_gid != vap->va_gid)))) {
+           (!newvp || nfs_getattrcache(np, nvattr, 0) ||
+           (gotuid && (nvattr->nva_uid != vap->va_uid)) ||
+           (gotgid && (nvattr->nva_gid != vap->va_gid)))) {
                /* clear ID bits if server didn't use them (or we can't tell) */
                VATTR_CLEAR_SUPPORTED(vap, va_uid);
                VATTR_CLEAR_SUPPORTED(vap, va_gid);
@@ -5025,6 +5261,10 @@ nfsmout:
                nfs_node_unlock(np);
                *ap->a_vpp = newvp;
        }
+       NFS_ZFREE(nfs_fhandle_zone, fh);
+       NFS_ZFREE(nfs_req_zone, req);
+       FREE(dul, M_TEMP);
+       FREE(nvattr, M_TEMP);
        return error;
 }
 
@@ -5046,25 +5286,29 @@ nfs3_vnop_mkdir(
        vnode_t dvp = ap->a_dvp;
        struct vnode_attr *vap = ap->a_vap;
        struct componentname *cnp = ap->a_cnp;
-       struct nfs_vattr nvattr;
+       struct nfs_vattr *nvattr;
        nfsnode_t np = NULL;
        struct nfsmount *nmp;
        nfsnode_t dnp = VTONFS(dvp);
        vnode_t newvp = NULL;
-       int error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0;
-       struct timespec premtime = { 0, 0 };
+       int error = 0, lockerror = ENOENT, busyerror = ENOENT, status = 0, wccpostattr = 0;
+       struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
        int nfsvers, gotuid, gotgid;
        u_int64_t xid = 0, dxid;
-       fhandle_t fh;
+       fhandle_t *fh;
        struct nfsm_chain nmreq, nmrep;
-       struct nfsreq rq, *req = &rq;
-       struct nfs_dulookup dul;
+       struct nfsreq *req;
+       struct nfs_dulookup *dul;
+       int namedattrs;
+       int dul_in_progress = 0;
 
        nmp = VTONMP(dvp);
        if (nfs_mount_gone(nmp)) {
                return ENXIO;
        }
        nfsvers = nmp->nm_vers;
+       namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
+
        if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN)) {
                return ENAMETOOLONG;
        }
@@ -5080,8 +5324,15 @@ nfs3_vnop_mkdir(
        gotuid = VATTR_IS_ACTIVE(vap, va_uid);
        gotgid = VATTR_IS_ACTIVE(vap, va_gid);
 
+       fh = zalloc(nfs_fhandle_zone);
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
+       MALLOC(dul, struct nfs_dulookup *, sizeof(*dul), M_TEMP, M_WAITOK);
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+
        error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx));
-       nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
+       if (!namedattrs) {
+               nfs_dulookup_init(dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
+       }
 
        nfsm_chain_null(&nmreq);
        nfsm_chain_null(&nmrep);
@@ -5092,7 +5343,7 @@ nfs3_vnop_mkdir(
        nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
        nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
        if (nfsvers == NFS_VER3) {
-               nfsm_chain_add_v3sattr(error, &nmreq, vap);
+               nfsm_chain_add_v3sattr(nmp, error, &nmreq, vap);
        } else {
                nfsm_chain_add_v2sattr(error, &nmreq, vap, -1);
        }
@@ -5102,7 +5353,10 @@ nfs3_vnop_mkdir(
        error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_MKDIR,
            vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req);
        if (!error) {
-               nfs_dulookup_start(&dul, dnp, ctx);
+               if (!namedattrs) {
+                       nfs_dulookup_start(dul, dnp, ctx);
+                       dul_in_progress = 1;
+               }
                error = nfs_request_async_finish(req, &nmrep, &xid, &status);
        }
 
@@ -5115,7 +5369,7 @@ nfs3_vnop_mkdir(
                        dnp->n_flag &= ~NNEGNCENTRIES;
                        cache_purge_negatives(dvp);
                }
-               error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr);
+               error = nfsm_chain_get_fh_attr(nmp, &nmrep, dnp, ctx, nfsvers, &xid, fh, nvattr);
        }
        if (nfsvers == NFS_VER3) {
                nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid);
@@ -5138,14 +5392,16 @@ nfsmout:
                nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
        }
 
-       if (!error && fh.fh_len) {
-               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
+       if (!error && fh->fh_len) {
+               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh->fh_data, fh->fh_len, nvattr, &xid, req->r_auth, NG_MAKEENTRY, &np);
        }
        if (!error && np) {
                newvp = NFSTOV(np);
        }
 
-       nfs_dulookup_finish(&dul, dnp, ctx);
+       if (dul_in_progress) {
+               nfs_dulookup_finish(dul, dnp, ctx);
+       }
 
        /*
         * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
@@ -5169,9 +5425,9 @@ nfsmout:
                nfs_node_clear_busy(dnp);
        }
        if (!error && (gotuid || gotgid) &&
-           (!newvp || nfs_getattrcache(np, &nvattr, 0) ||
-           (gotuid && (nvattr.nva_uid != vap->va_uid)) ||
-           (gotgid && (nvattr.nva_gid != vap->va_gid)))) {
+           (!newvp || nfs_getattrcache(np, nvattr, 0) ||
+           (gotuid && (nvattr->nva_uid != vap->va_uid)) ||
+           (gotgid && (nvattr->nva_gid != vap->va_gid)))) {
                /* clear ID bits if server didn't use them (or we can't tell) */
                VATTR_CLEAR_SUPPORTED(vap, va_uid);
                VATTR_CLEAR_SUPPORTED(vap, va_gid);
@@ -5185,6 +5441,10 @@ nfsmout:
                nfs_node_unlock(np);
                *ap->a_vpp = newvp;
        }
+       NFS_ZFREE(nfs_fhandle_zone, fh);
+       NFS_ZFREE(nfs_req_zone, req);
+       FREE(dul, M_TEMP);
+       FREE(nvattr, M_TEMP);
        return error;
 }
 
@@ -5205,22 +5465,26 @@ nfs3_vnop_rmdir(
        vnode_t vp = ap->a_vp;
        vnode_t dvp = ap->a_dvp;
        struct componentname *cnp = ap->a_cnp;
-       int error = 0, lockerror = ENOENT, status, wccpostattr = 0;
-       struct timespec premtime = { 0, 0 };
+       int error = 0, lockerror = ENOENT, status = 0, wccpostattr = 0;
+       struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
        struct nfsmount *nmp;
        nfsnode_t np = VTONFS(vp);
        nfsnode_t dnp = VTONFS(dvp);
        int nfsvers;
        u_int64_t xid;
        struct nfsm_chain nmreq, nmrep;
-       struct nfsreq rq, *req = &rq;
-       struct nfs_dulookup dul;
+       struct nfsreq *req;
+       struct nfs_dulookup *dul;
+       int namedattrs;
+       int dul_in_progress = 0;
 
        nmp = VTONMP(vp);
        if (nfs_mount_gone(nmp)) {
                return ENXIO;
        }
        nfsvers = nmp->nm_vers;
+       namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
+
        if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN)) {
                return ENAMETOOLONG;
        }
@@ -5229,7 +5493,12 @@ nfs3_vnop_rmdir(
                return error;
        }
 
-       nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
+       MALLOC(dul, struct nfs_dulookup *, sizeof(*dul), M_TEMP, M_WAITOK);
+
+       if (!namedattrs) {
+               nfs_dulookup_init(dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
+       }
 
        nfsm_chain_null(&nmreq);
        nfsm_chain_null(&nmrep);
@@ -5244,7 +5513,10 @@ nfs3_vnop_rmdir(
        error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_RMDIR,
            vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req);
        if (!error) {
-               nfs_dulookup_start(&dul, dnp, ctx);
+               if (!namedattrs) {
+                       nfs_dulookup_start(dul, dnp, ctx);
+                       dul_in_progress = 1;
+               }
                error = nfs_request_async_finish(req, &nmrep, &xid, &status);
        }
 
@@ -5272,7 +5544,9 @@ nfsmout:
                /* nfs_getattr() will check changed and purge caches */
                nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
        }
-       nfs_dulookup_finish(&dul, dnp, ctx);
+       if (dul_in_progress) {
+               nfs_dulookup_finish(dul, dnp, ctx);
+       }
        nfs_node_clear_busy2(dnp, np);
 
        /*
@@ -5295,6 +5569,8 @@ nfsmout:
                }
                lck_mtx_unlock(nfs_node_hash_mutex);
        }
+       NFS_ZFREE(nfs_req_zone, req);
+       FREE(dul, M_TEMP);
        return error;
 }
 
@@ -5338,6 +5614,7 @@ nfs_vnop_readdir(
        struct nfsmount *nmp;
        uio_t uio = ap->a_uio;
        int error, nfsvers, extended, numdirent, bigcookies, ptc, done;
+       long attrcachetimeout;
        uint16_t i, iptc, rlen, nlen;
        uint64_t cookie, nextcookie, lbn = 0;
        struct nfsbuf *bp = NULL;
@@ -5345,6 +5622,7 @@ nfs_vnop_readdir(
        struct direntry *dp, *dpptc;
        struct dirent dent;
        char *cp = NULL;
+       struct timeval now;
        thread_t thd;
 
        nmp = VTONMP(dvp);
@@ -5366,12 +5644,12 @@ nfs_vnop_readdir(
        if (uio_resid(uio) == 0) {
                return 0;
        }
-
+#if CONFIG_NFS4
        if ((nfsvers >= NFS_VER4) && (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER)) {
                /* trigger directories should never be read, return nothing */
                return 0;
        }
-
+#endif
        thd = vfs_context_thread(ctx);
        numdirent = done = 0;
        nextcookie = uio_offset(uio);
@@ -5394,6 +5672,23 @@ nfs_vnop_readdir(
                }
        }
 
+       if (dnp->n_rdirplusstamp_eof && dnp->n_rdirplusstamp_sof) {
+               attrcachetimeout = nfs_attrcachetimeout(dnp);
+               microuptime(&now);
+               if (attrcachetimeout && (now.tv_sec - dnp->n_rdirplusstamp_sof > attrcachetimeout - 1)) {
+                       dnp->n_rdirplusstamp_eof = dnp->n_rdirplusstamp_sof = 0;
+                       nfs_invaldir(dnp);
+                       nfs_node_unlock(dnp);
+                       error = nfs_vinvalbuf(dvp, 0, ctx, 1);
+                       if (!error) {
+                               error = nfs_node_lock(dnp);
+                       }
+                       if (error) {
+                               goto out;
+                       }
+               }
+       }
+
        /*
         * check for need to invalidate when (re)starting at beginning
         */
@@ -5507,9 +5802,9 @@ getbuffer:
                                }
                                rlen = NFS_DIRENT_LEN(nlen);
                                dent.d_reclen = rlen;
-                               dent.d_ino = dp->d_ino;
+                               dent.d_ino = (ino_t)dp->d_ino;
                                dent.d_type = dp->d_type;
-                               dent.d_namlen = nlen;
+                               dent.d_namlen = (uint8_t)nlen;
                                strlcpy(dent.d_name, dp->d_name, nlen + 1);
                        }
                        /* check that the record fits */
@@ -5581,11 +5876,11 @@ nfs_invaldir(nfsnode_t dnp)
 /*
  * calculate how much space is available for additional directory entries.
  */
-uint32_t
+uint64_t
 nfs_dir_buf_freespace(struct nfsbuf *bp, int rdirplus)
 {
        struct nfs_dir_buf_header *ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
-       uint32_t space;
+       uint64_t space;
 
        if (!ndbhp) {
                return 0;
@@ -5622,13 +5917,7 @@ nfs_dir_cookie_cache(nfsnode_t dnp, uint64_t cookie, uint64_t lbn)
        ndcc = dnp->n_cookiecache;
        if (!ndcc) {
                /* allocate the cookie cache structure */
-               MALLOC_ZONE(dnp->n_cookiecache, struct nfsdmap *,
-                   sizeof(struct nfsdmap), M_NFSDIROFF, M_WAITOK);
-               if (!dnp->n_cookiecache) {
-                       nfs_node_unlock(dnp);
-                       return;
-               }
-               ndcc = dnp->n_cookiecache;
+               ndcc = dnp->n_cookiecache = zalloc(ZV_NFSDIROFF);
                ndcc->free = 0;
                ndcc->mru = -1;
                memset(ndcc->next, -1, NFSNUMCOOKIES);
@@ -5855,9 +6144,9 @@ nfs_dir_buf_search(
        for (i = 0; i < ndbhp->ndbh_count; i++) {
                nextlbn = dp->d_seekoff;
                if ((cnp->cn_namelen == dp->d_namlen) && !strcmp(cnp->cn_nameptr, dp->d_name)) {
-                       fhlen = dp->d_name[dp->d_namlen + 1];
+                       fhlen = (uint8_t)dp->d_name[dp->d_namlen + 1];
                        nvattrp = NFS_DIR_BUF_NVATTR(bp, i);
-                       if ((ndbhp->ndbh_ncgen != bp->nb_np->n_ncgen) || (fhp->fh_len == 0) ||
+                       if ((ndbhp->ndbh_ncgen != bp->nb_np->n_ncgen) || (fhlen == 0) ||
                            (nvattrp->nva_type == VNON) || (nvattrp->nva_fileid == 0)) {
                                /* entry is not valid */
                                error = ENOENT;
@@ -5875,6 +6164,7 @@ nfs_dir_buf_search(
                                        bcopy(nvap, nvattrp, sizeof(*nvap));
                                        dp->d_fileno = nvattrp->nva_fileid;
                                        nvattrp->nva_fileid = *xidp;
+                                       nvap->nva_flags |= NFS_FFLAG_FILEID_CONTAINS_XID;
                                        *(time_t*)(&dp->d_name[dp->d_namlen + 2 + fhp->fh_len]) = *attrstampp;
                                }
                                error = 0;
@@ -5887,6 +6177,7 @@ nfs_dir_buf_search(
                        bcopy(nvattrp, nvap, sizeof(*nvap));
                        *xidp = nvap->nva_fileid;
                        nvap->nva_fileid = dp->d_fileno;
+                       nvap->nva_flags &= ~NFS_FFLAG_FILEID_CONTAINS_XID;
                        error = 0;
                        break;
                }
@@ -5903,20 +6194,23 @@ nfs_dir_buf_search(
  * Note: should only be called with RDIRPLUS directory buffers
  */
 int
-nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cnp, vfs_context_t ctx, int purge)
+nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cnp, vfs_context_t ctx, int purge, int *skipdu)
 {
        nfsnode_t newnp;
        struct nfsmount *nmp;
        int error = 0, i, found = 0, count = 0;
        u_int64_t xid;
-       struct nfs_vattr nvattr;
-       fhandle_t fh;
+       struct nfs_vattr *nvattr;
+       fhandle_t *fh;
        time_t attrstamp = 0;
        thread_t thd = vfs_context_thread(ctx);
        struct nfsbuf *bp, *lastbp, *foundbp;
        struct nfsbuflists blist;
        daddr64_t lbn, nextlbn;
        int dotunder = (cnp->cn_namelen > 2) && (cnp->cn_nameptr[0] == '.') && (cnp->cn_nameptr[1] == '_');
+       int isdot = (cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.');
+       int isdotdot = (cnp->cn_namelen == 2) && (cnp->cn_nameptr[0] == '.') && (cnp->cn_nameptr[1] == '.');
+       int eof = 0, sof = 0, skipped = 0;
 
        nmp = NFSTONMP(dnp);
        if (nfs_mount_gone(nmp)) {
@@ -5926,17 +6220,26 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn
                *npp = NULL;
        }
 
+       if (isdot || isdotdot) {
+               return 0;
+       }
+
+       fh = zalloc(nfs_fhandle_zone);
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+
        /* first check most recent buffer (and next one too) */
        lbn = dnp->n_lastdbl;
        for (i = 0; i < 2; i++) {
                if ((error = nfs_buf_get(dnp, lbn, NFS_DIRBLKSIZ, thd, NBLK_READ | NBLK_ONLYVALID, &bp))) {
-                       return error;
+                       goto out;
                }
                if (!bp) {
+                       skipped = 1;
                        break;
                }
                count++;
-               error = nfs_dir_buf_search(bp, cnp, &fh, &nvattr, &xid, &attrstamp, &nextlbn, purge ? NDBS_PURGE : 0);
+               nfs_dir_buf_cache_lookup_boundaries(bp, &sof, &eof);
+               error = nfs_dir_buf_search(bp, cnp, fh, nvattr, &xid, &attrstamp, &nextlbn, purge ? NDBS_PURGE : 0);
                nfs_buf_release(bp, 0);
                if (error == ESRCH) {
                        error = 0;
@@ -5953,6 +6256,11 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn
                goto done;
        }
 
+       /* If we detect that we fetched full directory listing we should avoid sending lookups for ._ files */
+       if (dotunder && !found && !error && eof && sof && !skipped && skipdu) {
+               *skipdu = 1;
+       }
+
        /*
         * Scan the list of buffers, keeping them in order.
         * Note that itercomplete inserts each of the remaining buffers
@@ -5962,6 +6270,7 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn
         * Also note: the LIST_INSERT_AFTER(lastbp) is only safe because
         * we don't drop nfs_buf_mutex.
         */
+       eof = sof = skipped = 0;
        if (!nfs_buf_iterprepare(dnp, &blist, NBI_CLEAN)) {
                lastbp = foundbp = NULL;
                while ((bp = LIST_FIRST(&blist))) {
@@ -5973,9 +6282,11 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn
                        }
                        lastbp = bp;
                        if (error || found) {
+                               skipped = 1;
                                continue;
                        }
                        if (!purge && dotunder && (count > 100)) { /* don't waste too much time looking for ._ files */
+                               skipped = 1;
                                continue;
                        }
                        nfs_buf_refget(bp);
@@ -5983,11 +6294,13 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn
                        if (nfs_buf_acquire(bp, NBAC_NOWAIT, 0, 0)) {
                                /* just skip this buffer */
                                nfs_buf_refrele(bp);
+                               skipped = 1;
                                continue;
                        }
                        nfs_buf_refrele(bp);
                        count++;
-                       error = nfs_dir_buf_search(bp, cnp, &fh, &nvattr, &xid, &attrstamp, NULL, purge ? NDBS_PURGE : 0);
+                       nfs_dir_buf_cache_lookup_boundaries(bp, &sof, &eof);
+                       error = nfs_dir_buf_search(bp, cnp, fh, nvattr, &xid, &attrstamp, NULL, purge ? NDBS_PURGE : 0);
                        if (error == ESRCH) {
                                error = 0;
                        } else {
@@ -6003,33 +6316,43 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn
                }
                nfs_buf_itercomplete(dnp, &blist, NBI_CLEAN);
        }
+
+       /* If we detect that we fetched full directory listing we should avoid sending lookups for ._ files */
+       if (dotunder && !found && !error && eof && sof && !skipped && skipdu) {
+               *skipdu = 1;
+       }
+
 done:
        lck_mtx_unlock(nfs_buf_mutex);
 
        if (!error && found && !purge) {
-               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len,
-                   &nvattr, &xid, dnp->n_auth, NG_MAKEENTRY, &newnp);
+               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh->fh_data,
+                   fh->fh_len, nvattr, &xid, dnp->n_auth, NG_MAKEENTRY,
+                   &newnp);
                if (error) {
-                       return error;
+                       goto out;
                }
                newnp->n_attrstamp = attrstamp;
                *npp = newnp;
                nfs_node_unlock(newnp);
                /* check if the dir buffer's attrs are out of date */
-               if (!nfs_getattr(newnp, &nvattr, ctx, NGA_CACHED) &&
+               if (!nfs_getattr(newnp, nvattr, ctx, NGA_CACHED) &&
                    (newnp->n_attrstamp != attrstamp)) {
                        /* they are, so update them */
                        error = nfs_buf_get(dnp, lbn, NFS_DIRBLKSIZ, thd, NBLK_READ | NBLK_ONLYVALID, &bp);
                        if (!error && bp) {
                                attrstamp = newnp->n_attrstamp;
                                xid = newnp->n_xid;
-                               nfs_dir_buf_search(bp, cnp, &fh, &nvattr, &xid, &attrstamp, NULL, NDBS_UPDATE);
+                               nfs_dir_buf_search(bp, cnp, fh, nvattr, &xid, &attrstamp, NULL, NDBS_UPDATE);
                                nfs_buf_release(bp, 0);
                        }
                        error = 0;
                }
        }
 
+out:
+       NFS_ZFREE(nfs_fhandle_zone, fh);
+       FREE(nvattr, M_TEMP);
        return error;
 }
 
@@ -6044,7 +6367,7 @@ nfs_name_cache_purge(nfsnode_t dnp, nfsnode_t np, struct componentname *cnp, vfs
 
        cache_purge(NFSTOV(np));
        if (nmp && (nmp->nm_vers > NFS_VER2) && NMFLAG(nmp, RDIRPLUS)) {
-               nfs_dir_buf_cache_lookup(dnp, NULL, cnp, ctx, 1);
+               nfs_dir_buf_cache_lookup(dnp, NULL, cnp, ctx, 1, NULL);
        }
 }
 
@@ -6056,17 +6379,19 @@ nfs3_readdir_rpc(nfsnode_t dnp, struct nfsbuf *bp, vfs_context_t ctx)
 {
        struct nfsmount *nmp;
        int error = 0, lockerror, nfsvers, rdirplus, bigcookies;
-       int i, status, attrflag, fhflag, more_entries = 1, eof, bp_dropped = 0;
+       int i, status = 0, attrflag, fhflag, more_entries = 1, eof, bp_dropped = 0;
        uint32_t nmreaddirsize, nmrsize;
-       uint32_t namlen, skiplen, fhlen, xlen, attrlen, reclen, space_free, space_needed;
-       uint64_t cookie, lastcookie, xid, savedxid, fileno;
+       uint32_t namlen, skiplen, fhlen, xlen, attrlen;
+       uint64_t cookie, lastcookie, xid, savedxid, fileno, space_free, space_needed;
        struct nfsm_chain nmreq, nmrep, nmrepsave;
-       fhandle_t fh;
+       fhandle_t *fh;
        struct nfs_vattr *nvattrp;
        struct nfs_dir_buf_header *ndbhp;
        struct direntry *dp;
-       char *padstart, padlen;
+       char *padstart;
        struct timeval now;
+       uint16_t reclen;
+       size_t padlen;
 
        nmp = NFSTONMP(dnp);
        if (nfs_mount_gone(nmp)) {
@@ -6076,10 +6401,12 @@ nfs3_readdir_rpc(nfsnode_t dnp, struct nfsbuf *bp, vfs_context_t ctx)
        nmreaddirsize = nmp->nm_readdirsize;
        nmrsize = nmp->nm_rsize;
        bigcookies = nmp->nm_state & NFSSTA_BIGCOOKIES;
+       fh = zalloc(nfs_fhandle_zone);
 noplus:
        rdirplus = ((nfsvers > NFS_VER2) && NMFLAG(nmp, RDIRPLUS)) ? 1 : 0;
 
        if ((lockerror = nfs_node_lock(dnp))) {
+               NFS_ZFREE(nfs_fhandle_zone, fh);
                return lockerror;
        }
 
@@ -6162,6 +6489,10 @@ noplus:
 
                if (rdirplus) {
                        microuptime(&now);
+                       if (lastcookie == 0) {
+                               dnp->n_rdirplusstamp_sof = now.tv_sec;
+                               dnp->n_rdirplusstamp_eof = 0;
+                       }
                }
 
                /* loop through the entries packing them into the buffer */
@@ -6188,7 +6519,7 @@ noplus:
                        fhlen = rdirplus ? (1 + dnp->n_fhsize) : 0;
                        xlen = rdirplus ? (fhlen + sizeof(time_t)) : 0;
                        attrlen = rdirplus ? sizeof(struct nfs_vattr) : 0;
-                       reclen = NFS_DIRENTRY_LEN(namlen + xlen);
+                       reclen = NFS_DIRENTRY_LEN_16(namlen + xlen);
                        space_needed = reclen + attrlen;
                        space_free = nfs_dir_buf_freespace(bp, rdirplus);
                        if (space_needed > space_free) {
@@ -6219,7 +6550,7 @@ nextbuffer:
                        }
                        nmrepsave = nmrep;
                        dp->d_fileno = fileno;
-                       dp->d_namlen = namlen;
+                       dp->d_namlen = (uint16_t)namlen;
                        dp->d_reclen = reclen;
                        dp->d_type = DT_UNKNOWN;
                        nfsm_chain_get_opaque(error, &nmrep, namlen, dp->d_name);
@@ -6250,11 +6581,12 @@ nextbuffer:
                                nfsmout_if(error);
                                if (attrflag) {
                                        /* grab attributes */
-                                       error = nfs_parsefattr(&nmrep, NFS_VER3, nvattrp);
+                                       error = nfs_parsefattr(nmp, &nmrep, NFS_VER3, nvattrp);
                                        nfsmout_if(error);
                                        dp->d_type = IFTODT(VTTOIF(nvattrp->nva_type));
                                        /* fileid is already in d_fileno, so stash xid in attrs */
                                        nvattrp->nva_fileid = savedxid;
+                                       nvattrp->nva_flags |= NFS_FFLAG_FILEID_CONTAINS_XID;
                                } else {
                                        /* mark the attributes invalid */
                                        bzero(nvattrp, sizeof(struct nfs_vattr));
@@ -6263,11 +6595,11 @@ nextbuffer:
                                nfsm_chain_get_32(error, &nmrep, fhflag);
                                nfsmout_if(error);
                                if (fhflag) {
-                                       nfsm_chain_get_fh(error, &nmrep, NFS_VER3, &fh);
+                                       nfsm_chain_get_fh(error, &nmrep, NFS_VER3, fh);
                                        nfsmout_if(error);
-                                       fhlen = fh.fh_len + 1;
+                                       fhlen = fh->fh_len + 1;
                                        xlen = fhlen + sizeof(time_t);
-                                       reclen = NFS_DIRENTRY_LEN(namlen + xlen);
+                                       reclen = NFS_DIRENTRY_LEN_16(namlen + xlen);
                                        space_needed = reclen + attrlen;
                                        if (space_needed > space_free) {
                                                /* didn't actually have the room... move on to next buffer */
@@ -6275,18 +6607,19 @@ nextbuffer:
                                                goto nextbuffer;
                                        }
                                        /* pack the file handle into the record */
-                                       dp->d_name[dp->d_namlen + 1] = fh.fh_len;
-                                       bcopy(fh.fh_data, &dp->d_name[dp->d_namlen + 2], fh.fh_len);
+                                       dp->d_name[dp->d_namlen + 1] = (unsigned char)fh->fh_len; /* No truncation because fh_len's value is checked during nfsm_chain_get_fh() */
+                                       bcopy(fh->fh_data, &dp->d_name[dp->d_namlen + 2], fh->fh_len);
                                } else {
                                        /* mark the file handle invalid */
-                                       fh.fh_len = 0;
-                                       fhlen = fh.fh_len + 1;
+                                       fh->fh_len = 0;
+                                       fhlen = fh->fh_len + 1;
                                        xlen = fhlen + sizeof(time_t);
-                                       reclen = NFS_DIRENTRY_LEN(namlen + xlen);
+                                       reclen = NFS_DIRENTRY_LEN_16(namlen + xlen);
                                        bzero(&dp->d_name[dp->d_namlen + 1], fhlen);
                                }
                                *(time_t*)(&dp->d_name[dp->d_namlen + 1 + fhlen]) = now.tv_sec;
                                dp->d_reclen = reclen;
+                               nfs_rdirplus_update_node_attrs(dnp, dp, fh, nvattrp, &savedxid);
                        }
                        padstart = dp->d_name + dp->d_namlen + 1 + xlen;
                        ndbhp->ndbh_count++;
@@ -6310,6 +6643,9 @@ nextbuffer:
                        ndbhp->ndbh_flags |= (NDB_FULL | NDB_EOF);
                        nfs_node_lock_force(dnp);
                        dnp->n_eofcookie = lastcookie;
+                       if (rdirplus) {
+                               dnp->n_rdirplusstamp_eof = now.tv_sec;
+                       }
                        nfs_node_unlock(dnp);
                } else {
                        more_entries = 1;
@@ -6335,6 +6671,7 @@ nfsmout:
        }
        nfsm_chain_cleanup(&nmreq);
        nfsm_chain_cleanup(&nmrep);
+       NFS_ZFREE(nfs_fhandle_zone, fh);
        return bp_dropped ? NFSERR_DIRBUFDROPPED : error;
 }
 
@@ -6362,7 +6699,7 @@ nfs_sillyrename(
 {
        struct nfs_sillyrename *nsp;
        int error;
-       short pid;
+       pid_t pid;
        kauth_cred_t cred;
        uint32_t num;
        struct nfsmount *nmp;
@@ -6374,8 +6711,8 @@ nfs_sillyrename(
 
        nfs_name_cache_purge(dnp, np, cnp, ctx);
 
-       MALLOC_ZONE(nsp, struct nfs_sillyrename *,
-           sizeof(struct nfs_sillyrename), M_NFSREQ, M_WAITOK);
+       MALLOC(nsp, struct nfs_sillyrename *,
+           sizeof(struct nfs_sillyrename), M_TEMP, M_WAITOK);
        if (!nsp) {
                return ENOMEM;
        }
@@ -6437,7 +6774,7 @@ bad:
 bad_norele:
        nsp->nsr_cred = NOCRED;
        kauth_cred_unref(&cred);
-       FREE_ZONE(nsp, sizeof(*nsp), M_NFSREQ);
+       FREE(nsp, M_TEMP);
        return error;
 }
 
@@ -6485,7 +6822,7 @@ nfs3_lookup_rpc_async_finish(
        fhandle_t *fhp,
        struct nfs_vattr *nvap)
 {
-       int error = 0, lockerror = ENOENT, status, nfsvers, attrflag;
+       int error = 0, lockerror = ENOENT, status = 0, nfsvers, attrflag;
        u_int64_t xid;
        struct nfsmount *nmp;
        struct nfsm_chain nmrep;
@@ -6521,13 +6858,13 @@ nfs3_lookup_rpc_async_finish(
 
        /* get the attributes */
        if (nfsvers == NFS_VER3) {
-               nfsm_chain_postop_attr_get(error, &nmrep, attrflag, nvap);
+               nfsm_chain_postop_attr_get(nmp, error, &nmrep, attrflag, nvap);
                nfsm_chain_postop_attr_update(error, &nmrep, dnp, &xid);
                if (!error && !attrflag) {
                        error = nfs3_getattr_rpc(NULL, NFSTOMP(dnp), fhp->fh_data, fhp->fh_len, 0, ctx, nvap, xidp);
                }
        } else {
-               error = nfs_parsefattr(&nmrep, nfsvers, nvap);
+               error = nfs_parsefattr(nmp, &nmrep, nfsvers, nvap);
        }
 nfsmout:
        if (!lockerror) {
@@ -6556,10 +6893,10 @@ nfs_lookitup(
        int error = 0;
        nfsnode_t np, newnp = NULL;
        u_int64_t xid;
-       fhandle_t fh;
+       fhandle_t *fh;
        struct nfsmount *nmp;
-       struct nfs_vattr nvattr;
-       struct nfsreq rq, *req = &rq;
+       struct nfs_vattr *nvattr;
+       struct nfsreq *req;
 
        nmp = NFSTONMP(dnp);
        if (nfs_mount_gone(nmp)) {
@@ -6567,31 +6904,34 @@ nfs_lookitup(
        }
 
        if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXNAME) &&
-           (namelen > (int)nmp->nm_fsattr.nfsa_maxname)) {
+           (namelen > nmp->nm_fsattr.nfsa_maxname)) {
                return ENAMETOOLONG;
        }
 
-       NVATTR_INIT(&nvattr);
+       fh = zalloc(nfs_fhandle_zone);
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+       NVATTR_INIT(nvattr);
 
        /* check for lookup of "." */
        if ((name[0] == '.') && (namelen == 1)) {
                /* skip lookup, we know who we are */
-               fh.fh_len = 0;
+               fh->fh_len = 0;
                newnp = dnp;
                goto nfsmout;
        }
 
        error = nmp->nm_funcs->nf_lookup_rpc_async(dnp, name, namelen, ctx, &req);
        nfsmout_if(error);
-       error = nmp->nm_funcs->nf_lookup_rpc_async_finish(dnp, name, namelen, ctx, req, &xid, &fh, &nvattr);
+       error = nmp->nm_funcs->nf_lookup_rpc_async_finish(dnp, name, namelen, ctx, req, &xid, fh, nvattr);
        nfsmout_if(!npp || error);
 
        if (*npp) {
                np = *npp;
-               if (fh.fh_len != np->n_fhsize) {
+               if (fh->fh_len != np->n_fhsize) {
                        u_char *oldbuf = (np->n_fhsize > NFS_SMALLFH) ? np->n_fhp : NULL;
-                       if (fh.fh_len > NFS_SMALLFH) {
-                               MALLOC_ZONE(np->n_fhp, u_char *, fh.fh_len, M_NFSBIGFH, M_WAITOK);
+                       if (fh->fh_len > NFS_SMALLFH) {
+                               MALLOC(np->n_fhp, u_char *, fh->fh_len, M_NFSBIGFH, M_WAITOK);
                                if (!np->n_fhp) {
                                        np->n_fhp = oldbuf;
                                        error = ENOMEM;
@@ -6601,20 +6941,20 @@ nfs_lookitup(
                                np->n_fhp = &np->n_fh[0];
                        }
                        if (oldbuf) {
-                               FREE_ZONE(oldbuf, np->n_fhsize, M_NFSBIGFH);
+                               FREE(oldbuf, M_NFSBIGFH);
                        }
                }
-               bcopy(fh.fh_data, np->n_fhp, fh.fh_len);
-               np->n_fhsize = fh.fh_len;
+               bcopy(fh->fh_data, np->n_fhp, fh->fh_len);
+               np->n_fhsize = fh->fh_len;
                nfs_node_lock_force(np);
-               error = nfs_loadattrcache(np, &nvattr, &xid, 0);
+               error = nfs_loadattrcache(np, nvattr, &xid, 0);
                nfs_node_unlock(np);
                nfsmout_if(error);
                newnp = np;
-       } else if (NFS_CMPFH(dnp, fh.fh_data, fh.fh_len)) {
+       } else if (NFS_CMPFH(dnp, fh->fh_data, fh->fh_len)) {
                nfs_node_lock_force(dnp);
                if (dnp->n_xid <= xid) {
-                       error = nfs_loadattrcache(dnp, &nvattr, &xid, 0);
+                       error = nfs_loadattrcache(dnp, nvattr, &xid, 0);
                }
                nfs_node_unlock(dnp);
                nfsmout_if(error);
@@ -6624,8 +6964,8 @@ nfs_lookitup(
                bzero(cnp, sizeof(*cnp));
                cnp->cn_nameptr = name;
                cnp->cn_namelen = namelen;
-               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len,
-                   &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
+               error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh->fh_data, fh->fh_len,
+                   nvattr, &xid, req->r_auth, NG_MAKEENTRY, &np);
                nfsmout_if(error);
                newnp = np;
        }
@@ -6634,7 +6974,10 @@ nfsmout:
        if (npp && !*npp && !error) {
                *npp = newnp;
        }
-       NVATTR_CLEANUP(&nvattr);
+       NVATTR_CLEANUP(nvattr);
+       NFS_ZFREE(nfs_fhandle_zone, fh);
+       NFS_ZFREE(nfs_req_zone, req);
+       FREE(nvattr, M_TEMP);
        return error;
 }
 
@@ -6681,7 +7024,7 @@ nfs_dulookup_init(struct nfs_dulookup *dulp, nfsnode_t dnp, const char *name, in
                if (nmp && (nmp->nm_vers > NFS_VER2) && NMFLAG(nmp, RDIRPLUS)) {
                        /* if rdirplus, try dir buf cache lookup */
                        nfsnode_t du_np = NULL;
-                       if (!nfs_dir_buf_cache_lookup(dnp, &du_np, &dulp->du_cn, ctx, 0) && du_np) {
+                       if (!nfs_dir_buf_cache_lookup(dnp, &du_np, &dulp->du_cn, ctx, 0, NULL) && du_np) {
                                /* dir buf cache hit */
                                du_vp = NFSTOV(du_np);
                                vnode_put(du_vp);
@@ -6722,16 +7065,18 @@ nfs_dulookup_finish(struct nfs_dulookup *dulp, nfsnode_t dnp, vfs_context_t ctx)
        int error;
        nfsnode_t du_np;
        u_int64_t xid;
-       fhandle_t fh;
-       struct nfs_vattr nvattr;
+       fhandle_t *fh;
+       struct nfs_vattr *nvattr;
 
        if (!nmp || !(dulp->du_flags & NFS_DULOOKUP_INPROG)) {
                goto out;
        }
 
-       NVATTR_INIT(&nvattr);
+       fh = zalloc(nfs_fhandle_zone);
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
+       NVATTR_INIT(nvattr);
        error = nmp->nm_funcs->nf_lookup_rpc_async_finish(dnp, dulp->du_cn.cn_nameptr,
-           dulp->du_cn.cn_namelen, ctx, &dulp->du_req, &xid, &fh, &nvattr);
+           dulp->du_cn.cn_namelen, ctx, &dulp->du_req, &xid, fh, nvattr);
        dulp->du_flags &= ~NFS_DULOOKUP_INPROG;
        if (error == ENOENT) {
                /* add a negative entry in the name cache */
@@ -6740,14 +7085,16 @@ nfs_dulookup_finish(struct nfs_dulookup *dulp, nfsnode_t dnp, vfs_context_t ctx)
                dnp->n_flag |= NNEGNCENTRIES;
                nfs_node_unlock(dnp);
        } else if (!error) {
-               error = nfs_nget(NFSTOMP(dnp), dnp, &dulp->du_cn, fh.fh_data, fh.fh_len,
-                   &nvattr, &xid, dulp->du_req.r_auth, NG_MAKEENTRY, &du_np);
+               error = nfs_nget(NFSTOMP(dnp), dnp, &dulp->du_cn, fh->fh_data, fh->fh_len,
+                   nvattr, &xid, dulp->du_req.r_auth, NG_MAKEENTRY, &du_np);
                if (!error) {
                        nfs_node_unlock(du_np);
                        vnode_put(NFSTOV(du_np));
                }
        }
-       NVATTR_CLEANUP(&nvattr);
+       NVATTR_CLEANUP(nvattr);
+       NFS_ZFREE(nfs_fhandle_zone, fh);
+       FREE(nvattr, M_TEMP);
 out:
        if (dulp->du_flags & NFS_DULOOKUP_INPROG) {
                nfs_request_async_cancel(&dulp->du_req);
@@ -6770,8 +7117,8 @@ nfs3_commit_rpc(
        uint64_t wverf)
 {
        struct nfsmount *nmp;
-       int error = 0, lockerror, status, wccpostattr = 0, nfsvers;
-       struct timespec premtime = { 0, 0 };
+       int error = 0, lockerror, status = 0, wccpostattr = 0, nfsvers;
+       struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 };
        u_int64_t xid, newwverf;
        uint32_t count32;
        struct nfsm_chain nmreq, nmrep;
@@ -6785,12 +7132,7 @@ nfs3_commit_rpc(
                return 0;
        }
        nfsvers = nmp->nm_vers;
-
-       if (count > UINT32_MAX) {
-               count32 = 0;
-       } else {
-               count32 = count;
-       }
+       count32 = count > UINT32_MAX ? 0 : (uint32_t)count;
 
        nfsm_chain_null(&nmreq);
        nfsm_chain_null(&nmrep);
@@ -6875,7 +7217,7 @@ nfs3_pathconf_rpc(
        vfs_context_t ctx)
 {
        u_int64_t xid;
-       int error = 0, lockerror, status, nfsvers;
+       int error = 0, lockerror, status = 0, nfsvers;
        struct nfsm_chain nmreq, nmrep;
        struct nfsmount *nmp = NFSTONMP(np);
        uint32_t val = 0;
@@ -7004,8 +7346,8 @@ nfs_vnop_pathconf(
                if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR) {
                        break;  /* Yes */
                }
-       /* No... so just return an error */
-       /* FALLTHROUGH */
+               /* No... so just return an error */
+               return EINVAL;
        default:
                /* don't bother contacting the server if we know the answer */
                return EINVAL;
@@ -7017,8 +7359,8 @@ nfs_vnop_pathconf(
 
        lck_mtx_lock(&nmp->nm_lock);
        if (nmp->nm_vers == NFS_VER3) {
-               if (!(nmp->nm_state & NFSSTA_GOTPATHCONF)) {
-                       /* no pathconf info cached */
+               if (!(nmp->nm_state & NFSSTA_GOTPATHCONF) || (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS) && nmp->nm_dnp != np)) {
+                       /* no pathconf info cached OR we were asked for non-root pathconf and filesystem does not support FSF_HOMOGENEOUS */
                        lck_mtx_unlock(&nmp->nm_lock);
                        NFS_CLEAR_ATTRIBUTES(nfsa.nfsa_bitmap);
                        error = nfs3_pathconf_rpc(np, &nfsa, ap->a_context);
@@ -7039,7 +7381,9 @@ nfs_vnop_pathconf(
                } else {
                        nfsap = &nmp->nm_fsattr;
                }
-       } else if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS)) {
+       }
+#if CONFIG_NFS4
+       else if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS)) {
                /* no pathconf info cached */
                lck_mtx_unlock(&nmp->nm_lock);
                NFS_CLEAR_ATTRIBUTES(nfsa.nfsa_bitmap);
@@ -7053,16 +7397,19 @@ nfs_vnop_pathconf(
                }
                lck_mtx_lock(&nmp->nm_lock);
                nfsap = &nfsa;
-       } else {
+       }
+#endif
+       else {
                nfsap = &nmp->nm_fsattr;
        }
-
        switch (ap->a_name) {
        case _PC_LINK_MAX:
                if (NFS_BITMAP_ISSET(nfsap->nfsa_bitmap, NFS_FATTR_MAXLINK)) {
                        *ap->a_retval = nfsap->nfsa_maxlink;
+#if CONFIG_NFS4
                } else if ((nmp->nm_vers == NFS_VER4) && NFS_BITMAP_ISSET(np->n_vattr.nva_bitmap, NFS_FATTR_MAXLINK)) {
                        *ap->a_retval = np->n_vattr.nva_maxlink;
+#endif
                } else {
                        error = EINVAL;
                }
@@ -7390,14 +7737,15 @@ nfs_vnop_ioctl(
        vfs_context_t ctx = ap->a_context;
        vnode_t vp = ap->a_vp;
        struct nfsmount *mp = VTONMP(vp);
-       struct user_nfs_gss_principal gprinc = {};
-       uint32_t len;
        int error = ENOTTY;
+#if CONFIG_NFS_GSS
+       struct user_nfs_gss_principal gprinc = {};
+       size_t len;
+#endif
 
        if (mp == NULL) {
                return ENXIO;
        }
-
        switch (ap->a_command) {
        case F_FULLFSYNC:
                if (vnode_vfsisrdonly(vp)) {
@@ -7405,6 +7753,7 @@ nfs_vnop_ioctl(
                }
                error = nfs_flush(VTONFS(vp), MNT_WAIT, vfs_context_thread(ctx), 0);
                break;
+#if CONFIG_NFS_GSS
        case NFS_IOC_DESTROY_CRED:
                if (!auth_is_kerberized(mp->nm_auth)) {
                        return ENOTSUP;
@@ -7429,7 +7778,7 @@ nfs_vnop_ioctl(
                        gprinc.nametype = tp->nametype;
                        gprinc.principal = CAST_USER_ADDR_T(tp->principal);
                }
-               NFS_DBG(NFS_FAC_GSS, 7, "Enter NFS_FSCTL_SET_CRED (64-bit=%d): principal length %d name type %d usr pointer 0x%llx\n", vfs_context_is64bit(ctx), gprinc.princlen, gprinc.nametype, (unsigned long long)gprinc.principal);
+               NFS_DBG(NFS_FAC_GSS, 7, "Enter NFS_FSCTL_SET_CRED (64-bit=%d): principal length %zu name type %d usr pointer 0x%llx\n", vfs_context_is64bit(ctx), gprinc.princlen, gprinc.nametype, gprinc.principal);
                if (gprinc.princlen > MAXPATHLEN) {
                        return EINVAL;
                }
@@ -7438,9 +7787,10 @@ nfs_vnop_ioctl(
                if (p == NULL) {
                        return ENOMEM;
                }
-               error = copyin(gprinc.principal, p, gprinc.princlen);
+               assert((user_addr_t)gprinc.principal == gprinc.principal);
+               error = copyin((user_addr_t)gprinc.principal, p, gprinc.princlen);
                if (error) {
-                       NFS_DBG(NFS_FAC_GSS, 7, "NFS_FSCTL_SET_CRED could not copy in princiapl data of len %d: %d\n",
+                       NFS_DBG(NFS_FAC_GSS, 7, "NFS_FSCTL_SET_CRED could not copy in princiapl data of len %zu: %d\n",
                            gprinc.princlen, error);
                        FREE(p, M_TEMP);
                        return error;
@@ -7473,7 +7823,8 @@ nfs_vnop_ioctl(
                        upp->nametype = gprinc.nametype;
                        upp->flags = gprinc.flags;
                        if (gprinc.principal) {
-                               error = copyout((void *)gprinc.principal, upp->principal, len);
+                               assert((user_addr_t)upp->principal == upp->principal);
+                               error = copyout((void *)gprinc.principal, (user_addr_t)upp->principal, len);
                        } else {
                                upp->principal = USER_ADDR_NULL;
                        }
@@ -7493,12 +7844,15 @@ nfs_vnop_ioctl(
                        }
                }
                if (error) {
-                       NFS_DBG(NFS_FAC_GSS, 7, "NFS_FSCTL_GET_CRED could not copy out princiapl data of len %d: %d\n",
+                       NFS_DBG(NFS_FAC_GSS, 7, "NFS_FSCTL_GET_CRED could not copy out princiapl data of len %zu: %d\n",
                            gprinc.princlen, error);
                }
                if (gprinc.principal) {
-                       FREE(gprinc.principal, M_TEMP);
+                       void *ptr = (void *)gprinc.principal;
+                       gprinc.principal = 0;
+                       FREE(ptr, M_TEMP);
                }
+#endif /* CONFIG_NFS_GSS */
        }
 
        return error;
@@ -7542,9 +7896,9 @@ nfs_vnop_pagein(
 {
        vnode_t vp = ap->a_vp;
        upl_t pl = ap->a_pl;
-       size_t size = ap->a_size;
+       upl_size_t size = (upl_size_t)ap->a_size;
        off_t f_offset = ap->a_f_offset;
-       vm_offset_t pl_offset = ap->a_pl_offset;
+       upl_offset_t pl_offset = ap->a_pl_offset;
        int flags = ap->a_flags;
        thread_t thd;
        kauth_cred_t cred;
@@ -7561,7 +7915,10 @@ nfs_vnop_pagein(
 #define MAXPAGINGREQS   16      /* max outstanding RPCs for pagein/pageout */
        struct nfsreq *req[MAXPAGINGREQS];
        int nextsend, nextwait;
-       uint32_t stategenid = 0, restart = 0;
+#if CONFIG_NFS4
+       uint32_t stategenid = 0;
+#endif
+       uint32_t restart = 0;
        kern_return_t kret;
 
        FSDBG(322, np, f_offset, size, flags);
@@ -7570,7 +7927,7 @@ nfs_vnop_pagein(
        }
 
        if (size <= 0) {
-               printf("nfs_pagein: invalid size %ld", size);
+               printf("nfs_pagein: invalid size %u", size);
                if (!nofreeupl) {
                        (void) ubc_upl_abort_range(pl, pl_offset, size, 0);
                }
@@ -7611,9 +7968,11 @@ nfs_vnop_pagein(
        ioaddr += pl_offset;
 
 tryagain:
+#if CONFIG_NFS4
        if (nmp->nm_vers >= NFS_VER4) {
                stategenid = nmp->nm_stategenid;
        }
+#endif
        txsize = rxsize = size;
        txoffset = f_offset;
        rxaddr = ioaddr;
@@ -7649,6 +8008,7 @@ tryagain:
                        error = nmp->nm_funcs->nf_read_rpc_async_finish(np, req[nextwait], uio, &retsize, NULL);
                        req[nextwait] = NULL;
                        nextwait = (nextwait + 1) % MAXPAGINGREQS;
+#if CONFIG_NFS4
                        if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error)) {
                                lck_mtx_lock(&nmp->nm_lock);
                                if ((error != NFSERR_GRACE) && (stategenid == nmp->nm_stategenid)) {
@@ -7659,13 +8019,14 @@ tryagain:
                                restart++;
                                goto cancel;
                        }
+#endif
                        if (error) {
                                FSDBG(322, uio_offset(uio), uio_resid(uio), error, -1);
                                break;
                        }
                        if (retsize < iosize) {
                                /* Just zero fill the rest of the valid area. */
-                               int zcnt = iosize - retsize;
+                               size_t zcnt = iosize - retsize;
                                bzero((char *)rxaddr + retsize, zcnt);
                                FSDBG(324, uio_offset(uio), retsize, zcnt, rxaddr);
                                uio_update(uio, zcnt);
@@ -7681,7 +8042,9 @@ tryagain:
        restart = 0;
 
        if (error) {
+#if CONFIG_NFS4
 cancel:
+#endif
                /* cancel any outstanding requests */
                while (req[nextwait]) {
                        nfs_request_async_cancel(req[nextwait]);
@@ -7708,9 +8071,15 @@ cancel:
 
        if (!nofreeupl) {
                if (error) {
-                       ubc_upl_abort_range(pl, pl_offset, size,
-                           UPL_ABORT_ERROR |
-                           UPL_ABORT_FREE_ON_EMPTY);
+                       /*
+                        * See comment in vnode_pagein() on handling EAGAIN, even though UPL_NOCOMMIT flag
+                        * is not set, we will not abort this upl, since VM subsystem will handle it.
+                        */
+                       if (error != EAGAIN && error != EPERM) {
+                               ubc_upl_abort_range(pl, pl_offset, size,
+                                   UPL_ABORT_ERROR |
+                                   UPL_ABORT_FREE_ON_EMPTY);
+                       }
                } else {
                        ubc_upl_commit_range(pl, pl_offset, size,
                            UPL_COMMIT_CLEAR_DIRTY |
@@ -7865,9 +8234,10 @@ nfs_vnop_pageout(
 {
        vnode_t vp = ap->a_vp;
        upl_t pl = ap->a_pl;
-       size_t size = ap->a_size;
+       upl_size_t size = (upl_size_t)ap->a_size;
        off_t f_offset = ap->a_f_offset;
-       vm_offset_t pl_offset = ap->a_pl_offset;
+       upl_offset_t pl_offset = ap->a_pl_offset;
+       upl_offset_t pgsize;
        int flags = ap->a_flags;
        nfsnode_t np = VTONFS(vp);
        thread_t thd;
@@ -7881,11 +8251,14 @@ nfs_vnop_pageout(
        uio_t auio;
        char uio_buf[UIO_SIZEOF(1)];
        int nofreeupl = flags & UPL_NOCOMMIT;
-       size_t nmwsize, biosize, iosize, pgsize, txsize, rxsize, xsize, remsize;
+       size_t nmwsize, biosize, iosize, remsize;
        struct nfsreq *req[MAXPAGINGREQS];
        int nextsend, nextwait, wverfset, commit;
-       uint64_t wverf, wverf2;
-       uint32_t stategenid = 0, vrestart = 0, restart = 0, vrestarts = 0, restarts = 0;
+       uint64_t wverf, wverf2, xsize, txsize, rxsize;
+#if CONFIG_NFS4
+       uint32_t stategenid = 0;
+#endif
+       uint32_t vrestart = 0, restart = 0, vrestarts = 0, restarts = 0;
        kern_return_t kret;
 
        FSDBG(323, f_offset, size, pl, pl_offset);
@@ -7895,7 +8268,7 @@ nfs_vnop_pageout(
        }
 
        if (size <= 0) {
-               printf("nfs_pageout: invalid size %ld", size);
+               printf("nfs_pageout: invalid size %u", size);
                if (!nofreeupl) {
                        ubc_upl_abort_range(pl, pl_offset, size, 0);
                }
@@ -7921,7 +8294,7 @@ nfs_vnop_pageout(
                off = f_offset + iosize;
                /* need make sure we do things on block boundaries */
                xsize = biosize - (off % biosize);
-               if (off + xsize > f_offset + size) {
+               if (off + (off_t)xsize > f_offset + (off_t)size) {
                        xsize = f_offset + size - off;
                }
                lbn = (daddr64_t)(off / biosize);
@@ -7990,10 +8363,10 @@ nfs_vnop_pageout(
                                    (bp->nb_dirtyend > end)) {
                                        /* clip dirty region, if necessary */
                                        if (bp->nb_dirtyoff < start) {
-                                               bp->nb_dirtyend = min(bp->nb_dirtyend, start);
+                                               bp->nb_dirtyend = MIN(bp->nb_dirtyend, start);
                                        }
                                        if (bp->nb_dirtyend > end) {
-                                               bp->nb_dirtyoff = max(bp->nb_dirtyoff, end);
+                                               bp->nb_dirtyoff = MAX(bp->nb_dirtyoff, end);
                                        }
                                        FSDBG(323, bp, bp->nb_dirtyoff, bp->nb_dirtyend, 0xd00dee00);
                                        /* we're leaving this block dirty */
@@ -8059,7 +8432,7 @@ nfs_vnop_pageout(
                xsize = size;
        }
 
-       pgsize = round_page_64(xsize);
+       pgsize = (upl_offset_t)round_page_64(xsize);
        if ((size > pgsize) && !nofreeupl) {
                ubc_upl_abort_range(pl, pl_offset + pgsize, size - pgsize,
                    UPL_ABORT_FREE_ON_EMPTY);
@@ -8071,8 +8444,8 @@ nfs_vnop_pageout(
         * releasing it in the VM page cache
         */
        if ((u_quad_t)f_offset < np->n_size && (u_quad_t)f_offset + size > np->n_size) {
-               size_t io = np->n_size - f_offset;
-               bzero((caddr_t)(ioaddr + io), size - io);
+               uint64_t io = np->n_size - f_offset;
+               NFS_BZERO((caddr_t)(ioaddr + io), size - io);
                FSDBG(321, np->n_size, f_offset, f_offset + io, size - io);
        }
        nfs_data_unlock_noupdate(np);
@@ -8081,9 +8454,11 @@ nfs_vnop_pageout(
            &uio_buf, sizeof(uio_buf));
 
 tryagain:
+#if CONFIG_NFS4
        if (nmp->nm_vers >= NFS_VER4) {
                stategenid = nmp->nm_stategenid;
        }
+#endif
        wverf = wverf2 = wverfset = 0;
        txsize = rxsize = xsize;
        txoffset = rxoffset = f_offset;
@@ -8099,7 +8474,7 @@ tryagain:
                }
                /* send requests while we need to and have available slots */
                while ((txsize > 0) && (req[nextsend] == NULL)) {
-                       iosize = MIN(nmwsize, txsize);
+                       iosize = (size_t)MIN(nmwsize, txsize);
                        uio_reset(auio, txoffset, UIO_SYSSPACE, UIO_WRITE);
                        uio_addiov(auio, CAST_USER_ADDR_T(txaddr), iosize);
                        FSDBG(323, uio_offset(auio), iosize, txaddr, txsize);
@@ -8124,7 +8499,7 @@ tryagain:
                }
                /* wait while we need to and break out if more requests to send */
                while ((rxsize > 0) && req[nextwait]) {
-                       iosize = remsize = MIN(nmwsize, rxsize);
+                       iosize = remsize = (size_t)MIN(nmwsize, rxsize);
                        error = nmp->nm_funcs->nf_write_rpc_async_finish(np, req[nextwait], &iomode, &iosize, &wverf2);
                        req[nextwait] = NULL;
                        nextwait = (nextwait + 1) % MAXPAGINGREQS;
@@ -8132,6 +8507,7 @@ tryagain:
                        nfs_node_lock_force(np);
                        np->n_numoutput--;
                        nfs_node_unlock(np);
+#if CONFIG_NFS4
                        if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error)) {
                                lck_mtx_lock(&nmp->nm_lock);
                                if ((error != NFSERR_GRACE) && (stategenid == nmp->nm_stategenid)) {
@@ -8142,6 +8518,7 @@ tryagain:
                                restart = 1;
                                goto cancel;
                        }
+#endif
                        if (error) {
                                FSDBG(323, rxoffset, rxsize, error, -1);
                                break;
@@ -8169,6 +8546,7 @@ tryagain:
                                uio_addiov(auio, CAST_USER_ADDR_T(rxaddr), remsize);
                                iomode = NFS_WRITE_UNSTABLE;
                                error = nfs_write_rpc2(np, auio, thd, cred, &iomode, &wverf2);
+#if CONFIG_NFS4
                                if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error)) {
                                        NP(np, "nfs_vnop_pageout: restart: error %d", error);
                                        lck_mtx_lock(&nmp->nm_lock);
@@ -8180,6 +8558,7 @@ tryagain:
                                        restart = 1;
                                        goto cancel;
                                }
+#endif
                                if (error) {
                                        FSDBG(323, rxoffset, rxsize, error, -1);
                                        break;
@@ -8394,7 +8773,7 @@ nfs_vnop_monitor(
                /* This vnode is no longer being monitored, make sure we're not tracking it. */
                /* Wait for any in-progress getattr to complete first. */
                while (np->n_mflag & NMMONSCANINPROG) {
-                       struct timespec ts = { 1, 0 };
+                       struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
                        np->n_mflag |= NMMONSCANWANT;
                        msleep(&np->n_mflag, &nmp->nm_lock, PZERO - 1, "nfswaitmonscan", &ts);
                }
@@ -8415,7 +8794,7 @@ void
 nfs_vnode_notify(nfsnode_t np, uint32_t events)
 {
        struct nfsmount *nmp = NFSTONMP(np);
-       struct nfs_vattr nvattr;
+       struct nfs_vattr *nvattr;
        struct vnode_attr vattr, *vap = NULL;
        struct timeval now;
 
@@ -8428,18 +8807,22 @@ nfs_vnode_notify(nfsnode_t np, uint32_t events)
        events |= np->n_events;
        np->n_events = 0;
        np->n_evtstamp = now.tv_sec;
+       MALLOC(nvattr, struct nfs_vattr *, sizeof(*nvattr), M_TEMP, M_WAITOK);
 
        vfs_get_notify_attributes(&vattr);
-       if (!nfs_getattrcache(np, &nvattr, 0)) {
+       if (!nfs_getattrcache(np, nvattr, 0)) {
                vap = &vattr;
                VATTR_INIT(vap);
 
                VATTR_RETURN(vap, va_fsid, vfs_statfs(nmp->nm_mountp)->f_fsid.val[0]);
-               VATTR_RETURN(vap, va_fileid, nvattr.nva_fileid);
-               VATTR_RETURN(vap, va_mode, nvattr.nva_mode);
-               VATTR_RETURN(vap, va_uid, nvattr.nva_uid);
-               VATTR_RETURN(vap, va_gid, nvattr.nva_gid);
-               VATTR_RETURN(vap, va_nlink, nvattr.nva_nlink);
+               VATTR_RETURN(vap, va_fileid, nvattr->nva_fileid);
+               VATTR_RETURN(vap, va_mode, nvattr->nva_mode);
+               VATTR_RETURN(vap, va_uid, nvattr->nva_uid);
+               VATTR_RETURN(vap, va_gid, nvattr->nva_gid);
+               VATTR_RETURN(vap, va_nlink, nvattr->nva_nlink);
        }
        vnode_notify(NFSTOV(np), events, vap);
+       FREE(nvattr, M_TEMP);
 }
+
+#endif /* CONFIG_NFS_CLIENT */