]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_vnops.c
xnu-792.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_vnops.c
index 882ed59fe681b848d03f6e0ee8f58c46e260c446..c858df06191c8751534a4a5f842bd11645fb90cc 100644 (file)
@@ -1,24 +1,21 @@
 /*
- * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
 #include <sys/kernel.h>
 #include <sys/systm.h>
 #include <sys/resourcevar.h>
-#include <sys/proc.h>
-#include <sys/mount.h>
+#include <sys/proc_internal.h>
+#include <sys/kauth.h>
+#include <sys/mount_internal.h>
 #include <sys/malloc.h>
-#include <sys/mbuf.h>
+#include <sys/kpi_mbuf.h>
 #include <sys/conf.h>
-#include <sys/namei.h>
-#include <sys/vnode.h>
+#include <sys/vnode_internal.h>
 #include <sys/dirent.h>
 #include <sys/fcntl.h>
 #include <sys/lockf.h>
-#include <sys/ubc.h>
+#include <sys/ubc_internal.h>
+#include <sys/attr.h>
+#include <sys/signalvar.h>
+#include <sys/uio_internal.h>
 
 #include <vfs/vfs_support.h>
 
 #include <sys/vm.h>
-#include <machine/spl.h>
-#include <vm/vm_pageout.h>
 
 #include <sys/time.h> 
 #include <kern/clock.h>
+#include <libkern/OSAtomic.h>
 
 #include <miscfs/fifofs/fifo.h>
 #include <miscfs/specfs/specdev.h>
 #include <nfs/nfs_lock.h>
 #include <nfs/xdr_subs.h>
 #include <nfs/nfsm_subs.h>
-#include <nfs/nqnfs.h>
 
 #include <net/if.h>
 #include <netinet/in.h>
        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
                (int)(B), (int)(C), (int)(D), (int)(E), 0)
 
-#define        TRUE    1
-#define        FALSE   0
-
-#define NFS_FREE_PNBUF(CNP) \
-       do { \
-               char *tmp = (CNP)->cn_pnbuf; \
-               (CNP)->cn_pnbuf = NULL; \
-               (CNP)->cn_flags &= ~HASBUF; \
-               FREE_ZONE(tmp, (CNP)->cn_pnlen, M_NAMEI); \
-       } while (0)
-
-
-static int     nfsspec_read __P((struct vop_read_args *));
-static int     nfsspec_write __P((struct vop_write_args *));
-static int     nfsfifo_read __P((struct vop_read_args *));
-static int     nfsfifo_write __P((struct vop_write_args *));
-static int     nfsspec_close __P((struct vop_close_args *));
-static int     nfsfifo_close __P((struct vop_close_args *));
-#define nfs_poll vop_nopoll
-static int     nfs_ioctl __P((struct vop_ioctl_args *));
-static int     nfs_select __P((struct vop_select_args *));
-static int     nfs_flush __P((struct vnode *,struct ucred *,int,struct proc *,int));
-static int     nfs_setattrrpc __P((struct vnode *,struct vattr *,struct ucred *,struct proc *));
-static int     nfs_lookup __P((struct vop_lookup_args *));
-static int     nfs_create __P((struct vop_create_args *));
-static int     nfs_mknod __P((struct vop_mknod_args *));
-static int     nfs_open __P((struct vop_open_args *));
-static int     nfs_close __P((struct vop_close_args *));
-static int     nfs_access __P((struct vop_access_args *));
-static int     nfs_getattr __P((struct vop_getattr_args *));
-static int     nfs_setattr __P((struct vop_setattr_args *));
-static int     nfs_read __P((struct vop_read_args *));
-static int     nfs_mmap __P((struct vop_mmap_args *));
-static int     nfs_fsync __P((struct vop_fsync_args *));
-static int     nfs_remove __P((struct vop_remove_args *));
-static int     nfs_link __P((struct vop_link_args *));
-static int     nfs_rename __P((struct vop_rename_args *));
-static int     nfs_mkdir __P((struct vop_mkdir_args *));
-static int     nfs_rmdir __P((struct vop_rmdir_args *));
-static int     nfs_symlink __P((struct vop_symlink_args *));
-static int     nfs_readdir __P((struct vop_readdir_args *));
-static int     nfs_bmap __P((struct vop_bmap_args *));
-static int     nfs_lookitup __P((struct vnode *,char *,int,struct ucred *,struct proc *,struct nfsnode **));
-static int     nfs_sillyrename __P((struct vnode *,struct vnode *,struct componentname *));
-static int     nfsspec_access __P((struct vop_access_args *));
-static int     nfs_readlink __P((struct vop_readlink_args *));
-static int     nfs_print __P((struct vop_print_args *));
-static int     nfs_pathconf __P((struct vop_pathconf_args *));
-static int     nfs_advlock __P((struct vop_advlock_args *));
-static int     nfs_blkatoff __P((struct vop_blkatoff_args *));
-static int     nfs_valloc __P((struct vop_valloc_args *));
-static int     nfs_vfree __P((struct vop_vfree_args *));
-static int     nfs_truncate __P((struct vop_truncate_args *));
-static int     nfs_update __P((struct vop_update_args *));
-static int     nfs_pagein __P((struct vop_pagein_args *));
-static int     nfs_pageout __P((struct vop_pageout_args *));
-static int nfs_blktooff __P((struct vop_blktooff_args *));
-static int nfs_offtoblk __P((struct vop_offtoblk_args *));
-static int nfs_cmap __P((struct vop_cmap_args *));
+static int     nfsspec_read(struct vnop_read_args *);
+static int     nfsspec_write(struct vnop_write_args *);
+static int     nfsfifo_read(struct vnop_read_args *);
+static int     nfsfifo_write(struct vnop_write_args *);
+static int     nfsspec_close(struct vnop_close_args *);
+static int     nfsfifo_close(struct vnop_close_args *);
+static int     nfs_ioctl(struct vnop_ioctl_args *);
+static int     nfs_select(struct vnop_select_args *);
+static int     nfs_setattrrpc(vnode_t,struct vnode_attr *,kauth_cred_t,proc_t);
+static int     nfs_lookup(struct vnop_lookup_args *);
+static int     nfs_create(struct vnop_create_args *);
+static int     nfs_mknod(struct vnop_mknod_args *);
+static int     nfs_open(struct vnop_open_args *);
+static int     nfs_close(struct vnop_close_args *);
+static int     nfs_access(struct vnop_access_args *);
+static int     nfs_vnop_getattr(struct vnop_getattr_args *);
+static int     nfs_setattr(struct vnop_setattr_args *);
+static int     nfs_read(struct vnop_read_args *);
+static int     nfs_mmap(struct vnop_mmap_args *);
+static int     nfs_fsync(struct vnop_fsync_args *);
+static int     nfs_remove(struct vnop_remove_args *);
+static int     nfs_link(struct vnop_link_args *);
+static int     nfs_rename(struct vnop_rename_args *);
+static int     nfs_mkdir(struct vnop_mkdir_args *);
+static int     nfs_rmdir(struct vnop_rmdir_args *);
+static int     nfs_symlink(struct vnop_symlink_args *);
+static int     nfs_readdir(struct vnop_readdir_args *);
+static int     nfs_lookitup(vnode_t,char *,int,kauth_cred_t,proc_t,struct nfsnode **);
+static int     nfs_sillyrename(vnode_t,vnode_t,struct componentname *,kauth_cred_t,proc_t);
+static int     nfs_readlink(struct vnop_readlink_args *);
+static int     nfs_pathconf(struct vnop_pathconf_args *);
+static int     nfs_advlock(struct vnop_advlock_args *);
+static int     nfs_pagein(struct vnop_pagein_args *);
+static int     nfs_pageout(struct vnop_pageout_args *);
+static int nfs_blktooff(struct vnop_blktooff_args *);
+static int nfs_offtoblk(struct vnop_offtoblk_args *);
+static int nfs_blockmap(struct vnop_blockmap_args *);
 
 /*
  * Global vfs data structures for nfs
  */
-vop_t **nfsv2_vnodeop_p;
+vnop_t **nfsv2_vnodeop_p;
 static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
-       { &vop_default_desc, (vop_t *)vn_default_error },
-       { &vop_lookup_desc, (vop_t *)nfs_lookup },      /* lookup */
-       { &vop_create_desc, (vop_t *)nfs_create },      /* create */
-       { &vop_mknod_desc, (vop_t *)nfs_mknod },        /* mknod */
-       { &vop_open_desc, (vop_t *)nfs_open },          /* open */
-       { &vop_close_desc, (vop_t *)nfs_close },        /* close */
-       { &vop_access_desc, (vop_t *)nfs_access },      /* access */
-       { &vop_getattr_desc, (vop_t *)nfs_getattr },    /* getattr */
-       { &vop_setattr_desc, (vop_t *)nfs_setattr },    /* setattr */
-       { &vop_read_desc, (vop_t *)nfs_read },          /* read */
-       { &vop_write_desc, (vop_t *)nfs_write },        /* write */
-       { &vop_lease_desc, (vop_t *)nfs_lease_check },  /* lease */
-       { &vop_ioctl_desc, (vop_t *)nfs_ioctl },        /* ioctl */
-       { &vop_select_desc, (vop_t *)nfs_select },      /* select */
-       { &vop_revoke_desc, (vop_t *)nfs_revoke },      /* revoke */
-       { &vop_mmap_desc, (vop_t *)nfs_mmap },          /* mmap */
-       { &vop_fsync_desc, (vop_t *)nfs_fsync },        /* fsync */
-       { &vop_seek_desc, (vop_t *)nfs_seek },          /* seek */
-       { &vop_remove_desc, (vop_t *)nfs_remove },      /* remove */
-       { &vop_link_desc, (vop_t *)nfs_link },          /* link */
-       { &vop_rename_desc, (vop_t *)nfs_rename },      /* rename */
-       { &vop_mkdir_desc, (vop_t *)nfs_mkdir },        /* mkdir */
-       { &vop_rmdir_desc, (vop_t *)nfs_rmdir },        /* rmdir */
-       { &vop_symlink_desc, (vop_t *)nfs_symlink },    /* symlink */
-       { &vop_readdir_desc, (vop_t *)nfs_readdir },    /* readdir */
-       { &vop_readlink_desc, (vop_t *)nfs_readlink },  /* readlink */
-       { &vop_abortop_desc, (vop_t *)nop_abortop },    /* abortop */
-       { &vop_inactive_desc, (vop_t *)nfs_inactive },  /* inactive */
-       { &vop_reclaim_desc, (vop_t *)nfs_reclaim },    /* reclaim */
-       { &vop_lock_desc, (vop_t *)nfs_lock },          /* lock */
-       { &vop_unlock_desc, (vop_t *)nfs_unlock },      /* unlock */
-       { &vop_bmap_desc, (vop_t *)nfs_bmap },          /* bmap */
-       { &vop_strategy_desc, (vop_t *)err_strategy },  /* strategy */
-       { &vop_print_desc, (vop_t *)nfs_print },        /* print */
-       { &vop_islocked_desc, (vop_t *)nfs_islocked },  /* islocked */
-       { &vop_pathconf_desc, (vop_t *)nfs_pathconf },  /* pathconf */
-       { &vop_advlock_desc, (vop_t *)nfs_advlock },    /* advlock */
-       { &vop_blkatoff_desc, (vop_t *)nfs_blkatoff },  /* blkatoff */
-       { &vop_valloc_desc, (vop_t *)nfs_valloc },      /* valloc */
-       { &vop_reallocblks_desc, (vop_t *)nfs_reallocblks },    /* reallocblks */
-       { &vop_vfree_desc, (vop_t *)nfs_vfree },        /* vfree */
-       { &vop_truncate_desc, (vop_t *)nfs_truncate },  /* truncate */
-       { &vop_update_desc, (vop_t *)nfs_update },      /* update */
-       { &vop_bwrite_desc, (vop_t *)err_bwrite },      /* bwrite */
-       { &vop_pagein_desc, (vop_t *)nfs_pagein },              /* Pagein */
-       { &vop_pageout_desc, (vop_t *)nfs_pageout },            /* Pageout */
-       { &vop_copyfile_desc, (vop_t *)err_copyfile },          /* Copyfile */
-       { &vop_blktooff_desc, (vop_t *)nfs_blktooff },          /* blktooff */
-       { &vop_offtoblk_desc, (vop_t *)nfs_offtoblk },          /* offtoblk */
-       { &vop_cmap_desc, (vop_t *)nfs_cmap },          /* cmap */
+       { &vnop_default_desc, (vnop_t *)vn_default_error },
+       { &vnop_lookup_desc, (vnop_t *)nfs_lookup },            /* lookup */
+       { &vnop_create_desc, (vnop_t *)nfs_create },            /* create */
+       { &vnop_mknod_desc, (vnop_t *)nfs_mknod },              /* mknod */
+       { &vnop_open_desc, (vnop_t *)nfs_open },                /* open */
+       { &vnop_close_desc, (vnop_t *)nfs_close },              /* close */
+       { &vnop_access_desc, (vnop_t *)nfs_access },            /* access */
+       { &vnop_getattr_desc, (vnop_t *)nfs_vnop_getattr },     /* getattr */
+       { &vnop_setattr_desc, (vnop_t *)nfs_setattr },          /* setattr */
+       { &vnop_read_desc, (vnop_t *)nfs_read },                /* read */
+       { &vnop_write_desc, (vnop_t *)nfs_write },              /* write */
+       { &vnop_ioctl_desc, (vnop_t *)nfs_ioctl },              /* ioctl */
+       { &vnop_select_desc, (vnop_t *)nfs_select },            /* select */
+       { &vnop_revoke_desc, (vnop_t *)nfs_revoke },            /* revoke */
+       { &vnop_mmap_desc, (vnop_t *)nfs_mmap },                /* mmap */
+       { &vnop_fsync_desc, (vnop_t *)nfs_fsync },              /* fsync */
+       { &vnop_remove_desc, (vnop_t *)nfs_remove },            /* remove */
+       { &vnop_link_desc, (vnop_t *)nfs_link },                /* link */
+       { &vnop_rename_desc, (vnop_t *)nfs_rename },            /* rename */
+       { &vnop_mkdir_desc, (vnop_t *)nfs_mkdir },              /* mkdir */
+       { &vnop_rmdir_desc, (vnop_t *)nfs_rmdir },              /* rmdir */
+       { &vnop_symlink_desc, (vnop_t *)nfs_symlink },          /* symlink */
+       { &vnop_readdir_desc, (vnop_t *)nfs_readdir },          /* readdir */
+       { &vnop_readlink_desc, (vnop_t *)nfs_readlink },        /* readlink */
+       { &vnop_inactive_desc, (vnop_t *)nfs_inactive },        /* inactive */
+       { &vnop_reclaim_desc, (vnop_t *)nfs_reclaim },          /* reclaim */
+       { &vnop_strategy_desc, (vnop_t *)err_strategy },        /* strategy */
+       { &vnop_pathconf_desc, (vnop_t *)nfs_pathconf },        /* pathconf */
+       { &vnop_advlock_desc, (vnop_t *)nfs_advlock },          /* advlock */
+       { &vnop_bwrite_desc, (vnop_t *)err_bwrite },            /* bwrite */
+       { &vnop_pagein_desc, (vnop_t *)nfs_pagein },            /* Pagein */
+       { &vnop_pageout_desc, (vnop_t *)nfs_pageout },          /* Pageout */
+       { &vnop_copyfile_desc, (vnop_t *)err_copyfile },        /* Copyfile */
+       { &vnop_blktooff_desc, (vnop_t *)nfs_blktooff },        /* blktooff */
+       { &vnop_offtoblk_desc, (vnop_t *)nfs_offtoblk },        /* offtoblk */
+       { &vnop_blockmap_desc, (vnop_t *)nfs_blockmap },        /* blockmap */
        { NULL, NULL }
 };
 struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
@@ -250,58 +212,42 @@ VNODEOP_SET(nfsv2_vnodeop_opv_desc);
 /*
  * Special device vnode ops
  */
-vop_t **spec_nfsv2nodeop_p;
+vnop_t **spec_nfsv2nodeop_p;
 static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
-       { &vop_default_desc, (vop_t *)vn_default_error },
-       { &vop_lookup_desc, (vop_t *)spec_lookup },     /* lookup */
-       { &vop_create_desc, (vop_t *)spec_create },     /* create */
-       { &vop_mknod_desc, (vop_t *)spec_mknod },       /* mknod */
-       { &vop_open_desc, (vop_t *)spec_open },         /* open */
-       { &vop_close_desc, (vop_t *)nfsspec_close },    /* close */
-       { &vop_access_desc, (vop_t *)nfsspec_access },  /* access */
-       { &vop_getattr_desc, (vop_t *)nfs_getattr },    /* getattr */
-       { &vop_setattr_desc, (vop_t *)nfs_setattr },    /* setattr */
-       { &vop_read_desc, (vop_t *)nfsspec_read },      /* read */
-       { &vop_write_desc, (vop_t *)nfsspec_write },    /* write */
-       { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */
-       { &vop_ioctl_desc, (vop_t *)spec_ioctl },       /* ioctl */
-       { &vop_select_desc, (vop_t *)spec_select },     /* select */
-       { &vop_revoke_desc, (vop_t *)spec_revoke },     /* revoke */
-       { &vop_mmap_desc, (vop_t *)spec_mmap },         /* mmap */
-       { &vop_fsync_desc, (vop_t *)nfs_fsync },        /* fsync */
-       { &vop_seek_desc, (vop_t *)spec_seek },         /* seek */
-       { &vop_remove_desc, (vop_t *)spec_remove },     /* remove */
-       { &vop_link_desc, (vop_t *)spec_link },         /* link */
-       { &vop_rename_desc, (vop_t *)spec_rename },     /* rename */
-       { &vop_mkdir_desc, (vop_t *)spec_mkdir },       /* mkdir */
-       { &vop_rmdir_desc, (vop_t *)spec_rmdir },       /* rmdir */
-       { &vop_symlink_desc, (vop_t *)spec_symlink },   /* symlink */
-       { &vop_readdir_desc, (vop_t *)spec_readdir },   /* readdir */
-       { &vop_readlink_desc, (vop_t *)spec_readlink }, /* readlink */
-       { &vop_abortop_desc, (vop_t *)spec_abortop },   /* abortop */
-       { &vop_inactive_desc, (vop_t *)nfs_inactive },  /* inactive */
-       { &vop_reclaim_desc, (vop_t *)nfs_reclaim },    /* reclaim */
-       { &vop_lock_desc, (vop_t *)nfs_lock },          /* lock */
-       { &vop_unlock_desc, (vop_t *)nfs_unlock },      /* unlock */
-       { &vop_bmap_desc, (vop_t *)spec_bmap },         /* bmap */
-       { &vop_strategy_desc, (vop_t *)spec_strategy }, /* strategy */
-       { &vop_print_desc, (vop_t *)nfs_print },        /* print */
-       { &vop_islocked_desc, (vop_t *)nfs_islocked },  /* islocked */
-       { &vop_pathconf_desc, (vop_t *)spec_pathconf }, /* pathconf */
-       { &vop_advlock_desc, (vop_t *)spec_advlock },   /* advlock */
-       { &vop_blkatoff_desc, (vop_t *)spec_blkatoff }, /* blkatoff */
-       { &vop_valloc_desc, (vop_t *)spec_valloc },     /* valloc */
-       { &vop_reallocblks_desc, (vop_t *)spec_reallocblks },   /* reallocblks */
-       { &vop_vfree_desc, (vop_t *)spec_vfree },       /* vfree */
-       { &vop_truncate_desc, (vop_t *)spec_truncate }, /* truncate */
-       { &vop_update_desc, (vop_t *)nfs_update },      /* update */
-       { &vop_bwrite_desc, (vop_t *)vn_bwrite },       /* bwrite */
-       { &vop_devblocksize_desc, (vop_t *)spec_devblocksize },  /* devblocksize */
-       { &vop_pagein_desc, (vop_t *)nfs_pagein },              /* Pagein */
-       { &vop_pageout_desc, (vop_t *)nfs_pageout },            /* Pageout */
-       { &vop_blktooff_desc, (vop_t *)nfs_blktooff },          /* blktooff */
-       { &vop_offtoblk_desc, (vop_t *)nfs_offtoblk },          /* offtoblk */
-       { &vop_cmap_desc, (vop_t *)nfs_cmap },          /* cmap */
+       { &vnop_default_desc, (vnop_t *)vn_default_error },
+       { &vnop_lookup_desc, (vnop_t *)spec_lookup },           /* lookup */
+       { &vnop_create_desc, (vnop_t *)spec_create },           /* create */
+       { &vnop_mknod_desc, (vnop_t *)spec_mknod },             /* mknod */
+       { &vnop_open_desc, (vnop_t *)spec_open },               /* open */
+       { &vnop_close_desc, (vnop_t *)nfsspec_close },          /* close */
+       { &vnop_getattr_desc, (vnop_t *)nfs_vnop_getattr },     /* getattr */
+       { &vnop_setattr_desc, (vnop_t *)nfs_setattr },          /* setattr */
+       { &vnop_read_desc, (vnop_t *)nfsspec_read },            /* read */
+       { &vnop_write_desc, (vnop_t *)nfsspec_write },          /* write */
+       { &vnop_ioctl_desc, (vnop_t *)spec_ioctl },             /* ioctl */
+       { &vnop_select_desc, (vnop_t *)spec_select },           /* select */
+       { &vnop_revoke_desc, (vnop_t *)spec_revoke },           /* revoke */
+       { &vnop_mmap_desc, (vnop_t *)spec_mmap },               /* mmap */
+       { &vnop_fsync_desc, (vnop_t *)nfs_fsync },              /* fsync */
+       { &vnop_remove_desc, (vnop_t *)spec_remove },           /* remove */
+       { &vnop_link_desc, (vnop_t *)spec_link },               /* link */
+       { &vnop_rename_desc, (vnop_t *)spec_rename },           /* rename */
+       { &vnop_mkdir_desc, (vnop_t *)spec_mkdir },             /* mkdir */
+       { &vnop_rmdir_desc, (vnop_t *)spec_rmdir },             /* rmdir */
+       { &vnop_symlink_desc, (vnop_t *)spec_symlink },         /* symlink */
+       { &vnop_readdir_desc, (vnop_t *)spec_readdir },         /* readdir */
+       { &vnop_readlink_desc, (vnop_t *)spec_readlink },       /* readlink */
+       { &vnop_inactive_desc, (vnop_t *)nfs_inactive },        /* inactive */
+       { &vnop_reclaim_desc, (vnop_t *)nfs_reclaim },          /* reclaim */
+       { &vnop_strategy_desc, (vnop_t *)spec_strategy },       /* strategy */
+       { &vnop_pathconf_desc, (vnop_t *)spec_pathconf },       /* pathconf */
+       { &vnop_advlock_desc, (vnop_t *)spec_advlock },         /* advlock */
+       { &vnop_bwrite_desc, (vnop_t *)vn_bwrite },             /* bwrite */
+       { &vnop_pagein_desc, (vnop_t *)nfs_pagein },            /* Pagein */
+       { &vnop_pageout_desc, (vnop_t *)nfs_pageout },          /* Pageout */
+       { &vnop_blktooff_desc, (vnop_t *)nfs_blktooff },        /* blktooff */
+       { &vnop_offtoblk_desc, (vnop_t *)nfs_offtoblk },        /* offtoblk */
+       { &vnop_blockmap_desc, (vnop_t *)nfs_blockmap },        /* blockmap */
        { NULL, NULL }
 };
 struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
@@ -310,57 +256,42 @@ struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
 VNODEOP_SET(spec_nfsv2nodeop_opv_desc);
 #endif
 
-vop_t **fifo_nfsv2nodeop_p;
+vnop_t **fifo_nfsv2nodeop_p;
 static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
-       { &vop_default_desc, (vop_t *)vn_default_error },
-       { &vop_lookup_desc, (vop_t *)fifo_lookup },     /* lookup */
-       { &vop_create_desc, (vop_t *)fifo_create },     /* create */
-       { &vop_mknod_desc, (vop_t *)fifo_mknod },       /* mknod */
-       { &vop_open_desc, (vop_t *)fifo_open },         /* open */
-       { &vop_close_desc, (vop_t *)nfsfifo_close },    /* close */
-       { &vop_access_desc, (vop_t *)nfsspec_access },  /* access */
-       { &vop_getattr_desc, (vop_t *)nfs_getattr },    /* getattr */
-       { &vop_setattr_desc, (vop_t *)nfs_setattr },    /* setattr */
-       { &vop_read_desc, (vop_t *)nfsfifo_read },      /* read */
-       { &vop_write_desc, (vop_t *)nfsfifo_write },    /* write */
-       { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */
-       { &vop_ioctl_desc, (vop_t *)fifo_ioctl },       /* ioctl */
-       { &vop_select_desc, (vop_t *)fifo_select },     /* select */
-       { &vop_revoke_desc, (vop_t *)fifo_revoke },     /* revoke */
-       { &vop_mmap_desc, (vop_t *)fifo_mmap },         /* mmap */
-       { &vop_fsync_desc, (vop_t *)nfs_fsync },        /* fsync */
-       { &vop_seek_desc, (vop_t *)fifo_seek },         /* seek */
-       { &vop_remove_desc, (vop_t *)fifo_remove },     /* remove */
-       { &vop_link_desc, (vop_t *)fifo_link },         /* link */
-       { &vop_rename_desc, (vop_t *)fifo_rename },     /* rename */
-       { &vop_mkdir_desc, (vop_t *)fifo_mkdir },       /* mkdir */
-       { &vop_rmdir_desc, (vop_t *)fifo_rmdir },       /* rmdir */
-       { &vop_symlink_desc, (vop_t *)fifo_symlink },   /* symlink */
-       { &vop_readdir_desc, (vop_t *)fifo_readdir },   /* readdir */
-       { &vop_readlink_desc, (vop_t *)fifo_readlink }, /* readlink */
-       { &vop_abortop_desc, (vop_t *)fifo_abortop },   /* abortop */
-       { &vop_inactive_desc, (vop_t *)nfs_inactive },  /* inactive */
-       { &vop_reclaim_desc, (vop_t *)nfs_reclaim },    /* reclaim */
-       { &vop_lock_desc, (vop_t *)nfs_lock },          /* lock */
-       { &vop_unlock_desc, (vop_t *)nfs_unlock },      /* unlock */
-       { &vop_bmap_desc, (vop_t *)fifo_bmap },         /* bmap */
-       { &vop_strategy_desc, (vop_t *)fifo_strategy }, /* strategy */
-       { &vop_print_desc, (vop_t *)nfs_print },        /* print */
-       { &vop_islocked_desc, (vop_t *)nfs_islocked },  /* islocked */
-       { &vop_pathconf_desc, (vop_t *)fifo_pathconf }, /* pathconf */
-       { &vop_advlock_desc, (vop_t *)fifo_advlock },   /* advlock */
-       { &vop_blkatoff_desc, (vop_t *)fifo_blkatoff }, /* blkatoff */
-       { &vop_valloc_desc, (vop_t *)fifo_valloc },     /* valloc */
-       { &vop_reallocblks_desc, (vop_t *)fifo_reallocblks },   /* reallocblks */
-       { &vop_vfree_desc, (vop_t *)fifo_vfree },       /* vfree */
-       { &vop_truncate_desc, (vop_t *)fifo_truncate }, /* truncate */
-       { &vop_update_desc, (vop_t *)nfs_update },      /* update */
-       { &vop_bwrite_desc, (vop_t *)vn_bwrite },       /* bwrite */
-       { &vop_pagein_desc, (vop_t *)nfs_pagein },              /* Pagein */
-       { &vop_pageout_desc, (vop_t *)nfs_pageout },            /* Pageout */
-       { &vop_blktooff_desc, (vop_t *)nfs_blktooff },          /* blktooff */
-       { &vop_offtoblk_desc, (vop_t *)nfs_offtoblk },          /* offtoblk */
-       { &vop_cmap_desc, (vop_t *)nfs_cmap },          /* cmap */
+       { &vnop_default_desc, (vnop_t *)vn_default_error },
+       { &vnop_lookup_desc, (vnop_t *)fifo_lookup },           /* lookup */
+       { &vnop_create_desc, (vnop_t *)fifo_create },           /* create */
+       { &vnop_mknod_desc, (vnop_t *)fifo_mknod },             /* mknod */
+       { &vnop_open_desc, (vnop_t *)fifo_open },               /* open */
+       { &vnop_close_desc, (vnop_t *)nfsfifo_close },          /* close */
+       { &vnop_getattr_desc, (vnop_t *)nfs_vnop_getattr },     /* getattr */
+       { &vnop_setattr_desc, (vnop_t *)nfs_setattr },          /* setattr */
+       { &vnop_read_desc, (vnop_t *)nfsfifo_read },            /* read */
+       { &vnop_write_desc, (vnop_t *)nfsfifo_write },          /* write */
+       { &vnop_ioctl_desc, (vnop_t *)fifo_ioctl },             /* ioctl */
+       { &vnop_select_desc, (vnop_t *)fifo_select },           /* select */
+       { &vnop_revoke_desc, (vnop_t *)fifo_revoke },           /* revoke */
+       { &vnop_mmap_desc, (vnop_t *)fifo_mmap },               /* mmap */
+       { &vnop_fsync_desc, (vnop_t *)nfs_fsync },              /* fsync */
+       { &vnop_remove_desc, (vnop_t *)fifo_remove },           /* remove */
+       { &vnop_link_desc, (vnop_t *)fifo_link },               /* link */
+       { &vnop_rename_desc, (vnop_t *)fifo_rename },           /* rename */
+       { &vnop_mkdir_desc, (vnop_t *)fifo_mkdir },             /* mkdir */
+       { &vnop_rmdir_desc, (vnop_t *)fifo_rmdir },             /* rmdir */
+       { &vnop_symlink_desc, (vnop_t *)fifo_symlink },         /* symlink */
+       { &vnop_readdir_desc, (vnop_t *)fifo_readdir },         /* readdir */
+       { &vnop_readlink_desc, (vnop_t *)fifo_readlink },       /* readlink */
+       { &vnop_inactive_desc, (vnop_t *)nfs_inactive },        /* inactive */
+       { &vnop_reclaim_desc, (vnop_t *)nfs_reclaim },          /* reclaim */
+       { &vnop_strategy_desc, (vnop_t *)fifo_strategy },       /* strategy */
+       { &vnop_pathconf_desc, (vnop_t *)fifo_pathconf },       /* pathconf */
+       { &vnop_advlock_desc, (vnop_t *)fifo_advlock },         /* advlock */
+       { &vnop_bwrite_desc, (vnop_t *)vn_bwrite },             /* bwrite */
+       { &vnop_pagein_desc, (vnop_t *)nfs_pagein },            /* Pagein */
+       { &vnop_pageout_desc, (vnop_t *)nfs_pageout },          /* Pageout */
+       { &vnop_blktooff_desc, (vnop_t *)nfs_blktooff },        /* blktooff */
+       { &vnop_offtoblk_desc, (vnop_t *)nfs_offtoblk },        /* offtoblk */
+       { &vnop_blockmap_desc, (vnop_t *)nfs_blockmap },        /* blockmap */
        { NULL, NULL }
 };
 struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
@@ -369,29 +300,35 @@ struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
 VNODEOP_SET(fifo_nfsv2nodeop_opv_desc);
 #endif
 
-static int     nfs_mknodrpc __P((struct vnode *dvp, struct vnode **vpp,
-                                 struct componentname *cnp,
-                                 struct vattr *vap));
-static int     nfs_removerpc __P((struct vnode *dvp, char *name, int namelen,
-                                  struct ucred *cred, struct proc *proc));
-static int     nfs_renamerpc __P((struct vnode *fdvp, char *fnameptr,
-                                  int fnamelen, struct vnode *tdvp,
-                                  char *tnameptr, int tnamelen,
-                                  struct ucred *cred, struct proc *proc));
-static int     nfs_renameit __P((struct vnode *sdvp,
-                                 struct componentname *scnp,
-                                 struct sillyrename *sp));
+static int     nfs_mknodrpc(vnode_t dvp, vnode_t *vpp,
+                               struct componentname *cnp,
+                               struct vnode_attr *vap,
+                               kauth_cred_t cred, proc_t p);
+static int     nfs_removerpc(vnode_t dvp, char *name, int namelen,
+                               kauth_cred_t cred, proc_t proc);
+static int     nfs_renamerpc(vnode_t fdvp, char *fnameptr,
+                               int fnamelen, vnode_t tdvp,
+                               char *tnameptr, int tnamelen,
+                               kauth_cred_t cred, proc_t proc);
 
 /*
  * Global variables
  */
+extern u_long nfs_xdrneg1;
 extern u_long nfs_true, nfs_false;
 extern struct nfsstats nfsstats;
 extern nfstype nfsv3_type[9];
-struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
+proc_t nfs_iodwant[NFS_MAXASYNCDAEMON];
 struct nfsmount *nfs_iodmount[NFS_MAXASYNCDAEMON];
+
+lck_grp_t *nfs_iod_lck_grp;
+lck_grp_attr_t *nfs_iod_lck_grp_attr;
+lck_attr_t *nfs_iod_lck_attr;
+lck_mtx_t *nfs_iod_mutex;
+
 int nfs_numasync = 0;
 int nfs_ioddelwri = 0;
+
 #define        DIRHDSIZ        (sizeof (struct dirent) - (MAXNAMLEN + 1))
 
 static int     nfsaccess_cache_timeout = NFS_MAXATTRTIMO;
@@ -517,8 +454,7 @@ static const short errortooutcome[ELAST+1] = {
 
 
 static short
-nfs_pageouterrorhandler(error)
-       int error;
+nfs_pageouterrorhandler(int error)
 {
        if (error > ELAST) 
                return(DUMP);
@@ -527,16 +463,16 @@ nfs_pageouterrorhandler(error)
 }
 
 static int
-nfs3_access_otw(struct vnode *vp,  
+nfs3_access_otw(vnode_t vp,  
                int wmode,
-               struct proc *p,
-               struct ucred *cred)  
+               proc_t p,
+               kauth_cred_t cred)  
 {
        const int v3 = 1;
        u_long *tl;
        int error = 0, attrflag;
 
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       mbuf_t mreq, mrep, md, mb, mb2;
        caddr_t bpos, dpos, cp2;
        register long t1, t2;
        register caddr_t cp;
@@ -545,18 +481,22 @@ nfs3_access_otw(struct vnode *vp,
        u_int64_t xid;
        struct timeval now;
 
-       nfsstats.rpccnt[NFSPROC_ACCESS]++;   
-       nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
+       nfsm_reqhead(NFSX_FH(v3) + NFSX_UNSIGNED);
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_ACCESS]);   
        nfsm_fhtom(vp, v3);
        nfsm_build(tl, u_long *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(wmode);
        nfsm_request(vp, NFSPROC_ACCESS, p, cred, &xid);
-       nfsm_postop_attr(vp, attrflag, &xid);
+       if (mrep) {
+               nfsm_postop_attr_update(vp, 1, attrflag, &xid);
+       }
        if (!error) {
                nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
                rmode = fxdr_unsigned(u_int32_t, *tl);
                np->n_mode = rmode;
-               np->n_modeuid = cred->cr_uid;
+               np->n_modeuid = kauth_cred_getuid(cred);
                microuptime(&now);
                np->n_modestamp = now.tv_sec;
        }
@@ -572,19 +512,20 @@ nfs3_access_otw(struct vnode *vp,
  */
 static int
 nfs_access(ap)
-       struct vop_access_args /* {
-               struct vnode *a_vp;
-               int  a_mode;
-               struct ucred *a_cred;
-               struct proc *a_p;
+       struct vnop_access_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               int a_mode;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       int error = 0;
+       vnode_t vp = ap->a_vp;
+       int error = 0, dorpc;
        u_long mode, wmode;
        int v3 = NFS_ISV3(vp);
        struct nfsnode *np = VTONFS(vp);
        struct timeval now;
+       kauth_cred_t cred;
 
        /*
         * For nfs v3, do an access rpc, otherwise you are stuck emulating
@@ -595,23 +536,50 @@ nfs_access(ap)
         * in the cache.
         */
        if (v3) {
-               if (ap->a_mode & VREAD)
-                       mode = NFSV3ACCESS_READ;
-               else
-                       mode = 0;
-               if (vp->v_type == VDIR) {
-                       if (ap->a_mode & VWRITE)
-                               mode |= NFSV3ACCESS_MODIFY |
-                                       NFSV3ACCESS_EXTEND | NFSV3ACCESS_DELETE;
-                       if (ap->a_mode & VEXEC)
+               /*
+                * Convert KAUTH primitives to NFS access rights.
+                */
+               mode = 0;
+               if (vnode_isdir(vp)) {
+                       /* directory */
+                       if (ap->a_action &
+                           (KAUTH_VNODE_LIST_DIRECTORY |
+                           KAUTH_VNODE_READ_EXTATTRIBUTES))
+                               mode |= NFSV3ACCESS_READ;
+                       if (ap->a_action & KAUTH_VNODE_SEARCH)
                                mode |= NFSV3ACCESS_LOOKUP;
+                       if (ap->a_action &
+                           (KAUTH_VNODE_ADD_FILE |
+                           KAUTH_VNODE_ADD_SUBDIRECTORY))
+                               mode |= NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND;
+                       if (ap->a_action & KAUTH_VNODE_DELETE_CHILD)
+                               mode |= NFSV3ACCESS_MODIFY;
                } else {
-                       if (ap->a_mode & VWRITE)
+                       /* file */
+                       if (ap->a_action &
+                           (KAUTH_VNODE_READ_DATA |
+                           KAUTH_VNODE_READ_EXTATTRIBUTES))
+                               mode |= NFSV3ACCESS_READ;
+                       if (ap->a_action & KAUTH_VNODE_WRITE_DATA)
                                mode |= NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND;
-                       if (ap->a_mode & VEXEC)
+                       if (ap->a_action & KAUTH_VNODE_APPEND_DATA)
+                               mode |= NFSV3ACCESS_EXTEND;
+                       if (ap->a_action & KAUTH_VNODE_EXECUTE)
                                mode |= NFSV3ACCESS_EXECUTE;
                }
-               /* XXX safety belt, only make blanket request if caching */
+               /* common */
+               if (ap->a_action & KAUTH_VNODE_DELETE)
+                       mode |= NFSV3ACCESS_DELETE;
+               if (ap->a_action &
+                   (KAUTH_VNODE_WRITE_ATTRIBUTES |
+                   KAUTH_VNODE_WRITE_EXTATTRIBUTES |
+                   KAUTH_VNODE_WRITE_SECURITY))
+                       mode |= NFSV3ACCESS_MODIFY;
+               /* XXX this is pretty dubious */
+               if (ap->a_action & KAUTH_VNODE_CHANGE_OWNER)
+                       mode |= NFSV3ACCESS_MODIFY;
+
+               /* if caching, always ask for every right */
                if (nfsaccess_cache_timeout > 0) {
                        wmode = NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY |
                                NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE |
@@ -619,44 +587,50 @@ nfs_access(ap)
                } else
                        wmode = mode;
                 
+               cred = vfs_context_ucred(ap->a_context);
+
                /*
                 * Does our cached result allow us to give a definite yes to
                 * this request?
                 */     
-               microuptime(&now);
-               if (now.tv_sec < np->n_modestamp + nfsaccess_cache_timeout &&
-                   ap->a_cred->cr_uid == np->n_modeuid &&
-                   (np->n_mode & mode) == mode) {
-                       /* nfsstats.accesscache_hits++; */
-               } else {
+               dorpc = 1;
+               if (NMODEVALID(np)) {
+                       microuptime(&now);
+                       if ((now.tv_sec < (np->n_modestamp + nfsaccess_cache_timeout)) &&
+                           (kauth_cred_getuid(cred) == np->n_modeuid) &&
+                           ((np->n_mode & mode) == mode)) {
+                               /* OSAddAtomic(1, (SInt32*)&nfsstats.accesscache_hits); */
+                               dorpc = 0;
+                       }
+               }
+               if (dorpc) {
+                       /* Either a no, or a don't know.  Go to the wire. */
+                       /* OSAddAtomic(1, (SInt32*)&nfsstats.accesscache_misses); */
+                       error = nfs3_access_otw(vp, wmode, vfs_context_proc(ap->a_context), cred);
+               }
+               if (!error) {
                        /*
-                        * Either a no, or a don't know.  Go to the wire.
+                        * If we asked for DELETE but didn't get it, the server
+                        * may simply not support returning that bit (possible
+                        * on UNIX systems).  So, we'll assume that it is OK,
+                        * and just let any subsequent delete action fail if it
+                        * really isn't deletable.
                         */
-                       /* nfsstats.accesscache_misses++; */
-                       error = nfs3_access_otw(vp, wmode, ap->a_p,ap->a_cred);
-                       if (!error) {
-                               if ((np->n_mode & mode) != mode)
-                                       error = EACCES;
-                       }
+                       if ((mode & NFSV3ACCESS_DELETE) &&
+                           !(np->n_mode & NFSV3ACCESS_DELETE))
+                               np->n_mode |= NFSV3ACCESS_DELETE;
+                       if ((np->n_mode & mode) != mode)
+                               error = EACCES;
                }
-       } else
-               return (nfsspec_access(ap)); /* NFSv2 case checks for EROFS here */
-       /*
-        * Disallow write attempts on filesystems mounted read-only;
-        * unless the file is a socket, fifo, or a block or character
-        * device resident on the filesystem.
-        * CSM - moved EROFS check down per NetBSD rev 1.71.  So you
-        * get the correct error value with layered filesystems. 
-        * EKN - moved the return(error) below this so it does get called.       
-        */
-       if (!error && (ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
-               switch (vp->v_type) {
-                       case VREG: case VDIR: case VLNK:
-                               error = EROFS;
-                       default: 
-                               break;
+       } else {
+               /* v2 */
+               if ((ap->a_action & KAUTH_VNODE_WRITE_RIGHTS) && vfs_isrdonly(vnode_mount(vp))) {
+                       error = EROFS;
+               } else {
+                       error = 0;
                }
        }
+
        return (error);
 }
 
@@ -671,77 +645,69 @@ nfs_access(ap)
 
 static int
 nfs_open(ap)
-       struct vop_open_args /* {
-               struct vnode *a_vp;
-               int  a_mode;
-               struct ucred *a_cred;
-               struct proc *a_p;
+       struct vnop_open_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               int a_mode;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
+       vnode_t vp = ap->a_vp;
        struct nfsnode *np = VTONFS(vp);
-       struct nfsmount *nmp = VFSTONFS(vp->v_mount);
-       struct vattr vattr;
+       struct nfs_vattr nvattr;
+       kauth_cred_t cred;
+       proc_t p;
+       enum vtype vtype;
        int error;
 
-       if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
+       vtype = vnode_vtype(vp);
+       if (vtype != VREG && vtype != VDIR && vtype != VLNK) {
                return (EACCES);
        }
-       /*
-        * Get a valid lease. If cached data is stale, flush it.
-        */
-       if (nmp->nm_flag & NFSMNT_NQNFS) {
-               if (NQNFS_CKINVALID(vp, np, ND_READ)) {
-                   do {
-                       error = nqnfs_getlease(vp, ND_READ, ap->a_cred,
-                           ap->a_p);
-                   } while (error == NQNFS_EXPIRED);
-                   if (error)
+
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
+
+       if (np->n_flag & NNEEDINVALIDATE) {
+               np->n_flag &= ~NNEEDINVALIDATE;
+               nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, cred, p, 1);
+       }
+       if (np->n_flag & NMODIFIED) {
+               if ((error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1)) == EINTR)
                        return (error);
-                   if (np->n_lrev != np->n_brev ||
-                       (np->n_flag & NQNFSNONCACHE)) {
-                       if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
-                               ap->a_p, 1)) == EINTR)
-                               return (error);
-                       np->n_brev = np->n_lrev;
-                   }
+               NATTRINVALIDATE(np);
+               if (vtype == VDIR)
+                       np->n_direofoffset = 0;
+               error = nfs_getattr(vp, &nvattr, cred, p);
+               if (error)
+                       return (error);
+               if (vtype == VDIR) {
+                       /* if directory changed, purge any name cache entries */
+                       if (nfstimespeccmp(&np->n_ncmtime, &nvattr.nva_mtime, !=))
+                               cache_purge(vp);
+                       np->n_ncmtime = nvattr.nva_mtime;
                }
+               np->n_mtime = nvattr.nva_mtime;
        } else {
-               if (np->n_flag & NMODIFIED) {
-                       if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
-                               ap->a_p, 1)) == EINTR)
-                               return (error);
-                       np->n_attrstamp = 0;
-                       if (vp->v_type == VDIR)
+               error = nfs_getattr(vp, &nvattr, cred, p);
+               if (error)
+                       return (error);
+               if (nfstimespeccmp(&np->n_mtime, &nvattr.nva_mtime, !=)) {
+                       if (vtype == VDIR) {
                                np->n_direofoffset = 0;
-                       error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
-                       if (error)
-                               return (error);
-                       /* if directory changed, purge any name cache entries */
-                       if ((vp->v_type == VDIR) &&
-                           (np->n_mtime != vattr.va_mtime.tv_sec))
-                               cache_purge(vp);
-                       np->n_mtime = vattr.va_mtime.tv_sec;
-               } else {
-                       error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
-                       if (error)
-                               return (error);
-                       if (np->n_mtime != vattr.va_mtime.tv_sec) {
-                               if (vp->v_type == VDIR) {
-                                       np->n_direofoffset = 0;
-                                       nfs_invaldir(vp);
-                                       /* purge name cache entries */
+                               nfs_invaldir(vp);
+                               /* purge name cache entries */
+                               if (nfstimespeccmp(&np->n_ncmtime, &nvattr.nva_mtime, !=))
                                        cache_purge(vp);
-                               }
-                               if ((error = nfs_vinvalbuf(vp, V_SAVE,
-                                       ap->a_cred, ap->a_p, 1)) == EINTR)
-                                       return (error);
-                               np->n_mtime = vattr.va_mtime.tv_sec;
                        }
+                       if ((error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1)) == EINTR)
+                               return (error);
+                       if (vtype == VDIR)
+                               np->n_ncmtime = nvattr.nva_mtime;
+                       np->n_mtime = nvattr.nva_mtime;
                }
        }
-       if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
-               np->n_attrstamp = 0; /* For Open/Close consistency */
+       NATTRINVALIDATE(np); /* For Open/Close consistency */
        return (0);
 }
 
@@ -765,33 +731,29 @@ nfs_open(ap)
  * The current code does the following:
  * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
  * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
- *                     or commit them (this satisfies 1 and 2 except for the
- *                     case where the server crashes after this close but
- *                     before the commit RPC, which is felt to be "good
- *                     enough". Changing the last argument to nfs_flush() to
- *                     a 1 would force a commit operation, if it is felt a
- *                     commit is necessary now.
- * for NQNFS         - do nothing now, since 2 is dealt with via leases and
- *                     1 should be dealt with via an fsync() system call for
- *                     cases where write errors are important.
+ *                     them.
  */
 /* ARGSUSED */
 static int
 nfs_close(ap)
-       struct vop_close_args /* {
+       struct vnop_close_args /* {
                struct vnodeop_desc *a_desc;
-               struct vnode *a_vp;
-               int  a_fflag;
-               struct ucred *a_cred;
-               struct proc *a_p;
+               vnode_t a_vp;
+               int a_fflag;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct nfsnode *np = VTONFS(vp);
+       vnode_t vp = ap->a_vp;
+       struct nfsnode *np = VTONFS(vp);
        struct nfsmount *nmp;
+       kauth_cred_t cred;
+       proc_t p;
        int error = 0;
 
-       if (vp->v_type == VREG) {
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
+
+       if (vnode_vtype(vp) == VREG) {
 #if DIAGNOSTIC
            register struct sillyrename *sp = np->n_sillyrename;
            if (sp)
@@ -799,23 +761,16 @@ nfs_close(ap)
                        &sp->s_name[0], (unsigned)(sp->s_dvp), (unsigned)vp,
                        (unsigned)ap, (unsigned)np, (unsigned)sp);
 #endif
-           nmp = VFSTONFS(vp->v_mount);
+           nmp = VFSTONFS(vnode_mount(vp));
            if (!nmp)
                return (ENXIO);
-           if ((nmp->nm_flag & NFSMNT_NQNFS) == 0 &&
-               (np->n_flag & NMODIFIED)) {
-               int getlock = !VOP_ISLOCKED(vp);
-               if (getlock) {
-                       error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
-                       if (!error && !VFSTONFS(vp->v_mount)) {
-                               VOP_UNLOCK(vp, 0, ap->a_p);
-                               error = ENXIO;
-                       }
-                       if (error)
-                               return (error);
-               }
+           if (np->n_flag & NNEEDINVALIDATE) {
+               np->n_flag &= ~NNEEDINVALIDATE;
+               nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, cred, p, 1);
+           }
+           if (np->n_flag & NMODIFIED) {
                if (NFS_ISV3(vp)) {
-                   error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 1);
+                   error = nfs_flush(vp, MNT_WAIT, cred, p, 0);
                     /*
                      * We cannot clear the NMODIFIED bit in np->n_flag due to
                      * potential races with other processes
@@ -823,11 +778,9 @@ nfs_close(ap)
                      */
                    /* np->n_flag &= ~NMODIFIED; */
                } else {
-                   error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
+                   error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
                }
-               np->n_attrstamp = 0;
-               if (getlock)
-                       VOP_UNLOCK(vp, 0, ap->a_p);
+               NATTRINVALIDATE(np);
            }
            if (np->n_flag & NWRITEERR) {
                np->n_flag &= ~NWRITEERR;
@@ -837,31 +790,99 @@ nfs_close(ap)
        return (error);
 }
 
+
+int
+nfs_getattr_no_vnode(
+       mount_t mp,
+       u_char *fhp,
+       int fhsize,
+       kauth_cred_t cred,
+       proc_t p,
+       struct nfs_vattr *nvap,
+       u_int64_t *xidp)
+{
+       mbuf_t mreq, mrep, md, mb, mb2;
+       caddr_t bpos, dpos;
+       int t2;
+       u_long *tl;
+       caddr_t cp;
+       struct nfsmount *nmp = VFSTONFS(mp);
+       int v3 = (nmp->nm_flag & NFSMNT_NFSV3);
+       int hsiz;
+       int error = 0;
+
+       // XXX fix this to use macros once the macros get cleaned up
+       //nfsm_reqhead(NFSX_FH(v3));
+               hsiz = NFSX_FH(v3);
+               mb = NULL;
+               if (hsiz >= nfs_mbuf_minclsize)
+                       error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &mb);
+               else
+                       error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mb);
+               if (error)
+                       return (error);
+               bpos = mbuf_data(mb);
+               mreq = mb;
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_GETATTR]);
+       //nfsm_fhtom(vp, v3);
+             if (v3) {
+                       t2 = nfsm_rndup(fhsize) + NFSX_UNSIGNED;
+                       if (t2 <= mbuf_trailingspace(mb)) {
+                               nfsm_build(tl, u_long *, t2);
+                               *tl++ = txdr_unsigned(fhsize);
+                               *(tl + ((t2>>2) - 2)) = 0;
+                               bcopy((caddr_t)fhp,(caddr_t)tl, fhsize);
+                       } else if ((t2 = nfsm_strtmbuf(&mb, &bpos, (caddr_t)fhp, fhsize))) {
+                               error = t2;
+                               mbuf_freem(mreq);
+                               goto nfsmout;
+                       }
+               } else {
+                       nfsm_build(cp, caddr_t, NFSX_V2FH);
+                       bcopy((caddr_t)fhp, cp, NFSX_V2FH);
+               }
+       //nfsm_request(vp, NFSPROC_GETATTR, p, cred, xidp);
+               if ((error = nfs_request(NULL, mp, mreq, NFSPROC_GETATTR, p, cred, &mrep, &md, &dpos, xidp))) {
+                       if (error & NFSERR_RETERR)
+                               error &= ~NFSERR_RETERR;
+                       else
+                               goto nfsmout;
+               }
+       if (!error) {
+               //nfsm_loadattr(vp, nvap, xidp);
+               error = nfs_parsefattr(&md, &dpos, v3, nvap);
+               if (error) {
+                       mbuf_freem(mrep);
+                       goto nfsmout;
+               }
+       }
+       nfsm_reqdone;
+       return (error);
+}
+
 /*
  * nfs getattr call from vfs.
  */
-static int
-nfs_getattr(ap)
-       struct vop_getattr_args /* {
-               struct vnode *a_vp;
-               struct vattr *a_vap;
-               struct ucred *a_cred;
-               struct proc *a_p;
-       } */ *ap;
+int
+nfs_getattr(
+       vnode_t vp,
+       struct nfs_vattr *nvap,
+       kauth_cred_t cred,
+       proc_t p)
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct nfsnode *np = VTONFS(vp);
-       register caddr_t cp;
-       register u_long *tl;
-       register int t1, t2;
+       struct nfsnode *np = VTONFS(vp);
+       caddr_t cp;
+       u_long *tl;
+       int t1, t2;
        caddr_t bpos, dpos;
        int error = 0;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       mbuf_t mreq, mrep, md, mb, mb2;
        int v3;
        u_int64_t xid;
        int avoidfloods;
-       
-       FSDBG_TOP(513, np->n_size, np, np->n_vattr.va_size, np->n_flag);
+
+       FSDBG_TOP(513, np->n_size, np, np->n_vattr.nva_size, np->n_flag);
+
        /*
         * Update local times for special files.
         */
@@ -870,29 +891,35 @@ nfs_getattr(ap)
        /*
         * First look in the cache.
         */
-       if ((error = nfs_getattrcache(vp, ap->a_vap)) == 0) {
-               FSDBG_BOT(513, np->n_size, 0, np->n_vattr.va_size, np->n_flag);
+       if ((error = nfs_getattrcache(vp, nvap)) == 0) {
+               FSDBG_BOT(513, np->n_size, 0, np->n_vattr.nva_size, np->n_flag);
                return (0);
        }
        if (error != ENOENT) {
-               FSDBG_BOT(513, np->n_size, error, np->n_vattr.va_size,
+               FSDBG_BOT(513, np->n_size, error, np->n_vattr.nva_size,
                          np->n_flag);
                return (error);
        }
 
-       if (!VFSTONFS(vp->v_mount)) {
-               FSDBG_BOT(513, np->n_size, ENXIO, np->n_vattr.va_size, np->n_flag);
+       if (!VFSTONFS(vnode_mount(vp))) {
+               FSDBG_BOT(513, np->n_size, ENXIO, np->n_vattr.nva_size, np->n_flag);
                return (ENXIO);
        }
        v3 = NFS_ISV3(vp);
        error = 0;
 
-       if (v3 && nfsaccess_cache_timeout > 0) {
-               /*  nfsstats.accesscache_misses++; */
-               if (error = nfs3_access_otw(vp, NFSV3ACCESS_ALL, ap->a_p,
-                                           ap->a_cred))
+       /*
+        * Try to get both the attributes and access info by making an
+        * ACCESS call and seeing if it returns updated attributes.
+        * But don't bother if we aren't caching access info or if the
+        * attributes returned wouldn't be cached.
+        */
+       if (v3 && (nfsaccess_cache_timeout > 0) &&
+           (nfs_attrcachetimeout(vp) > 0)) {
+               /*  OSAddAtomic(1, (SInt32*)&nfsstats.accesscache_misses); */
+               if ((error = nfs3_access_otw(vp, NFSV3ACCESS_ALL, p, cred)))
                        return (error);
-               if ((error = nfs_getattrcache(vp, ap->a_vap)) == 0)
+               if ((error = nfs_getattrcache(vp, nvap)) == 0)
                        return (0);
                if (error != ENOENT)
                        return (error);
@@ -900,14 +927,19 @@ nfs_getattr(ap)
        }
        avoidfloods = 0;
 tryagain:
-       nfsstats.rpccnt[NFSPROC_GETATTR]++;
-       nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
+       nfsm_reqhead(NFSX_FH(v3));
+       if (error) {
+               FSDBG_BOT(513, np->n_size, error, np->n_vattr.nva_size, np->n_flag);
+               return (error);
+       }
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_GETATTR]);
        nfsm_fhtom(vp, v3);
-       nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred, &xid);
+       nfsm_request(vp, NFSPROC_GETATTR, p, cred, &xid);
        if (!error) {
-               nfsm_loadattr(vp, ap->a_vap, &xid);
+               nfsm_loadattr(vp, v3, nvap, &xid);
                if (!xid) { /* out-of-order rpc - attributes were dropped */
-                       m_freem(mrep);
+                       mbuf_freem(mrep);
+                       mrep = NULL;
                        FSDBG(513, -1, np, np->n_xid << 32, np->n_xid);
                        if (avoidfloods++ < 100)
                                goto tryagain;
@@ -916,24 +948,72 @@ tryagain:
                         */
                        panic("nfs_getattr: getattr flood\n");
                }
-               if (np->n_mtime != ap->a_vap->va_mtime.tv_sec) {
+               if (nfstimespeccmp(&np->n_mtime, &nvap->nva_mtime, !=)) {
+                       enum vtype vtype = vnode_vtype(vp);
                        FSDBG(513, -1, np, -1, vp);
-                       if (vp->v_type == VDIR) {
+                       if (vtype == VDIR) {
                                nfs_invaldir(vp);
                                /* purge name cache entries */
-                               cache_purge(vp);
+                               if (nfstimespeccmp(&np->n_ncmtime, &nvap->nva_mtime, !=))
+                                       cache_purge(vp);
                        }
-                       error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
-                                             ap->a_p, 1);
+                       error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
                        FSDBG(513, -1, np, -2, error);
                        if (!error) {
-                               np->n_mtime = ap->a_vap->va_mtime.tv_sec;
+                               if (vtype == VDIR)
+                                       np->n_ncmtime = nvap->nva_mtime;
+                               np->n_mtime = nvap->nva_mtime;
                        }
                }
        }
        nfsm_reqdone;
 
-       FSDBG_BOT(513, np->n_size, -1, np->n_vattr.va_size, error);
+       FSDBG_BOT(513, np->n_size, -1, np->n_vattr.nva_size, error);
+       return (error);
+}
+
+
+static int
+nfs_vnop_getattr(
+       struct vnop_getattr_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               struct vnode_attr *a_vap;
+               vfs_context_t a_context;
+       } */ *ap)
+{
+       int error;
+       struct nfs_vattr nva;
+       struct vnode_attr *vap = ap->a_vap;
+
+       error = nfs_getattr(ap->a_vp, &nva,
+               vfs_context_ucred(ap->a_context),
+               vfs_context_proc(ap->a_context));
+       if (error)
+               return (error);
+
+       /* copy nva to *a_vap */
+       VATTR_RETURN(vap, va_type, nva.nva_type);
+       VATTR_RETURN(vap, va_mode, nva.nva_mode);
+       VATTR_RETURN(vap, va_rdev, nva.nva_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);
+       VATTR_RETURN(vap, va_iosize, nva.nva_blocksize);  /* should this just be f_iosize? */
+       VATTR_RETURN(vap, va_fsid, nva.nva_fsid);
+       vap->va_access_time.tv_sec = nva.nva_atime.tv_sec;
+       vap->va_access_time.tv_nsec = nva.nva_atime.tv_nsec;
+       VATTR_SET_SUPPORTED(vap, va_access_time);
+       vap->va_modify_time.tv_sec = nva.nva_mtime.tv_sec;
+       vap->va_modify_time.tv_nsec = nva.nva_mtime.tv_nsec;
+       VATTR_SET_SUPPORTED(vap, va_modify_time);
+       vap->va_change_time.tv_sec = nva.nva_ctime.tv_sec;
+       vap->va_change_time.tv_nsec = nva.nva_ctime.tv_nsec;
+       VATTR_SET_SUPPORTED(vap, va_change_time);
+
        return (error);
 }
 
@@ -942,158 +1022,174 @@ tryagain:
  */
 static int
 nfs_setattr(ap)
-       struct vop_setattr_args /* {
+       struct vnop_setattr_args /* {
                struct vnodeop_desc *a_desc;
-               struct vnode *a_vp;
-               struct vattr *a_vap;
-               struct ucred *a_cred;
-               struct proc *a_p;
+               vnode_t a_vp;
+               struct vnode_attr *a_vap;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct nfsnode *np = VTONFS(vp);
-       register struct vattr *vap = ap->a_vap;
+       vnode_t vp = ap->a_vp;
+       struct nfsnode *np = VTONFS(vp);
+       struct vnode_attr *vap = ap->a_vap;
        int error = 0;
        u_quad_t tsize;
+       kauth_cred_t cred;
+       proc_t p;
 
 #ifndef nolint
        tsize = (u_quad_t)0;
 #endif
 
-#ifdef XXX /* enable this code soon! (but test it first) */
-       /*                
-        * Setting of flags is not supported.
-        */
-       if (vap->va_flags != VNOVAL)
-               return (EOPNOTSUPP);
-#endif
-
-       /*
-        * Disallow write attempts if the filesystem is mounted read-only.
-        */
-       if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
-           vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
-           vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
-           (vp->v_mount->mnt_flag & MNT_RDONLY))
+       /* Setting of flags is not supported. */
+       if (VATTR_IS_ACTIVE(vap, va_flags))
+               return (ENOTSUP);
+
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
+
+       VATTR_SET_SUPPORTED(vap, va_mode);
+       VATTR_SET_SUPPORTED(vap, va_uid);
+       VATTR_SET_SUPPORTED(vap, va_gid);
+       VATTR_SET_SUPPORTED(vap, va_data_size);
+       VATTR_SET_SUPPORTED(vap, va_access_time);
+       VATTR_SET_SUPPORTED(vap, va_modify_time);
+
+       /* Disallow write attempts if the filesystem is mounted read-only. */
+       if ((VATTR_IS_ACTIVE(vap, va_flags) || VATTR_IS_ACTIVE(vap, va_mode) ||
+            VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid) ||
+            VATTR_IS_ACTIVE(vap, va_access_time) ||
+            VATTR_IS_ACTIVE(vap, va_modify_time)) &&
+           vnode_vfsisrdonly(vp))
                return (EROFS);
-       if (vap->va_size != VNOVAL) {
-               switch (vp->v_type) {
+
+       if (VATTR_IS_ACTIVE(vap, va_data_size)) {
+               switch (vnode_vtype(vp)) {
                case VDIR:
                        return (EISDIR);
                case VCHR:
                case VBLK:
                case VSOCK:
                case VFIFO:
-                       if (vap->va_mtime.tv_sec == VNOVAL &&
-                           vap->va_atime.tv_sec == VNOVAL &&
-                           vap->va_mode == (u_short)VNOVAL &&
-                           vap->va_uid == (uid_t)VNOVAL &&
-                           vap->va_gid == (gid_t)VNOVAL)
+                       if (!VATTR_IS_ACTIVE(vap, va_modify_time) &&
+                           !VATTR_IS_ACTIVE(vap, va_access_time) &&
+                           !VATTR_IS_ACTIVE(vap, va_mode) &&
+                           !VATTR_IS_ACTIVE(vap, va_uid) &&
+                           !VATTR_IS_ACTIVE(vap, va_gid))
                                return (0);
-                       vap->va_size = VNOVAL;
+                       VATTR_CLEAR_ACTIVE(vap, va_data_size);
                        break;
                default:
                        /*
                         * Disallow write attempts if the filesystem is
                         * mounted read-only.
                         */
-                       if (vp->v_mount->mnt_flag & MNT_RDONLY)
+                       if (vnode_vfsisrdonly(vp))
                                return (EROFS);
-                       FSDBG_TOP(512, np->n_size, vap->va_size,
-                                 np->n_vattr.va_size, np->n_flag);
+                       FSDBG_TOP(512, np->n_size, vap->va_data_size,
+                                 np->n_vattr.nva_size, np->n_flag);
                        if (np->n_flag & NMODIFIED) {
-                               if (vap->va_size == 0)
-                                       error = nfs_vinvalbuf(vp, 0,
-                                               ap->a_cred, ap->a_p, 1);
+                               if (vap->va_data_size == 0)
+                                       error = nfs_vinvalbuf(vp, 0, cred, p, 1);
                                else
-                                       error = nfs_vinvalbuf(vp, V_SAVE,
-                                               ap->a_cred, ap->a_p, 1);
+                                       error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
                                if (error) {
                                        printf("nfs_setattr: nfs_vinvalbuf %d\n", error);
-                                       FSDBG_BOT(512, np->n_size, vap->va_size,
-                                                 np->n_vattr.va_size, -1);
+                                       FSDBG_BOT(512, np->n_size, vap->va_data_size,
+                                                 np->n_vattr.nva_size, -1);
                                        return (error);
                                }
-                       } else if (np->n_size > vap->va_size) { /* shrinking? */
-                               daddr_t obn, bn;
-                               int biosize;
+                       } else if (np->n_size > vap->va_data_size) { /* shrinking? */
+                               daddr64_t obn, bn;
+                               int biosize, neweofoff, mustwrite;
                                struct nfsbuf *bp;
 
-                               biosize = vp->v_mount->mnt_stat.f_iosize;
+                               biosize = vfs_statfs(vnode_mount(vp))->f_iosize;
                                obn = (np->n_size - 1) / biosize;
-                               bn = vap->va_size / biosize; 
-                               for ( ; obn >= bn; obn--)
-                                   if (nfs_buf_incore(vp, obn)) {
-                                       bp = nfs_buf_get(vp, obn, biosize, 0, BLK_READ);
-                                       if (!bp)
+                               bn = vap->va_data_size / biosize; 
+                               for ( ; obn >= bn; obn--) {
+                                       if (!nfs_buf_is_incore(vp, obn))
+                                               continue;
+                                       error = nfs_buf_get(vp, obn, biosize, 0, NBLK_READ, &bp);
+                                       if (error)
                                                continue;
-                                       if (obn == bn) {
-                                           int neweofoff, mustwrite;
-                                           mustwrite = 0;
-                                           neweofoff = vap->va_size - NBOFF(bp);
-                                           /* check for any dirty data before the new EOF */
-                                           if (bp->nb_dirtyend && bp->nb_dirtyoff < neweofoff) {
+                                       if (obn != bn) {
+                                               FSDBG(512, bp, bp->nb_flags, 0, obn);
+                                               SET(bp->nb_flags, NB_INVAL);
+                                               nfs_buf_release(bp, 1);
+                                               continue;
+                                       }
+                                       mustwrite = 0;
+                                       neweofoff = vap->va_data_size - NBOFF(bp);
+                                       /* check for any dirty data before the new EOF */
+                                       if (bp->nb_dirtyend && bp->nb_dirtyoff < neweofoff) {
                                                /* clip dirty range to EOF */
                                                if (bp->nb_dirtyend > neweofoff)
-                                                   bp->nb_dirtyend = neweofoff;
+                                                       bp->nb_dirtyend = neweofoff;
                                                mustwrite++;
-                                           }
-                                           bp->nb_dirty &= (1 << round_page_32(neweofoff)/PAGE_SIZE) - 1;
-                                           if (bp->nb_dirty)
+                                       }
+                                       bp->nb_dirty &= (1 << round_page_32(neweofoff)/PAGE_SIZE) - 1;
+                                       if (bp->nb_dirty)
                                                mustwrite++;
-                                           if (mustwrite) {
-                                               /* gotta write out dirty data before invalidating */
-                                               /* (NB_STABLE indicates that data writes should be FILESYNC) */
-                                               /* (NB_NOCACHE indicates buffer should be discarded) */
-                                               CLR(bp->nb_flags, (NB_DONE | NB_ERROR | NB_INVAL | NB_ASYNC | NB_READ));
-                                               SET(bp->nb_flags, NB_STABLE | NB_NOCACHE);
+                                       if (!mustwrite) {
+                                               FSDBG(512, bp, bp->nb_flags, 0, obn);
+                                               SET(bp->nb_flags, NB_INVAL);
+                                               nfs_buf_release(bp, 1);
+                                               continue;
+                                       }
+                                       /* gotta write out dirty data before invalidating */
+                                       /* (NB_STABLE indicates that data writes should be FILESYNC) */
+                                       /* (NB_NOCACHE indicates buffer should be discarded) */
+                                       CLR(bp->nb_flags, (NB_DONE | NB_ERROR | NB_INVAL | NB_ASYNC | NB_READ));
+                                       SET(bp->nb_flags, NB_STABLE | NB_NOCACHE);
+                                       if (bp->nb_wcred == NOCRED) {
+                                               kauth_cred_ref(cred);
+                                               bp->nb_wcred = cred;
+                                       }
+                                       error = nfs_buf_write(bp);
+                                       // Note: bp has been released
+                                       if (error) {
+                                               FSDBG(512, bp, 0xd00dee, 0xbad, error);
+                                               np->n_error = error;
+                                               np->n_flag |= NWRITEERR;
                                                /*
-                                                * NFS has embedded ucred so crhold() risks zone corruption
+                                                * There was a write error and we need to
+                                                * invalidate attrs and flush buffers in
+                                                * order to sync up with the server.
+                                                * (if this write was extending the file,
+                                                * we may no longer know the correct size)
                                                 */
-                                               if (bp->nb_wcred == NOCRED)
-                                                   bp->nb_wcred = crdup(ap->a_cred);
-                                               error = nfs_buf_write(bp);
-                                               // Note: bp has been released
-                                               if (error) {
-                                                   FSDBG(512, bp, 0xd00dee, 0xbad, error);
-                                                   np->n_error = error;
-                                                   np->n_flag |= NWRITEERR;
-                                                   error = 0;
-                                               }
-                                               bp = NULL;
-                                           }
+                                               NATTRINVALIDATE(np);
+                                               nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, cred, p, 1);
+                                               error = 0;
                                        }
-                                       if (bp) {
-                                           FSDBG(512, bp, bp->nb_flags, 0, obn);
-                                           SET(bp->nb_flags, NB_INVAL);
-                                           nfs_buf_release(bp);
-                                       }
-                                   }
+                               }
                        }
                        tsize = np->n_size;
-                       np->n_size = np->n_vattr.va_size = vap->va_size;
-                       ubc_setsize(vp, (off_t)vap->va_size); /* XXX error? */
-               };
-       } else if ((vap->va_mtime.tv_sec != VNOVAL ||
-                   vap->va_atime.tv_sec != VNOVAL) &&
-                  (np->n_flag & NMODIFIED) && vp->v_type == VREG) {
-               error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
+                       np->n_size = np->n_vattr.nva_size = vap->va_data_size;
+                       ubc_setsize(vp, (off_t)vap->va_data_size); /* XXX error? */
+               }
+       } else if ((VATTR_IS_ACTIVE(vap, va_modify_time) ||
+                   VATTR_IS_ACTIVE(vap, va_access_time)) &&
+                  (np->n_flag & NMODIFIED) && (vnode_vtype(vp) == VREG)) {
+               error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
                if (error == EINTR)
                        return (error);
        }
-       error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
-       FSDBG_BOT(512, np->n_size, vap->va_size, np->n_vattr.va_size, error);
-       if (error && vap->va_size != VNOVAL) {
+       if (VATTR_IS_ACTIVE(vap, va_mode)) {
+               NMODEINVALIDATE(np);
+       }
+       error = nfs_setattrrpc(vp, vap, cred, p);
+       FSDBG_BOT(512, np->n_size, vap->va_data_size, np->n_vattr.nva_size, error);
+       if (error && VATTR_IS_ACTIVE(vap, va_data_size)) {
                /* make every effort to resync file size w/ server... */
-               int err = 0; /* preserve "error" for return */
+               int err; /* preserve "error" for return */
 
-               printf("nfs_setattr: nfs_setattrrpc %d\n", error);
-               np->n_size = np->n_vattr.va_size = tsize;
+               np->n_size = np->n_vattr.nva_size = tsize;
                ubc_setsize(vp, (off_t)np->n_size); /* XXX check error */
-               vap->va_size = tsize;
-               err = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
-               if (err)
-                       printf("nfs_setattr1: nfs_setattrrpc %d\n", err);
+               vap->va_data_size = tsize;
+               err = nfs_setattrrpc(vp, vap, cred, p);
+               printf("nfs_setattr: nfs_setattrrpc %d %d\n", error, err);
        }
        return (error);
 }
@@ -1103,31 +1199,33 @@ nfs_setattr(ap)
  */
 static int
 nfs_setattrrpc(vp, vap, cred, procp)
-       register struct vnode *vp;
-       register struct vattr *vap;
-       struct ucred *cred;
-       struct proc *procp;
+       vnode_t vp;
+       struct vnode_attr *vap;
+       kauth_cred_t cred;
+       proc_t procp;
 {
        register struct nfsv2_sattr *sp;
        register caddr_t cp;
        register long t1, t2;
        caddr_t bpos, dpos, cp2;
        u_long *tl;
-       int error = 0, wccflag = NFSV3_WCCRATTR;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       int error = 0, wccpostattr = 0;
+       mbuf_t mreq, mrep, md, mb, mb2;
        int v3;
        u_int64_t xid;
        struct timeval now;
 
-       if (!VFSTONFS(vp->v_mount))
+       if (!VFSTONFS(vnode_mount(vp)))
                return (ENXIO);
        v3 = NFS_ISV3(vp);
 
-       nfsstats.rpccnt[NFSPROC_SETATTR]++;
-       nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
+       nfsm_reqhead(NFSX_FH(v3) + NFSX_SATTR(v3));
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_SETATTR]);
        nfsm_fhtom(vp, v3);
        if (v3) {
-               if (vap->va_mode != (u_short)VNOVAL) {
+               if (VATTR_IS_ACTIVE(vap, va_mode)) {
                        nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
                        *tl++ = nfs_true;
                        *tl = txdr_unsigned(vap->va_mode);
@@ -1135,7 +1233,7 @@ nfs_setattrrpc(vp, vap, cred, procp)
                        nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                        *tl = nfs_false;
                }
-               if (vap->va_uid != (uid_t)VNOVAL) {
+               if (VATTR_IS_ACTIVE(vap, va_uid)) {
                        nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
                        *tl++ = nfs_true;
                        *tl = txdr_unsigned(vap->va_uid);
@@ -1143,7 +1241,7 @@ nfs_setattrrpc(vp, vap, cred, procp)
                        nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                        *tl = nfs_false;
                }
-               if (vap->va_gid != (gid_t)VNOVAL) {
+               if (VATTR_IS_ACTIVE(vap, va_gid)) {
                        nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
                        *tl++ = nfs_true;
                        *tl = txdr_unsigned(vap->va_gid);
@@ -1151,20 +1249,20 @@ nfs_setattrrpc(vp, vap, cred, procp)
                        nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                        *tl = nfs_false;
                }
-               if (vap->va_size != VNOVAL) {
+               if (VATTR_IS_ACTIVE(vap, va_data_size)) {
                        nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
                        *tl++ = nfs_true;
-                       txdr_hyper(&vap->va_size, tl);
+                       txdr_hyper(&vap->va_data_size, tl);
                } else {
                        nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                        *tl = nfs_false;
                }
                microtime(&now);
-               if (vap->va_atime.tv_sec != VNOVAL) {
-                       if (vap->va_atime.tv_sec != now.tv_sec) {
+               if (VATTR_IS_ACTIVE(vap, va_access_time)) {
+                       if (vap->va_access_time.tv_sec != now.tv_sec) {
                                nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
                                *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
-                               txdr_nfsv3time(&vap->va_atime, tl);
+                               txdr_nfsv3time(&vap->va_access_time, tl);
                        } else {
                                nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                                *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
@@ -1173,11 +1271,11 @@ nfs_setattrrpc(vp, vap, cred, procp)
                        nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                        *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
                }
-               if (vap->va_mtime.tv_sec != VNOVAL) {
-                       if (vap->va_mtime.tv_sec != now.tv_sec) {
+               if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
+                       if (vap->va_modify_time.tv_sec != now.tv_sec) {
                                nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
                                *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
-                               txdr_nfsv3time(&vap->va_mtime, tl);
+                               txdr_nfsv3time(&vap->va_modify_time, tl);
                        } else {
                                nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                                *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
@@ -1189,30 +1287,57 @@ nfs_setattrrpc(vp, vap, cred, procp)
                nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                *tl = nfs_false;
        } else {
+               struct timespec neg1time = { -1, -1 };
                nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
-               if (vap->va_mode == (u_short)VNOVAL)
-                       sp->sa_mode = VNOVAL;
-               else
-                       sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
-               if (vap->va_uid == (uid_t)VNOVAL)
-                       sp->sa_uid = VNOVAL;
+               if (VATTR_IS_ACTIVE(vap, va_mode))
+                       sp->sa_mode = vtonfsv2_mode(vnode_vtype(vp), vap->va_mode);
                else
+                       sp->sa_mode = nfs_xdrneg1;
+               if (VATTR_IS_ACTIVE(vap, va_uid))
                        sp->sa_uid = txdr_unsigned(vap->va_uid);
-               if (vap->va_gid == (gid_t)VNOVAL)
-                       sp->sa_gid = VNOVAL;
                else
+                       sp->sa_uid = nfs_xdrneg1;
+               if (VATTR_IS_ACTIVE(vap, va_gid))
                        sp->sa_gid = txdr_unsigned(vap->va_gid);
-               sp->sa_size = txdr_unsigned(vap->va_size);
-               txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
-               txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
+               else
+                       sp->sa_gid = nfs_xdrneg1;
+               if (VATTR_IS_ACTIVE(vap, va_data_size))
+                       sp->sa_size = txdr_unsigned(vap->va_data_size);
+               else
+                       sp->sa_size = nfs_xdrneg1;
+               if (VATTR_IS_ACTIVE(vap, va_access_time)) {
+                       txdr_nfsv2time(&vap->va_access_time, &sp->sa_atime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_atime);
+               }
+               if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
+                       txdr_nfsv2time(&vap->va_modify_time, &sp->sa_mtime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_mtime);
+               }
        }
        nfsm_request(vp, NFSPROC_SETATTR, procp, cred, &xid);
        if (v3) {
-               nfsm_wcc_data(vp, wccflag, &xid);
-               if (!wccflag)
-                       VTONFS(vp)->n_attrstamp = 0;
-       } else
-               nfsm_loadattr(vp, (struct vattr *)0, &xid);
+               struct timespec premtime = { 0, 0 };
+               if (mrep) {
+                       nfsm_wcc_data(vp, &premtime, wccpostattr, &xid);
+               }
+               /* if file hadn't changed, update cached mtime */
+               if (nfstimespeccmp(&VTONFS(vp)->n_mtime, &premtime, ==)) {
+                       VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.nva_mtime;
+               }
+               /* if directory hadn't changed, update namecache mtime */
+               if ((vnode_vtype(vp) == VDIR) &&
+                   nfstimespeccmp(&VTONFS(vp)->n_ncmtime, &premtime, ==)) {
+                       VTONFS(vp)->n_ncmtime = VTONFS(vp)->n_vattr.nva_mtime;
+               }
+               if (!wccpostattr)
+                       NATTRINVALIDATE(VTONFS(vp));
+       } else {
+               if (mrep) {
+                       nfsm_loadattr(vp, v3, NULL, &xid);
+               }
+       }
        nfsm_reqdone;
        return (error);
 }
@@ -1224,230 +1349,234 @@ nfs_setattrrpc(vp, vap, cred, procp)
  */
 static int
 nfs_lookup(ap)
-       struct vop_lookup_args /* {
+       struct vnop_lookup_args /* {
                struct vnodeop_desc *a_desc;
-               struct vnode *a_dvp;
-               struct vnode **a_vpp;
+               vnode_t a_dvp;
+               vnode_t *a_vpp;
                struct componentname *a_cnp;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct componentname *cnp = ap->a_cnp;
-       register struct vnode *dvp = ap->a_dvp;
-       register struct vnode **vpp = ap->a_vpp;
-       register int flags = cnp->cn_flags;
-       register struct vnode *newvp;
-       register u_long *tl;
-       register caddr_t cp;
-       register long t1, t2;
+       struct componentname *cnp = ap->a_cnp;
+       vnode_t dvp = ap->a_dvp;
+       vnode_t *vpp = ap->a_vpp;
+       int flags = cnp->cn_flags;
+       vnode_t newvp;
+       u_long *tl;
+       caddr_t cp;
+       long t1, t2;
        caddr_t bpos, dpos, cp2;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       mbuf_t mreq, mrep, md, mb, mb2;
        long len;
-       nfsfh_t *fhp;
-       struct nfsnode *np;
-       int lockparent, wantparent, error = 0, attrflag, fhsize;
+       u_char *fhp;
+       struct nfsnode *dnp, *np;
+       int wantparent, error, attrflag, dattrflag, fhsize, fhisdvp;
        int v3 = NFS_ISV3(dvp);
-       struct proc *p = cnp->cn_proc;
-       int unlockdvp = 0;
-       u_int64_t xid;
-       struct vattr vattr;
+       u_int64_t xid, dxid;
+       struct nfs_vattr nvattr;
+       kauth_cred_t cred;
+       proc_t p;
+       int ngflags;
 
-       if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
-           (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
-               return (EROFS);
        *vpp = NULLVP;
-       if (dvp->v_type != VDIR)
-               return (ENOTDIR);
-
-       lockparent = flags & LOCKPARENT;
-       wantparent = flags & (LOCKPARENT|WANTPARENT);
-       np = VTONFS(dvp);
-
-       /* if directory has changed, purge any name cache entries */
-       if (!VOP_GETATTR(dvp, &vattr, cnp->cn_cred, p) &&
-           (np->n_mtime != vattr.va_mtime.tv_sec))
-               cache_purge(dvp);
-
-       if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
-               int vpid;
 
-               newvp = *vpp;
-               vpid = newvp->v_id;
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
 
-               /*
-                * See the comment starting `Step through' in ufs/ufs_lookup.c
-                * for an explanation of the locking protocol
-                */
+       wantparent = flags & (LOCKPARENT|WANTPARENT);
+       dnp = VTONFS(dvp);
 
+       error = nfs_getattr(dvp, &nvattr, cred, p);
+       if (error)
+               goto error_return;
+       if (nfstimespeccmp(&dnp->n_ncmtime, &nvattr.nva_mtime, !=)) {
                /*
-                * Note: we need to make sure to get a lock/ref on newvp
-                * before we possibly go off to the server in VOP_ACCESS.
+                * This directory has changed on us.
+                * Purge any name cache entries.
                 */
-               if (dvp == newvp) {
-                       VREF(newvp);
-                       error = 0;
-               } else if (flags & ISDOTDOT) {
-                       VOP_UNLOCK(dvp, 0, p);
-                       error = vget(newvp, LK_EXCLUSIVE, p);
-                       if (!error)
-                               error = vn_lock(dvp, LK_EXCLUSIVE, p);
-               } else {
-                       error = vget(newvp, LK_EXCLUSIVE, p);
-                       if (error)
-                               VOP_UNLOCK(dvp, 0, p);
-               }
+               cache_purge(dvp);
+               dnp->n_ncmtime = nvattr.nva_mtime;
+       }
 
-               if (error)
-                       goto cache_lookup_out;
+       error = cache_lookup(dvp, vpp, cnp);
+       switch (error) {
+       case ENOENT:
+               /* negative cache entry same as cache miss */
+               error = 0;
+               /* FALLTHROUGH */
+       case 0:
+               /* cache miss */
+               break;
+       case -1:
+               /* cache hit, not really an error */
+       {
+               struct vnop_access_args naa;
+
+               OSAddAtomic(1, (SInt32*)&nfsstats.lookupcache_hits);
+
+               /* check for directory access */
+               naa.a_vp = dvp;
+               naa.a_action = KAUTH_VNODE_SEARCH;
+               naa.a_context = ap->a_context;
+
+               /* compute actual success/failure based on accessibility */
+               error = nfs_access(&naa);
+       }
+               /* FALLTHROUGH */
+       default:
+               /* unexpected error from cache_lookup */
+               goto error_return;
+       }
+       
+       /* check for lookup of "." */
+       if ((cnp->cn_nameptr[0] == '.') && (cnp->cn_namelen == 1)) {
+               /* skip lookup, we know who we are */
+               fhisdvp = 1;
+               fhp = NULL;
+               fhsize = 0;
+               mrep = NULL;
+               goto found;
+       }
 
-               if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p))) {
-                       if (dvp == newvp)
-                               vrele(newvp);
-                       else
-                               vput(newvp);
-                       *vpp = NULLVP;
+       /* do we know this name is too long? */
+       if (v3) {
+               /* For NFSv3: need uniform pathconf info to test pc_namemax */
+               struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
+               if (!nmp) {
+                       error = ENXIO;
                        goto error_return;
-                       }
-
-               if ((dvp != newvp) && (!lockparent || !(flags & ISLASTCN)))
-                       VOP_UNLOCK(dvp, 0, p);
-
-               if (vpid == newvp->v_id) {
-                       if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, p)
-                               && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
-                               nfsstats.lookupcache_hits++;
-                               if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
-                                       cnp->cn_flags |= SAVENAME;
-                               error = 0; /* ignore any from VOP_GETATTR  */
-                               goto error_return;
-                       }
-                       cache_purge(newvp);
                }
-               vput(newvp);
-               if ((dvp != newvp) && lockparent && (flags & ISLASTCN))
-                       VOP_UNLOCK(dvp, 0, p);
-cache_lookup_out:
-               error = vn_lock(dvp, LK_EXCLUSIVE, p);
-               *vpp = NULLVP;
-               if (error) 
+               if (((nmp->nm_state & (NFSSTA_GOTFSINFO|NFSSTA_GOTPATHCONF)) ==
+                       (NFSSTA_GOTFSINFO|NFSSTA_GOTPATHCONF)) &&
+                    (nmp->nm_fsinfo.fsproperties & NFSV3FSINFO_HOMOGENEOUS) &&
+                    (cnp->cn_namelen > (long)nmp->nm_fsinfo.namemax)) {
+                       error = ENAMETOOLONG;
                        goto error_return;
+               }
+       } else if (cnp->cn_namelen > NFS_MAXNAMLEN) {
+               error = ENAMETOOLONG;
+               goto error_return;
        }
 
        error = 0;
        newvp = NULLVP;
-       nfsstats.lookupcache_misses++;
-       nfsstats.rpccnt[NFSPROC_LOOKUP]++;
+
+       OSAddAtomic(1, (SInt32*)&nfsstats.lookupcache_misses);
        len = cnp->cn_namelen;
-       nfsm_reqhead(dvp, NFSPROC_LOOKUP,
-               NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
+       nfsm_reqhead(NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
+       if (error)
+               goto error_return;
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_LOOKUP]);
        nfsm_fhtom(dvp, v3);
-       nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
+       nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN, v3);
        /* nfsm_request for NFSv2 causes you to goto to nfsmout upon errors */
-       nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred, &xid); 
+       nfsm_request(dvp, NFSPROC_LOOKUP, p, cred, &xid); 
 
        if (error) {
-               nfsm_postop_attr(dvp, attrflag, &xid);
-               m_freem(mrep);
+               if (mrep) {
+                       nfsm_postop_attr_update(dvp, v3, dattrflag, &xid);
+                       mbuf_freem(mrep);
+               }
                goto nfsmout;
        }
+
+       /* get the filehandle */
        nfsm_getfh(fhp, fhsize, v3);
+       /* is the file handle the same as this directory's file handle? */
+       fhisdvp = NFS_CMPFH(dnp, fhp, fhsize);
+
+       /* get attributes */
+       if (v3) {
+               dxid = xid;
+               nfsm_postop_attr_get(v3, attrflag, &nvattr);
+               nfsm_postop_attr_update(dvp, v3, dattrflag, &dxid);
+               if (!attrflag && (!fhisdvp || !dattrflag)) {
+                       /* We need valid attributes in order */
+                       /* to call nfs_nget/vnode_create().  */
+                       error = nfs_getattr_no_vnode(vnode_mount(dvp),
+                                       fhp, fhsize, cred, p, &nvattr, &xid);
+                       if (error) {
+                               mbuf_freem(mrep);
+                               goto error_return;
+                       }
+               }
+       } else {
+               nfsm_attr_get(v3, &nvattr);
+       }
+
+found:
 
        /*
         * Handle RENAME case...
         */
        if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
-               if (NFS_CMPFH(np, fhp, fhsize)) {
-                       m_freem(mrep);
+               if (fhisdvp) {
+                       mbuf_freem(mrep);
                        error = EISDIR;
                        goto error_return;
                }
-               if ((error = nfs_nget(dvp->v_mount, fhp, fhsize, &np))) {
-                       m_freem(mrep);
+               error = nfs_nget(vnode_mount(dvp), dvp, cnp, fhp, fhsize,
+                               &nvattr, &xid, 0, &np);
+               if (error) {
+                       mbuf_freem(mrep);
                        goto error_return;
                }
-               newvp = NFSTOV(np);
-               if (v3) {
-                       u_int64_t dxid = xid;
+               *vpp = NFSTOV(np);
+               mbuf_freem(mrep);
 
-                       nfsm_postop_attr(newvp, attrflag, &xid);
-                       nfsm_postop_attr(dvp, attrflag, &dxid);
-               } else
-                       nfsm_loadattr(newvp, (struct vattr *)0, &xid);
-               *vpp = newvp;
-               m_freem(mrep);
-               cnp->cn_flags |= SAVENAME;
-               if (!lockparent)
-                       VOP_UNLOCK(dvp, 0, p);
-               error = 0;
                goto error_return;
        }
 
-       if (NFS_CMPFH(np, fhp, fhsize)) {
-               VREF(dvp);
-               newvp = dvp;
-       } else if (flags & ISDOTDOT) {
-               VOP_UNLOCK(dvp, 0, p);
-               error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
+       if ((cnp->cn_flags & MAKEENTRY) &&
+           (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)))
+               ngflags = NG_MAKEENTRY;
+       else
+               ngflags = 0;
+
+       if (fhisdvp) {
+               error = vnode_get(dvp);
                if (error) {
-                       m_freem(mrep);
-                       vn_lock(dvp, LK_EXCLUSIVE + LK_RETRY, p);
+                       mbuf_freem(mrep);
                        goto error_return;
                }
-               newvp = NFSTOV(np);
-               if (!lockparent || !(flags & ISLASTCN))
-                       unlockdvp = 1; /* keep dvp locked until after postops */
-               if (error = vn_lock(dvp, LK_EXCLUSIVE, p)) {
-                       m_freem(mrep);
-                       vput(newvp);
-                       goto error_return;
+               newvp = dvp;
+               /* test fhp to see if we have valid attributes in nvattr */
+               if (fhp && (dnp->n_xid <= xid)) {
+                       error = nfs_loadattrcache(dnp, &nvattr, &xid, 0);
+                       if (error) {
+                               vnode_put(dvp);
+                               mbuf_freem(mrep);
+                               goto error_return;
+                       }
                }
        } else {
-               if ((error = nfs_nget(dvp->v_mount, fhp, fhsize, &np))) {
-                       m_freem(mrep);
+               error = nfs_nget(vnode_mount(dvp), dvp, cnp, fhp, fhsize,
+                               &nvattr, &xid, ngflags, &np);
+               if (error) {
+                       mbuf_freem(mrep);
                        goto error_return;
                }
-               if (!lockparent || !(flags & ISLASTCN))
-                       unlockdvp = 1; /* keep dvp locked until after postops */
                newvp = NFSTOV(np);
        }
-       if (v3) {
-               u_int64_t dxid = xid;
-
-               nfsm_postop_attr(newvp, attrflag, &xid);
-               nfsm_postop_attr(dvp, attrflag, &dxid);
-       } else
-               nfsm_loadattr(newvp, (struct vattr *)0, &xid);
-       if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
-               cnp->cn_flags |= SAVENAME;
-       if ((cnp->cn_flags & MAKEENTRY) &&
-           (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
-               np->n_ctime = np->n_vattr.va_ctime.tv_sec;
-               cache_enter(dvp, newvp, cnp);
-       }
        *vpp = newvp;
+//     if (error == 0 && *vpp != NULL && *vpp != dvp)
+//             nfs_unlock(VTONFS(*vpp));
+
        nfsm_reqdone;
-       if (unlockdvp)
-               VOP_UNLOCK(dvp, 0, p);
        if (error) {
-               if (newvp != NULLVP) {
-                       if (newvp == dvp)
-                               vrele(newvp);
-                       else
-                               vput(newvp);
-                       *vpp = NULLVP;
-               }
                if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
                    (flags & ISLASTCN) && error == ENOENT) {
-                       if (dvp->v_mount && (dvp->v_mount->mnt_flag & MNT_RDONLY))
+                       if (vnode_mount(dvp) && vnode_vfsisrdonly(dvp))
                                error = EROFS;
                        else
                                error = EJUSTRETURN;
-                       if (!lockparent)
-                               VOP_UNLOCK(dvp, 0, p);
                }
-               if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
-                       cnp->cn_flags |= SAVENAME;
        }
 error_return:
+       if (error && *vpp) {
+               vnode_put(*vpp);
+               *vpp = NULLVP;
+       }
        return (error);
 }
 
@@ -1457,18 +1586,19 @@ error_return:
  */
 static int
 nfs_read(ap)
-       struct vop_read_args /* {
-               struct vnode *a_vp;
+       struct vnop_read_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
                struct uio *a_uio;
-               int  a_ioflag;
-               struct ucred *a_cred;
+               int a_ioflag;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-
-       if (vp->v_type != VREG)
+       if (vnode_vtype(ap->a_vp) != VREG)
                return (EPERM);
-       return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred, 0));
+       return (nfs_bioread(ap->a_vp, ap->a_uio, ap->a_ioflag,
+               vfs_context_ucred(ap->a_context),
+               vfs_context_proc(ap->a_context)));
 }
 
 
@@ -1477,17 +1607,18 @@ nfs_read(ap)
  */
 static int
 nfs_readlink(ap)
-       struct vop_readlink_args /* {
-               struct vnode *a_vp;
+       struct vnop_readlink_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
                struct uio *a_uio;
-               struct ucred *a_cred;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-
-       if (vp->v_type != VLNK)
+       if (vnode_vtype(ap->a_vp) != VLNK)
                return (EPERM);
-       return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred, 0));
+       return (nfs_bioread(ap->a_vp, ap->a_uio, 0,
+               vfs_context_ucred(ap->a_context),
+               vfs_context_proc(ap->a_context)));
 }
 
 /*
@@ -1495,33 +1626,36 @@ nfs_readlink(ap)
  * Called by nfs_doio() from below the buffer cache.
  */
 int
-nfs_readlinkrpc(vp, uiop, cred)
-       register struct vnode *vp;
-       struct uio *uiop;
-       struct ucred *cred;
+nfs_readlinkrpc(
+       vnode_t vp,
+       struct uio *uiop,
+       kauth_cred_t cred,
+       proc_t p)
 {
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
        caddr_t bpos, dpos, cp2;
        int error = 0, len, attrflag;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       mbuf_t mreq, mrep, md, mb, mb2;
        int v3;
        u_int64_t xid;
 
-       if (!VFSTONFS(vp->v_mount))
+       if (!VFSTONFS(vnode_mount(vp)))
                return (ENXIO);
        v3 = NFS_ISV3(vp);
 
-       nfsstats.rpccnt[NFSPROC_READLINK]++;
-       nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
+       nfsm_reqhead(NFSX_FH(v3));
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_READLINK]);
        nfsm_fhtom(vp, v3);
-       nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred, &xid);
-       if (v3)
-               nfsm_postop_attr(vp, attrflag, &xid);
+       nfsm_request(vp, NFSPROC_READLINK, p, cred, &xid);
+       if (v3 && mrep)
+               nfsm_postop_attr_update(vp, v3, attrflag, &xid);
        if (!error) {
-               nfsm_strsiz(len, NFS_MAXPATHLEN);
-               if (len == NFS_MAXPATHLEN) {
+               nfsm_strsiz(len, NFS_MAXPATHLEN, v3);
+               if (len >= NFS_MAXPATHLEN) {
                        struct nfsnode *np = VTONFS(vp);
 #if DIAGNOSTIC
                         if (!np)
@@ -1541,37 +1675,41 @@ nfs_readlinkrpc(vp, uiop, cred)
  * Ditto above
  */
 int
-nfs_readrpc(vp, uiop, cred)
-       register struct vnode *vp;
-       struct uio *uiop;
-       struct ucred *cred;
+nfs_readrpc(
+       vnode_t vp,
+       struct uio *uiop,
+       kauth_cred_t cred,
+       proc_t p)
 {
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
        caddr_t bpos, dpos, cp2;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       mbuf_t mreq, mrep, md, mb, mb2;
        struct nfsmount *nmp;
        int error = 0, len, retlen, tsiz, eof = 0, attrflag;
        int v3, nmrsize;
        u_int64_t xid;
 
-       FSDBG_TOP(536, vp, uiop->uio_offset, uiop->uio_resid, 0);
-       nmp = VFSTONFS(vp->v_mount);
+       FSDBG_TOP(536, vp, uiop->uio_offset, uio_uio_resid(uiop), 0);
+       nmp = VFSTONFS(vnode_mount(vp));
        if (!nmp)
                return (ENXIO);
        v3 = NFS_ISV3(vp);
        nmrsize = nmp->nm_rsize;
 
-       tsiz = uiop->uio_resid;
+       // LP64todo - fix this
+       tsiz = uio_uio_resid(uiop);
         if (((u_int64_t)uiop->uio_offset + (unsigned int)tsiz > 0xffffffff) && !v3) {
-               FSDBG_BOT(536, vp, uiop->uio_offset, uiop->uio_resid, EFBIG);
+               FSDBG_BOT(536, vp, uiop->uio_offset, uio_uio_resid(uiop), EFBIG);
                return (EFBIG);
        }
        while (tsiz > 0) {
-               nfsstats.rpccnt[NFSPROC_READ]++;
                len = (tsiz > nmrsize) ? nmrsize : tsiz;
-               nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
+               nfsm_reqhead(NFSX_FH(v3) + NFSX_UNSIGNED * 3);
+               if (error)
+                       break;
+               OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_READ]);
                nfsm_fhtom(vp, v3);
                nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3);
                if (v3) {
@@ -1583,29 +1721,38 @@ nfs_readrpc(vp, uiop, cred)
                        *tl = 0;
                }
                FSDBG(536, vp, uiop->uio_offset, len, 0);
-               nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred, &xid);
+               nfsm_request(vp, NFSPROC_READ, p, cred, &xid);
                if (v3) {
-                       nfsm_postop_attr(vp, attrflag, &xid);
+                       if (mrep) {
+                               nfsm_postop_attr_update(vp, v3, attrflag, &xid);
+                       }
                        if (error) {
-                               m_freem(mrep);
+                               mbuf_freem(mrep);
                                goto nfsmout;
                        }
                        nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
                        eof = fxdr_unsigned(int, *(tl + 1));
-               } else
-                       nfsm_loadattr(vp, (struct vattr *)0, &xid);
-               nfsm_strsiz(retlen, nmrsize);
-               nfsm_mtouio(uiop, retlen);
-               m_freem(mrep);
-               tsiz -= retlen;
-               if (v3) {
-                       if (eof || retlen == 0)
-                               tsiz = 0;
+               } else {
+                       if (mrep) {
+                               nfsm_loadattr(vp, v3, NULL, &xid);
+                       }
+               }
+               if (mrep) {
+                       nfsm_strsiz(retlen, nmrsize, 0);
+                       nfsm_mtouio(uiop, retlen);
+                       mbuf_freem(mrep);
+               } else {
+                       retlen = 0;
+               }
+               tsiz -= retlen;
+               if (v3) {
+                       if (eof || retlen == 0)
+                               tsiz = 0;
                } else if (retlen < len)
                        tsiz = 0;
        }
 nfsmout:
-       FSDBG_BOT(536, vp, eof, uiop->uio_resid, error);
+       FSDBG_BOT(536, vp, eof, uio_uio_resid(uiop), error);
        return (error);
 }
 
@@ -1613,47 +1760,52 @@ nfsmout:
  * nfs write call
  */
 int
-nfs_writerpc(vp, uiop, cred, iomode, must_commit)
-       register struct vnode *vp;
-       register struct uio *uiop;
-       struct ucred *cred;
-       int *iomode, *must_commit;
+nfs_writerpc(
+       vnode_t vp,
+       struct uio *uiop,
+       kauth_cred_t cred,
+       proc_t p,
+       int *iomode,
+       int *must_commit)
 {
        register u_long *tl;
        register caddr_t cp;
        register int t1, t2, backup;
        caddr_t bpos, dpos, cp2;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       mbuf_t mreq, mrep, md, mb, mb2;
        struct nfsmount *nmp;
-       int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
+       int error = 0, len, tsiz, updatemtime = 0, wccpostattr = 0, rlen, commit;
        int v3, committed = NFSV3WRITE_FILESYNC;
        u_int64_t xid;
+       mount_t mp;
 
 #if DIAGNOSTIC
        if (uiop->uio_iovcnt != 1)
                panic("nfs_writerpc: iovcnt > 1");
 #endif
-       FSDBG_TOP(537, vp, uiop->uio_offset, uiop->uio_resid, *iomode);
-       nmp = VFSTONFS(vp->v_mount);
+       FSDBG_TOP(537, vp, uiop->uio_offset, uio_uio_resid(uiop), *iomode);
+       nmp = VFSTONFS(vnode_mount(vp));
        if (!nmp)
                return (ENXIO);
        v3 = NFS_ISV3(vp);
        *must_commit = 0;
-       tsiz = uiop->uio_resid;
+       // LP64todo - fix this
+       tsiz = uio_uio_resid(uiop);
         if (((u_int64_t)uiop->uio_offset + (unsigned int)tsiz > 0xffffffff) && !v3) {
-               FSDBG_BOT(537, vp, uiop->uio_offset, uiop->uio_resid, EFBIG);
+               FSDBG_BOT(537, vp, uiop->uio_offset, uio_uio_resid(uiop), EFBIG);
                return (EFBIG);
        }
        while (tsiz > 0) {
-               nmp = VFSTONFS(vp->v_mount);
+               nmp = VFSTONFS(vnode_mount(vp));
                if (!nmp) {
                        error = ENXIO;
                        break;
                }
-               nfsstats.rpccnt[NFSPROC_WRITE]++;
                len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
-               nfsm_reqhead(vp, NFSPROC_WRITE,
-                       NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
+               nfsm_reqhead(NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
+               if (error)
+                       break;
+               OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_WRITE]);
                nfsm_fhtom(vp, v3);
                if (v3) {
                        nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
@@ -1669,13 +1821,17 @@ nfs_writerpc(vp, uiop, cred, iomode, must_commit)
                *tl = txdr_unsigned(len);
                FSDBG(537, vp, uiop->uio_offset, len, 0);
                nfsm_uiotom(uiop, len);
-               nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred, &xid);
-               nmp = VFSTONFS(vp->v_mount);
+               nfsm_request(vp, NFSPROC_WRITE, p, cred, &xid);
+               nmp = VFSTONFS(vnode_mount(vp));
                if (!nmp)
                        error = ENXIO;
                if (v3) {
-                       wccflag = NFSV3_WCCCHK;
-                       nfsm_wcc_data(vp, wccflag, &xid);
+                       if (mrep) {
+                               struct timespec premtime;
+                               nfsm_wcc_data(vp, &premtime, wccpostattr, &xid);
+                               if (nfstimespeccmp(&VTONFS(vp)->n_mtime, &premtime, ==))
+                                       updatemtime = 1;
+                       }
                        if (!error) {
                                nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
                                        NFSX_V3WRITEVERF);
@@ -1685,10 +1841,10 @@ nfs_writerpc(vp, uiop, cred, iomode, must_commit)
                                        break;
                                } else if (rlen < len) {
                                        backup = len - rlen;
-                                       uiop->uio_iov->iov_base -= backup;
-                                       uiop->uio_iov->iov_len += backup;
+                                       uio_iov_base_add(uiop, -backup);
+                                       uio_iov_len_add(uiop, backup);
                                        uiop->uio_offset -= backup;
-                                       uiop->uio_resid += backup;
+                                       uio_uio_resid_add(uiop, backup);
                                        len = rlen;
                                }
                                commit = fxdr_unsigned(int, *tl++);
@@ -1713,12 +1869,15 @@ nfs_writerpc(vp, uiop, cred, iomode, must_commit)
                                        NFSX_V3WRITEVERF);
                                }
                        }
-               } else
-                   nfsm_loadattr(vp, (struct vattr *)0, &xid);
+               } else {
+                       if (mrep) {
+                               nfsm_loadattr(vp, v3, NULL, &xid);
+                       }
+               }
 
-               if (wccflag)
-                   VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
-               m_freem(mrep);
+               if (updatemtime)
+                       VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.nva_mtime;
+               mbuf_freem(mrep);
                /*
                 * we seem to have a case where we end up looping on shutdown
                 * and taking down nfs servers.  For V3, error cases, there is
@@ -1731,12 +1890,12 @@ nfs_writerpc(vp, uiop, cred, iomode, must_commit)
                tsiz -= len;
        }
 nfsmout:
-        if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_ASYNC))
+        if ((mp = vnode_mount(vp)) && (vfs_flags(mp) & MNT_ASYNC))
                committed = NFSV3WRITE_FILESYNC;
         *iomode = committed;
        if (error)
-               uiop->uio_resid = tsiz;
-       FSDBG_BOT(537, vp, committed, uiop->uio_resid, error);
+               uio_uio_resid_set(uiop, tsiz);
+       FSDBG_BOT(537, vp, committed, uio_uio_resid(uiop), error);
        return (error);
 }
 
@@ -1746,96 +1905,121 @@ nfsmout:
  * mode set to specify the file type and the size field for rdev.
  */
 static int
-nfs_mknodrpc(dvp, vpp, cnp, vap)
-       register struct vnode *dvp;
-       register struct vnode **vpp;
-       register struct componentname *cnp;
-       register struct vattr *vap;
+nfs_mknodrpc(
+       vnode_t dvp,
+       vnode_t *vpp,
+       struct componentname *cnp,
+       struct vnode_attr *vap,
+       kauth_cred_t cred,
+       proc_t p)
 {
        register struct nfsv2_sattr *sp;
-       register struct nfsv3_sattr *sp3;
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
-       struct vnode *newvp = (struct vnode *)0;
+       vnode_t newvp = (vnode_t)0;
        struct nfsnode *np = (struct nfsnode *)0;
-       struct vattr vattr;
+       struct nfs_vattr nvattr;
        char *cp2;
        caddr_t bpos, dpos;
-       int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       int error = 0, wccpostattr = 0, gotvp = 0;
+       struct timespec premtime = { 0, 0 };
+       mbuf_t mreq, mrep, md, mb, mb2;
        u_long rdev;
        u_int64_t xid;
        int v3 = NFS_ISV3(dvp);
+       int gotuid, gotgid;
 
-       if (vap->va_type == VCHR || vap->va_type == VBLK)
+       if (!VATTR_IS_ACTIVE(vap, va_type))
+               return (EINVAL);
+       if (vap->va_type == VCHR || vap->va_type == VBLK) {
+               if (!VATTR_IS_ACTIVE(vap, va_rdev))
+                       return (EINVAL);
                rdev = txdr_unsigned(vap->va_rdev);
-       else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
+       else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
                rdev = 0xffffffff;
        else {
-               VOP_ABORTOP(dvp, cnp);
-               vput(dvp);
-               return (EOPNOTSUPP);
+               return (ENOTSUP);
        }
-       if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
-               VOP_ABORTOP(dvp, cnp);
-               vput(dvp);
+       nfsm_reqhead(NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
+               nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
+       if (error)
                return (error);
-       }
-       nfsstats.rpccnt[NFSPROC_MKNOD]++;
-       nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
-               + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
+
+       VATTR_SET_SUPPORTED(vap, va_mode);
+       VATTR_SET_SUPPORTED(vap, va_uid);
+       VATTR_SET_SUPPORTED(vap, va_gid);
+       VATTR_SET_SUPPORTED(vap, va_data_size);
+       VATTR_SET_SUPPORTED(vap, va_access_time);
+       VATTR_SET_SUPPORTED(vap, va_modify_time);
+       gotuid = VATTR_IS_ACTIVE(vap, va_uid);
+       gotgid = VATTR_IS_ACTIVE(vap, va_gid);
+
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_MKNOD]);
        nfsm_fhtom(dvp, v3);
-       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
+       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, v3);
        if (v3) {
-               nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR);
+               nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                *tl++ = vtonfsv3_type(vap->va_type);
-               sp3 = (struct nfsv3_sattr *)tl;
-               nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
+               nfsm_v3sattr(vap);
                if (vap->va_type == VCHR || vap->va_type == VBLK) {
                        nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
                        *tl++ = txdr_unsigned(major(vap->va_rdev));
                        *tl = txdr_unsigned(minor(vap->va_rdev));
                }
        } else {
+               struct timespec neg1time = { -1, -1 };
                nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
-               sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
-               sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
-               sp->sa_gid = txdr_unsigned(vattr.va_gid);
+               sp->sa_mode = vtonfsv2_mode(vap->va_type,
+                       (VATTR_IS_ACTIVE(vap, va_mode) ? vap->va_mode : 0600));
+               sp->sa_uid = gotuid ? (u_long)txdr_unsigned(vap->va_uid) : nfs_xdrneg1;
+               sp->sa_gid = gotgid ? (u_long)txdr_unsigned(vap->va_gid) : nfs_xdrneg1;
                sp->sa_size = rdev;
-               txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
-               txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
+               if (VATTR_IS_ACTIVE(vap, va_access_time)) {
+                       txdr_nfsv2time(&vap->va_access_time, &sp->sa_atime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_atime);
+               }
+               if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
+                       txdr_nfsv2time(&vap->va_modify_time, &sp->sa_mtime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_mtime);
+               }
        }
-       nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred, &xid);
+       nfsm_request(dvp, NFSPROC_MKNOD, p, cred, &xid);
+       /* XXX no EEXIST kludge here? */
        if (!error) {
-               nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
+               nfsm_mtofh(dvp, cnp, newvp, v3, &xid, gotvp);
                if (!gotvp) {
-                       if (newvp) {
-                               vput(newvp);
-                               newvp = (struct vnode *)0;
-                       }
                        error = nfs_lookitup(dvp, cnp->cn_nameptr,
-                           cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
+                           cnp->cn_namelen, cred, p, &np);
                        if (!error)
                                newvp = NFSTOV(np);
                }
        }
-       if (v3)
-               nfsm_wcc_data(dvp, wccflag, &xid);
+       if (v3 && mrep)
+               nfsm_wcc_data(dvp, &premtime, wccpostattr, &xid);
+       if (!error && (gotuid || gotgid) &&
+           (!newvp || nfs_getattrcache(newvp, &nvattr) ||
+            (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);
+       }
        nfsm_reqdone;
        if (error) {
                if (newvp)
-                       vput(newvp);
+                       vnode_put(newvp);
        } else {
-               if (cnp->cn_flags & MAKEENTRY)
-                       cache_enter(dvp, newvp, cnp);
                *vpp = newvp;
        }
        VTONFS(dvp)->n_flag |= NMODIFIED;
-       if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
-       vput(dvp);
-       NFS_FREE_PNBUF(cnp);
+       /* if directory hadn't changed, update namecache mtime */
+       if (nfstimespeccmp(&VTONFS(dvp)->n_ncmtime, &premtime, ==))
+               VTONFS(dvp)->n_ncmtime = VTONFS(dvp)->n_vattr.nva_mtime;
+       if (!wccpostattr)
+               NATTRINVALIDATE(VTONFS(dvp));
        return (error);
 }
 
@@ -1846,20 +2030,21 @@ nfs_mknodrpc(dvp, vpp, cnp, vap)
 /* ARGSUSED */
 static int
 nfs_mknod(ap)
-       struct vop_mknod_args /* {
-               struct vnode *a_dvp;
-               struct vnode **a_vpp;
+       struct vnop_mknod_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_dvp;
+               vnode_t *a_vpp;
                struct componentname *a_cnp;
-               struct vattr *a_vap;
+               struct vnode_attr *a_vap;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       struct vnode *newvp;
        int error;
 
-       error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
-       if (!error && newvp)
-               vput(newvp);
-       *ap->a_vpp = 0;
+       error = nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap,
+                       vfs_context_ucred(ap->a_context),
+                       vfs_context_proc(ap->a_context));
+
        return (error);
 }
 
@@ -1869,49 +2054,66 @@ static u_long create_verf;
  */
 static int
 nfs_create(ap)
-       struct vop_create_args /* {
-               struct vnode *a_dvp;
-               struct vnode **a_vpp;
+       struct vnop_create_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_dvp;
+               vnode_t *a_vpp;
                struct componentname *a_cnp;
-               struct vattr *a_vap;
+               struct vnode_attr *a_vap;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *dvp = ap->a_dvp;
-       register struct vattr *vap = ap->a_vap;
-       register struct componentname *cnp = ap->a_cnp;
-       register struct nfsv2_sattr *sp;
-       register struct nfsv3_sattr *sp3;
-       register u_long *tl;
-       register caddr_t cp;
-       register long t1, t2;
+       vnode_t dvp = ap->a_dvp;
+       struct vnode_attr *vap = ap->a_vap;
+       struct componentname *cnp = ap->a_cnp;
+       struct nfs_vattr nvattr;
+       struct nfsv2_sattr *sp;
+       u_long *tl;
+       caddr_t cp;
+       long t1, t2;
        struct nfsnode *np = (struct nfsnode *)0;
-       struct vnode *newvp = (struct vnode *)0;
+       vnode_t newvp = (vnode_t)0;
        caddr_t bpos, dpos, cp2;
-       int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-       struct vattr vattr;
+       int error = 0, wccpostattr = 0, gotvp = 0, fmode = 0;
+       struct timespec premtime = { 0, 0 };
+       mbuf_t mreq, mrep, md, mb, mb2;
        int v3 = NFS_ISV3(dvp);
+       int gotuid, gotgid;
        u_int64_t xid;
+       kauth_cred_t cred;
+       proc_t p;
+
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
+
+       if (!VATTR_IS_ACTIVE(vap, va_type))
+               return (EINVAL);
 
        /*
         * Oops, not for me..
         */
        if (vap->va_type == VSOCK)
-               return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
+               return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap, cred, p));
+
+       VATTR_SET_SUPPORTED(vap, va_mode);
+       VATTR_SET_SUPPORTED(vap, va_uid);
+       VATTR_SET_SUPPORTED(vap, va_gid);
+       VATTR_SET_SUPPORTED(vap, va_data_size);
+       VATTR_SET_SUPPORTED(vap, va_access_time);
+       VATTR_SET_SUPPORTED(vap, va_modify_time);
+       gotuid = VATTR_IS_ACTIVE(vap, va_uid);
+       gotgid = VATTR_IS_ACTIVE(vap, va_gid);
 
-       if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
-               VOP_ABORTOP(dvp, cnp);
-               vput(dvp);
-               return (error);
-       }
        if (vap->va_vaflags & VA_EXCLUSIVE)
                fmode |= O_EXCL;
 again:
-       nfsstats.rpccnt[NFSPROC_CREATE]++;
-       nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
+       nfsm_reqhead(NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
                nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_CREATE]);
        nfsm_fhtom(dvp, v3);
-       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
+       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, v3);
        if (v3) {
                nfsm_build(tl, u_long *, NFSX_UNSIGNED);
                if (fmode & O_EXCL) {
@@ -1924,35 +2126,39 @@ again:
                    *tl = ++create_verf;
                } else {
                    *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
-                   nfsm_build(tl, u_long *, NFSX_V3SRVSATTR);
-                   sp3 = (struct nfsv3_sattr *)tl;
-                   nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
+                   nfsm_v3sattr(vap);
                }
        } else {
+               struct timespec neg1time = { -1, -1 };
                nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
-               sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
-               sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
-               sp->sa_gid = txdr_unsigned(vattr.va_gid);
+               sp->sa_mode = vtonfsv2_mode(vap->va_type,
+                       (VATTR_IS_ACTIVE(vap, va_mode) ? vap->va_mode : 0600));
+               sp->sa_uid = gotuid ? (u_long)txdr_unsigned(vap->va_uid) : nfs_xdrneg1;
+               sp->sa_gid = gotgid ? (u_long)txdr_unsigned(vap->va_gid) : nfs_xdrneg1;
                sp->sa_size = 0;
-               txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
-               txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
+               if (VATTR_IS_ACTIVE(vap, va_access_time)) {
+                       txdr_nfsv2time(&vap->va_access_time, &sp->sa_atime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_atime);
+               }
+               if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
+                       txdr_nfsv2time(&vap->va_modify_time, &sp->sa_mtime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_mtime);
+               }
        }
-       nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred, &xid);
+       nfsm_request(dvp, NFSPROC_CREATE, p, cred, &xid);
        if (!error) {
-               nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
+               nfsm_mtofh(dvp, cnp, newvp, v3, &xid, gotvp);
                if (!gotvp) {
-                       if (newvp) {
-                               vput(newvp);
-                               newvp = (struct vnode *)0;
-                       }
                        error = nfs_lookitup(dvp, cnp->cn_nameptr,
-                           cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
+                           cnp->cn_namelen, cred, p, &np);
                        if (!error)
                                newvp = NFSTOV(np);
                }
        }
-       if (v3)
-               nfsm_wcc_data(dvp, wccflag, &xid);
+       if (v3 && mrep)
+               nfsm_wcc_data(dvp, &premtime, wccpostattr, &xid);
        nfsm_reqdone;
        if (error) {
                if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
@@ -1960,19 +2166,36 @@ again:
                        goto again;
                }
                if (newvp)
-                       vput(newvp);
-       } else if (v3 && (fmode & O_EXCL))
-               error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
+                       vnode_put(newvp);
+       } else if (v3 && (fmode & O_EXCL)) {
+               error = nfs_setattrrpc(newvp, vap, cred, p);
+               if (error && (gotuid || gotgid)) {
+                       /* it's possible the server didn't like our attempt to set IDs. */
+                       /* so, let's try it again without those */
+                       VATTR_CLEAR_ACTIVE(vap, va_uid);
+                       VATTR_CLEAR_ACTIVE(vap, va_gid);
+                       error = nfs_setattrrpc(newvp, vap, cred, p);
+               }
+               if (error)
+                       vnode_put(newvp);
+       }
        if (!error) {
-               if (cnp->cn_flags & MAKEENTRY)
-                       cache_enter(dvp, newvp, cnp);
                *ap->a_vpp = newvp;
        }
        VTONFS(dvp)->n_flag |= NMODIFIED;
-       if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
-       vput(dvp);
-       NFS_FREE_PNBUF(cnp);
+       /* if directory hadn't changed, update namecache mtime */
+       if (nfstimespeccmp(&VTONFS(dvp)->n_ncmtime, &premtime, ==))
+               VTONFS(dvp)->n_ncmtime = VTONFS(dvp)->n_vattr.nva_mtime;
+       if (!wccpostattr)
+               NATTRINVALIDATE(VTONFS(dvp));
+       if (!error && (gotuid || gotgid) &&
+           (!newvp || nfs_getattrcache(newvp, &nvattr) ||
+            (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);
+       }
        return (error);
 }
 
@@ -1981,7 +2204,7 @@ again:
  * To try and make nfs semantics closer to ufs semantics, a file that has
  * other processes using the vnode is renamed instead of removed and then
  * removed later on the last close.
- * - If v_usecount > 1
+ * - If vnode_isinuse()
  *       If a rename is not already in the works
  *          call nfs_sillyrename() to set it up
  *     else
@@ -1989,72 +2212,52 @@ again:
  */
 static int
 nfs_remove(ap)
-       struct vop_remove_args /* {
+       struct vnop_remove_args /* {
                struct vnodeop_desc *a_desc;
-               struct vnode * a_dvp;
-               struct vnode * a_vp;
-               struct componentname * a_cnp;
+               vnode_t a_dvp;
+               vnode_t a_vp;
+               struct componentname *a_cnp;
+               int a_flags;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct vnode *dvp = ap->a_dvp;
-       register struct componentname *cnp = ap->a_cnp;
-       register struct nfsnode *np = VTONFS(vp);
+       vnode_t vp = ap->a_vp;
+       vnode_t dvp = ap->a_dvp;
+       struct componentname *cnp = ap->a_cnp;
+       struct nfsnode *np = VTONFS(vp);
        int error = 0, gofree = 0;
-       struct vattr vattr;
+       struct nfs_vattr nvattr;
+       kauth_cred_t cred;
+       proc_t p;
 
-#if DIAGNOSTIC
-       if ((cnp->cn_flags & HASBUF) == 0)
-               panic("nfs_remove: no name");
-       if (vp->v_usecount < 1)
-               panic("nfs_remove: bad v_usecount");
-#endif
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
 
-       if (UBCISVALID(vp)) {
-               /* regular files */
-               if (UBCINFOEXISTS(vp))
-                       gofree = (ubc_isinuse(vp, 1)) ? 0 : 1;
-               else {
-                       /* dead or dying vnode.With vnode locking panic instead of error */
-                       vput(dvp);
-                       vput(vp);
-                       NFS_FREE_PNBUF(cnp);
-                       return (EIO);
-               }
-       } else {
-               /* UBC not in play */
-               if (vp->v_usecount == 1)
-                       gofree = 1;
-       }
-       if ((ap->a_cnp->cn_flags & NODELETEBUSY) && !gofree) {
+       gofree = vnode_isinuse(vp, 0) ? 0 : 1;
+       if ((ap->a_flags & VNODE_REMOVE_NODELETEBUSY) && !gofree) {
                /* Caller requested Carbon delete semantics, but file is busy */
-               vput(dvp);
-               vput(vp);
-               NFS_FREE_PNBUF(cnp);
                return (EBUSY);
        }
        if (gofree || (np->n_sillyrename &&
-               VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
-               vattr.va_nlink > 1)) {
+               nfs_getattr(vp, &nvattr, cred, p) == 0 &&
+               nvattr.nva_nlink > 1)) {
                /*
                 * Purge the name cache so that the chance of a lookup for
                 * the name succeeding while the remove is in progress is
-                * minimized. Without node locking it can still happen, such
-                * that an I/O op returns ESTALE, but since you get this if
-                * another host removes the file..
+                * minimized.
                 */
                cache_purge(vp);
                /*
                 * throw away biocache buffers, mainly to avoid
                 * unnecessary delayed writes later.
                 */
-               error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
+               error = nfs_vinvalbuf(vp, 0, cred, p, 1);
                np->n_size = 0;
                ubc_setsize(vp, (off_t)0); /* XXX check error */
                /* Do the rpc */
                if (error != EINTR)
                        error = nfs_removerpc(dvp, cnp->cn_nameptr,
-                               cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
+                               cnp->cn_namelen, cred, p);
                /*
                 * Kludge City: If the first reply to the remove rpc is lost..
                 *   the reply to the retransmitted request will be ENOENT
@@ -2069,19 +2272,21 @@ nfs_remove(ap)
                         * again if another object gets created with the same filehandle
                         * before this vnode gets reclaimed
                         */
+                       lck_mtx_lock(nfs_node_hash_mutex);
                        LIST_REMOVE(np, n_hash);
                        np->n_flag &= ~NHASHED;
+                       lck_mtx_unlock(nfs_node_hash_mutex);
+               }
+               if (!error && !np->n_sillyrename) {
+                       /* clear flags now: won't get nfs_inactive for recycled vnode */
+                       /* clear all flags other than these */
+                       np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NHASHED);
+                       vnode_recycle(vp);
                }
        } else if (!np->n_sillyrename) {
-               error = nfs_sillyrename(dvp, vp, cnp);
+               error = nfs_sillyrename(dvp, vp, cnp, cred, p);
        }
-       np->n_attrstamp = 0;
-       vput(dvp);
-
-       VOP_UNLOCK(vp, 0, cnp->cn_proc);
-       NFS_FREE_PNBUF(cnp);
-       ubc_uncache(vp);
-       vrele(vp);
+       NATTRINVALIDATE(np);
 
        return (error);
 }
@@ -2090,12 +2295,9 @@ nfs_remove(ap)
  * nfs file remove rpc called from nfs_inactive
  */
 int
-nfs_removeit(sp)
-       register struct sillyrename *sp;
+nfs_removeit(struct sillyrename *sp)
 {
-
-       return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
-               (struct proc *)0));
+       return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred, NULL));
 }
 
 /*
@@ -2103,37 +2305,42 @@ nfs_removeit(sp)
  */
 static int
 nfs_removerpc(dvp, name, namelen, cred, proc)
-       register struct vnode *dvp;
+       vnode_t dvp;
        char *name;
        int namelen;
-       struct ucred *cred;
-       struct proc *proc;
+       kauth_cred_t cred;
+       proc_t proc;
 {
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
        caddr_t bpos, dpos, cp2;
-       int error = 0, wccflag = NFSV3_WCCRATTR;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       int error = 0, wccpostattr = 0;
+       struct timespec premtime = { 0, 0 };
+       mbuf_t mreq, mrep, md, mb, mb2;
        int v3;
        u_int64_t xid;
 
-       if (!VFSTONFS(dvp->v_mount))
+       if (!VFSTONFS(vnode_mount(dvp)))
                return (ENXIO);
        v3 = NFS_ISV3(dvp);
 
-       nfsstats.rpccnt[NFSPROC_REMOVE]++;
-       nfsm_reqhead(dvp, NFSPROC_REMOVE,
-               NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
+       nfsm_reqhead(NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_REMOVE]);
        nfsm_fhtom(dvp, v3);
-       nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
+       nfsm_strtom(name, namelen, NFS_MAXNAMLEN, v3);
        nfsm_request(dvp, NFSPROC_REMOVE, proc, cred, &xid);
-       if (v3)
-               nfsm_wcc_data(dvp, wccflag, &xid);
+       if (v3 && mrep)
+               nfsm_wcc_data(dvp, &premtime, wccpostattr, &xid);
        nfsm_reqdone;
        VTONFS(dvp)->n_flag |= NMODIFIED;
-       if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
+       /* if directory hadn't changed, update namecache mtime */
+       if (nfstimespeccmp(&VTONFS(dvp)->n_ncmtime, &premtime, ==))
+               VTONFS(dvp)->n_ncmtime = VTONFS(dvp)->n_vattr.nva_mtime;
+       if (!wccpostattr)
+               NATTRINVALIDATE(VTONFS(dvp));
        return (error);
 }
 
@@ -2142,34 +2349,40 @@ nfs_removerpc(dvp, name, namelen, cred, proc)
  */
 static int
 nfs_rename(ap)
-       struct vop_rename_args  /* {
-               struct vnode *a_fdvp;
-               struct vnode *a_fvp;
+       struct vnop_rename_args  /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_fdvp;
+               vnode_t a_fvp;
                struct componentname *a_fcnp;
-               struct vnode *a_tdvp;
-               struct vnode *a_tvp;
+               vnode_t a_tdvp;
+               vnode_t a_tvp;
                struct componentname *a_tcnp;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *fvp = ap->a_fvp;
-       register struct vnode *tvp = ap->a_tvp;
-       register struct vnode *fdvp = ap->a_fdvp;
-       register struct vnode *tdvp = ap->a_tdvp;
-       register struct componentname *tcnp = ap->a_tcnp;
-       register struct componentname *fcnp = ap->a_fcnp;
-       int error, purged=0, inuse=0;
+       vnode_t fvp = ap->a_fvp;
+       vnode_t tvp = ap->a_tvp;
+       vnode_t fdvp = ap->a_fdvp;
+       vnode_t tdvp = ap->a_tdvp;
+       struct componentname *tcnp = ap->a_tcnp;
+       struct componentname *fcnp = ap->a_fcnp;
+       int error, inuse=0;
+       mount_t fmp, tdmp, tmp;
+       struct nfsnode *tnp;
+       kauth_cred_t cred;
+       proc_t p;
+
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
+
+       tnp = tvp ? VTONFS(tvp) : NULL;
 
-#if DIAGNOSTIC
-       if ((tcnp->cn_flags & HASBUF) == 0 ||
-           (fcnp->cn_flags & HASBUF) == 0)
-               panic("nfs_rename: no name");
-#endif
        /* Check for cross-device rename */
-       if ((fvp->v_mount != tdvp->v_mount) ||
-           (tvp && (fvp->v_mount != tvp->v_mount))) {
+       fmp = vnode_mount(fvp);
+       tmp = tvp ? vnode_mount(tvp) : NULL;
+       tdmp = vnode_mount(tdvp);
+       if ((fmp != tdmp) || (tvp && (fmp != tmp))) {
                error = EXDEV;
-               if (tvp)
-                       VOP_UNLOCK(tvp, 0, tcnp->cn_proc);
                goto out;
        }
 
@@ -2181,76 +2394,54 @@ nfs_rename(ap)
         * links or case-variants)
         */
        if (tvp && tvp != fvp) {
-               if (UBCISVALID(tvp)) {
-                       /* regular files */
-                       if (UBCINFOEXISTS(tvp))
-                               inuse = (ubc_isinuse(tvp, 1)) ? 1 : 0;
-                       else {
-                               /* dead or dying vnode.With vnode locking panic instead of error */
-                               error = EIO;
-                               VOP_UNLOCK(tvp, 0, tcnp->cn_proc);
-                               goto out;  
-                       }
-               } else {
-                       /* UBC not in play */
-                       if (tvp->v_usecount > 1)
-                               inuse = 1;
-               }
+               inuse = vnode_isinuse(tvp, 0);
        }
-       if (inuse && !VTONFS(tvp)->n_sillyrename && tvp->v_type != VDIR) {
-               if  (error = nfs_sillyrename(tdvp, tvp, tcnp)) {
+       if (inuse && !tnp->n_sillyrename && vnode_vtype(tvp) != VDIR) {
+               if  ((error = nfs_sillyrename(tdvp, tvp, tcnp, cred, p))) {
                        /* sillyrename failed. Instead of pressing on, return error */
-                       VOP_UNLOCK(tvp, 0, tcnp->cn_proc);
                        goto out; /* should not be ENOENT. */
                } else {
                        /* sillyrename succeeded.*/
-                       VOP_UNLOCK(tvp, 0, tcnp->cn_proc);
-                       ubc_uncache(tvp); /* get the nfs turd file to disappear */
-                       vrele(tvp);
                        tvp = NULL;
                }
        }
 
        error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
-               tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
-               tcnp->cn_proc);
+               tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, cred, p);
+
+       /*
+        * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
+        */
+       if (error == ENOENT)
+               error = 0;
 
-       if (!error && tvp && tvp != fvp && !VTONFS(tvp)->n_sillyrename) {
+       if (!error && tvp && tvp != fvp && !tnp->n_sillyrename) {
                /*
                 * remove nfsnode from hash now so we can't accidentally find it
                 * again if another object gets created with the same filehandle
                 * before this vnode gets reclaimed
                 */
-               LIST_REMOVE(VTONFS(tvp), n_hash);
-               VTONFS(tvp)->n_flag &= ~NHASHED;
-       }
-
-       if (fvp->v_type == VDIR) {
-               if (tvp != NULL && tvp->v_type == VDIR) {
-                       cache_purge(tdvp);
-                       if (tvp == tdvp) 
-                               purged = 1;
-               }
-               cache_purge(fdvp);
+               lck_mtx_lock(nfs_node_hash_mutex);
+               LIST_REMOVE(tnp, n_hash);
+               tnp->n_flag &= ~NHASHED;
+               lck_mtx_unlock(nfs_node_hash_mutex);
        }
        
+       /* purge the old name cache entries and enter the new one */
        cache_purge(fvp);
        if (tvp) {
-               if (!purged)
-                       cache_purge(tvp);
-               VOP_UNLOCK(tvp, 0, tcnp->cn_proc);
-               ubc_uncache(tvp); /* get the nfs turd file to disappear */
+               cache_purge(tvp);
+               if (!error && !tnp->n_sillyrename) {
+                       /* clear flags now: won't get nfs_inactive for recycled vnode */
+                       /* clear all flags other than these */
+                       tnp->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NHASHED);
+                       vnode_recycle(tvp);
+               }
        }
-       
+       if (!error)
+               cache_enter(tdvp, fvp, tcnp);
+
 out:
-       if (tdvp == tvp)
-               vrele(tdvp);
-       else
-               vput(tdvp);
-       if (tvp)
-               vrele(tvp); /* already unlocked */
-       vrele(fdvp);
-       vrele(fvp);
        /*
         * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
         */
@@ -2260,67 +2451,62 @@ out:
 }
 
 /*
- * nfs file rename rpc called from nfs_remove() above
- */
-static int
-nfs_renameit(sdvp, scnp, sp)
-       struct vnode *sdvp;
-       struct componentname *scnp;
-       register struct sillyrename *sp;
-{
-       return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
-               sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
-}
-
-/*
- * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
+ * Do an nfs rename rpc. Called from nfs_rename() and nfs_sillyrename().
  */
 static int
 nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
-       register struct vnode *fdvp;
+       vnode_t fdvp;
        char *fnameptr;
        int fnamelen;
-       register struct vnode *tdvp;
+       vnode_t tdvp;
        char *tnameptr;
        int tnamelen;
-       struct ucred *cred;
-       struct proc *proc;
+       kauth_cred_t cred;
+       proc_t proc;
 {
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
        caddr_t bpos, dpos, cp2;
-       int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       int error = 0, fwccpostattr = 0, twccpostattr = 0;
+       struct timespec fpremtime = { 0, 0 }, tpremtime = { 0, 0 };
+       mbuf_t mreq, mrep, md, mb, mb2;
        int v3;
        u_int64_t xid;
 
-       if (!VFSTONFS(fdvp->v_mount))
+       if (!VFSTONFS(vnode_mount(fdvp)))
                return (ENXIO);
        v3 = NFS_ISV3(fdvp);
 
-       nfsstats.rpccnt[NFSPROC_RENAME]++;
-       nfsm_reqhead(fdvp, NFSPROC_RENAME,
-                    (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
+       nfsm_reqhead((NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
                      nfsm_rndup(tnamelen));
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_RENAME]);
        nfsm_fhtom(fdvp, v3);
-       nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
+       nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN, v3);
        nfsm_fhtom(tdvp, v3);
-       nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
+       nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN, v3);
        nfsm_request(fdvp, NFSPROC_RENAME, proc, cred, &xid);
-       if (v3) {
+       if (v3 && mrep) {
                u_int64_t txid = xid;
 
-               nfsm_wcc_data(fdvp, fwccflag, &xid);
-               nfsm_wcc_data(tdvp, twccflag, &txid);
+               nfsm_wcc_data(fdvp, &fpremtime, fwccpostattr, &xid);
+               nfsm_wcc_data(tdvp, &tpremtime, twccpostattr, &txid);
        }
        nfsm_reqdone;
        VTONFS(fdvp)->n_flag |= NMODIFIED;
-       if (!fwccflag)
-               VTONFS(fdvp)->n_attrstamp = 0;
+       /* if directory hadn't changed, update namecache mtime */
+       if (nfstimespeccmp(&VTONFS(fdvp)->n_ncmtime, &fpremtime, ==))
+               VTONFS(fdvp)->n_ncmtime = VTONFS(fdvp)->n_vattr.nva_mtime;
+       if (!fwccpostattr)
+               NATTRINVALIDATE(VTONFS(fdvp));
        VTONFS(tdvp)->n_flag |= NMODIFIED;
-       if (!twccflag)
-               VTONFS(tdvp)->n_attrstamp = 0;
+       /* if directory hadn't changed, update namecache mtime */
+       if (nfstimespeccmp(&VTONFS(tdvp)->n_ncmtime, &tpremtime, ==))
+               VTONFS(tdvp)->n_ncmtime = VTONFS(tdvp)->n_vattr.nva_mtime;
+       if (!twccpostattr)
+               NATTRINVALIDATE(VTONFS(tdvp));
        return (error);
 }
 
@@ -2329,43 +2515,36 @@ nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
  */
 static int
 nfs_link(ap)
-       struct vop_link_args /* {
-               struct vnode *a_vp;
-               struct vnode *a_tdvp;
+       struct vnop_link_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               vnode_t a_tdvp;
                struct componentname *a_cnp;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct vnode *tdvp = ap->a_tdvp;
-       register struct componentname *cnp = ap->a_cnp;
-       register u_long *tl;
-       register caddr_t cp;
-       register long t1, t2;
+       vnode_t vp = ap->a_vp;
+       vnode_t tdvp = ap->a_tdvp;
+       struct componentname *cnp = ap->a_cnp;
+       u_long *tl;
+       caddr_t cp;
+       long t1, t2;
        caddr_t bpos, dpos, cp2;
-       int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-       int v3, didhold;
+       int error = 0, wccpostattr = 0, attrflag = 0;
+       struct timespec premtime = { 0, 0 };
+       mbuf_t mreq, mrep, md, mb, mb2;
+       int v3;
        u_int64_t xid;
+       kauth_cred_t cred;
+       proc_t p;
 
-       if (vp->v_mount != tdvp->v_mount) {
-               VOP_ABORTOP(vp, cnp);
-               vput(tdvp);
+       if (vnode_mount(vp) != vnode_mount(tdvp)) {
                return (EXDEV);
        }
 
-       /* need to get vnode lock for vp before calling VOP_FSYNC() */
-       if (error = vn_lock(vp, LK_EXCLUSIVE, cnp->cn_proc)) {
-               VOP_ABORTOP(vp, cnp);
-               vput(tdvp);
-               return (error);
-       }
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
 
-       if (!VFSTONFS(vp->v_mount)) {
-               VOP_UNLOCK(vp, 0, cnp->cn_proc);
-               VOP_ABORTOP(vp, cnp);
-               vput(tdvp);
-               return (ENXIO);
-       }
        v3 = NFS_ISV3(vp);
 
        /*
@@ -2373,34 +2552,32 @@ nfs_link(ap)
         * doesn't get "out of sync" with the server.
         * XXX There should be a better way!
         */
-       didhold = ubc_hold(vp);
-       VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
-       VOP_UNLOCK(vp, 0, cnp->cn_proc);
+       nfs_flush(vp, MNT_WAIT, cred, p, 0);
 
-       nfsstats.rpccnt[NFSPROC_LINK]++;
-       nfsm_reqhead(vp, NFSPROC_LINK,
-               NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
+       nfsm_reqhead(NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_LINK]);
        nfsm_fhtom(vp, v3);
        nfsm_fhtom(tdvp, v3);
-       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
-       nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred, &xid);
-       if (v3) {
+       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, v3);
+       nfsm_request(vp, NFSPROC_LINK, p, cred, &xid);
+       if (v3 && mrep) {
                u_int64_t txid = xid;
 
-               nfsm_postop_attr(vp, attrflag, &xid);
-               nfsm_wcc_data(tdvp, wccflag, &txid);
+               nfsm_postop_attr_update(vp, v3, attrflag, &xid);
+               nfsm_wcc_data(tdvp, &premtime, wccpostattr, &txid);
        }
        nfsm_reqdone;
 
        VTONFS(tdvp)->n_flag |= NMODIFIED;
        if (!attrflag)
-               VTONFS(vp)->n_attrstamp = 0;
-       if (!wccflag)
-               VTONFS(tdvp)->n_attrstamp = 0;
-       if (didhold)
-               ubc_rele(vp);
-       vput(tdvp);
-       NFS_FREE_PNBUF(cnp);
+               NATTRINVALIDATE(VTONFS(vp));
+       /* if directory hadn't changed, update namecache mtime */
+       if (nfstimespeccmp(&VTONFS(tdvp)->n_ncmtime, &premtime, ==))
+               VTONFS(tdvp)->n_ncmtime = VTONFS(tdvp)->n_vattr.nva_mtime;
+       if (!wccpostattr)
+               NATTRINVALIDATE(VTONFS(tdvp));
        /*
         * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
         */
@@ -2414,72 +2591,127 @@ nfs_link(ap)
  */
 static int
 nfs_symlink(ap)
-       struct vop_symlink_args /* {
-               struct vnode *a_dvp;
-               struct vnode **a_vpp;
+       struct vnop_symlink_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_dvp;
+               vnode_t *a_vpp;
                struct componentname *a_cnp;
-               struct vattr *a_vap;
+               struct vnode_attr *a_vap;
                char *a_target;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *dvp = ap->a_dvp;
-       register struct vattr *vap = ap->a_vap;
-       register struct componentname *cnp = ap->a_cnp;
-       register struct nfsv2_sattr *sp;
-       register struct nfsv3_sattr *sp3;
-       register u_long *tl;
-       register caddr_t cp;
-       register long t1, t2;
+       vnode_t dvp = ap->a_dvp;
+       struct vnode_attr *vap = ap->a_vap;
+       struct componentname *cnp = ap->a_cnp;
+       struct nfs_vattr nvattr;
+       struct nfsv2_sattr *sp;
+       u_long *tl;
+       caddr_t cp;
+       long t1, t2;
        caddr_t bpos, dpos, cp2;
-       int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-       struct vnode *newvp = (struct vnode *)0;
+       int slen, error = 0, wccpostattr = 0, gotvp = 0;
+       struct timespec premtime = { 0, 0 };
+       mbuf_t mreq, mrep, md, mb, mb2;
+       vnode_t newvp = (vnode_t)0;
        int v3 = NFS_ISV3(dvp);
+       int gotuid, gotgid;
        u_int64_t xid;
+       kauth_cred_t cred;
+       proc_t p;
+       struct nfsnode *np = NULL;
+
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
 
-       nfsstats.rpccnt[NFSPROC_SYMLINK]++;
        slen = strlen(ap->a_target);
-       nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
+       nfsm_reqhead(NFSX_FH(v3) + 2*NFSX_UNSIGNED +
            nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
+       if (error)
+               return (error);
+
+       VATTR_SET_SUPPORTED(vap, va_mode);
+       VATTR_SET_SUPPORTED(vap, va_uid);
+       VATTR_SET_SUPPORTED(vap, va_gid);
+       VATTR_SET_SUPPORTED(vap, va_data_size);
+       VATTR_SET_SUPPORTED(vap, va_access_time);
+       VATTR_SET_SUPPORTED(vap, va_modify_time);
+       gotuid = VATTR_IS_ACTIVE(vap, va_uid);
+       gotgid = VATTR_IS_ACTIVE(vap, va_gid);
+
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_SYMLINK]);
        nfsm_fhtom(dvp, v3);
-       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
+       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, v3);
        if (v3) {
-               nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
-               nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid,
-                       cnp->cn_cred->cr_gid);
+               nfsm_v3sattr(vap);
        }
-       nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
+       nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN, v3);
        if (!v3) {
+               struct timespec neg1time = { -1, -1 };
                nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
-               sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
-               sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
-               sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
-               sp->sa_size = -1;
-               txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
-               txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
+               sp->sa_mode = vtonfsv2_mode(VLNK,
+                       (VATTR_IS_ACTIVE(vap, va_mode) ? vap->va_mode : 0600));
+               sp->sa_uid = gotuid ? (u_long)txdr_unsigned(vap->va_uid) : nfs_xdrneg1;
+               sp->sa_gid = gotgid ? (u_long)txdr_unsigned(vap->va_gid) : nfs_xdrneg1;
+               sp->sa_size = nfs_xdrneg1;
+               if (VATTR_IS_ACTIVE(vap, va_access_time)) {
+                       txdr_nfsv2time(&vap->va_access_time, &sp->sa_atime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_atime);
+               }
+               if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
+                       txdr_nfsv2time(&vap->va_modify_time, &sp->sa_mtime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_mtime);
+               }
        }
-       nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred, &xid);
-       if (v3) {
+       nfsm_request(dvp, NFSPROC_SYMLINK, p, cred, &xid);
+       if (v3 && mrep) {
                u_int64_t dxid = xid;
 
                if (!error)
-                       nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
-               nfsm_wcc_data(dvp, wccflag, &dxid);
+                       nfsm_mtofh(dvp, cnp, newvp, v3, &xid, gotvp);
+               nfsm_wcc_data(dvp, &premtime, wccpostattr, &dxid);
        }
        nfsm_reqdone;
-       if (newvp)
-               vput(newvp);
 
        VTONFS(dvp)->n_flag |= NMODIFIED;
-       if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
-       vput(dvp);
-       NFS_FREE_PNBUF(cnp);
+       /* if directory hadn't changed, update namecache mtime */
+       if (nfstimespeccmp(&VTONFS(dvp)->n_ncmtime, &premtime, ==))
+               VTONFS(dvp)->n_ncmtime = VTONFS(dvp)->n_vattr.nva_mtime;
+       if (!wccpostattr)
+               NATTRINVALIDATE(VTONFS(dvp));
+
        /*
-        * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
+        * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
+        * if we can succeed in looking up the symlink.
         */
-       if (error == EEXIST)
-               error = 0;
+       if ((error == EEXIST) || (!error && !gotvp)) {
+               if (newvp) {
+                       vnode_put(newvp);
+                       newvp = NULL;
+               }
+               error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, cred, p, &np);
+               if (!error) {
+                       newvp = NFSTOV(np);
+                       if (vnode_vtype(newvp) != VLNK)
+                               error = EEXIST;
+               }
+       }
+       if (!error && (gotuid || gotgid) &&
+           (!newvp || nfs_getattrcache(newvp, &nvattr) ||
+            (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);
+       }
+       if (error) {
+               if (newvp)
+                       vnode_put(newvp);
+       } else {
+               *ap->a_vpp = newvp;
+       }
        return (error);
 }
 
@@ -2488,89 +2720,121 @@ nfs_symlink(ap)
  */
 static int
 nfs_mkdir(ap)
-       struct vop_mkdir_args /* {
-               struct vnode *a_dvp;
-               struct vnode **a_vpp;
+       struct vnop_mkdir_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_dvp;
+               vnode_t *a_vpp;
                struct componentname *a_cnp;
-               struct vattr *a_vap;
+               struct vnode_attr *a_vap;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *dvp = ap->a_dvp;
-       register struct vattr *vap = ap->a_vap;
-       register struct componentname *cnp = ap->a_cnp;
-       register struct nfsv2_sattr *sp;
-       register struct nfsv3_sattr *sp3;
-       register u_long *tl;
-       register caddr_t cp;
-       register long t1, t2;
-       register int len;
+       vnode_t dvp = ap->a_dvp;
+       struct vnode_attr *vap = ap->a_vap;
+       struct componentname *cnp = ap->a_cnp;
+       struct nfs_vattr nvattr;
+       struct nfsv2_sattr *sp;
+       u_long *tl;
+       caddr_t cp;
+       long t1, t2;
+       int len;
        struct nfsnode *np = (struct nfsnode *)0;
-       struct vnode *newvp = (struct vnode *)0;
+       vnode_t newvp = (vnode_t)0;
        caddr_t bpos, dpos, cp2;
-       int error = 0, wccflag = NFSV3_WCCRATTR;
+       int error = 0, wccpostattr = 0;
+       struct timespec premtime = { 0, 0 };
        int gotvp = 0;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-       struct vattr vattr;
+       mbuf_t mreq, mrep, md, mb, mb2;
        int v3 = NFS_ISV3(dvp);
+       int gotuid, gotgid;
        u_int64_t xid, dxid;
+       kauth_cred_t cred;
+       proc_t p;
+
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
 
-       if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
-               VOP_ABORTOP(dvp, cnp);
-               vput(dvp);
-               return (error);
-       }
        len = cnp->cn_namelen;
-       nfsstats.rpccnt[NFSPROC_MKDIR]++;
-       nfsm_reqhead(dvp, NFSPROC_MKDIR,
-         NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
+       nfsm_reqhead(NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
+       if (error)
+               return (error);
+
+       VATTR_SET_SUPPORTED(vap, va_mode);
+       VATTR_SET_SUPPORTED(vap, va_uid);
+       VATTR_SET_SUPPORTED(vap, va_gid);
+       VATTR_SET_SUPPORTED(vap, va_data_size);
+       VATTR_SET_SUPPORTED(vap, va_access_time);
+       VATTR_SET_SUPPORTED(vap, va_modify_time);
+       gotuid = VATTR_IS_ACTIVE(vap, va_uid);
+       gotgid = VATTR_IS_ACTIVE(vap, va_gid);
+
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_MKDIR]);
        nfsm_fhtom(dvp, v3);
-       nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
+       nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN, v3);
        if (v3) {
-               nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
-               nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
+               nfsm_v3sattr(vap);
        } else {
+               struct timespec neg1time = { -1, -1 };
                nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
-               sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
-               sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
-               sp->sa_gid = txdr_unsigned(vattr.va_gid);
-               sp->sa_size = -1;
-               txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
-               txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
+               sp->sa_mode = vtonfsv2_mode(VDIR,
+                       (VATTR_IS_ACTIVE(vap, va_mode) ? vap->va_mode : 0600));
+               sp->sa_uid = gotuid ? (u_long)txdr_unsigned(vap->va_uid) : nfs_xdrneg1;
+               sp->sa_gid = gotgid ? (u_long)txdr_unsigned(vap->va_gid) : nfs_xdrneg1;
+               sp->sa_size = nfs_xdrneg1;
+               if (VATTR_IS_ACTIVE(vap, va_access_time)) {
+                       txdr_nfsv2time(&vap->va_access_time, &sp->sa_atime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_atime);
+               }
+               if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
+                       txdr_nfsv2time(&vap->va_modify_time, &sp->sa_mtime);
+               } else {
+                       txdr_nfsv2time(&neg1time, &sp->sa_mtime);
+               }
        }
-       nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred, &xid);
+       nfsm_request(dvp, NFSPROC_MKDIR, p, cred, &xid);
        dxid = xid;
        if (!error)
-               nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
-       if (v3)
-               nfsm_wcc_data(dvp, wccflag, &dxid);
+               nfsm_mtofh(dvp, cnp, newvp, v3, &xid, gotvp);
+       if (v3 && mrep)
+               nfsm_wcc_data(dvp, &premtime, wccpostattr, &dxid);
        nfsm_reqdone;
        VTONFS(dvp)->n_flag |= NMODIFIED;
-       if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
+       /* if directory hadn't changed, update namecache mtime */
+       if (nfstimespeccmp(&VTONFS(dvp)->n_ncmtime, &premtime, ==))
+               VTONFS(dvp)->n_ncmtime = VTONFS(dvp)->n_vattr.nva_mtime;
+       if (!wccpostattr)
+               NATTRINVALIDATE(VTONFS(dvp));
        /*
         * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
         * if we can succeed in looking up the directory.
         */
        if (error == EEXIST || (!error && !gotvp)) {
                if (newvp) {
-                       vput(newvp);
-                       newvp = (struct vnode *)0;
+                       vnode_put(newvp);
+                       newvp = NULL;
                }
-               error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
-                                    cnp->cn_proc, &np);
+               error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cred, p, &np);
                if (!error) {
                        newvp = NFSTOV(np);
-                       if (newvp->v_type != VDIR)
+                       if (vnode_vtype(newvp) != VDIR)
                                error = EEXIST;
                }
        }
+       if (!error && (gotuid || gotgid) &&
+           (!newvp || nfs_getattrcache(newvp, &nvattr) ||
+            (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);
+       }
        if (error) {
                if (newvp)
-                       vput(newvp);
-       } else
+                       vnode_put(newvp);
+       } else {
                *ap->a_vpp = newvp;
-       vput(dvp);
-       NFS_FREE_PNBUF(cnp);
+       }
        return (error);
 }
 
@@ -2579,46 +2843,65 @@ nfs_mkdir(ap)
  */
 static int
 nfs_rmdir(ap)
-       struct vop_rmdir_args /* {
-               struct vnode *a_dvp;
-               struct vnode *a_vp;
+       struct vnop_rmdir_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_dvp;
+               vnode_t a_vp;
                struct componentname *a_cnp;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct vnode *dvp = ap->a_dvp;
-       register struct componentname *cnp = ap->a_cnp;
-       register u_long *tl;
-       register caddr_t cp;
-       register long t1, t2;
+       vnode_t vp = ap->a_vp;
+       vnode_t dvp = ap->a_dvp;
+       struct componentname *cnp = ap->a_cnp;
+       u_long *tl;
+       caddr_t cp;
+       long t1, t2;
        caddr_t bpos, dpos, cp2;
-       int error = 0, wccflag = NFSV3_WCCRATTR;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       int error = 0, wccpostattr = 0;
+       struct timespec premtime = { 0, 0 };
+       mbuf_t mreq, mrep, md, mb, mb2;
        int v3 = NFS_ISV3(dvp);
        u_int64_t xid;
+       kauth_cred_t cred;
+       proc_t p;
+
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
 
-       nfsstats.rpccnt[NFSPROC_RMDIR]++;
-       nfsm_reqhead(dvp, NFSPROC_RMDIR,
-               NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
+       nfsm_reqhead(NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_RMDIR]);
        nfsm_fhtom(dvp, v3);
-       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
-       nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred, &xid);
-       if (v3)
-               nfsm_wcc_data(dvp, wccflag, &xid);
+       nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, v3);
+       nfsm_request(dvp, NFSPROC_RMDIR, p, cred, &xid);
+       if (v3 && mrep)
+               nfsm_wcc_data(dvp, &premtime, wccpostattr, &xid);
        nfsm_reqdone;
        VTONFS(dvp)->n_flag |= NMODIFIED;
-       if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
-       cache_purge(dvp);
+       /* if directory hadn't changed, update namecache mtime */
+       if (nfstimespeccmp(&VTONFS(dvp)->n_ncmtime, &premtime, ==))
+               VTONFS(dvp)->n_ncmtime = VTONFS(dvp)->n_vattr.nva_mtime;
+       if (!wccpostattr)
+               NATTRINVALIDATE(VTONFS(dvp));
        cache_purge(vp);
-       vput(vp);
-       vput(dvp);
-       NFS_FREE_PNBUF(cnp);
        /*
         * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
         */
        if (error == ENOENT)
                error = 0;
+       if (!error) {
+               /*
+                * remove nfsnode from hash now so we can't accidentally find it
+                * again if another object gets created with the same filehandle
+                * before this vnode gets reclaimed
+                */
+               lck_mtx_lock(nfs_node_hash_mutex);
+               LIST_REMOVE(VTONFS(vp), n_hash);
+               VTONFS(vp)->n_flag &= ~NHASHED;
+               lck_mtx_unlock(nfs_node_hash_mutex);
+       }
        return (error);
 }
 
@@ -2627,48 +2910,56 @@ nfs_rmdir(ap)
  */
 static int
 nfs_readdir(ap)
-       struct vop_readdir_args /* {
-               struct vnode *a_vp;
+       struct vnop_readdir_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
                struct uio *a_uio;
-               struct ucred *a_cred;
+               int *a_eofflag;
+               int *a_ncookies;
+               u_long **a_cookies;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct nfsnode *np = VTONFS(vp);
-       register struct uio *uio = ap->a_uio;
+       vnode_t vp = ap->a_vp;
+       struct nfsnode *np = VTONFS(vp);
+       struct uio *uio = ap->a_uio;
        int tresid, error;
-       struct vattr vattr;
+       struct nfs_vattr nvattr;
+       kauth_cred_t cred;
+       proc_t p;
 
-       if (vp->v_type != VDIR)
+       if (vnode_vtype(vp) != VDIR)
                return (EPERM);
+
+       cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
+
        /*
         * First, check for hit on the EOF offset cache
         */
        if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
            (np->n_flag & NMODIFIED) == 0) {
-               if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
-                       if (NQNFS_CKCACHABLE(vp, ND_READ)) {
-                               nfsstats.direofcache_hits++;
+               if (!nfs_getattr(vp, &nvattr, cred, p)) {
+                       if (nfstimespeccmp(&np->n_mtime, &nvattr.nva_mtime, ==)) {
+                               OSAddAtomic(1, (SInt32*)&nfsstats.direofcache_hits);
                                return (0);
                        }
-               } else if (!VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp)) {
-                       if (np->n_mtime == vattr.va_mtime.tv_sec) {
-                               nfsstats.direofcache_hits++;
-                               return (0);
+                       if (nfstimespeccmp(&np->n_ncmtime, &nvattr.nva_mtime, !=)) {
+                               /* directory changed, purge any name cache entries */
+                               cache_purge(vp);
                        }
-                       /* directory changed, purge any name cache entries */
-                       cache_purge(vp);
                }
        }
 
        /*
         * Call nfs_bioread() to do the real work.
         */
-       tresid = uio->uio_resid;
-       error = nfs_bioread(vp, uio, 0, ap->a_cred, 0);
+       // LP64todo - fix this
+       tresid = uio_uio_resid(uio);
+       error = nfs_bioread(vp, uio, 0, cred, p);
 
-       if (!error && uio->uio_resid == tresid)
-               nfsstats.direofcache_misses++;
+       if (!error && uio_uio_resid(uio) == tresid)
+               OSAddAtomic(1, (SInt32*)&nfsstats.direofcache_misses);
        return (error);
 }
 
@@ -2677,20 +2968,20 @@ nfs_readdir(ap)
  * Called from below the buffer cache by nfs_doio().
  */
 int
-nfs_readdirrpc(vp, uiop, cred)
-       struct vnode *vp;
-       register struct uio *uiop;
-       struct ucred *cred;
-
+nfs_readdirrpc(
+       vnode_t vp,
+       struct uio *uiop,
+       kauth_cred_t cred,
+       proc_t p)
 {
-       register int len, left;
+       register int len, skiplen, left;
        register struct dirent *dp;
        register u_long *tl;
        register caddr_t cp;
        register long t1, t2;
        register nfsuint64 *cookiep;
        caddr_t bpos, dpos, cp2;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       mbuf_t mreq, mrep, md, mb, mb2;
        nfsuint64 cookie;
        struct nfsmount *nmp;
        struct nfsnode *dnp = VTONFS(vp);
@@ -2705,10 +2996,10 @@ nfs_readdirrpc(vp, uiop, cred)
 #endif
 #if DIAGNOSTIC
        if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) ||
-               (uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
+               (uio_uio_resid(uiop) & (NFS_DIRBLKSIZ - 1)))
                panic("nfs_readdirrpc: bad uio");
 #endif
-       nmp = VFSTONFS(vp->v_mount);
+       nmp = VFSTONFS(vnode_mount(vp));
        if (!nmp)
                return (ENXIO);
        v3 = NFS_ISV3(vp);
@@ -2728,9 +3019,10 @@ nfs_readdirrpc(vp, uiop, cred)
         * The stopping criteria is EOF or buffer full.
         */
        while (more_dirs && bigenough) {
-               nfsstats.rpccnt[NFSPROC_READDIR]++;
-               nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
-                       NFSX_READDIR(v3));
+               nfsm_reqhead(NFSX_FH(v3) + NFSX_READDIR(v3));
+               if (error)
+                       goto nfsmout;
+               OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_READDIR]);
                nfsm_fhtom(vp, v3);
                if (v3) {
                        nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
@@ -2743,17 +3035,22 @@ nfs_readdirrpc(vp, uiop, cred)
                        *tl++ = cookie.nfsuquad[0];
                }
                *tl = txdr_unsigned(nmreaddirsize);
-               nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred, &xid);
+               nfsm_request(vp, NFSPROC_READDIR, p, cred, &xid);
                if (v3) {
-                       nfsm_postop_attr(vp, attrflag, &xid);
+                       if (mrep) {
+                               nfsm_postop_attr_update(vp, v3, attrflag, &xid);
+                       }
                        if (!error) {
                                nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
                                dnp->n_cookieverf.nfsuquad[0] = *tl++;
                                dnp->n_cookieverf.nfsuquad[1] = *tl;
                        } else {
-                               m_freem(mrep);
+                               mbuf_freem(mrep);
                                goto nfsmout;
                        }
+               } else if (!mrep) {
+                       // XXX assert error?
+                       goto nfsmout;
                }
                nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
                more_dirs = fxdr_unsigned(int, *tl);
@@ -2769,27 +3066,36 @@ nfs_readdirrpc(vp, uiop, cred)
                                fileno = fxdr_unsigned(u_quad_t, *tl++);
                                len = fxdr_unsigned(int, *tl);
                        }
-                       if (len <= 0 || len > NFS_MAXNAMLEN) {
+                       /* Note: v3 supports longer names, but struct dirent doesn't */
+                       /* so we just truncate the names to fit */
+                       if (len <= 0) {
                                error = EBADRPC;
-                               m_freem(mrep);
+                               mbuf_freem(mrep);
                                goto nfsmout;
                        }
+                       if (len > MAXNAMLEN) {
+                               skiplen = len - MAXNAMLEN;
+                               len = MAXNAMLEN;
+                       } else {
+                               skiplen = 0;
+                       }
                        tlen = nfsm_rndup(len);
                        if (tlen == len)
                                tlen += 4;      /* To ensure null termination */
                        left = DIRBLKSIZ - blksiz;
-                       if ((tlen + DIRHDSIZ) > left) {
+                       if ((tlen + (int)DIRHDSIZ) > left) {
                                dp->d_reclen += left;
-                               uiop->uio_iov->iov_base += left;
-                               uiop->uio_iov->iov_len -= left;
+                               uio_iov_base_add(uiop, left);
+                               uio_iov_len_add(uiop, -left);
                                uiop->uio_offset += left;
-                               uiop->uio_resid -= left;
+                               uio_uio_resid_add(uiop, -left);
                                blksiz = 0;
                        }
-                       if ((tlen + DIRHDSIZ) > uiop->uio_resid)
+                       if ((tlen + (int)DIRHDSIZ) > uio_uio_resid(uiop))
                                bigenough = 0;
                        if (bigenough) {
-                               dp = (struct dirent *)uiop->uio_iov->iov_base;
+                               // LP64todo - fix this!
+                               dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
                                dp->d_fileno = (int)fileno;
                                dp->d_namlen = len;
                                dp->d_reclen = tlen + DIRHDSIZ;
@@ -2798,19 +3104,28 @@ nfs_readdirrpc(vp, uiop, cred)
                                if (blksiz == DIRBLKSIZ)
                                        blksiz = 0;
                                uiop->uio_offset += DIRHDSIZ;
-                               uiop->uio_resid -= DIRHDSIZ;
-                               uiop->uio_iov->iov_base += DIRHDSIZ;
-                               uiop->uio_iov->iov_len -= DIRHDSIZ;
+#if LP64KERN
+                               uio_uio_resid_add(uiop, -((int64_t)DIRHDSIZ));
+                               uio_iov_len_add(uiop, -((int64_t)DIRHDSIZ));
+#else
+                               uio_uio_resid_add(uiop, -((int)DIRHDSIZ));
+                               uio_iov_len_add(uiop, -((int)DIRHDSIZ));
+#endif
+                               uio_iov_base_add(uiop, DIRHDSIZ);
                                nfsm_mtouio(uiop, len);
-                               cp = uiop->uio_iov->iov_base;
+                               // LP64todo - fix this!
+                               cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
                                tlen -= len;
                                *cp = '\0';     /* null terminate */
-                               uiop->uio_iov->iov_base += tlen;
-                               uiop->uio_iov->iov_len -= tlen;
+                               uio_iov_base_add(uiop, tlen);
+                               uio_iov_len_add(uiop, -tlen);
                                uiop->uio_offset += tlen;
-                               uiop->uio_resid -= tlen;
-                       } else
+                               uio_uio_resid_add(uiop, -tlen);
+                       } else {
                                nfsm_adv(nfsm_rndup(len));
+                       }
+                       if (skiplen)
+                               nfsm_adv(nfsm_rndup(skiplen));
                        if (v3) {
                                nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
                        } else {
@@ -2833,7 +3148,7 @@ nfs_readdirrpc(vp, uiop, cred)
                        nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
                        more_dirs = (fxdr_unsigned(int, *tl) == 0);
                }
-               m_freem(mrep);
+               mbuf_freem(mrep);
        }
        /*
         * Fill last record, iff any, out to a multiple of DIRBLKSIZ
@@ -2842,10 +3157,10 @@ nfs_readdirrpc(vp, uiop, cred)
        if (blksiz > 0) {
                left = DIRBLKSIZ - blksiz;
                dp->d_reclen += left;
-               uiop->uio_iov->iov_base += left;
-               uiop->uio_iov->iov_len -= left;
+               uio_iov_base_add(uiop, left);
+               uio_iov_len_add(uiop, -left);
                uiop->uio_offset += left;
-               uiop->uio_resid -= left;
+               uio_uio_resid_add(uiop, -left);
        }
 
        /*
@@ -2855,10 +3170,11 @@ nfs_readdirrpc(vp, uiop, cred)
        if (bigenough)
                dnp->n_direofoffset = uiop->uio_offset;
        else {
-               if (uiop->uio_resid > 0)
+               if (uio_uio_resid(uiop) > 0)
                        printf("EEK! readdirrpc resid > 0\n");
                cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
-               *cookiep = cookie;
+               if (cookiep)
+                       *cookiep = cookie;
        }
 nfsmout:
        return (error);
@@ -2868,46 +3184,47 @@ nfsmout:
  * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
  */
 int
-nfs_readdirplusrpc(vp, uiop, cred)
-       struct vnode *vp;
-       register struct uio *uiop;
-       struct ucred *cred;
+nfs_readdirplusrpc(
+       vnode_t vp,
+       struct uio *uiop,
+       kauth_cred_t cred,
+       proc_t p)
 {
-       register int len, left;
-       register struct dirent *dp;
-       register u_long *tl;
-       register caddr_t cp;
-       register long t1, t2;
-       register struct vnode *newvp;
-       register nfsuint64 *cookiep;
-       caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
-       struct nameidata nami, *ndp = &nami;
-       struct componentname *cnp = &ndp->ni_cnd;
+       int len, skiplen, left;
+       struct dirent *dp;
+       u_long *tl;
+       caddr_t cp;
+       long t1, t2;
+       vnode_t newvp;
+       nfsuint64 *cookiep;
+       caddr_t bpos, dpos, cp2;
+       mbuf_t mreq, mrep, md, mb, mb2;
+       struct componentname cn, *cnp = &cn;
        nfsuint64 cookie;
        struct nfsmount *nmp;
        struct nfsnode *dnp = VTONFS(vp), *np;
-       nfsfh_t *fhp;
+       u_char *fhp;
        u_quad_t fileno;
        int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
        int attrflag, fhsize, nmreaddirsize, nmrsize;
        u_int64_t xid, savexid;
+       struct nfs_vattr nvattr;
 
 #ifndef nolint
        dp = (struct dirent *)0;
 #endif
 #if DIAGNOSTIC
        if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
-               (uiop->uio_resid & (DIRBLKSIZ - 1)))
+               (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)))
                panic("nfs_readdirplusrpc: bad uio");
 #endif
-       nmp = VFSTONFS(vp->v_mount);
+       nmp = VFSTONFS(vnode_mount(vp));
        if (!nmp)
                return (ENXIO);
        nmreaddirsize = nmp->nm_readdirsize;
        nmrsize = nmp->nm_rsize;
 
-       ndp->ni_dvp = vp;
+       bzero(cnp, sizeof(*cnp));
        newvp = NULLVP;
 
        /*
@@ -2924,9 +3241,10 @@ nfs_readdirplusrpc(vp, uiop, cred)
         * The stopping criteria is EOF or buffer full.
         */
        while (more_dirs && bigenough) {
-               nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
-               nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
-                       NFSX_FH(1) + 6 * NFSX_UNSIGNED);
+               nfsm_reqhead(NFSX_FH(1) + 6 * NFSX_UNSIGNED);
+               if (error)
+                       goto nfsmout;
+               OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_READDIRPLUS]);
                nfsm_fhtom(vp, 1);
                nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED);
                *tl++ = cookie.nfsuquad[0];
@@ -2935,12 +3253,13 @@ nfs_readdirplusrpc(vp, uiop, cred)
                *tl++ = dnp->n_cookieverf.nfsuquad[1];
                *tl++ = txdr_unsigned(nmreaddirsize);
                *tl = txdr_unsigned(nmrsize);
-               nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred,
-                            &xid);
+               nfsm_request(vp, NFSPROC_READDIRPLUS, p, cred, &xid);
                savexid = xid;
-               nfsm_postop_attr(vp, attrflag, &xid);
+               if (mrep) {
+                       nfsm_postop_attr_update(vp, 1, attrflag, &xid);
+               }
                if (error) {
-                       m_freem(mrep);
+                       mbuf_freem(mrep);
                        goto nfsmout;
                }
                nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
@@ -2953,27 +3272,36 @@ nfs_readdirplusrpc(vp, uiop, cred)
                        nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
                        fxdr_hyper(tl, &fileno);
                        len = fxdr_unsigned(int, *(tl + 2));
-                       if (len <= 0 || len > NFS_MAXNAMLEN) {
+                       /* Note: v3 supports longer names, but struct dirent doesn't */
+                       /* so we just truncate the names to fit */
+                       if (len <= 0) {
                                error = EBADRPC;
-                               m_freem(mrep);
+                               mbuf_freem(mrep);
                                goto nfsmout;
                        }
+                       if (len > MAXNAMLEN) {
+                               skiplen = len - MAXNAMLEN;
+                               len = MAXNAMLEN;
+                       } else {
+                               skiplen = 0;
+                       }
                        tlen = nfsm_rndup(len);
                        if (tlen == len)
                                tlen += 4;      /* To ensure null termination*/
                        left = DIRBLKSIZ - blksiz;
-                       if ((tlen + DIRHDSIZ) > left) {
+                       if ((tlen + (int)DIRHDSIZ) > left) {
                                dp->d_reclen += left;
-                               uiop->uio_iov->iov_base += left;
-                               uiop->uio_iov->iov_len -= left;
+                               uio_iov_base_add(uiop, left);
+                               uio_iov_len_add(uiop, -left);
                                uiop->uio_offset += left;
-                               uiop->uio_resid -= left;
+                               uio_uio_resid_add(uiop, -left);
                                blksiz = 0;
                        }
-                       if ((tlen + DIRHDSIZ) > uiop->uio_resid)
+                       if ((tlen + (int)DIRHDSIZ) > uio_uio_resid(uiop))
                                bigenough = 0;
                        if (bigenough) {
-                               dp = (struct dirent *)uiop->uio_iov->iov_base;
+                               // LP64todo - fix this!
+                               dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
                                dp->d_fileno = (int)fileno;
                                dp->d_namlen = len;
                                dp->d_reclen = tlen + DIRHDSIZ;
@@ -2982,21 +3310,30 @@ nfs_readdirplusrpc(vp, uiop, cred)
                                if (blksiz == DIRBLKSIZ)
                                        blksiz = 0;
                                uiop->uio_offset += DIRHDSIZ;
-                               uiop->uio_resid -= DIRHDSIZ;
-                               uiop->uio_iov->iov_base += DIRHDSIZ;
-                               uiop->uio_iov->iov_len -= DIRHDSIZ;
-                               cnp->cn_nameptr = uiop->uio_iov->iov_base;
+#if LP64KERN
+                               uio_uio_resid_add(uiop, -((int64_t)DIRHDSIZ));
+                               uio_iov_len_add(uiop, -((int64_t)DIRHDSIZ));
+#else
+                               uio_uio_resid_add(uiop, -((int)DIRHDSIZ));
+                               uio_iov_len_add(uiop, -((int)DIRHDSIZ));
+#endif
+                               uio_iov_base_add(uiop, DIRHDSIZ);
+                               // LP64todo - fix this!
+                               cnp->cn_nameptr = CAST_DOWN(caddr_t, uio_iov_base(uiop));
                                cnp->cn_namelen = len;
                                nfsm_mtouio(uiop, len);
-                               cp = uiop->uio_iov->iov_base;
+                               cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
                                tlen -= len;
                                *cp = '\0';
-                               uiop->uio_iov->iov_base += tlen;
-                               uiop->uio_iov->iov_len -= tlen;
+                               uio_iov_base_add(uiop, tlen);
+                               uio_iov_len_add(uiop, -tlen);
                                uiop->uio_offset += tlen;
-                               uiop->uio_resid -= tlen;
-                       } else
+                               uio_uio_resid_add(uiop, -tlen);
+                       } else {
                                nfsm_adv(nfsm_rndup(len));
+                       }
+                       if (skiplen)
+                               nfsm_adv(nfsm_rndup(skiplen));
                        nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
                        if (bigenough) {
                                cookie.nfsuquad[0] = *tl++;
@@ -3011,57 +3348,54 @@ nfs_readdirplusrpc(vp, uiop, cred)
                         */
                        attrflag = fxdr_unsigned(int, *tl);
                        if (attrflag) {
-                           dpossav1 = dpos;
-                           mdsav1 = md;
-                           nfsm_adv(NFSX_V3FATTR);
+                           /* grab attributes */
+                           nfsm_attr_get(1, &nvattr);
+                           dp->d_type = IFTODT(VTTOIF(nvattr.nva_type));
+                           /* check for file handle */
                            nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
                            doit = fxdr_unsigned(int, *tl);
                            if (doit) {
                                nfsm_getfh(fhp, fhsize, 1);
                                if (NFS_CMPFH(dnp, fhp, fhsize)) {
-                                   VREF(vp);
-                                   newvp = vp;
-                                   np = dnp;
+                                   error = vnode_ref(vp);
+                                   if (error) {
+                                       doit = 0;
+                                   } else {
+                                       newvp = vp;
+                                       np = dnp;
+                                   }
                                } else if (!bigenough ||
                                        (cnp->cn_namelen == 2 &&
                                         cnp->cn_nameptr[1] == '.' &&
                                         cnp->cn_nameptr[0] == '.')) {
                                    /*
+                                    * XXXmacko I don't think this ".." thing is a problem anymore.
                                     * don't doit if we can't guarantee
                                     * that this entry is NOT ".." because
                                     * we would have to drop the lock on
                                     * the directory before getting the
-                                    * (lock on) the ".." vnode... and we
+                                    * lock on the ".." vnode... and we
                                     * don't want to drop the dvp lock in
                                     * the middle of a readdirplus.
                                     */
                                    doit = 0;
                                } else {
-                                   if ((error = nfs_nget(vp->v_mount, fhp,
-                                       fhsize, &np)))
+                                   cnp->cn_hash = 0;
+
+                                   error = nfs_nget(vnode_mount(vp), vp, cnp,
+                                               fhp, fhsize, &nvattr, &xid,
+                                               NG_MAKEENTRY, &np);
+                                   if (error)
                                        doit = 0;
                                    else
                                        newvp = NFSTOV(np);
                                }
                            }
-                           if (doit && bigenough) {
-                               dpossav2 = dpos;
-                               dpos = dpossav1;
-                               mdsav2 = md;
-                               md = mdsav1;
+                           /* update attributes if not already updated */
+                           if (doit && bigenough && (np->n_xid <= savexid)) {
                                xid = savexid;
-                               nfsm_loadattr(newvp, (struct vattr *)0, &xid);
-                               dpos = dpossav2;
-                               md = mdsav2;
-                               dp->d_type =
-                                   IFTODT(VTTOIF(np->n_vattr.va_type));
-                               ndp->ni_vp = newvp;
-                               cnp->cn_hash = 0;
-                               for (cp = cnp->cn_nameptr, i = 1; i <= len;
-                                   i++, cp++)
-                                   cnp->cn_hash += (unsigned char)*cp * i;
-                               if (cnp->cn_namelen <= NCHNAMLEN)
-                                   cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
+                               nfs_loadattrcache(np, &nvattr, &xid, 0);
+                               /* any error can be ignored */
                            }
                        } else {
                            /* Just skip over the file handle */
@@ -3071,9 +3405,9 @@ nfs_readdirplusrpc(vp, uiop, cred)
                        }
                        if (newvp != NULLVP) {
                            if (newvp == vp)
-                               vrele(newvp);
+                               vnode_rele(newvp);
                            else
-                               vput(newvp);
+                               vnode_put(newvp);
                            newvp = NULLVP;
                        }
                        nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
@@ -3086,7 +3420,7 @@ nfs_readdirplusrpc(vp, uiop, cred)
                        nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
                        more_dirs = (fxdr_unsigned(int, *tl) == 0);
                }
-               m_freem(mrep);
+               mbuf_freem(mrep);
        }
        /*
         * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
@@ -3095,10 +3429,10 @@ nfs_readdirplusrpc(vp, uiop, cred)
        if (blksiz > 0) {
                left = DIRBLKSIZ - blksiz;
                dp->d_reclen += left;
-               uiop->uio_iov->iov_base += left;
-               uiop->uio_iov->iov_len -= left;
+               uio_iov_base_add(uiop, left);
+               uio_iov_len_add(uiop, -left);
                uiop->uio_offset += left;
-               uiop->uio_resid -= left;
+               uio_uio_resid_add(uiop, -left);
        }
 
        /*
@@ -3108,19 +3442,13 @@ nfs_readdirplusrpc(vp, uiop, cred)
        if (bigenough)
                dnp->n_direofoffset = uiop->uio_offset;
        else {
-               if (uiop->uio_resid > 0)
+               if (uio_uio_resid(uiop) > 0)
                        printf("EEK! readdirplusrpc resid > 0\n");
                cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
-               *cookiep = cookie;
+               if (cookiep)
+                       *cookiep = cookie;
        }
 nfsmout:
-       if (newvp != NULLVP) {
-               if (newvp == vp)
-                       vrele(newvp);
-               else
-                       vput(newvp);
-               newvp = NULLVP;
-       }
        return (error);
 }
 
@@ -3138,37 +3466,44 @@ nfsmout:
 static char sillyrename_name[] = ".nfsAAA%04x4.4";
 
 static int
-nfs_sillyrename(dvp, vp, cnp)
-       struct vnode *dvp, *vp;
-       struct componentname *cnp;
+nfs_sillyrename(
+       vnode_t dvp,
+       vnode_t vp,
+       struct componentname *cnp,
+       kauth_cred_t cred,
+       proc_t p)
 {
        register struct sillyrename *sp;
        struct nfsnode *np;
        int error;
        short pid;
-       struct ucred *cred;
+       kauth_cred_t tmpcred;
        int i, j, k;
 
-       cache_purge(dvp);
+       cache_purge(vp);
        np = VTONFS(vp);
 #if DIAGNOSTIC
-       if (vp->v_type == VDIR)
+       if (vnode_vtype(vp) == VDIR)
                panic("nfs_sillyrename: dir");
 #endif
        MALLOC_ZONE(sp, struct sillyrename *,
                        sizeof (struct sillyrename), M_NFSREQ, M_WAITOK);
-       sp->s_cred = crdup(cnp->cn_cred);
+       if (!sp)
+               return (ENOMEM);
+       kauth_cred_ref(cred);
+       sp->s_cred = cred;
        sp->s_dvp = dvp;
-       VREF(dvp);
+       error = vnode_ref(dvp);
+       if (error)
+               goto bad_norele;
 
        /* Fudge together a funny name */
-       pid = cnp->cn_proc->p_pid;
+       pid = proc_pid(p);
        sp->s_namlen = sprintf(sp->s_name, sillyrename_name, pid);
 
        /* Try lookitups until we get one that isn't there */
        i = j = k = 0;
-       while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
-               cnp->cn_proc, (struct nfsnode **)0) == 0) {
+       while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, p, NULL) == 0) {
                if (sp->s_name[4]++ >= 'z')
                        sp->s_name[4] = 'A';
                if (++i > ('z' - 'A' + 1)) {
@@ -3196,10 +3531,11 @@ nfs_sillyrename(dvp, vp, cnp)
                }
        }
        /* now, do the rename */
-       if ((error = nfs_renameit(dvp, cnp, sp)))
+       error = nfs_renamerpc(dvp, cnp->cn_nameptr, cnp->cn_namelen,
+                               dvp, sp->s_name, sp->s_namlen, sp->s_cred, p);
+       if (error)
                goto bad;
-       error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
-               cnp->cn_proc, &np);
+       error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, p, &np);
 #if DIAGNOSTIC
        kprintf("sillyrename: %s, vp=%x, np=%x, dvp=%x\n",
                &sp->s_name[0], (unsigned)vp, (unsigned)np, (unsigned)dvp);
@@ -3207,10 +3543,11 @@ nfs_sillyrename(dvp, vp, cnp)
        np->n_sillyrename = sp;
        return (0);
 bad:
-       vrele(sp->s_dvp);
-       cred = sp->s_cred;
+       vnode_rele(sp->s_dvp);
+bad_norele:
+       tmpcred = sp->s_cred;
        sp->s_cred = NOCRED;
-       crfree(cred);
+       kauth_cred_rele(tmpcred);
        FREE_ZONE((caddr_t)sp, sizeof (struct sillyrename), M_NFSREQ);
        return (error);
 }
@@ -3225,81 +3562,119 @@ bad:
  */
 static int
 nfs_lookitup(dvp, name, len, cred, procp, npp)
-       register struct vnode *dvp;
+       vnode_t dvp;
        char *name;
        int len;
-       struct ucred *cred;
-       struct proc *procp;
+       kauth_cred_t cred;
+       proc_t procp;
        struct nfsnode **npp;
 {
-       register u_long *tl;
-       register caddr_t cp;
-       register long t1, t2;
-       struct vnode *newvp = (struct vnode *)0;
+       u_long *tl;
+       caddr_t cp;
+       long t1, t2;
+       vnode_t newvp = (vnode_t)0;
        struct nfsnode *np, *dnp = VTONFS(dvp);
        caddr_t bpos, dpos, cp2;
        int error = 0, fhlen, attrflag;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-       nfsfh_t *nfhp;
+       mbuf_t mreq, mrep, md, mb, mb2;
+       u_char *nfhp;
        int v3;
-       u_int64_t xid;
+       u_int64_t xid, dxid, savedxid;
+       struct nfs_vattr nvattr;
 
-       if (!VFSTONFS(dvp->v_mount))
+       if (!VFSTONFS(vnode_mount(dvp)))
                return (ENXIO);
        v3 = NFS_ISV3(dvp);
 
-       nfsstats.rpccnt[NFSPROC_LOOKUP]++;
-       nfsm_reqhead(dvp, NFSPROC_LOOKUP,
-               NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
+       nfsm_reqhead(NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_LOOKUP]);
        nfsm_fhtom(dvp, v3);
-       nfsm_strtom(name, len, NFS_MAXNAMLEN);
+       nfsm_strtom(name, len, NFS_MAXNAMLEN, v3);
        nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred, &xid);
        if (npp && !error) {
+               savedxid = xid;
                nfsm_getfh(nfhp, fhlen, v3);
+               /* get attributes */
+               if (v3) {
+                       nfsm_postop_attr_get(v3, attrflag, &nvattr);
+                       if (!attrflag) {
+                               /* We need valid attributes in order */
+                               /* to call nfs_nget/vnode_create().  */
+                               error = nfs_getattr_no_vnode(vnode_mount(dvp),
+                                               nfhp, fhlen, cred, procp, &nvattr, &xid);
+                               if (error) {
+                                       mbuf_freem(mrep);
+                                       goto nfsmout;
+                               }
+                       }
+                       dxid = savedxid;
+                       nfsm_postop_attr_update(dvp, v3, attrflag, &dxid);
+               } else {
+                       nfsm_attr_get(v3, &nvattr);
+               }
                if (*npp) {
                    np = *npp;
-                   if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
-                       FREE_ZONE((caddr_t)np->n_fhp,
-                                       np->n_fhsize, M_NFSBIGFH);
-                       np->n_fhp = &np->n_fh;
-                   } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
-                       MALLOC_ZONE(np->n_fhp, nfsfh_t *,
-                                               fhlen, M_NFSBIGFH, M_WAITOK);
-                   bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
+                   if (fhlen != np->n_fhsize) {
+                       u_char *oldbuf = (np->n_fhsize > NFS_SMALLFH) ? np->n_fhp : NULL;
+                       if (fhlen > NFS_SMALLFH) {
+                           MALLOC_ZONE(np->n_fhp, u_char *, fhlen, M_NFSBIGFH, M_WAITOK);
+                           if (!np->n_fhp) {
+                               np->n_fhp = oldbuf;
+                               error = ENOMEM;
+                               mbuf_freem(mrep);
+                               goto nfsmout;
+                           }
+                       } else {
+                           np->n_fhp = &np->n_fh[0];
+                       }
+                       if (oldbuf) {
+                           FREE_ZONE(oldbuf, np->n_fhsize, M_NFSBIGFH);
+                       }
+                   }
+                   bcopy(nfhp, np->n_fhp, fhlen);
                    np->n_fhsize = fhlen;
                    newvp = NFSTOV(np);
+                   error = nfs_loadattrcache(np, &nvattr, &xid, 0);
+                   if (error) {
+                       mbuf_freem(mrep);
+                       goto nfsmout;
+                   }
                } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
-                   VREF(dvp);
                    newvp = dvp;
+                   if (dnp->n_xid <= savedxid) {
+                       dxid = savedxid;
+                       error = nfs_loadattrcache(dnp, &nvattr, &dxid, 0);
+                       if (error) {
+                           mbuf_freem(mrep);
+                           goto nfsmout;
+                       }
+                   }
                } else {
-                   error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
+                   struct componentname cn, *cnp = &cn;
+                   bzero(cnp, sizeof(*cnp));
+                   cnp->cn_nameptr = name;
+                   cnp->cn_namelen = len;
+
+                   error = nfs_nget(vnode_mount(dvp), dvp, cnp, nfhp, fhlen,
+                               &nvattr, &xid, NG_MAKEENTRY, &np);
                    if (error) {
-                       m_freem(mrep);
+                       mbuf_freem(mrep);
                        return (error);
                    }
                    newvp = NFSTOV(np);
                }
-               if (v3) {
-                       nfsm_postop_attr(newvp, attrflag, &xid);
-                       if (!attrflag && *npp == NULL) {
-                               m_freem(mrep);
-                               if (newvp == dvp)
-                                       vrele(newvp);
-                               else
-                                       vput(newvp);
-                               return (ENOENT);
-                       }
-               } else
-                       nfsm_loadattr(newvp, (struct vattr *)0, &xid);
        }
        nfsm_reqdone;
        if (npp && *npp == NULL) {
                if (error) {
-                       if (newvp)
+                       if (newvp) {
                                if (newvp == dvp)
-                                       vrele(newvp);
+                                       vnode_rele(newvp);
                                else
-                                       vput(newvp);
+                                       vnode_put(newvp);
+                       }
                } else
                        *npp = np;
        }
@@ -3310,36 +3685,42 @@ nfs_lookitup(dvp, name, len, cred, procp, npp)
  * Nfs Version 3 commit rpc
  */
 int
-nfs_commit(vp, offset, cnt, cred, procp)
-       register struct vnode *vp;
+nfs_commit(vp, offset, count, cred, procp)
+       vnode_t vp;
        u_quad_t offset;
-       int cnt;
-       struct ucred *cred;
-       struct proc *procp;
+       u_int32_t count;
+       kauth_cred_t cred;
+       proc_t procp;
 {
-       register caddr_t cp;
-       register u_long *tl;
-       register int t1, t2;
-       register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+       caddr_t cp;
+       u_long *tl;
+       int t1, t2;
+       struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
        caddr_t bpos, dpos, cp2;
-       int error = 0, wccflag = NFSV3_WCCRATTR;
-       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       int error = 0, wccpostattr = 0;
+       struct timespec premtime = { 0, 0 };
+       mbuf_t mreq, mrep, md, mb, mb2;
        u_int64_t xid;
        
-       FSDBG(521, vp, offset, cnt, nmp->nm_state);
+       FSDBG(521, vp, offset, count, nmp->nm_state);
        if (!nmp)
                return (ENXIO);
        if ((nmp->nm_state & NFSSTA_HASWRITEVERF) == 0)
                return (0);
-       nfsstats.rpccnt[NFSPROC_COMMIT]++;
-       nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
+       nfsm_reqhead(NFSX_FH(1));
+       if (error)
+               return (error);
+       OSAddAtomic(1, (SInt32*)&nfsstats.rpccnt[NFSPROC_COMMIT]);
        nfsm_fhtom(vp, 1);
        nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
        txdr_hyper(&offset, tl);
        tl += 2;
-       *tl = txdr_unsigned(cnt);
+       *tl = txdr_unsigned(count);
        nfsm_request(vp, NFSPROC_COMMIT, procp, cred, &xid);
-       nfsm_wcc_data(vp, wccflag, &xid);
+       if (mrep) {
+               nfsm_wcc_data(vp, &premtime, wccpostattr, &xid);
+               /* XXX can we do anything useful with the wcc info? */
+       }
        if (!error) {
                nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
                if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
@@ -3354,34 +3735,19 @@ nfs_commit(vp, offset, cnt, cred, procp)
 }
 
 static int
-nfs_bmap(ap)
-       struct vop_bmap_args /* {
-               struct vnode *a_vp;
-               daddr_t  a_bn;
-               struct vnode **a_vpp;
-               daddr_t *a_bnp;
-               int *a_runp;
-               int *a_runb;
-       } */ *ap;
+nfs_blockmap(
+       __unused struct vnop_blockmap_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               off_t a_foffset;
+               size_t a_size;
+               daddr64_t *a_bpn;
+               size_t *a_run;
+               void *a_poff;
+               int a_flags;
+       } */ *ap)
 {
-       register struct vnode *vp = ap->a_vp;
-       int devBlockSize = DEV_BSIZE;
-
-       if (ap->a_vpp != NULL)
-               *ap->a_vpp = vp;
-       if (ap->a_bnp != NULL) {
-               if (!vp->v_mount)
-                       return (ENXIO);
-               *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize,
-                                             devBlockSize);
-       }
-       if (ap->a_runp != NULL)
-               *ap->a_runp = 0;
-#ifdef notyet
-       if (ap->a_runb != NULL)
-               *ap->a_runb = 0;
-#endif
-       return (0);
+       return (ENOTSUP);
 }
 
 /*
@@ -3389,15 +3755,16 @@ nfs_bmap(ap)
  *
  * NB Currently unsupported.
  */
-/* ARGSUSED */
+/*ARGSUSED*/
 static int
-nfs_mmap(ap)
-       struct vop_mmap_args /* {
-               struct vnode *a_vp;
-               int  a_fflags;
-               struct ucred *a_cred;
-               struct proc *a_p;
-       } */ *ap;
+nfs_mmap(
+       __unused struct vnop_mmap_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               int a_fflags;
+               kauth_cred_t a_cred;
+               proc_t a_p;
+       } */ *ap)
 {
 
        return (EINVAL);
@@ -3409,30 +3776,34 @@ nfs_mmap(ap)
 /* ARGSUSED */
 static int
 nfs_fsync(ap)
-       struct vop_fsync_args /* {
+       struct vnop_fsync_args /* {
                struct vnodeop_desc *a_desc;
-               struct vnode * a_vp;
-               struct ucred * a_cred;
-               int  a_waitfor;
-               struct proc * a_p;
+               vnode_t a_vp;
+               int a_waitfor;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
+       kauth_cred_t cred = vfs_context_ucred(ap->a_context);
+       proc_t p = vfs_context_proc(ap->a_context);
+       struct nfsnode *np = VTONFS(ap->a_vp);
+       int error;
+
+       np->n_flag |= NWRBUSY;
+       error = nfs_flush(ap->a_vp, ap->a_waitfor, cred, p, 0);
+       np->n_flag &= ~NWRBUSY;
+       return (error);
 }
  
 int
-nfs_flushcommits(struct vnode *vp, struct proc *p)
+nfs_flushcommits(vnode_t vp, proc_t p, int nowait)
 {
        struct nfsnode *np = VTONFS(vp);
-       struct nfsbuf *bp, *nbp;
-       int i, s, error = 0, retv, bvecpos, wcred_set;
+       struct nfsbuf *bp;
+       struct nfsbuflists blist, commitlist;
+       int error = 0, retv, wcred_set, flags;
        u_quad_t off, endoff, toff;
-       struct ucred* wcred;
-       struct nfsbuf **bvec = NULL;
-#define NFS_COMMITBVECSIZ      20
-#define NFS_MAXCOMMITBVECSIZ   1024
-       struct nfsbuf *bvec_on_stack[NFS_COMMITBVECSIZ];
-       int bvecsize = NFS_MAXCOMMITBVECSIZ;
+       u_int32_t count;
+       kauth_cred_t wcred = NULL;
 
        FSDBG_TOP(557, vp, np, 0, 0);
 
@@ -3442,15 +3813,15 @@ nfs_flushcommits(struct vnode *vp, struct proc *p)
         * yet. The byte range is worked out for as many nfsbufs as we can handle
         * and the commit rpc is done.
         */
-       if (np->n_dirtyblkhd.lh_first)
+       if (!LIST_EMPTY(&np->n_dirtyblkhd))
                np->n_flag |= NMODIFIED;
 
        off = (u_quad_t)-1;
        endoff = 0;
-       bvecpos = 0;
        wcred_set = 0;
+       LIST_INIT(&commitlist);
 
-       if (!VFSTONFS(vp->v_mount)) {
+       if (!VFSTONFS(vnode_mount(vp))) {
                error = ENXIO;
                goto done;
        }
@@ -3458,95 +3829,96 @@ nfs_flushcommits(struct vnode *vp, struct proc *p)
                error = EINVAL;
                goto done;
        }
-       s = splbio();
-
-       /*
-        * Allocate space to remember the list of bufs to commit.  It is
-        * important to use M_NOWAIT here to avoid a race with nfs_write
-        */
-       MALLOC(bvec, struct nfsbuf **,
-                      bvecsize * sizeof(struct nfsbuf *), M_TEMP,
-                      M_NOWAIT);
-       if (bvec == NULL) {
-               bvec = bvec_on_stack;
-               bvecsize = NFS_COMMITBVECSIZ;
-       }
-       for (bp = np->n_dirtyblkhd.lh_first; bp && bvecpos < bvecsize; bp = nbp) {
-               nbp = bp->nb_vnbufs.le_next;
 
-               if (((bp->nb_flags & (NB_BUSY | NB_DELWRI | NB_NEEDCOMMIT))
-                       != (NB_DELWRI | NB_NEEDCOMMIT)))
-                       continue;
-
-               nfs_buf_remfree(bp);
-               SET(bp->nb_flags, NB_BUSY);
-               /*
-                * we need a upl to see if the page has been
-                * dirtied (think mmap) since the unstable write, and
-                * also to prevent vm from paging it during our commit rpc
-                */
-               if (!ISSET(bp->nb_flags, NB_PAGELIST)) {
-                       retv = nfs_buf_upl_setup(bp);
-                       if (retv) {
-                               /* unable to create upl */
-                               /* vm object must no longer exist */
-                               /* this could be fatal if we need */
-                               /* to write the data again, we'll see...  */
-                               printf("nfs_flushcommits: upl create failed %d\n", retv);
-                               bp->nb_valid = bp->nb_dirty = 0;
+       flags = NBI_DIRTY;
+       if (nowait)
+               flags |= NBI_NOWAIT;
+       lck_mtx_lock(nfs_buf_mutex);
+       if (!nfs_buf_iterprepare(np, &blist, flags)) {
+               while ((bp = LIST_FIRST(&blist))) {
+                       LIST_REMOVE(bp, nb_vnbufs);
+                       LIST_INSERT_HEAD(&np->n_dirtyblkhd, bp, nb_vnbufs);
+                       error = nfs_buf_acquire(bp, NBAC_NOWAIT, 0, 0);
+                       if (error)
+                               continue;
+                       if (((bp->nb_flags & (NB_DELWRI | NB_NEEDCOMMIT))
+                               != (NB_DELWRI | NB_NEEDCOMMIT))) {
+                               nfs_buf_drop(bp);
+                               continue;
                        }
-               }
-               nfs_buf_upl_check(bp);
+                       nfs_buf_remfree(bp);
+                       lck_mtx_unlock(nfs_buf_mutex);
+                       /*
+                        * we need a upl to see if the page has been
+                        * dirtied (think mmap) since the unstable write, and
+                        * also to prevent vm from paging it during our commit rpc
+                        */
+                       if (!ISSET(bp->nb_flags, NB_PAGELIST)) {
+                               retv = nfs_buf_upl_setup(bp);
+                               if (retv) {
+                                       /* unable to create upl */
+                                       /* vm object must no longer exist */
+                                       /* this could be fatal if we need */
+                                       /* to write the data again, we'll see...  */
+                                       printf("nfs_flushcommits: upl create failed %d\n", retv);
+                                       bp->nb_valid = bp->nb_dirty = 0;
+                               }
+                       }
+                       nfs_buf_upl_check(bp);
+                       lck_mtx_lock(nfs_buf_mutex);
 
-               FSDBG(557, bp, bp->nb_flags, bp->nb_valid, bp->nb_dirty);
-               FSDBG(557, bp->nb_validoff, bp->nb_validend,
-                     bp->nb_dirtyoff, bp->nb_dirtyend);
+                       FSDBG(557, bp, bp->nb_flags, bp->nb_valid, bp->nb_dirty);
+                       FSDBG(557, bp->nb_validoff, bp->nb_validend,
+                             bp->nb_dirtyoff, bp->nb_dirtyend);
 
-               /*
-                * We used to check for dirty pages here; if there were any
-                * we'd abort the commit and force the entire buffer to be
-                * written again.
-                *
-                * Instead of doing that, we now go ahead and commit the dirty
-                * range, and then leave the buffer around with dirty pages
-                * that will be written out later.
-                */
+                       /*
+                        * We used to check for dirty pages here; if there were any
+                        * we'd abort the commit and force the entire buffer to be
+                        * written again.
+                        *
+                        * Instead of doing that, we now go ahead and commit the dirty
+                        * range, and then leave the buffer around with dirty pages
+                        * that will be written out later.
+                        */
 
-               /* in case blocking calls were made, re-evaluate nbp */
-               nbp = bp->nb_vnbufs.le_next;
+                       /*
+                        * Work out if all buffers are using the same cred
+                        * so we can deal with them all with one commit.
+                        *
+                        * XXX creds in bp's must be obtained by kauth_cred_ref on
+                        *     the same original cred in order for them to be equal.
+                        */
+                       if (wcred_set == 0) {
+                               wcred = bp->nb_wcred;
+                               if (wcred == NOCRED)
+                                       panic("nfs: needcommit w/out wcred");
+                               wcred_set = 1;
+                       } else if ((wcred_set == 1) && wcred != bp->nb_wcred) {
+                               wcred_set = -1;
+                       }
+                       SET(bp->nb_flags, NB_WRITEINPROG);
 
-               /*
-                * Work out if all buffers are using the same cred
-                * so we can deal with them all with one commit.
-                */
-               if (wcred_set == 0) {
-                       wcred = bp->nb_wcred;
-                       if (wcred == NOCRED)
-                               panic("nfs: needcommit w/out wcred");
-                       wcred_set = 1;
-               } else if ((wcred_set == 1) && crcmp(wcred, bp->nb_wcred)) {
-                       wcred_set = -1;
+                       /*
+                        * A list of these buffers is kept so that the
+                        * second loop knows which buffers have actually
+                        * been committed. This is necessary, since there
+                        * may be a race between the commit rpc and new
+                        * uncommitted writes on the file.
+                        */
+                       LIST_REMOVE(bp, nb_vnbufs);
+                       LIST_INSERT_HEAD(&commitlist, bp, nb_vnbufs);
+                       toff = NBOFF(bp) + bp->nb_dirtyoff;
+                       if (toff < off)
+                               off = toff;
+                       toff += (u_quad_t)(bp->nb_dirtyend - bp->nb_dirtyoff);
+                       if (toff > endoff)
+                               endoff = toff;
                }
-               SET(bp->nb_flags, NB_WRITEINPROG);
-
-               /*
-                * A list of these buffers is kept so that the
-                * second loop knows which buffers have actually
-                * been committed. This is necessary, since there
-                * may be a race between the commit rpc and new
-                * uncommitted writes on the file.
-                */
-               bvec[bvecpos++] = bp;
-               toff = NBOFF(bp) + bp->nb_dirtyoff;
-               if (toff < off)
-                       off = toff;
-               toff += (u_quad_t)(bp->nb_dirtyend - bp->nb_dirtyoff);
-               if (toff > endoff)
-                       endoff = toff;
+               nfs_buf_itercomplete(np, &blist, NBI_DIRTY);
        }
-       splx(s);
+       lck_mtx_unlock(nfs_buf_mutex);
 
-       if (bvecpos == 0) {
+       if (LIST_EMPTY(&commitlist)) {
                error = ENOBUFS;
                goto done;
        }
@@ -3557,74 +3929,78 @@ nfs_flushcommits(struct vnode *vp, struct proc *p)
         * one call for all of them, otherwise commit each one
         * separately.
         */
-       if (wcred_set == 1)
-               retv = nfs_commit(vp, off, (int)(endoff - off), wcred, p);
-       else {
+       if (wcred_set == 1) {
+               /*
+                * Note, it's possible the commit range could be >2^32-1.
+                * If it is, we'll send one commit that covers the whole file.
+                */
+               if ((endoff - off) > 0xffffffff)
+                       count = 0; 
+               else
+                       count = (endoff - off); 
+               retv = nfs_commit(vp, off, count, wcred, p);
+       } else {
                retv = 0;
-
-               for (i = 0; i < bvecpos; i++) {
-                       off_t off, size;
-                       bp = bvec[i];
-                       off = NBOFF(bp) + bp->nb_dirtyoff;
-                       size = (u_quad_t)(bp->nb_dirtyend - bp->nb_dirtyoff);
-                       retv = nfs_commit(vp, off, (int)size, bp->nb_wcred, p);
-                       if (retv) break;
+               LIST_FOREACH(bp, &commitlist, nb_vnbufs) {
+                       toff = NBOFF(bp) + bp->nb_dirtyoff;
+                       count = bp->nb_dirtyend - bp->nb_dirtyoff;
+                       retv = nfs_commit(vp, toff, count, bp->nb_wcred, p);
+                       if (retv)
+                               break;
                }
        }
        if (retv == NFSERR_STALEWRITEVERF)
-               nfs_clearcommit(vp->v_mount);
+               nfs_clearcommit(vnode_mount(vp));
 
        /*
         * Now, either mark the blocks I/O done or mark the
         * blocks dirty, depending on whether the commit
         * succeeded.
         */
-       for (i = 0; i < bvecpos; i++) {
-               bp = bvec[i];
+       while ((bp = LIST_FIRST(&commitlist))) {
+               LIST_REMOVE(bp, nb_vnbufs);
                FSDBG(557, bp, retv, bp->nb_flags, bp->nb_dirty);
-
                CLR(bp->nb_flags, (NB_NEEDCOMMIT | NB_WRITEINPROG));
-
                np->n_needcommitcnt--;
                CHECK_NEEDCOMMITCNT(np);
 
                if (retv) {
-                       nfs_buf_release(bp);
-               } else {
-                       s = splbio();
-                       vp->v_numoutput++;
+                       /* move back to dirty list */
+                       lck_mtx_lock(nfs_buf_mutex);
+                       LIST_INSERT_HEAD(&VTONFS(vp)->n_dirtyblkhd, bp, nb_vnbufs);
+                       lck_mtx_unlock(nfs_buf_mutex);
+                       nfs_buf_release(bp, 1);
+                       continue;
+               }
 
-                       if (ISSET(bp->nb_flags, NB_DELWRI)) {
-                               nfs_nbdwrite--;
-                               NFSBUFCNTCHK();
-                               wakeup((caddr_t)&nfs_nbdwrite);
-                       }
-                       CLR(bp->nb_flags, (NB_READ|NB_DONE|NB_ERROR|NB_DELWRI));
-                       /* if block still has dirty pages, we don't want it to */
-                       /* be released in nfs_buf_iodone().  So, don't set NB_ASYNC. */
-                       if (!bp->nb_dirty)
-                               SET(bp->nb_flags, NB_ASYNC);
+               vnode_startwrite(vp);
+               if (ISSET(bp->nb_flags, NB_DELWRI)) {
+                       OSAddAtomic(-1, (SInt32*)&nfs_nbdwrite);
+                       NFSBUFCNTCHK(0);
+                       wakeup(&nfs_nbdwrite);
+               }
+               CLR(bp->nb_flags, (NB_READ|NB_DONE|NB_ERROR|NB_DELWRI));
+               /* if block still has dirty pages, we don't want it to */
+               /* be released in nfs_buf_iodone().  So, don't set NB_ASYNC. */
+               if (!bp->nb_dirty)
+                       SET(bp->nb_flags, NB_ASYNC);
 
-                       /* move to clean list */
-                       if (bp->nb_vnbufs.le_next != NFSNOLIST)
-                               LIST_REMOVE(bp, nb_vnbufs);
-                       LIST_INSERT_HEAD(&VTONFS(vp)->n_cleanblkhd, bp, nb_vnbufs);
+               /* move to clean list */
+               lck_mtx_lock(nfs_buf_mutex);
+               LIST_INSERT_HEAD(&VTONFS(vp)->n_cleanblkhd, bp, nb_vnbufs);
+               lck_mtx_unlock(nfs_buf_mutex);
 
-                       bp->nb_dirtyoff = bp->nb_dirtyend = 0;
-                       splx(s);
+               bp->nb_dirtyoff = bp->nb_dirtyend = 0;
 
-                       nfs_buf_iodone(bp);
-                       if (bp->nb_dirty) {
-                               /* throw it back in as a delayed write buffer */
-                               CLR(bp->nb_flags, NB_DONE);
-                               nfs_buf_write_delayed(bp);
-                       }
+               nfs_buf_iodone(bp);
+               if (bp->nb_dirty) {
+                       /* throw it back in as a delayed write buffer */
+                       CLR(bp->nb_flags, NB_DONE);
+                       nfs_buf_write_delayed(bp, p);
                }
        }
 
 done:
-       if (bvec != NULL && bvec != bvec_on_stack)
-               _FREE(bvec, M_TEMP);
        FSDBG_BOT(557, vp, np, 0, error);
        return (error);
 }
@@ -3634,21 +4010,22 @@ done:
  *     Walk through the buffer pool and push any dirty pages
  *     associated with the vnode.
  */
-static int
-nfs_flush(vp, cred, waitfor, p, commit)
-       register struct vnode *vp;
-       struct ucred *cred;
-       int waitfor;
-       struct proc *p;
-       int commit;
+int
+nfs_flush(
+       vnode_t vp,
+       int waitfor,
+       __unused kauth_cred_t cred,
+       proc_t p,
+       int ignore_writeerr)
 {
        struct nfsnode *np = VTONFS(vp);
-       struct nfsbuf *bp, *nbp;
-       struct nfsmount *nmp = VFSTONFS(vp->v_mount);
-       int i, s, error = 0, error2, slptimeo = 0, slpflag = 0;
-       int passone = 1;
+       struct nfsbuf *bp;
+       struct nfsbuflists blist;
+       struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
+       int error = 0, error2, slptimeo = 0, slpflag = 0;
+       int flags, passone = 1;
 
-       FSDBG_TOP(517, vp, np, waitfor, commit);
+       FSDBG_TOP(517, vp, np, waitfor, 0);
 
        if (!nmp) {
                error = ENXIO;
@@ -3656,109 +4033,124 @@ nfs_flush(vp, cred, waitfor, p, commit)
        }
        if (nmp->nm_flag & NFSMNT_INT)
                slpflag = PCATCH;
-       if (!commit)
-               passone = 0;
 
        /*
-        * On the first pass, commit all the bufs that can be.
-        * On the second pass, nfs_buf_write() is called to do the job.
+        * On the first pass, start async/unstable writes on all
+        * delayed write buffers.  Then wait for all writes to complete
+        * and call nfs_flushcommits() to commit any uncommitted buffers.
+        * On all subsequent passes, start STABLE writes on any remaining
+        * dirty buffers.  Then wait for all writes to complete.
         */
 again:
-       FSDBG(518, np->n_dirtyblkhd.lh_first, np->n_flag, 0, 0);
-       if (np->n_dirtyblkhd.lh_first)
+       lck_mtx_lock(nfs_buf_mutex);
+       FSDBG(518, LIST_FIRST(&np->n_dirtyblkhd), np->n_flag, 0, 0);
+       if (!LIST_EMPTY(&np->n_dirtyblkhd))
                np->n_flag |= NMODIFIED;
-       if (!VFSTONFS(vp->v_mount)) {
+       if (!VFSTONFS(vnode_mount(vp))) {
+               lck_mtx_unlock(nfs_buf_mutex);
                error = ENXIO;
                goto done;
        }
-       if (NFS_ISV3(vp) && commit) {
-               /* loop while it looks like there are still buffers to be */
-               /* commited and nfs_flushcommits() seems to be handling them. */
-               while (np->n_needcommitcnt)
-                       if (nfs_flushcommits(vp, p))
-                               break;
-       }
 
        /* Start/do any write(s) that are required. */
-loop:
-       s = splbio();
-       for (bp = np->n_dirtyblkhd.lh_first; bp; bp = nbp) {
-               nbp = bp->nb_vnbufs.le_next;
-               if (ISSET(bp->nb_flags, NB_BUSY)) {
-                       FSDBG(524, bp, waitfor, passone, bp->nb_flags);
-                       if (waitfor != MNT_WAIT || passone)
-                               continue;
-                       SET(bp->nb_flags, NB_WANTED);
-                       error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
-                                      "nfsfsync", slptimeo);
-                       splx(s);
-                       if (error) {
-                               error2 = nfs_sigintr(VFSTONFS(vp->v_mount),
-                                   (struct nfsreq *)0, p);
-                               if (error2) {
-                                       error = error2;
-                                       goto done;
-                               }
-                               if (slpflag == PCATCH) {
-                                       slpflag = 0;
-                                       slptimeo = 2 * hz;
+       if (!nfs_buf_iterprepare(np, &blist, NBI_DIRTY)) {
+               while ((bp = LIST_FIRST(&blist))) {
+                       LIST_REMOVE(bp, nb_vnbufs);
+                       LIST_INSERT_HEAD(&np->n_dirtyblkhd, bp, nb_vnbufs);
+                       flags = (passone || (waitfor != MNT_WAIT)) ? NBAC_NOWAIT : 0;
+                       if (flags != NBAC_NOWAIT)
+                               nfs_buf_refget(bp);
+                       while ((error = nfs_buf_acquire(bp, flags, slpflag, slptimeo))) {
+                               FSDBG(524, bp, flags, bp->nb_lflags, bp->nb_flags);
+                               if (error == EBUSY)
+                                       break;
+                               if (error) {
+                                       error2 = nfs_sigintr(VFSTONFS(vnode_mount(vp)), NULL, p);
+                                       if (error2) {
+                                               if (flags != NBAC_NOWAIT)
+                                                       nfs_buf_refrele(bp);
+                                               nfs_buf_itercomplete(np, &blist, NBI_DIRTY);
+                                               lck_mtx_unlock(nfs_buf_mutex);
+                                               error = error2;
+                                               goto done;
+                                       }
+                                       if (slpflag == PCATCH) {
+                                               slpflag = 0;
+                                               slptimeo = 2 * hz;
+                                       }
                                }
                        }
-                       goto loop;
-               }
-               if (!ISSET(bp->nb_flags, NB_DELWRI))
-                       panic("nfs_fsync: not dirty");
-               FSDBG(525, bp, passone, commit, bp->nb_flags);
-               if ((passone || !commit) && ISSET(bp->nb_flags, NB_NEEDCOMMIT))
-                       continue;
-               nfs_buf_remfree(bp);
-               if (ISSET(bp->nb_flags, NB_ERROR)) {
-                       np->n_error = bp->nb_error ? bp->nb_error : EIO;
-                       np->n_flag |= NWRITEERR;
-                       nfs_buf_release(bp);
-                       continue;
-               }
-               if (passone || !commit)
-                       SET(bp->nb_flags, NB_BUSY|NB_ASYNC);
-               else {
-                       /* the NB_STABLE forces this to be written FILESYNC */
-                       SET(bp->nb_flags, NB_BUSY|NB_ASYNC|NB_STABLE);
+                       if (flags != NBAC_NOWAIT)
+                               nfs_buf_refrele(bp);
+                       if (error == EBUSY)
+                               continue;
+                       if (!bp->nb_vp) {
+                               /* buffer is no longer valid */
+                               nfs_buf_drop(bp);
+                               continue;
+                       }
+                       if (!ISSET(bp->nb_flags, NB_DELWRI))
+                               panic("nfs_flush: not dirty");
+                       FSDBG(525, bp, passone, bp->nb_lflags, bp->nb_flags);
+                       if ((passone || (waitfor != MNT_WAIT)) &&
+                           ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
+                               nfs_buf_drop(bp);
+                               continue;
+                       }
+                       nfs_buf_remfree(bp);
+                       lck_mtx_unlock(nfs_buf_mutex);
+                       if (ISSET(bp->nb_flags, NB_ERROR)) {
+                               np->n_error = bp->nb_error ? bp->nb_error : EIO;
+                               np->n_flag |= NWRITEERR;
+                               nfs_buf_release(bp, 1);
+                               lck_mtx_lock(nfs_buf_mutex);
+                               continue;
+                       }
+                       SET(bp->nb_flags, NB_ASYNC);
+                       if (!passone) {
+                               /* NB_STABLE forces this to be written FILESYNC */
+                               SET(bp->nb_flags, NB_STABLE);
+                       }
+                       nfs_buf_write(bp);
+                       lck_mtx_lock(nfs_buf_mutex);
                }
-               splx(s);
-               nfs_buf_write(bp);
-               goto loop;
-       }
-       splx(s);
-
-       if (passone) {
-               passone = 0;
-               goto again;
+               nfs_buf_itercomplete(np, &blist, NBI_DIRTY);
        }
+       lck_mtx_unlock(nfs_buf_mutex);
 
        if (waitfor == MNT_WAIT) {
-               while (vp->v_numoutput) {
-                       vp->v_flag |= VBWAIT;
-                       error = tsleep((caddr_t)&vp->v_numoutput,
-                               slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
-                       if (error) {
-                               error2 = nfs_sigintr(VFSTONFS(vp->v_mount),
-                                   (struct nfsreq *)0, p);
-                           if (error2) {
-                               error = error2;
+               while ((error = vnode_waitforwrites(vp, 0, slpflag, slptimeo, "nfsflush"))) {
+                       error2 = nfs_sigintr(VFSTONFS(vnode_mount(vp)), NULL, p);
+                       if (error2) {
+                               error = error2;
                                goto done;
-                           }
-                           if (slpflag == PCATCH) {
+                       }
+                       if (slpflag == PCATCH) {
                                slpflag = 0;
                                slptimeo = 2 * hz;
-                           }
                        }
                }
-               if (np->n_dirtyblkhd.lh_first && commit) {
-                       goto loop;
-               }
        }
+
+       if (NFS_ISV3(vp)) {
+               /* loop while it looks like there are still buffers to be */
+               /* commited and nfs_flushcommits() seems to be handling them. */
+               while (np->n_needcommitcnt)
+                       if (nfs_flushcommits(vp, p, 0))
+                               break;
+       }
+
+       if (passone) {
+               passone = 0;
+               goto again;
+       }
+
+       if ((waitfor == MNT_WAIT) && !LIST_EMPTY(&np->n_dirtyblkhd)) {
+               goto again;
+       }
+
        FSDBG(526, np->n_flag, np->n_error, 0, 0);
-       if (np->n_flag & NWRITEERR) {
+       if (!ignore_writeerr && (np->n_flag & NWRITEERR)) {
                error = np->n_error;
                np->n_flag &= ~NWRITEERR;
        }
@@ -3768,155 +4160,182 @@ done:
 }
 
 /*
- * Return POSIX pathconf information applicable to nfs.
- *
- * The NFS V2 protocol doesn't support this, so just return EINVAL
- * for V2.
+ * Do an nfs pathconf rpc.
  */
-/* ARGSUSED */
-static int
-nfs_pathconf(ap)
-       struct vop_pathconf_args /* {
-               struct vnode *a_vp;
-               int a_name;
-               int *a_retval;
-       } */ *ap;
+int
+nfs_pathconfrpc(
+       vnode_t vp,
+       struct nfsv3_pathconf *pc,
+       kauth_cred_t cred,
+       proc_t procp)
 {
+       mbuf_t mreq, mrep, md, mb, mb2;
+       caddr_t bpos, dpos, cp, cp2;
+       int32_t t1, t2;
+       u_long *tl;
+       u_int64_t xid;
+       int attrflag, error = 0;
+       struct nfsv3_pathconf *mpc;
 
-       return (EINVAL);
-}
+       /* fetch pathconf info from server */
+       nfsm_reqhead(NFSX_FH(1));
+       if (error)
+               return (error);
+       nfsm_fhtom(vp, 1);
+       nfsm_request(vp, NFSPROC_PATHCONF, procp, cred, &xid);
+       nfsm_postop_attr_update(vp, 1, attrflag, &xid);
+       if (!error) {
+               nfsm_dissect(mpc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
+               pc->pc_linkmax = fxdr_unsigned(long, mpc->pc_linkmax);
+               pc->pc_namemax = fxdr_unsigned(long, mpc->pc_namemax);
+               pc->pc_chownrestricted = fxdr_unsigned(long, mpc->pc_chownrestricted);
+               pc->pc_notrunc = fxdr_unsigned(long, mpc->pc_notrunc);
+               pc->pc_caseinsensitive = fxdr_unsigned(long, mpc->pc_caseinsensitive);
+               pc->pc_casepreserving = fxdr_unsigned(long, mpc->pc_casepreserving);
+       }
+       nfsm_reqdone;
 
-/*
- * NFS advisory byte-level locks (client)
- */
-static int
-nfs_advlock(ap)
-       struct vop_advlock_args /* {
-               struct vnode *a_vp;
-               caddr_t  a_id;
-               int  a_op;
-               struct flock *a_fl;
-               int  a_flags;
-       } */ *ap;
-{
-       return (nfs_dolock(ap));
+       return (error);
 }
 
-/*
- * Print out the contents of an nfsnode.
- */
-static int
-nfs_print(ap)
-       struct vop_print_args /* {
-               struct vnode *a_vp;
-       } */ *ap;
+void
+nfs_pathconf_cache(struct nfsmount *nmp, struct nfsv3_pathconf *pc)
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct nfsnode *np = VTONFS(vp);
-
-       printf("tag VT_NFS, fileid %ld fsid 0x%lx",
-               np->n_vattr.va_fileid, np->n_vattr.va_fsid);
-       if (vp->v_type == VFIFO)
-               fifo_printinfo(vp);
-       printf("\n");
-       return (0);
+       nmp->nm_state |= NFSSTA_GOTPATHCONF;
+       nmp->nm_fsinfo.linkmax = pc->pc_linkmax;
+       nmp->nm_fsinfo.namemax = pc->pc_namemax;
+       nmp->nm_fsinfo.pcflags = 0;
+       if (pc->pc_notrunc)
+               nmp->nm_fsinfo.pcflags |= NFSPCINFO_NOTRUNC;
+       if (pc->pc_chownrestricted)
+               nmp->nm_fsinfo.pcflags |= NFSPCINFO_CHOWN_RESTRICTED;
+       if (pc->pc_caseinsensitive)
+               nmp->nm_fsinfo.pcflags |= NFSPCINFO_CASE_INSENSITIVE;
+       if (pc->pc_casepreserving)
+               nmp->nm_fsinfo.pcflags |= NFSPCINFO_CASE_PRESERVING;
 }
 
 /*
- * NFS directory offset lookup.
- * Currently unsupported.
+ * Return POSIX pathconf information applicable to nfs.
+ *
+ * The NFS V2 protocol doesn't support this, so just return EINVAL
+ * for V2.
  */
+/* ARGSUSED */
 static int
-nfs_blkatoff(ap)
-       struct vop_blkatoff_args /* {
-               struct vnode *a_vp;
-               off_t a_offset;
-               char **a_res;
-               struct buf **a_bpp;
+nfs_pathconf(ap)
+       struct vnop_pathconf_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               int a_name;
+               register_t *a_retval;
+               vfs_context_t a_context;
        } */ *ap;
 {
+       vnode_t vp = ap->a_vp;
+       struct nfsmount *nmp;
+       struct nfsv3_pathconf pc;
+       int error = 0, cached;
 
-#if DIAGNOSTIC
-       printf("nfs_blkatoff: unimplemented!!");
-#endif
-       return (EOPNOTSUPP);
-}
+       nmp = VFSTONFS(vnode_mount(vp));
+       if (!nmp)
+               return (ENXIO);
+       if (!NFS_ISV3(vp))
+               return (EINVAL);
 
-/*
- * NFS flat namespace allocation.
- * Currently unsupported.
- */
-static int
-nfs_valloc(ap)
-       struct vop_valloc_args /* {
-               struct vnode *a_pvp;
-               int a_mode;
-               struct ucred *a_cred;
-               struct vnode **a_vpp;
-       } */ *ap;
-{
+       switch (ap->a_name) {
+       case _PC_LINK_MAX:
+       case _PC_NAME_MAX:
+       case _PC_CHOWN_RESTRICTED:
+       case _PC_NO_TRUNC:
+       case _PC_CASE_SENSITIVE:
+       case _PC_CASE_PRESERVING:
+               break;
+       default:
+               /* don't bother contacting the server if we know the answer */
+               return (EINVAL);
+       }
 
-       return (EOPNOTSUPP);
-}
+       if (!(nmp->nm_state & NFSSTA_GOTPATHCONF)) {
+               /* no pathconf info cached */
+               kauth_cred_t cred = vfs_context_ucred(ap->a_context);
+               proc_t p = vfs_context_proc(ap->a_context);
+               error = nfs_pathconfrpc(vp, &pc, cred, p);
+               if (error)
+                       return (error);
+               nmp = VFSTONFS(vnode_mount(vp));
+               if (!nmp)
+                       return (ENXIO);
+               if (!(nmp->nm_state & NFSSTA_GOTFSINFO)) {
+                       nfs_fsinfo(nmp, vp, cred, p);
+                       nmp = VFSTONFS(vnode_mount(vp));
+                       if (!nmp)
+                               return (ENXIO);
+               }
+               if ((nmp->nm_state & NFSSTA_GOTFSINFO) &&
+                   (nmp->nm_fsinfo.fsproperties & NFSV3FSINFO_HOMOGENEOUS)) {
+                       /* all files have the same pathconf info, */
+                       /* so cache a copy of the results */
+                       nfs_pathconf_cache(nmp, &pc);
+               }
+       }
 
-/*
- * NFS flat namespace free.
- * Currently unsupported.
- */
-static int
-nfs_vfree(ap)
-       struct vop_vfree_args /* {
-               struct vnode *a_pvp;
-               ino_t a_ino;
-               int a_mode;
-       } */ *ap;
-{
+       cached = (nmp->nm_state & NFSSTA_GOTPATHCONF);
+
+       switch (ap->a_name) {
+       case _PC_LINK_MAX:
+               *ap->a_retval = cached ? nmp->nm_fsinfo.linkmax : pc.pc_linkmax;
+               break;
+       case _PC_NAME_MAX:
+               *ap->a_retval = cached ? nmp->nm_fsinfo.namemax : pc.pc_namemax;
+               break;
+       case _PC_CHOWN_RESTRICTED:
+               if (cached)
+                       *ap->a_retval = (nmp->nm_fsinfo.pcflags & NFSPCINFO_CHOWN_RESTRICTED) ? 1 : 0;
+               else
+                       *ap->a_retval = pc.pc_chownrestricted;
+               break;
+       case _PC_NO_TRUNC:
+               if (cached)
+                       *ap->a_retval = (nmp->nm_fsinfo.pcflags & NFSPCINFO_NOTRUNC) ? 1 : 0;
+               else
+                       *ap->a_retval = pc.pc_notrunc;
+               break;
+       case _PC_CASE_SENSITIVE:
+               if (cached)
+                       *ap->a_retval = (nmp->nm_fsinfo.pcflags & NFSPCINFO_CASE_INSENSITIVE) ? 0 : 1;
+               else
+                       *ap->a_retval = !pc.pc_caseinsensitive;
+               break;
+       case _PC_CASE_PRESERVING:
+               if (cached)
+                       *ap->a_retval = (nmp->nm_fsinfo.pcflags & NFSPCINFO_CASE_PRESERVING) ? 1 : 0;
+               else
+                       *ap->a_retval = pc.pc_casepreserving;
+               break;
+       default:
+               error = EINVAL;
+       }
 
-#if DIAGNOSTIC
-       printf("nfs_vfree: unimplemented!!");
-#endif
-       return (EOPNOTSUPP);
+       return (error);
 }
 
 /*
- * NFS file truncation.
+ * NFS advisory byte-level locks (client)
  */
 static int
-nfs_truncate(ap)
-       struct vop_truncate_args /* {
-               struct vnode *a_vp;
-               off_t a_length;
+nfs_advlock(ap)
+       struct vnop_advlock_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               caddr_t a_id;
+               int a_op;
+               struct flock *a_fl;
                int a_flags;
-               struct ucred *a_cred;
-               struct proc *a_p;
+               vfs_context_t a_context;
        } */ *ap;
 {
-
-       /* Use nfs_setattr */
-#if DIAGNOSTIC
-       printf("nfs_truncate: unimplemented!!");
-#endif
-       return (EOPNOTSUPP);
-}
-
-/*
- * NFS update.
- */
-static int
-nfs_update(ap)
-       struct vop_update_args /* {
-               struct vnode *a_vp;
-               struct timeval *a_ta;
-               struct timeval *a_tm;
-               int a_waitfor;
-       } */ *ap;
-{
-
-       /* Use nfs_setattr */
-#if DIAGNOSTIC
-       printf("nfs_update: unimplemented!!");
-#endif
-       return (EOPNOTSUPP);
+       return (nfs_dolock(ap));
 }
 
 /*
@@ -3925,44 +4344,43 @@ nfs_update(ap)
 int
 nfs_buf_write(struct nfsbuf *bp)
 {
-       int s;
        int oldflags = bp->nb_flags, rv = 0;
-       off_t off;
-       struct vnode *vp = bp->nb_vp;
-       struct ucred *cr;
-       struct proc *p = current_proc();
+       vnode_t vp = bp->nb_vp;
+       struct nfsnode *np = VTONFS(vp);
+       kauth_cred_t cr;
+       proc_t p = current_proc(); // XXX
 
        FSDBG_TOP(553, bp, NBOFF(bp), bp->nb_flags, 0);
 
-       if (!ISSET(bp->nb_flags, NB_BUSY))
+       if (!ISSET(bp->nb_lflags, NBL_BUSY))
                panic("nfs_buf_write: buffer is not busy???");
 
-       s = splbio();
        CLR(bp->nb_flags, (NB_READ|NB_DONE|NB_ERROR|NB_DELWRI));
        if (ISSET(oldflags, NB_DELWRI)) {
-               nfs_nbdwrite--;
-               NFSBUFCNTCHK();
-               wakeup((caddr_t)&nfs_nbdwrite);
+               OSAddAtomic(-1, (SInt32*)&nfs_nbdwrite);
+               NFSBUFCNTCHK(0);
+               wakeup(&nfs_nbdwrite);
        }
 
        /* move to clean list */
        if (ISSET(oldflags, (NB_ASYNC|NB_DELWRI))) {
+               lck_mtx_lock(nfs_buf_mutex);
                if (bp->nb_vnbufs.le_next != NFSNOLIST)
                        LIST_REMOVE(bp, nb_vnbufs);
                LIST_INSERT_HEAD(&VTONFS(vp)->n_cleanblkhd, bp, nb_vnbufs);
+               lck_mtx_unlock(nfs_buf_mutex);
        }
+       vnode_startwrite(vp);
 
-       vp->v_numoutput++;
        if (p && p->p_stats)
                p->p_stats->p_ru.ru_oublock++;
-       splx(s);
 
        /*
         * For async requests when nfsiod(s) are running, queue the request by
         * calling nfs_asyncio(), otherwise just all nfs_doio() to do the request.
         */
        if (ISSET(bp->nb_flags, NB_ASYNC))
-               p = (struct proc *)0;
+               p = NULL;
        if (ISSET(bp->nb_flags, NB_READ))
                cr = bp->nb_rcred;
        else
@@ -3974,14 +4392,34 @@ nfs_buf_write(struct nfsbuf *bp)
                rv = nfs_buf_iowait(bp);
                /* move to clean list */
                if (oldflags & NB_DELWRI) {
-                       s = splbio();
+                       lck_mtx_lock(nfs_buf_mutex);
                        if (bp->nb_vnbufs.le_next != NFSNOLIST)
                                LIST_REMOVE(bp, nb_vnbufs);
                        LIST_INSERT_HEAD(&VTONFS(vp)->n_cleanblkhd, bp, nb_vnbufs);
-                       splx(s);
+                       lck_mtx_unlock(nfs_buf_mutex);
                }
+               oldflags = bp->nb_flags;
                FSDBG_BOT(553, bp, NBOFF(bp), bp->nb_flags, rv);
-               nfs_buf_release(bp);
+               if (cr) {
+                       kauth_cred_ref(cr);
+               }
+               nfs_buf_release(bp, 1);
+               if (ISSET(oldflags, NB_ERROR) && !(np->n_flag & NFLUSHINPROG)) {
+                       /*
+                        * There was a write error and we need to
+                        * invalidate attrs and flush buffers in
+                        * order to sync up with the server.
+                        * (if this write was extending the file,
+                        * we may no longer know the correct size)
+                        *
+                        * But we couldn't call vinvalbuf while holding
+                        * the buffer busy.  So we call vinvalbuf() after
+                        * releasing the buffer.
+                        */
+                       nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, cr, p, 1);
+               }
+               if (cr)
+                       kauth_cred_rele(cr);
                return (rv);
        } 
 
@@ -3989,79 +4427,17 @@ nfs_buf_write(struct nfsbuf *bp)
        return (rv);
 }
 
-/*
- * nfs special file access vnode op.
- * Essentially just get vattr and then imitate iaccess() since the device is
- * local to the client.
- */
-static int
-nfsspec_access(ap)
-       struct vop_access_args /* {
-               struct vnode *a_vp;
-               int  a_mode;
-               struct ucred *a_cred;
-               struct proc *a_p;
-       } */ *ap;
-{
-       register struct vattr *vap;
-       register gid_t *gp;
-       register struct ucred *cred = ap->a_cred;
-       struct vnode *vp = ap->a_vp;
-       mode_t mode = ap->a_mode;
-       struct vattr vattr;
-       register int i;
-       int error;
-
-       /*
-        * Disallow write attempts on filesystems mounted read-only;
-        * unless the file is a socket, fifo, or a block or character
-        * device resident on the filesystem.
-        */
-       if ((mode & VWRITE) && vp->v_mount && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
-               switch (vp->v_type) {
-               case VREG: case VDIR: case VLNK:
-                       return (EROFS);
-               }
-       }
-       /*
-        * If you're the super-user,
-        * you always get access.
-        */
-       if (cred->cr_uid == 0)
-               return (0);
-       vap = &vattr;
-       error = VOP_GETATTR(vp, vap, cred, ap->a_p);
-       if (error)
-               return (error);
-       /*
-        * Access check is based on only one of owner, group, public.
-        * If not owner, then check group. If not a member of the
-        * group, then check public access.
-        */
-       if (cred->cr_uid != vap->va_uid) {
-               mode >>= 3;
-               gp = cred->cr_groups;
-               for (i = 0; i < cred->cr_ngroups; i++, gp++)
-                       if (vap->va_gid == *gp)
-                               goto found;
-               mode >>= 3;
-found:
-               ;
-       }
-       error = (vap->va_mode & mode) == mode ? 0 : EACCES;
-       return (error);
-}
-
 /*
  * Read wrapper for special devices.
  */
 static int
 nfsspec_read(ap)
-       struct vop_read_args /* {
-               struct vnode *a_vp;
+       struct vnop_read_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
                struct uio *a_uio;
-               int  a_ioflag;
-               struct ucred *a_cred;
+               int a_ioflag;
+               vfs_context_t a_context;
        } */ *ap;
 {
        register struct nfsnode *np = VTONFS(ap->a_vp);
@@ -4074,7 +4450,7 @@ nfsspec_read(ap)
        microtime(&now);
        np->n_atim.tv_sec = now.tv_sec;
        np->n_atim.tv_nsec = now.tv_usec * 1000;
-       return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
+       return (VOCALL(spec_vnodeop_p, VOFFSET(vnop_read), ap));
 }
 
 /*
@@ -4082,11 +4458,12 @@ nfsspec_read(ap)
  */
 static int
 nfsspec_write(ap)
-       struct vop_write_args /* {
-               struct vnode *a_vp;
+       struct vnop_write_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
                struct uio *a_uio;
-               int  a_ioflag;
-               struct ucred *a_cred;
+               int a_ioflag;
+               vfs_context_t a_context;
        } */ *ap;
 {
        register struct nfsnode *np = VTONFS(ap->a_vp);
@@ -4099,7 +4476,7 @@ nfsspec_write(ap)
        microtime(&now);
        np->n_mtim.tv_sec = now.tv_sec;
        np->n_mtim.tv_nsec = now.tv_usec * 1000;
-       return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
+       return (VOCALL(spec_vnodeop_p, VOFFSET(vnop_write), ap));
 }
 
 /*
@@ -4109,45 +4486,51 @@ nfsspec_write(ap)
  */
 static int
 nfsspec_close(ap)
-       struct vop_close_args /* {
-               struct vnode *a_vp;
-               int  a_fflag;
-               struct ucred *a_cred;
-               struct proc *a_p;
+       struct vnop_close_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               int a_fflag;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct nfsnode *np = VTONFS(vp);
-       struct vattr vattr;
+       vnode_t vp = ap->a_vp;
+       struct nfsnode *np = VTONFS(vp);
+       struct vnode_attr vattr;
+       mount_t mp;
 
        if (np->n_flag & (NACC | NUPD)) {
                np->n_flag |= NCHG;
-               if (vp->v_usecount == 1 && vp->v_mount &&
-                   (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
-                       VATTR_NULL(&vattr);
-                       if (np->n_flag & NACC)
-                               vattr.va_atime = np->n_atim;
-                       if (np->n_flag & NUPD)
-                               vattr.va_mtime = np->n_mtim;
-                       (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
+               if (!vnode_isinuse(vp, 1) && (mp = vnode_mount(vp)) && !vfs_isrdonly(mp)) {
+                       VATTR_INIT(&vattr);
+                       if (np->n_flag & NACC) {
+                               vattr.va_access_time = np->n_atim;
+                               VATTR_SET_ACTIVE(&vattr, va_access_time);
+                       }
+                       if (np->n_flag & NUPD) {
+                               vattr.va_modify_time = np->n_mtim;
+                               VATTR_SET_ACTIVE(&vattr, va_modify_time);
+                       }
+                       vnode_setattr(vp, &vattr, ap->a_context);
                }
        }
-       return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
+       return (VOCALL(spec_vnodeop_p, VOFFSET(vnop_close), ap));
 }
 
+extern vnop_t **fifo_vnodeop_p;
+
 /*
  * Read wrapper for fifos.
  */
 static int
 nfsfifo_read(ap)
-       struct vop_read_args /* {
-               struct vnode *a_vp;
+       struct vnop_read_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
                struct uio *a_uio;
-               int  a_ioflag;
-               struct ucred *a_cred;
+               int a_ioflag;
+               vfs_context_t a_context;
        } */ *ap;
 {
-        extern vop_t **fifo_vnodeop_p;
        register struct nfsnode *np = VTONFS(ap->a_vp);
        struct timeval now;
 
@@ -4158,7 +4541,7 @@ nfsfifo_read(ap)
        microtime(&now);
        np->n_atim.tv_sec = now.tv_sec;
        np->n_atim.tv_nsec = now.tv_usec * 1000;
-       return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
+       return (VOCALL(fifo_vnodeop_p, VOFFSET(vnop_read), ap));
 }
 
 /*
@@ -4166,14 +4549,14 @@ nfsfifo_read(ap)
  */
 static int
 nfsfifo_write(ap)
-       struct vop_write_args /* {
-               struct vnode *a_vp;
+       struct vnop_write_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
                struct uio *a_uio;
-               int  a_ioflag;
-               struct ucred *a_cred;
+               int a_ioflag;
+               vfs_context_t a_context;
        } */ *ap;
 {
-        extern vop_t **fifo_vnodeop_p;
        register struct nfsnode *np = VTONFS(ap->a_vp);
        struct timeval now;
 
@@ -4184,7 +4567,7 @@ nfsfifo_write(ap)
        microtime(&now);
        np->n_mtim.tv_sec = now.tv_sec;
        np->n_mtim.tv_nsec = now.tv_usec * 1000;
-       return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
+       return (VOCALL(fifo_vnodeop_p, VOFFSET(vnop_write), ap));
 }
 
 /*
@@ -4194,18 +4577,18 @@ nfsfifo_write(ap)
  */
 static int
 nfsfifo_close(ap)
-       struct vop_close_args /* {
-               struct vnode *a_vp;
-               int  a_fflag;
-               struct ucred *a_cred;
-               struct proc *a_p;
+       struct vnop_close_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               int a_fflag;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       register struct nfsnode *np = VTONFS(vp);
-       struct vattr vattr;
+       vnode_t vp = ap->a_vp;
+       struct nfsnode *np = VTONFS(vp);
+       struct vnode_attr vattr;
        struct timeval now;
-        extern vop_t **fifo_vnodeop_p;
+       mount_t mp;
 
        if (np->n_flag & (NACC | NUPD)) {
                microtime(&now);
@@ -4218,22 +4601,34 @@ nfsfifo_close(ap)
                        np->n_mtim.tv_nsec = now.tv_usec * 1000;
                }
                np->n_flag |= NCHG;
-               if (vp->v_usecount == 1 && vp->v_mount &&
-                   (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
-                       VATTR_NULL(&vattr);
-                       if (np->n_flag & NACC)
-                               vattr.va_atime = np->n_atim;
-                       if (np->n_flag & NUPD)
-                               vattr.va_mtime = np->n_mtim;
-                       (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
+               if (!vnode_isinuse(vp, 1) && (mp = vnode_mount(vp)) && !vfs_isrdonly(mp)) {
+                       VATTR_INIT(&vattr);
+                       if (np->n_flag & NACC) {
+                               vattr.va_access_time = np->n_atim;
+                               VATTR_SET_ACTIVE(&vattr, va_access_time);
+                       }
+                       if (np->n_flag & NUPD) {
+                               vattr.va_modify_time = np->n_mtim;
+                               VATTR_SET_ACTIVE(&vattr, va_modify_time);
+                       }
+                       vnode_setattr(vp, &vattr, ap->a_context);
                }
        }
-       return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
+       return (VOCALL(fifo_vnodeop_p, VOFFSET(vnop_close), ap));
 }
 
+/*ARGSUSED*/
 static int
-nfs_ioctl(ap)
-       struct vop_ioctl_args *ap;
+nfs_ioctl(
+       __unused struct vnop_ioctl_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               u_long a_command;
+               caddr_t a_data;
+               int a_fflag;
+               kauth_cred_t a_cred;
+               proc_t a_p;
+       } */ *ap)
 {
 
        /*
@@ -4243,9 +4638,18 @@ nfs_ioctl(ap)
        return (ENOTTY);
 }
 
+/*ARGSUSED*/
 static int
-nfs_select(ap)
-       struct vop_select_args *ap;
+nfs_select(
+       __unused struct vnop_select_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               int a_which;
+               int a_fflags;
+               kauth_cred_t a_cred;
+               void *a_wql;
+               proc_t a_p;
+       } */ *ap)
 {
 
        /*
@@ -4261,32 +4665,32 @@ nfs_select(ap)
  */
 static int
 nfs_pagein(ap)
-       struct vop_pagein_args /* {
-               struct vnode *a_vp,
-               upl_t   a_pl,
-               vm_offset_t   a_pl_offset,
-               off_t         a_f_offset,
-               size_t        a_size,
-               struct ucred *a_cred,
-               int           a_flags
+       struct vnop_pagein_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               upl_t a_pl;
+               vm_offset_t a_pl_offset;
+               off_t a_f_offset;
+               size_t a_size;
+               int a_flags;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
+       vnode_t vp = ap->a_vp;
        upl_t pl = ap->a_pl;
        size_t size= ap->a_size;
        off_t f_offset = ap->a_f_offset;
        vm_offset_t pl_offset = ap->a_pl_offset;
        int flags  = ap->a_flags;
-       struct ucred *cred;
+       kauth_cred_t cred;
+       proc_t p;
        struct nfsnode *np = VTONFS(vp);
        int biosize, xsize, iosize;
-       struct vattr vattr;
-       struct proc *p = current_proc();
        struct nfsmount *nmp;
        int error = 0;
        vm_offset_t ioaddr;
        struct uio      auio;
-       struct iovec    aiov;
+       struct iovec_32 aiov;
        struct uio * uio = &auio;
        int nofreeupl = flags & UPL_NOCOMMIT;
        upl_page_info_t *plinfo;
@@ -4298,7 +4702,7 @@ nfs_pagein(ap)
        if (UBCINVALID(vp)) {
                printf("nfs_pagein: invalid vnode 0x%x", (int)vp);
                if (!nofreeupl)
-                       (void) ubc_upl_abort(pl, NULL); 
+                       (void) ubc_upl_abort(pl, 0); 
                return (EPERM);
        }
        UBCINFOCHECK("nfs_pagein", vp);
@@ -4306,25 +4710,31 @@ nfs_pagein(ap)
        if (size <= 0) {
                printf("nfs_pagein: invalid size %d", size);
                if (!nofreeupl)
-                       (void) ubc_upl_abort(pl, NULL); 
+                       (void) ubc_upl_abort(pl, 0); 
                return (EINVAL);
        }
-       if (f_offset < 0 || f_offset >= np->n_size || (f_offset & PAGE_MASK_64)) {
+       if (f_offset < 0 || f_offset >= (off_t)np->n_size || (f_offset & PAGE_MASK_64)) {
                if (!nofreeupl)
                        ubc_upl_abort_range(pl, pl_offset, size, 
                                UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
                return (EINVAL);
        }
+
        cred = ubc_getcred(vp);
        if (cred == NOCRED)
-               cred = ap->a_cred;
+               cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
 
        auio.uio_offset = f_offset;
+#if 1   /* LP64todo - can't use new segment flags until the drivers are ready */
        auio.uio_segflg = UIO_SYSSPACE;
+#else
+       auio.uio_segflg = UIO_SYSSPACE32;
+#endif 
        auio.uio_rw = UIO_READ;
-       auio.uio_procp = NULL;
+       auio.uio_procp = p;
 
-       nmp = VFSTONFS(vp->v_mount);
+       nmp = VFSTONFS(vnode_mount(vp));
        if (!nmp) {
                if (!nofreeupl)
                        ubc_upl_abort_range(pl, pl_offset, size, 
@@ -4333,7 +4743,7 @@ nfs_pagein(ap)
        }
        if ((nmp->nm_flag & NFSMNT_NFSV3) && !(nmp->nm_state & NFSSTA_GOTFSINFO))
                (void)nfs_fsinfo(nmp, vp, cred, p);
-       biosize = vp->v_mount->mnt_stat.f_iosize;
+       biosize = vfs_statfs(vnode_mount(vp))->f_iosize;
 
        plinfo = ubc_upl_pageinfo(pl);
        ubc_upl_map(pl, &ioaddr);
@@ -4347,35 +4757,35 @@ nfs_pagein(ap)
                 * before sending the next one.
                 * XXX Should we align these requests to block boundaries?
                 */
-               iosize = min(biosize, xsize);
-               uio->uio_resid = iosize;
+               iosize = min(biosize, xsize);
                aiov.iov_len  = iosize;
-               aiov.iov_base = (caddr_t)ioaddr;
-               auio.uio_iov = &aiov;
+               aiov.iov_base = (uintptr_t)ioaddr;
+               auio.uio_iovs.iov32p = &aiov;
                auio.uio_iovcnt = 1;
+               uio_uio_resid_set(&auio, iosize);
 
-               FSDBG(322, uio->uio_offset, uio->uio_resid, ioaddr, xsize);
-// XXX #warning our nfs_pagein does not support NQNFS
+               FSDBG(322, uio->uio_offset, uio_uio_resid(uio), ioaddr, xsize);
                /*
                 * With UBC we get here only when the file data is not in the VM
                 * page cache, so go ahead and read in.
                 */
-#ifdef UBC_DEBUG
-               upl_ubc_alias_set(pl, current_act(), 2);
-#endif /* UBC_DEBUG */
-               nfsstats.pageins++;
+#ifdef UPL_DEBUG
+               upl_ubc_alias_set(pl, current_thread(), 2);
+#endif /* UPL_DEBUG */
+               OSAddAtomic(1, (SInt32*)&nfsstats.pageins);
 
-               error = nfs_readrpc(vp, uio, cred);
+               error = nfs_readrpc(vp, uio, cred, p);
 
                if (!error) {
-                       if (uio->uio_resid) {
+                       if (uio_uio_resid(uio)) {
                                /*
                                 * If uio_resid > 0, there is a hole in the file
                                 * and no writes after the hole have been pushed
                                 * to the server yet... or we're at the EOF
                                 * Just zero fill the rest of the valid area.
                                 */
-                               int zcnt = uio->uio_resid;
+                               // LP64todo - fix this
+                               int zcnt = uio_uio_resid(uio);
                                int zoff = iosize - zcnt;
                                bzero((char *)ioaddr + zoff, zcnt);
 
@@ -4384,21 +4794,11 @@ nfs_pagein(ap)
                        }
                        ioaddr += iosize;       
                        xsize  -= iosize;
-               } else
-                       FSDBG(322, uio->uio_offset, uio->uio_resid, error, -1);
-
-               nmp = VFSTONFS(vp->v_mount);
-               if (p && (vp->v_flag & VTEXT) && nmp &&
-                   ((nmp->nm_flag & NFSMNT_NQNFS &&
-                     NQNFS_CKINVALID(vp, np, ND_READ) &&
-                     np->n_lrev != np->n_brev) ||
-                    (!(nmp->nm_flag & NFSMNT_NQNFS) &&
-                     np->n_mtime != np->n_vattr.va_mtime.tv_sec))) {
-                       uprintf("Process killed due to text file modification\n");
-                       psignal(p, SIGKILL);
-                       p->p_flag |= P_NOSWAP;
+               } else {
+                       FSDBG(322, uio->uio_offset, uio_uio_resid(uio), error, -1);
                }
 
+               nmp = VFSTONFS(vnode_mount(vp));
        } while (error == 0 && xsize > 0);
 
        ubc_upl_unmap(pl);
@@ -4424,36 +4824,36 @@ nfs_pagein(ap)
  */
 static int
 nfs_pageout(ap)
-       struct vop_pageout_args /* {
-               struct vnode *a_vp,
-               upl_t   a_pl,
-               vm_offset_t   a_pl_offset,
-               off_t         a_f_offset,
-               size_t        a_size,
-               struct ucred *a_cred,
-               int           a_flags
+       struct vnop_pageout_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               upl_t a_pl;
+               vm_offset_t a_pl_offset;
+               off_t a_f_offset;
+               size_t a_size;
+               int a_flags;
+               vfs_context_t a_context;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
+       vnode_t vp = ap->a_vp;
        upl_t pl = ap->a_pl;
        size_t size= ap->a_size;
        off_t f_offset = ap->a_f_offset;
        vm_offset_t pl_offset = ap->a_pl_offset;
        int flags  = ap->a_flags;
-       int ioflag = ap->a_flags;
-       struct proc *p = current_proc();
        struct nfsnode *np = VTONFS(vp);
-       register struct ucred *cred;
+       kauth_cred_t cred;
+       proc_t p;
        struct nfsbuf *bp;
-       struct nfsmount *nmp = VFSTONFS(vp->v_mount);
-       daddr_t lbn;
-       int n = 0, on, error = 0, iomode, must_commit, s;
+       struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
+       daddr64_t lbn;
+       int error = 0, iomode, must_commit;
        off_t off;
        vm_offset_t ioaddr;
        struct uio      auio;
-       struct iovec    aiov;
+       struct iovec_32 aiov;
        int nofreeupl = flags & UPL_NOCOMMIT;
-       int biosize, iosize, pgsize, xsize;
+       size_t biosize, iosize, pgsize, xsize;
 
        FSDBG(323, f_offset, size, pl, pl_offset);
 
@@ -4480,7 +4880,7 @@ nfs_pageout(ap)
                        ubc_upl_abort(pl, UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY);
                return (ENXIO);
        }
-       biosize = vp->v_mount->mnt_stat.f_iosize;
+       biosize = vfs_statfs(vnode_mount(vp))->f_iosize;
 
        /*
         * Check to see whether the buffer is incore.
@@ -4493,10 +4893,11 @@ nfs_pageout(ap)
                if (off + xsize > f_offset + size)
                        xsize = f_offset + size - off;
                lbn = ubc_offtoblk(vp, off);
-               s = splbio();
-               if (bp = nfs_buf_incore(vp, lbn)) {
-                       FSDBG(323, off, 1, bp, bp->nb_flags);
-                       if (ISSET(bp->nb_flags, NB_BUSY)) {
+               lck_mtx_lock(nfs_buf_mutex);
+               if ((bp = nfs_buf_incore(vp, lbn))) {
+                       FSDBG(323, off, bp, bp->nb_lflags, bp->nb_flags);
+                       if (nfs_buf_acquire(bp, NBAC_NOWAIT, 0, 0)) {
+                               lck_mtx_unlock(nfs_buf_mutex);
                                /* no panic. just tell vm we are busy */
                                if (!nofreeupl)
                                        ubc_upl_abort(pl, 0); 
@@ -4504,8 +4905,8 @@ nfs_pageout(ap)
                        }
                        if (bp->nb_dirtyend > 0) {
                                /*
-                                * if there's a dirty range in the buffer, check to
-                                * see if it extends beyond the pageout region
+                                * if there's a dirty range in the buffer, check
+                                * to see if it extends beyond the pageout region
                                 *
                                 * if the dirty region lies completely within the
                                 * pageout region, we just invalidate the buffer
@@ -4523,7 +4924,7 @@ nfs_pageout(ap)
                                start = off;
                                end = off + xsize;
                                /* clip end to EOF */
-                               if (end > np->n_size)
+                               if (end > (off_t)np->n_size)
                                        end = np->n_size;
                                start -= boff;
                                end -= boff;
@@ -4531,6 +4932,8 @@ nfs_pageout(ap)
                                    (bp->nb_dirtyend > end)) {
                                    /* not gonna be able to clip the dirty region */
                                    FSDBG(323, vp, bp, 0xd00deebc, EBUSY);
+                                   nfs_buf_drop(bp);
+                                   lck_mtx_unlock(nfs_buf_mutex);
                                    if (!nofreeupl)
                                        ubc_upl_abort(pl, 0); 
                                    return (EBUSY);
@@ -4544,24 +4947,29 @@ nfs_pageout(ap)
                                        bp->nb_dirtyoff = max(bp->nb_dirtyoff, end);
                                    FSDBG(323, bp, bp->nb_dirtyoff, bp->nb_dirtyend, 0xd00dee00);
                                    /* we're leaving this block dirty */
+                                   nfs_buf_drop(bp);
+                                   lck_mtx_unlock(nfs_buf_mutex);
                                    continue;
                                }
                        }
                        nfs_buf_remfree(bp);
-                       SET(bp->nb_flags, (NB_BUSY | NB_INVAL));
+                       lck_mtx_unlock(nfs_buf_mutex);
+                       SET(bp->nb_flags, NB_INVAL);
                        if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
                                CLR(bp->nb_flags, NB_NEEDCOMMIT);
                                np->n_needcommitcnt--;
                                CHECK_NEEDCOMMITCNT(np);
                        }
-                       nfs_buf_release(bp);
+                       nfs_buf_release(bp, 1);
+               } else {
+                       lck_mtx_unlock(nfs_buf_mutex);
                }
-               splx(s);
        }
 
        cred = ubc_getcred(vp);
        if (cred == NOCRED)
-               cred = ap->a_cred;
+               cred = vfs_context_ucred(ap->a_context);
+       p = vfs_context_proc(ap->a_context);
 
        if (np->n_flag & NWRITEERR) {
                np->n_flag &= ~NWRITEERR;
@@ -4570,11 +4978,10 @@ nfs_pageout(ap)
                                            UPL_ABORT_FREE_ON_EMPTY);
                return (np->n_error);
        }
-       if ((nmp->nm_flag & NFSMNT_NFSV3) &&
-               !(nmp->nm_state & NFSSTA_GOTFSINFO))
-               (void)nfs_fsinfo(nmp, vp, cred, p);
+       if ((nmp->nm_flag & NFSMNT_NFSV3) && !(nmp->nm_state & NFSSTA_GOTFSINFO))
+               nfs_fsinfo(nmp, vp, cred, p);
 
-       if (f_offset < 0 || f_offset >= np->n_size ||
+       if (f_offset < 0 || f_offset >= (off_t)np->n_size ||
            f_offset & PAGE_MASK_64 || size & PAGE_MASK_64) {
                if (!nofreeupl)
                        ubc_upl_abort_range(pl, pl_offset, size,
@@ -4585,7 +4992,7 @@ nfs_pageout(ap)
        ubc_upl_map(pl, &ioaddr);
        ioaddr += pl_offset;
 
-       if (f_offset + size > np->n_size)
+       if ((u_quad_t)f_offset + size > np->n_size)
                xsize = np->n_size - f_offset;
        else
                xsize = size;
@@ -4603,16 +5010,20 @@ nfs_pageout(ap)
         * contents past end of the file before
         * releasing it in the VM page cache
         */
-       if (f_offset < np->n_size && f_offset + size > np->n_size) {
+       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);
                FSDBG(321, np->n_size, f_offset, f_offset + io, size - io);
        }
 
        auio.uio_offset = f_offset;
+#if 1   /* LP64todo - can't use new segment flags until the drivers are ready */
        auio.uio_segflg = UIO_SYSSPACE;
+#else
+       auio.uio_segflg = UIO_SYSSPACE32;
+#endif 
        auio.uio_rw = UIO_READ;
-       auio.uio_procp = NULL;
+       auio.uio_procp = p;
 
        do {
                /*
@@ -4622,23 +5033,23 @@ nfs_pageout(ap)
                 * XXX Should we align these requests to block boundaries?
                 */
                iosize = min(biosize, xsize);
-               auio.uio_resid = iosize;
+               uio_uio_resid_set(&auio, iosize);
                aiov.iov_len = iosize;
-               aiov.iov_base = (caddr_t)ioaddr;
-               auio.uio_iov = &aiov;
+               aiov.iov_base = (uintptr_t)ioaddr;
+               auio.uio_iovs.iov32p = &aiov;
                auio.uio_iovcnt = 1;
 
-               FSDBG(323, auio.uio_offset, auio.uio_resid, ioaddr, xsize);
-// XXX #warning our nfs_pageout does not support NQNFS
-               nfsstats.pageouts++;
+               FSDBG(323, auio.uio_offset, uio_uio_resid(&auio), ioaddr, xsize);
+               OSAddAtomic(1, (SInt32*)&nfsstats.pageouts);
+
+               vnode_startwrite(vp);
 
-               vp->v_numoutput++;
                /* NMODIFIED would be set here if doing unstable writes */
                iomode = NFSV3WRITE_FILESYNC;
-               error = nfs_writerpc(vp, &auio, cred, &iomode, &must_commit);
+               error = nfs_writerpc(vp, &auio, cred, p, &iomode, &must_commit);
                if (must_commit)
-                       nfs_clearcommit(vp->v_mount);
-               vpwakeup(vp);
+                       nfs_clearcommit(vnode_mount(vp));
+               vnode_writedone(vp);
                if (error)
                        goto cleanup;
                /* Note: no need to check uio_resid, because */
@@ -4675,7 +5086,7 @@ cleanup:
          
        if (!nofreeupl) { /* otherwise stacked file system has to handle this */
                if (error) {
-                       int abortflags; 
+                       int abortflags = 0
                        short action = nfs_pageouterrorhandler(error);
                        
                        switch (action) {
@@ -4695,8 +5106,7 @@ cleanup:
                                case RETRYWITHSLEEP:
                                        abortflags = UPL_ABORT_FREE_ON_EMPTY;
                                        /* pri unused. PSOCK for placeholder. */
-                                       (void) tsleep(&lbolt, PSOCK,
-                                                     "nfspageout", 0);
+                                       tsleep(&lbolt, PSOCK, "nfspageout", 0);
                                        break;
                                case SEVER: /* not implemented */
                                default:
@@ -4718,55 +5128,47 @@ cleanup:
 /* Blktooff derives file offset given a logical block number */
 static int
 nfs_blktooff(ap)
-       struct vop_blktooff_args /* {
-               struct vnode *a_vp;
-               daddr_t a_lblkno;
-               off_t *a_offset;    
+       struct vnop_blktooff_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               daddr64_t a_lblkno;
+               off_t *a_offset;
        } */ *ap;
 {
        int biosize;
-       register struct vnode *vp = ap->a_vp;
+       vnode_t vp = ap->a_vp;
+       mount_t mp = vnode_mount(vp);
 
-       if (!vp->v_mount)
+       if (!mp)
                return (ENXIO);
 
-       biosize = vp->v_mount->mnt_stat.f_iosize;
+       biosize = vfs_statfs(mp)->f_iosize;
 
-       *ap->a_offset = (off_t)ap->a_lblkno * biosize;
+       *ap->a_offset = (off_t)(ap->a_lblkno * biosize);
 
        return (0);
 }
 
 static int
 nfs_offtoblk(ap)
-       struct vop_offtoblk_args /* {
-               struct vnode *a_vp;
-               off_t a_offset;    
-               daddr_t *a_lblkno;
+       struct vnop_offtoblk_args /* {
+               struct vnodeop_desc *a_desc;
+               vnode_t a_vp;
+               off_t a_offset;
+               daddr64_t *a_lblkno;
        } */ *ap;
 {
        int biosize;
-       register struct vnode *vp = ap->a_vp;
+       vnode_t vp = ap->a_vp;
+       mount_t mp = vnode_mount(vp);
 
-       if (!vp->v_mount)
+       if (!mp)
                return (ENXIO);
 
-       biosize = vp->v_mount->mnt_stat.f_iosize;
+       biosize = vfs_statfs(mp)->f_iosize;
 
-       *ap->a_lblkno = (daddr_t)(ap->a_offset / biosize);
+       *ap->a_lblkno = (daddr64_t)(ap->a_offset / biosize);
 
        return (0);
 }
-static int
-nfs_cmap(ap)
-       struct vop_cmap_args /* {
-               struct vnode *a_vp;
-               off_t a_offset;    
-               size_t a_size;
-               daddr_t *a_bpn;
-               size_t *a_run;
-               void *a_poff;
-       } */ *ap;
-{
-       return (EOPNOTSUPP);
-}
+