]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/miscfs/volfs/volfs_vnops.c
xnu-792.17.14.tar.gz
[apple/xnu.git] / bsd / miscfs / volfs / volfs_vnops.c
index 0f5c6ecb8918bec261a0bc30faa1e430503851a1..2a8f29ebdef77bf3eeebc020ba26dbd335d0002b 100644 (file)
@@ -1,39 +1,29 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * 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. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved.
- *
- *     Modification History:
- *
- *       2/10/2000     Clark Warner    Added copyfile  
- *       5/24/1999     Don Brady       Fixed security hole in get_fsvnode.
- *      11/18/1998 Don Brady           Special case 2 to mean the root of a file system.
- *       9/28/1998     Umesh Vaishampayan      Use the default vnode ops. Cleanup 
- *                                                                     header includes.
- *     11/12/1998      Scott Roberts   validfsnode only checks to see if the volfs mount flag is set
- *       8/5/1998      Don Brady       fix validfsnode logic to handle a "bad" VFS_GET
- *       7/5/1998      Don Brady       In volfs_reclaim set vp->v_data to NULL after private data is free (VFS expects a NULL).
- *       4/5/1998      Don Brady       Changed lockstatus calls to VOP_ISLOCKED (radar #2231108);
- *      3/25/1998      Pat Dirks       Added include for sys/attr.h, which is no longer included indirectly.
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 
 #include <mach/mach_types.h>
 #include <sys/resourcevar.h>
 #include <sys/kernel.h>
 #include <sys/file.h>
+#include <sys/filedesc.h>
 #include <sys/stat.h>
-#include <sys/buf.h>
-#include <sys/proc.h>
+#include <sys/proc_internal.h> /* for p_fd */
+#include <sys/kauth.h>
 #include <sys/conf.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
+#include <sys/mount_internal.h>
+#include <sys/vnode_internal.h>
 #include <sys/malloc.h>
 #include <sys/dirent.h>
 #include <sys/namei.h>
 #include <sys/attr.h>
+#include <sys/kdebug.h>
+#include <sys/queue.h>
+#include <sys/uio_internal.h>
 
 #include <sys/vm.h>
 #include <sys/errno.h>
 #include <vfs/vfs_support.h>
 
+#include <kern/locks.h>
+
 #include "volfs.h"
 
 /*
  * a similar mechanism.
  */
 
+static int  volfs_reclaim  (struct vnop_reclaim_args*);
+static int  volfs_getattr  (struct vnop_getattr_args *);
+static int  volfs_select   (struct vnop_select_args *);
+static int  volfs_rmdir    (struct vnop_rmdir_args *);
+static int  volfs_readdir  (struct vnop_readdir_args *);
+static int  volfs_pathconf (struct vnop_pathconf_args *);
+static int  volfs_lookup   (struct vnop_lookup_args *);
+
+static int volfs_readdir_callback(mount_t, void *);
+static int get_filevnode(struct mount *parent_fs, u_int id, vnode_t *ret_vnode, vfs_context_t context);
+static int get_fsvnode(struct mount *our_mount, int id, vnode_t *ret_vnode);
+
+/* for the call back function in volfs_readdir */
+struct volfs_rdstruct {
+       int             validindex;
+       vnode_t         vp;
+       int             rec_offset;
+       struct uio * uio;
+};
+
 #define VOPFUNC int (*)(void *)
 
 /* Global vfs data structures for volfs. */
 int                 (**volfs_vnodeop_p) (void *);
 struct vnodeopv_entry_desc volfs_vnodeop_entries[] = {
-    {&vop_default_desc, (VOPFUNC)vn_default_error},
-    {&vop_strategy_desc, (VOPFUNC)err_strategy},       /* strategy */
-    {&vop_bwrite_desc, (VOPFUNC)err_bwrite},           /* bwrite */
-    {&vop_lookup_desc, (VOPFUNC)volfs_lookup},         /* lookup */
-    {&vop_create_desc, (VOPFUNC)err_create},           /* create */
-    {&vop_whiteout_desc, (VOPFUNC)err_whiteout},       /* whiteout */
-    {&vop_mknod_desc, (VOPFUNC)err_mknod},             /* mknod */
-    {&vop_mkcomplex_desc, (VOPFUNC)err_mkcomplex},     /* mkcomplex */
-    {&vop_open_desc, (VOPFUNC)nop_open},               /* open */
-    {&vop_close_desc, (VOPFUNC)nop_close},             /* close */
-    {&vop_access_desc, (VOPFUNC)volfs_access},         /* access */
-    {&vop_getattr_desc, (VOPFUNC)volfs_getattr},       /* getattr */
-    {&vop_setattr_desc, (VOPFUNC)err_setattr},         /* setattr */
-    {&vop_getattrlist_desc, (VOPFUNC)err_getattrlist}, /* getattrlist */
-    {&vop_setattrlist_desc, (VOPFUNC)err_setattrlist}, /* setattrlist */
-    {&vop_read_desc, (VOPFUNC)err_read},               /* read */
-    {&vop_write_desc, (VOPFUNC)err_write},             /* write */
-    {&vop_lease_desc, (VOPFUNC)err_lease},             /* lease */
-    {&vop_ioctl_desc, (VOPFUNC)err_ioctl},             /* ioctl */
-    {&vop_select_desc, (VOPFUNC)volfs_select},         /* select */
-    {&vop_exchange_desc, (VOPFUNC)err_exchange},       /* exchange */
-    {&vop_revoke_desc, (VOPFUNC)nop_revoke},           /* revoke */
-    {&vop_mmap_desc, (VOPFUNC)err_mmap},               /* mmap */
-    {&vop_fsync_desc, (VOPFUNC)err_fsync},             /* fsync */
-    {&vop_seek_desc, (VOPFUNC)nop_seek},               /* seek */
-    {&vop_remove_desc, (VOPFUNC)err_remove},           /* remove */
-    {&vop_link_desc, (VOPFUNC)err_link},               /* link */
-    {&vop_rename_desc, (VOPFUNC)err_rename},           /* rename */
-    {&vop_mkdir_desc, (VOPFUNC)err_mkdir},             /* mkdir */
-    {&vop_rmdir_desc, (VOPFUNC)volfs_rmdir},           /* rmdir */
-    {&vop_symlink_desc, (VOPFUNC)err_symlink},         /* symlink */
-    {&vop_readdir_desc, (VOPFUNC)volfs_readdir},       /* readdir */
-    {&vop_readdirattr_desc, (VOPFUNC)err_readdirattr}, /* readdirattr */
-    {&vop_readlink_desc, (VOPFUNC)err_readlink},       /* readlink */
-    {&vop_abortop_desc, (VOPFUNC)err_abortop},         /* abortop */
-    {&vop_inactive_desc, (VOPFUNC)err_inactive},       /* inactive */
-    {&vop_reclaim_desc, (VOPFUNC)volfs_reclaim},       /* reclaim */
-    {&vop_lock_desc, (VOPFUNC)volfs_lock},             /* lock */
-    {&vop_unlock_desc, (VOPFUNC)volfs_unlock},         /* unlock */
-    {&vop_bmap_desc, (VOPFUNC)err_bmap},               /* bmap */
-    {&vop_print_desc, (VOPFUNC)err_print},             /* print */
-    {&vop_islocked_desc, (VOPFUNC)volfs_islocked},     /* islocked */
-    {&vop_pathconf_desc, (VOPFUNC)volfs_pathconf},     /* pathconf */
-    {&vop_advlock_desc, (VOPFUNC)err_advlock},         /* advlock */
-    {&vop_blkatoff_desc, (VOPFUNC)err_blkatoff},       /* blkatoff */
-    {&vop_valloc_desc, (VOPFUNC)err_valloc},           /* valloc */
-    {&vop_reallocblks_desc, (VOPFUNC)err_reallocblks}, /* reallocblks */
-    {&vop_vfree_desc, (VOPFUNC)err_vfree},             /* vfree */
-    {&vop_truncate_desc, (VOPFUNC)err_truncate},       /* truncate */
-    {&vop_allocate_desc, (VOPFUNC)err_allocate},       /* allocate */
-    {&vop_update_desc, (VOPFUNC)err_update},           /* update */
-       {&vop_pgrd_desc, (VOPFUNC)err_pgrd},            /* pgrd */
-       {&vop_pgwr_desc, (VOPFUNC)err_pgwr},            /* pgwr */
-       {&vop_pagein_desc, (VOPFUNC)err_pagein},        /* pagein */
-       {&vop_pageout_desc, (VOPFUNC)err_pageout},      /* pageout */
-       {&vop_devblocksize_desc, (VOPFUNC)err_devblocksize},    /* devblocksize */
-       {&vop_searchfs_desc, (VOPFUNC)err_searchfs},    /* searchfs */
-        {&vop_copyfile_desc, (VOPFUNC)err_copyfile },  /* Copyfile */
-       {&vop_blktooff_desc, (VOPFUNC)err_blktooff},    /* blktooff */
-       {&vop_offtoblk_desc, (VOPFUNC)err_offtoblk },   /* offtoblk */
-       {&vop_cmap_desc, (VOPFUNC)err_cmap },           /* cmap */
+    {&vnop_default_desc, (VOPFUNC)vn_default_error},
+    {&vnop_strategy_desc, (VOPFUNC)err_strategy},      /* strategy */
+    {&vnop_bwrite_desc, (VOPFUNC)err_bwrite},          /* bwrite */
+    {&vnop_lookup_desc, (VOPFUNC)volfs_lookup},                /* lookup */
+    {&vnop_create_desc, (VOPFUNC)err_create},          /* create */
+    {&vnop_whiteout_desc, (VOPFUNC)err_whiteout},      /* whiteout */
+    {&vnop_mknod_desc, (VOPFUNC)err_mknod},            /* mknod */
+    {&vnop_open_desc, (VOPFUNC)nop_open},              /* open */
+    {&vnop_close_desc, (VOPFUNC)nop_close},            /* close */
+    {&vnop_getattr_desc, (VOPFUNC)volfs_getattr},      /* getattr */
+    {&vnop_setattr_desc, (VOPFUNC)err_setattr},                /* setattr */
+    {&vnop_getattrlist_desc, (VOPFUNC)err_getattrlist},        /* getattrlist */
+    {&vnop_setattrlist_desc, (VOPFUNC)err_setattrlist},        /* setattrlist */
+    {&vnop_read_desc, (VOPFUNC)err_read},              /* read */
+    {&vnop_write_desc, (VOPFUNC)err_write},            /* write */
+    {&vnop_ioctl_desc, (VOPFUNC)err_ioctl},            /* ioctl */
+    {&vnop_select_desc, (VOPFUNC)volfs_select},                /* select */
+    {&vnop_exchange_desc, (VOPFUNC)err_exchange},      /* exchange */
+    {&vnop_revoke_desc, (VOPFUNC)nop_revoke},          /* revoke */
+    {&vnop_mmap_desc, (VOPFUNC)err_mmap},              /* mmap */
+    {&vnop_fsync_desc, (VOPFUNC)err_fsync},            /* fsync */
+    {&vnop_remove_desc, (VOPFUNC)err_remove},          /* remove */
+    {&vnop_link_desc, (VOPFUNC)err_link},              /* link */
+    {&vnop_rename_desc, (VOPFUNC)err_rename},          /* rename */
+    {&vnop_mkdir_desc, (VOPFUNC)err_mkdir},            /* mkdir */
+    {&vnop_rmdir_desc, (VOPFUNC)volfs_rmdir},          /* rmdir */
+    {&vnop_symlink_desc, (VOPFUNC)err_symlink},                /* symlink */
+    {&vnop_readdir_desc, (VOPFUNC)volfs_readdir},      /* readdir */
+    {&vnop_readdirattr_desc, (VOPFUNC)err_readdirattr},        /* readdirattr */
+    {&vnop_readlink_desc, (VOPFUNC)err_readlink},      /* readlink */
+    {&vnop_inactive_desc, (VOPFUNC)err_inactive},      /* inactive */
+    {&vnop_reclaim_desc, (VOPFUNC)volfs_reclaim},      /* reclaim */
+    {&vnop_pathconf_desc, (VOPFUNC)volfs_pathconf},    /* pathconf */
+    {&vnop_advlock_desc, (VOPFUNC)err_advlock},                /* advlock */
+    {&vnop_allocate_desc, (VOPFUNC)err_allocate},      /* allocate */
+       {&vnop_pagein_desc, (VOPFUNC)err_pagein},       /* pagein */
+       {&vnop_pageout_desc, (VOPFUNC)err_pageout},     /* pageout */
+       {&vnop_devblocksize_desc, (VOPFUNC)err_devblocksize},   /* devblocksize */
+       {&vnop_searchfs_desc, (VOPFUNC)err_searchfs},   /* searchfs */
+       {&vnop_copyfile_desc, (VOPFUNC)err_copyfile },  /* Copyfile */
+       {&vnop_blktooff_desc, (VOPFUNC)err_blktooff},   /* blktooff */
+       {&vnop_offtoblk_desc, (VOPFUNC)err_offtoblk },  /* offtoblk */
+       {&vnop_blockmap_desc, (VOPFUNC)err_blockmap },          /* blockmap */
    {(struct vnodeop_desc *) NULL, (int (*) ()) NULL}
 };
 
@@ -165,183 +163,130 @@ struct vnodeopv_entry_desc volfs_vnodeop_entries[] = {
 struct vnodeopv_desc volfs_vnodeop_opv_desc =
 {&volfs_vnodeop_p, volfs_vnodeop_entries};
 
+static char gDotDot[] = "..";
 
-static int validfsnode(struct mount *fsnode);
+struct finfo {
+    fsobj_id_t parID;
+};
 
-#if DBG_VOP_TEST_LOCKS
-static void DbgVopTest (int max, int error, VopDbgStoreRec *VopDbgStore, char *funcname);
-#endif /* DBG_VOP_TEST_LOCKS */
+struct finfoattrbuf {
+    unsigned long length;
+    struct finfo fi;
+};
+
+
+static int volfs_getattr_callback(mount_t, void *);
 
 
 /*
  * volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
- *
- * Locking policy: ignored
  */
-int
+static int
 volfs_reclaim(ap)
-    struct vop_reclaim_args /* { struct vnode *a_vp; struct proc *a_p; } */ *ap;
+    struct vnop_reclaim_args /* { struct vnode *a_vp; vfs_context_t a_context; } */ *ap;
 {
-    struct vnode *vp = ap->a_vp;
-    void *data = vp->v_data;
-
-    DBG_FUNC_NAME("volfs_reclaim");
-    DBG_VOP_LOCKS_DECL(1);
-    DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
-    DBG_VOP_LOCKS_INIT(0, vp, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
+       struct vnode *vp = ap->a_vp;
+       void *data = vp->v_data;
 
        vp->v_data = NULL;
-    FREE(data, M_VOLFSNODE);
+       FREE(data, M_VOLFSNODE);
 
-    DBG_VOP_LOCKS_TEST(0);
-    return (0);
+       return (0);
 }
 
-/*
- * volfs_access - same access policy for all vnodes and all users (file/directory vnodes
- *             for the actual file systems are handled by actual file system)
- *
- * Locking policy: a_vp locked on input and output
- */
-int
-volfs_access(ap)
-    struct vop_access_args     /* { struct vnode *a_vp; int  a_mode; struct
-        ucred *a_cred; struct proc *a_p; } */ *ap;
-{
-    int        ret_err;
-    DBG_FUNC_NAME("volfs_access");
-    DBG_VOP_LOCKS_DECL(1);
-    DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
-    DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
+struct volfsgetattr_struct{
+       int     numMounts;
+       vnode_t a_vp;
+};
 
-    /*
-     * We don't need to check credentials!  FS is read-only for everyone
-     */
-    if (ap->a_mode == VREAD || ap->a_mode == VEXEC)
-        ret_err = 0;
-    else
-        ret_err = EACCES;
+static int
+volfs_getattr_callback(mount_t mp, void * arg)
+{
+       struct volfsgetattr_struct *vstrp = (struct volfsgetattr_struct *)arg;
 
-    DBG_VOP_LOCKS_TEST(ret_err);
-    return (ret_err);
+       if (mp != vnode_mount(vstrp->a_vp) && validfsnode(mp))
+               vstrp->numMounts++;
+       return(VFS_RETURNED);
 }
 
 /*
  * volfs_getattr - fill in the attributes for this vnode
- *
- * Locking policy: don't change anything
  */
-int
+static int
 volfs_getattr(ap)
-    struct vop_getattr_args    /* { struct vnode *a_vp; struct vattr *a_vap;
-        struct ucred *a_cred; struct proc *a_p; } */ *ap;
+    struct vnop_getattr_args   /* { struct vnode *a_vp; struct vnode_attr *a_vap;
+        vfs_context_t a_context; } */ *ap;
 {
     struct volfs_vndata *priv_data;
-    struct vnode       *a_vp;
-    struct vattr       *a_vap;
+    struct vnode               *a_vp;
+    struct vnode_attr  *a_vap;
     int                 numMounts = 0;
-    DBG_FUNC_NAME("volfs_getattr");
-    DBG_VOP_LOCKS_DECL(1);
-    DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
-    DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
+    struct volfsgetattr_struct vstr;
+    struct timespec ts;
 
     a_vp = ap->a_vp;
     a_vap = ap->a_vap;
 
     priv_data = a_vp->v_data;
 
-    a_vap->va_type = VDIR;
-    a_vap->va_mode = 0444;     /* Yup, hard - coded to read - only */
-    a_vap->va_nlink = 2;
-    a_vap->va_uid = 0;         /* Always owned by root */
-    a_vap->va_gid = 0;         /* Always part of group 0 */
-    a_vap->va_fsid = (int) a_vp->v_mount->mnt_stat.f_fsid.val[0];
-    a_vap->va_fileid = priv_data->nodeID;
+    VATTR_RETURN(a_vap, va_type, VDIR);
+    VATTR_RETURN(a_vap, va_mode, 0555);
+    VATTR_RETURN(a_vap, va_nlink, 2);
+    VATTR_RETURN(a_vap, va_uid, 0);
+    VATTR_RETURN(a_vap, va_gid, 0);
+    VATTR_RETURN(a_vap, va_fsid, (int) a_vp->v_mount->mnt_vfsstat.f_fsid.val[0]);
+    VATTR_RETURN(a_vap, va_fileid, (uint64_t)((u_long)priv_data->nodeID));
+    VATTR_RETURN(a_vap, va_acl, NULL);
 
     /*
      * If it's the root vnode calculate its size based on the number of eligible
      * file systems
      */
-    if (priv_data->vnode_type == VOLFS_ROOT)
-      {
-        register struct mount *mp, *nmp;
+    if (priv_data->vnode_type == VOLFS_ROOT) {
+           vstr.numMounts = 0;
+           vstr.a_vp = a_vp;
 
-        simple_lock(&mountlist_slock);
-        for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
-            if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, ap->a_p)) {
-                nmp = mp->mnt_list.cqe_next;
-                continue;
-            }
+           vfs_iterate(LK_NOWAIT, volfs_getattr_callback, (void *)&vstr);
 
-            if (mp != a_vp->v_mount && validfsnode(mp))
-                numMounts++;
+           numMounts = vstr.numMounts;
 
-            simple_lock(&mountlist_slock);
-            nmp = mp->mnt_list.cqe_next;
-            vfs_unbusy(mp, ap->a_p);
-        }
-        simple_unlock(&mountlist_slock);
-
-        DBG_VOP(("found %d file systems that volfs can support\n", numMounts));
-        a_vap->va_size = (numMounts + 2) * VLFSDIRENTLEN;
-      }
-    else
-      {
-        a_vap->va_size = 2 * VLFSDIRENTLEN;
-      }
-    DBG_VOP(("va_size = %d, VLFSDIRENTLEN = %ld\n", (int) a_vap->va_size, VLFSDIRENTLEN));
-    a_vap->va_blocksize = 512;
-
-    a_vap->va_atime.tv_sec = boottime.tv_sec;
-    a_vap->va_atime.tv_nsec = 0;
-
-    a_vap->va_mtime.tv_sec = boottime.tv_sec;
-    a_vap->va_mtime.tv_nsec = 0;
+           VATTR_RETURN(a_vap, va_data_size, (numMounts + 2) * VLFSDIRENTLEN);
+    } else {
+           VATTR_RETURN(a_vap, va_data_size, 2 * VLFSDIRENTLEN);
+    }
 
-    a_vap->va_ctime.tv_sec = boottime.tv_sec;
-    a_vap->va_ctime.tv_nsec = 0;
+    VATTR_RETURN(a_vap, va_iosize, 512);
+    ts.tv_sec = boottime_sec();
+    ts.tv_nsec = 0;
+    VATTR_RETURN(a_vap, va_access_time, ts);
+    VATTR_RETURN(a_vap, va_modify_time, ts);
+    VATTR_RETURN(a_vap, va_change_time, ts);
 
-    a_vap->va_gen = 0;
-    a_vap->va_flags = 0;
-    a_vap->va_rdev = 0;
-    a_vap->va_bytes = a_vap->va_size;
-    a_vap->va_filerev = 0;
-    a_vap->va_vaflags = 0;
+    VATTR_RETURN(a_vap, va_gen, 0);
+    VATTR_RETURN(a_vap, va_flags, 0);
+    VATTR_RETURN(a_vap, va_rdev, 0);
+    VATTR_RETURN(a_vap, va_filerev, 0);
 
-    DBG_VOP_LOCKS_TEST(0);
     return (0);
 }
 
 /*
  * volfs_select - just say OK.  Only possible op is readdir
- *
- * Locking policy: ignore
  */
-int
-volfs_select(ap)
-    struct vop_select_args     /* { struct vnode *a_vp; int  a_which; int
-                                * a_fflags; struct ucred *a_cred; void * a_wql; struct
-        proc *a_p; } */ *ap;
+static int
+volfs_select(__unused struct vnop_select_args *ap)
 {
-    DBG_VOP(("volfs_select called\n"));
-
-    return (1);
+       return (1);
 }
 
 /*
  * vofls_rmdir - not possible to remove directories in volfs
- *
- * Locking policy: a_dvp & a_vp - locked on entry, unlocked on exit
  */
-int
+static int
 volfs_rmdir(ap)
-    struct vop_rmdir_args      /* { struct vnode *a_dvp; struct vnode *a_vp;
-        struct componentname *a_cnp; } */ *ap;
+    struct vnop_rmdir_args     /* { struct vnode *a_dvp; struct vnode *a_vp;
+        struct componentname *a_cnp; vfs_context_t a_context; } */ *ap;
 {
-    DBG_VOP(("volfs_rmdir called\n"));
     if (ap->a_dvp == ap->a_vp) {
                (void) nop_rmdir(ap);
                return (EINVAL);
@@ -349,6 +294,31 @@ volfs_rmdir(ap)
                return (err_rmdir(ap));
 }
 
+
+
+static int
+volfs_readdir_callback(mount_t mp, void * v)
+{
+       struct volfs_rdstruct * vcsp = (struct volfs_rdstruct *)v;
+       struct dirent       local_dir;
+       int error;
+
+            if ((mp != vnode_mount(vcsp->vp)) && validfsnode(mp))
+                               vcsp->validindex++;
+
+            if (vcsp->rec_offset == vcsp->validindex)
+              {
+                local_dir.d_fileno = mp->mnt_vfsstat.f_fsid.val[0];
+                local_dir.d_type = DT_DIR;
+                local_dir.d_reclen = VLFSDIRENTLEN;
+                local_dir.d_namlen = sprintf(&local_dir.d_name[0], "%d", mp->mnt_vfsstat.f_fsid.val[0]);
+                error = uiomove((char *) &local_dir, VLFSDIRENTLEN, vcsp->uio);
+                vcsp->rec_offset++;
+              }
+
+               return(VFS_RETURNED);
+}
+
 /*
  * volfs_readdir - Get directory entries
  *
@@ -358,14 +328,12 @@ volfs_rmdir(ap)
  * equivalent of the f_fsid.val[0] from their mount structure (typically
  * the device id of the volume).  The maximum length for a name, then is
  * 10 characters.
- *
- * Locking policy: a_vp locked on entry and exit
  */
-int
+static int
 volfs_readdir(ap)
-    struct vop_readdir_args    /* { struct vnode *a_vp; struct uio *a_uio;
-                                * struct ucred *a_cred; int *a_eofflag; int
-        *ncookies; u_long **a_cookies; } */ *ap;
+    struct vnop_readdir_args   /* { struct vnode *a_vp; struct uio *a_uio;
+                                * int *a_eofflag; int
+        *ncookies; u_long **a_cookies; vfs_context_t a_context; } */ *ap;
 {
     struct volfs_vndata *priv_data;
     register struct uio *uio = ap->a_uio;
@@ -376,52 +344,42 @@ volfs_readdir(ap)
     int                 i;
     int                                        starting_resid;
     off_t               off;
-    DBG_FUNC_NAME("volfs_readdir");
-    DBG_VOP_LOCKS_DECL(1);
-
-    DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
-    DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
-    DBG_VOP(("\tuio_offset = %d, uio_resid = %d\n", (int) uio->uio_offset, uio->uio_resid));
-       /* We assume it's all one big buffer... */
-    if (uio->uio_iovcnt > 1)
-       DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio->uio_iovcnt));
-
+       struct volfs_rdstruct vcs;
+    
        off = uio->uio_offset;
     priv_data = ap->a_vp->v_data;
-    starting_resid = uio->uio_resid;
-    count = uio->uio_resid;
+       // LP64todo - fix this!
+    starting_resid = count = uio_resid(uio);
  
     /* Make sure we don't return partial entries. */
     count -= (uio->uio_offset + count) & (VLFSDIRENTLEN - 1);
-    if (count <= 0)
-               {
-        DBG_VOP(("volfs_readdir: Not enough buffer to read in entries\n"));
-        DBG_VOP_LOCKS_TEST(EINVAL);
-        return (EINVAL);
-               }
+       if (count <= 0) {
+               return (EINVAL);
+       }
     /*
      * Make sure we're starting on a directory boundary
      */
-    if (off & (VLFSDIRENTLEN - 1))
-        {
-        DBG_VOP_LOCKS_TEST(EINVAL);
-        return (EINVAL);
-        }
+       if (off & (VLFSDIRENTLEN - 1)) {
+               return (EINVAL);
+       }
     rec_offset = off / VLFSDIRENTLEN;
-    lost = uio->uio_resid - count;
-    uio->uio_resid = count;
-    uio->uio_iov->iov_len = count;
+       // LP64todo - fix this!
+    lost = uio_resid(uio) - count;
+    uio_setresid(uio, count);
+    uio_iov_len_set(uio, count); 
+#if LP64_DEBUG
+       if (IS_VALID_UIO_SEGFLG(uio->uio_segflg) == 0) {
+               panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__); 
+       }
+#endif /* LP64_DEBUG */
 
     local_dir.d_reclen = VLFSDIRENTLEN;
     /*
      * We must synthesize . and ..
      */
-    DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %d\n",
-            (int) uio->uio_offset, uio->uio_resid));
+
     if (rec_offset == 0)
       {
-        DBG_VOP(("\tAdding .\n"));
         /*
          * Synthesize .
          */
@@ -432,13 +390,10 @@ volfs_readdir(ap)
         for (i = 1; i < MAXVLFSNAMLEN; i++)
             local_dir.d_name[i] = 0;
         error = uiomove((char *) &local_dir, VLFSDIRENTLEN, uio);
-        DBG_VOP(("\t   after adding ., uio_offset = %d, uio_resid = %d\n",
-                (int) uio->uio_offset, uio->uio_resid));
         rec_offset++;
       }
     if (rec_offset == 1)
       {
-        DBG_VOP(("\tAdding ..\n"));
         /*
          * Synthesize ..
          * We only have two levels in the volfs hierarchy.  Root's
@@ -454,8 +409,6 @@ volfs_readdir(ap)
             local_dir.d_name[i] = 0;
         error = uiomove((char *) &local_dir, VLFSDIRENTLEN, uio);
         rec_offset++;
-        DBG_VOP(("\t   after adding .., uio_offset = %d, uio_resid = %d\n",
-                (int) uio->uio_offset, uio->uio_resid));
       }
 
     /*
@@ -466,58 +419,26 @@ volfs_readdir(ap)
     if (priv_data->vnode_type == VOLFS_FSNODE)
         {
         *ap->a_eofflag = 1;    /* we got all the way to the end */
-        DBG_VOP_LOCKS_TEST(error);
         return (error);
         }
 
     if (rec_offset > 1) {
-        register struct mount *mp, *nmp;
-        int                                    validnodeindex;
-        struct proc            *p = uio->uio_procp;
-
-        validnodeindex = 1;    /* we always have "." and ".." */
-
-        simple_lock(&mountlist_slock);
-        for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
-            if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
-                nmp = mp->mnt_list.cqe_next;
-                continue;
-            }
-
-            if (mp != ap->a_vp->v_mount && validfsnode(mp))
-                validnodeindex++;
-
-            if (rec_offset == validnodeindex)
-              {
-                local_dir.d_fileno = mp->mnt_stat.f_fsid.val[0];
-                local_dir.d_type = DT_DIR;
-                local_dir.d_reclen = VLFSDIRENTLEN;
-                DBG_VOP(("\tAdding dir entry %d for offset %d\n", mp->mnt_stat.f_fsid.val[0], rec_offset));
-                local_dir.d_namlen = sprintf(&local_dir.d_name[0], "%d", mp->mnt_stat.f_fsid.val[0]);
-                error = uiomove((char *) &local_dir, VLFSDIRENTLEN, uio);
-                DBG_VOP(("\t   after adding entry '%s', uio_offset = %d, uio_resid = %d\n",
-                         &local_dir.d_name[0], (int) uio->uio_offset, uio->uio_resid));
-                rec_offset++;
-              }
-
-            simple_lock(&mountlist_slock);
-            nmp = mp->mnt_list.cqe_next;
-            vfs_unbusy(mp, p);
-        }
-        simple_unlock(&mountlist_slock);
+               vcs.validindex = 1;             /* we always have "." and ".." */
+               vcs.rec_offset = rec_offset;
+               vcs.vp = ap->a_vp;
+               vcs.uio = uio;
+               
+       
+               vfs_iterate(0, volfs_readdir_callback, &vcs);
 
-        if (mp == (void *) &mountlist)
+        //if (mp == (void *) &mountlist)
             *ap->a_eofflag = 1;        /* we got all the way to the end */
     }
+    uio_setresid(uio, (uio_resid(uio) + lost));
 
-    uio->uio_resid += lost;
-    if (starting_resid == uio->uio_resid)
+    if (starting_resid == uio_resid(uio))
         uio->uio_offset = 0;
 
-    DBG_VOP(("\tExiting, uio_offset = %d, uio_resid = %d, ap->a_eofflag = %d\n",
-            (int) uio->uio_offset, uio->uio_resid, *ap->a_eofflag));
-
-    DBG_VOP_LOCKS_TEST(error);
     return (error);
 }
 
@@ -527,7 +448,7 @@ volfs_readdir(ap)
  *
  * This can cause context switching, so caller should be lock safe
  */
-static int
+int
 validfsnode(struct mount *fsnode)
 {
 
@@ -542,93 +463,14 @@ validfsnode(struct mount *fsnode)
                return 0;
 }
 
-/*
- * volfs_lock - Lock an inode.
- * If its already locked, set the WANT bit and sleep.
- *
- * Locking policy: handled by lockmgr
- */
-int
-volfs_lock(ap)
-    struct vop_lock_args       /* { struct vnode *a_vp; int a_flags; struct
-        proc *a_p; } */ *ap;
-{
-    int                 retval;
-    struct volfs_vndata *priv_data;
-    DBG_FUNC_NAME("volfs_lock");
-    DBG_VOP_LOCKS_DECL(1);
-    DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
-    DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
-
-    priv_data = (struct volfs_vndata *) ap->a_vp->v_data;
-    retval = lockmgr(&priv_data->lock, ap->a_flags, &ap->a_vp->v_interlock, ap->a_p);
-    DBG_VOP_LOCKS_TEST(retval);
-    return (retval);
-}
-
-/*
- * volfs_unlock - Unlock an inode.
- *
- * Locking policy: handled by lockmgr
- */
-int
-volfs_unlock(ap)
-    struct vop_unlock_args     /* { struct vnode *a_vp; int a_flags; struct
-        proc *a_p; } */ *ap;
-{
-    int                 retval;
-    struct volfs_vndata *priv_data;
-    DBG_FUNC_NAME("volfs_unlock");
-    DBG_VOP_LOCKS_DECL(1);
-    DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
-    DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
-
-    priv_data = (struct volfs_vndata *) ap->a_vp->v_data;
-    retval = lockmgr(&priv_data->lock, ap->a_flags | LK_RELEASE,
-                    &ap->a_vp->v_interlock, ap->a_p);
-
-    DBG_VOP_LOCKS_TEST(retval);
-    return (retval);
-}
-
-/*
- * volfs_islocked - Check for a locked inode.
- *
- * Locking policy: ignore
- */
-int
-volfs_islocked(ap)
-    struct vop_islocked_args /* { struct vnode *a_vp; } */ *ap;
-{
-    int                 retval;
-    struct volfs_vndata *priv_data;
-
-    DBG_FUNC_NAME("volfs_islocked");
-    DBG_VOP_LOCKS_DECL(1);
-    //DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
-
-    DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
-    priv_data = (struct volfs_vndata *) ap->a_vp->v_data;
-    retval = lockstatus(&priv_data->lock);
-
-    DBG_VOP_LOCKS_TEST(retval);
-    return (retval);
-}
-
 /*
  * volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
- *
- * Locking policy: a_vp locked on input and output
  */
-int
+static int
 volfs_pathconf(ap)
-    struct vop_pathconf_args   /* { struct vnode *a_vp; int a_name; int
-        *a_retval; } */ *ap;
+    struct vnop_pathconf_args  /* { struct vnode *a_vp; int a_name; int
+        *a_retval; vfs_context_t a_context; } */ *ap;
 {
-    DBG_VOP(("volfs_pathconf called\n"));
-
     switch (ap->a_name)
       {
         case _PC_LINK_MAX:
@@ -655,38 +497,228 @@ volfs_pathconf(ap)
     /* NOTREACHED */
 }
 
+/* 
+ * get_parentvp() - internal routine that tries to lookup the parent of vpp.
+ * On success, *vpp is the parent vp and is returned with a reference. 
+ */
+static int
+get_parentvp(struct vnode **vpp, struct mount *mp, vfs_context_t context)
+{
+       int result;
+       struct vnode_attr va;
+       struct vnode *child_vp = *vpp;
+       
+       VATTR_INIT(&va);
+       VATTR_WANTED(&va, va_parentid);
+       result = vnode_getattr(child_vp, &va, context);
+       if (result) {
+               return result;
+       }
+
+       /* Shift attention to the parent directory vnode: */
+       result = VFS_VGET(mp, (ino64_t)va.va_parentid, vpp, context);
+
+       if (result == 0 && child_vp->v_parent != *vpp) {
+               vnode_update_identity(child_vp, *vpp, NULL, 0, 0, VNODE_UPDATE_PARENT);
+       }
+
+       return result;
+}      
+
+
+/*
+ * Look up the parent directory of a given vnode.
+ */
+static int
+lookup_parent(vnode_t child_vp, vnode_t *parent_vpp, int is_authorized, vfs_context_t context)
+{
+       struct componentname cn;
+       vnode_t new_vp;
+       int error;
+
+       *parent_vpp = NULLVP;
+
+       if (is_authorized == 0) {
+               error = vnode_authorize(child_vp, NULL, KAUTH_VNODE_SEARCH, context);
+               if (error != 0) {
+                       return (error);
+               }
+       }
+       new_vp = child_vp->v_parent;
+
+       if (new_vp != NULLVP) {
+               if ( (error = vnode_getwithref(new_vp)) == 0 )
+                       *parent_vpp = new_vp;
+               return (error);
+       }
+       bzero(&cn, sizeof(cn));
+       cn.cn_nameiop = LOOKUP;
+       cn.cn_context = context;
+       cn.cn_pnbuf = CAST_DOWN(caddr_t, &gDotDot);
+       cn.cn_pnlen = strlen(cn.cn_pnbuf);
+       cn.cn_nameptr = cn.cn_pnbuf;
+       cn.cn_namelen = cn.cn_pnlen;
+       cn.cn_flags = (FOLLOW | LOCKLEAF | ISLASTCN | ISDOTDOT);
+
+       error = VNOP_LOOKUP(child_vp, &new_vp, &cn, context);
+       if (error != 0) {
+               return(error);
+       }
+       if (new_vp == child_vp) {
+               vnode_put(new_vp);
+               return ELOOP;
+       }
+       if (child_vp->v_parent == NULLVP) {
+               vnode_update_identity(child_vp, new_vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
+       }
+       *parent_vpp = new_vp;
+       return 0;
+}
+
+
+/*
+ *     verify_fullpathaccess(ret_vnode);
+ */
+
+static int
+verify_fullpathaccess(struct vnode *targetvp, vfs_context_t context)
+{
+       struct vnode *vp, *parent_vp;
+       struct mount *mp = targetvp->v_mount;
+       struct proc *p = vfs_context_proc(context);
+       int result;
+       int dp_authorized;
+       struct filedesc *fdp = p->p_fd; /* pointer to file descriptor state */
+       
+       vp = targetvp;
+       dp_authorized = 0;
+       
+       /* get the parent directory. */
+       if ((vp->v_flag & VROOT) == 0 && vp != fdp->fd_cdir && vp != fdp->fd_rdir) {
+               if (vp->v_parent == NULLVP || (vp->v_flag & VISHARDLINK) || (vnode_getwithref(vp->v_parent) != 0)) {
+                       if (vp->v_type == VDIR) {
+                               result = lookup_parent(vp, &parent_vp, dp_authorized, context);
+       
+                               /*
+                                * If the lookup fails with EACCES and the vp is a directory,
+                                * we should try again but bypass authorization check. Without this
+                                * workaround directories that you can navigate to but not traverse will 
+                                * disappear when clicked in the Finder.
+                                */
+                               if (result == EACCES && (vp->v_flag & VROOT) == 0) {
+                                       dp_authorized = 1;  /* bypass auth check */
+                                       if (lookup_parent(vp, &parent_vp, dp_authorized, context) == 0) {
+                                               result = 0;
+                                       }
+                                       dp_authorized = 0; /* force us to authorize */
+                               }
+                               vp = parent_vp;
+                       }
+                       else {
+                               /*
+                                * this is not a directory so we must get parent object ID
+                                */
+                               result = get_parentvp(&vp, mp, context);
+                               parent_vp = vp;
+                       }
+                       if (result != 0) 
+                               goto err_exit;
+               }
+               else {
+                       /*
+                        * we where able to get a reference on v_parent
+                        */
+                       parent_vp = vp = vp->v_parent;
+               }
+       } 
+
+       /*
+        * Keep going up until either the process's root or the process's working 
+        * directory is hit, either one of which are potential valid starting points 
+        * for a full pathname
+        */
+       while (vp != NULLVP) {
+
+               result = reverse_lookup(vp, &parent_vp, fdp, context, &dp_authorized);
+               if (result == 0) {
+                       /*
+                        * we're done and we have access
+                        */
+                       break;
+               }
+               if (vp != parent_vp) {
+                       /*
+                        * we where able to walk up the parent chain so now we don't need
+                        * vp any longer
+                        */
+                       vnode_put(vp);  
+                       vp = parent_vp;
+               }
+               /*
+                * we have a referenced vp at this point... if dp_authorized == 1, than
+                * it's been authorized for search, but v_parent was NULL...
+                * if dp_authorized == 0, than we need to do the authorization check
+                * before looking up the parent
+                */
+               if ((vp->v_flag & VROOT) != 0 ||
+                   vp == fdp->fd_cdir || vp == fdp->fd_rdir) {
+                       /*
+                        * we're already at the termination point, which implies that
+                        * the authorization check in the cache failed (otherwise we
+                        * would have returned 'done' from "reverse_lookup"... so,
+                        * do the authorization and bail
+                        */
+                       result = vnode_authorize(vp, NULL, KAUTH_VNODE_SEARCH, context);
+                       goto lookup_exit;
+               }
+               result = lookup_parent(vp, &parent_vp, dp_authorized, context);
+               if (result != 0) {
+                       goto lookup_exit;
+               }
+               if (vp != parent_vp) {
+                       /*
+                        * got the parent so now we don't need vp any longer
+                        */
+                       vnode_put(vp);  
+                       vp = parent_vp;
+               }
+       } /* while loop */
+
+       /*
+        * Success: the caller has complete access to the initial vnode
+        */
+       result = 0; 
+
+lookup_exit:
+       if (vp != NULLVP && vp != targetvp) {
+               vnode_put(vp);
+       }
+               
+err_exit:
+       return result;
+};
+
+
 /*
  * get_fsvnode - internal routine to create a vnode for a file system.  Called with mount pointer,
  *   id of filesystem to lookup and pointer to vnode pointer to fill in
  */
 static int
-get_fsvnode(our_mount, id, ret_vnode)
-    struct mount       *our_mount;
-    int id;
-    struct vnode      **ret_vnode;
+get_fsvnode(struct mount *our_mount, int id, vnode_t *ret_vnode)
 {
-    register struct mount *mp;
     struct mount       *cur_mount;
+       fsid_t                          cur_fsid;
     struct vnode       *cur_vnode;
     struct volfs_vndata *cur_privdata;
        int                                     retval;
-
-    //DBG_VOP(("volfs: get_fsvnode called\n"));
+       struct vnode_fsparam vfsp;
+       int     vid = 0;
 
     /*
      * OK, first look up the matching mount on the list of mounted file systems
      */
-    cur_mount = NULL;
-    simple_lock(&mountlist_slock);
-    for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = mp->mnt_list.cqe_next)
-      {
-        if (validfsnode(mp) && mp->mnt_stat.f_fsid.val[0] == id)
-          {
-            cur_mount = mp;
-            break;
-          }
-      }
-    simple_unlock(&mountlist_slock);
+       /* the following will return the mount point with vfs_busy held */
+       cur_mount = mount_lookupby_volfsid(id, 1);
 
     if (cur_mount == NULL) {
         /*
@@ -700,34 +732,36 @@ get_fsvnode(our_mount, id, ret_vnode)
         return ENOENT;
     };
 
+       cur_fsid = cur_mount->mnt_vfsstat.f_fsid;
+
     /*
      * Now search the list attached to the mount structure to
      * see if this vnode is already floating around
      */
 search_vnodelist:
-    cur_vnode = our_mount->mnt_vnodelist.lh_first;
-    while (cur_vnode != NULL)
-      {
+       mount_lock(our_mount);
+       TAILQ_FOREACH(cur_vnode, &our_mount->mnt_vnodelist, v_mntvnodes)  {
         cur_privdata = (struct volfs_vndata *) cur_vnode->v_data;
-        if (cur_privdata->nodeID == id)
+        if (cur_privdata->nodeID == (unsigned int)id)
             {
             if (cur_privdata->fs_mount != cur_mount) {
-                DBG_VOP(("volfs get_fsvnode: Updating fs_mount for vnode 0x%08lX (id = %d) from 0x%08lX to 0x%08lX...\n",
-                         (unsigned long)cur_vnode,
-                         cur_privdata->nodeID,
-                         (unsigned long)cur_privdata->fs_mount,
-                         (unsigned long)cur_mount));
                 cur_privdata->fs_mount = cur_mount;
+                cur_privdata->fs_fsid = cur_fsid;
             };
             break;
             }
-        cur_vnode = cur_vnode->v_mntvnodes.le_next;
-      }
+       }
+       mount_unlock(our_mount);
 
-    //DBG_VOP(("\tfinal cur_mount: 0x%x\n",cur_mount));
     if (cur_vnode) {
-        /* If vget returns an error, cur_vnode will not be what we think it is, try again */
-        if (vget(cur_vnode, LK_EXCLUSIVE, current_proc()) != 0) {
+        vid = vnode_vid(cur_vnode);
+
+        /*
+        * use vnode_getwithvid since it will wait for a vnode currently being
+        * terminated... if it returns an error, cur_vnode will not be what we
+        * think it is, try again
+        */
+        if (vnode_getwithvid(cur_vnode, vid) != 0) {
             goto search_vnodelist;
         };
         }
@@ -735,27 +769,40 @@ search_vnodelist:
       {
         MALLOC(cur_privdata, struct volfs_vndata *,
                sizeof(struct volfs_vndata), M_VOLFSNODE, M_WAITOK);
-        retval = getnewvnode(VT_VOLFS, our_mount, volfs_vnodeop_p, &cur_vnode);
-        if (retval != 0) {
-            FREE(cur_privdata, M_VOLFSNODE);
-            return retval;
-        };
-                       
+
         cur_privdata->vnode_type = VOLFS_FSNODE;
         cur_privdata->nodeID = id;
 
         cur_privdata->fs_mount = cur_mount;
-        lockinit(&cur_privdata->lock, PINOD, "volfsnode", 0, 0);
-        lockmgr(&cur_privdata->lock, LK_EXCLUSIVE, (struct slock *)0, current_proc());
-        cur_vnode->v_data = cur_privdata;
-        cur_vnode->v_type = VDIR;
-        DBG_VOP(("get_fsvnode returned with new node of "));
-        DBG_VOP_PRINT_VNODE_INFO(cur_vnode);DBG_VOP(("\n"));
+        cur_privdata->fs_fsid = cur_fsid;
+
+               vfsp.vnfs_mp = our_mount;
+               vfsp.vnfs_vtype = VDIR;
+               vfsp.vnfs_str = "volfs";
+               vfsp.vnfs_dvp = 0;
+               vfsp.vnfs_fsnode = cur_privdata;
+               vfsp.vnfs_cnp = 0;
+               vfsp.vnfs_vops = volfs_vnodeop_p;
+               vfsp.vnfs_rdev = 0;
+               vfsp.vnfs_filesize = 0;
+               vfsp.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE;
+               vfsp.vnfs_marksystem = 0;
+               vfsp.vnfs_markroot = 0;
+
+               retval = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &cur_vnode);
+        if (retval != 0) {
+            FREE(cur_privdata, M_VOLFSNODE);
+                       goto out;
+        };
+               cur_vnode->v_tag = VT_VOLFS;
+                       
       }
 
     *ret_vnode = cur_vnode;
-
-    return (0);
+       retval = 0;
+out:
+       vfs_unbusy(cur_mount);
+    return (retval);
 }
 
 
@@ -766,384 +813,173 @@ search_vnodelist:
  *             to a vnode pointer
  */
 static int
-get_filevnode(parent_fs, id, ret_vnode)
-    struct mount       *parent_fs;
-    u_int                              id;
-    struct vnode       **ret_vnode;
+get_filevnode(struct mount *parent_fs, u_int id, vnode_t *ret_vnode, vfs_context_t context)
 {
     int                 retval;
 
-    DBG_VOP(("get_filevnode called for ID %d\n", id));
-
+again:
        /*
         * Special case 2 to mean the root of a file system
         */
        if (id == 2)
-               retval = VFS_ROOT(parent_fs, ret_vnode);
+               retval = VFS_ROOT(parent_fs, ret_vnode, context);
        else
-       retval = VFS_VGET(parent_fs, &id, ret_vnode);
+               retval = VFS_VGET(parent_fs, (ino64_t)id, ret_vnode, context);
+       if (retval) goto error;
+
+       retval = verify_fullpathaccess(*ret_vnode, context);
+       if (retval) {
+               /* An error was encountered verifying that the caller has,
+                  in fact, got access all the way from "/" or their working
+                  directory to the specified item...
+                */
+               vnode_put(*ret_vnode);
+               *ret_vnode = NULL;
+               /* vnode was recycled during access verification. */
+               if (retval == EAGAIN) {
+                       goto again;
+               }
+       };
 
+error:
     return (retval);
 }
 
 
-int
-volfs_lookup(ap)
-    struct vop_lookup_args     /* { struct vnode *a_dvp; struct vnode
-        **a_vpp; struct componentname *a_cnp; } */ *ap;
+static int
+volfs_lookup(struct vnop_lookup_args *ap)
 {
-    struct volfs_vndata *priv_data;
-    char                               *cnp;
-    long                               namelen;
-    struct mount               *parent_fs;
-    int                                        unlocked_parent = 0;
-    int                 ret_err = ENOENT;
-    DBG_FUNC_NAME("volfs_lookup");
-    DBG_VOP_LOCKS_DECL(2);
-
-    DBG_VOP(("volfs_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
-
-    DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
-    DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
-    DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
-    DBG_VOP(("\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP(("\n"));
-       if (ap->a_cnp->cn_flags & LOCKPARENT)
-               DBG_VOP(("\tLOCKPARENT is set\n"));
-       if (ap->a_cnp->cn_flags & ISLASTCN)
-               {
-               DBG_VOP(("\tISLASTCN is set\n"));
-               if (ap->a_cnp->cn_nameiop == DELETE || ap->a_cnp->cn_nameiop == RENAME)         /* XXX PPD Shouldn't we check for CREATE, too? */
-                       {
-                       ret_err = EROFS;
-                       goto Err_Exit;
-                       }
-               }
+       struct volfs_vndata *priv_data;
+       char  *nameptr;
+       long  namelen;
+       struct mount  *parent_fs;
+       vnode_t vp;
+       int  isdot_or_dotdot = 0;
+       int  ret_err = ENOENT;
+       char firstchar;
+       int ret_val;
+
+#if 0
+       KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 8)) | DBG_FUNC_START,
+                    (unsigned int)ap->a_dvp, (unsigned int)ap->a_cnp, (unsigned int)p, 0, 0);
+#endif
        priv_data = ap->a_dvp->v_data;
-       cnp = ap->a_cnp->cn_nameptr;
+       nameptr = ap->a_cnp->cn_nameptr;
        namelen = ap->a_cnp->cn_namelen;
-       
-#if VOLFS_DEBUG
-    switch (priv_data->vnode_type) {
-        case VOLFS_ROOT:
-            DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_ROOT.\n", (unsigned long)ap->a_dvp));
-            break;
-
-        case VOLFS_FSNODE:
-            DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_FSNODE, nodeID = %d, fs_mount = 0x%08lX.\n",
-                     (unsigned long)ap->a_dvp,
-                     priv_data->nodeID,
-                     (unsigned long)priv_data->fs_mount));
+       firstchar = nameptr[0];
 
-        default:
-            DBG_VOP(("\tparent directory (vnode 0x%08lX) has unknown vnode_type (%d), nodeID = %d.\n",
-                     (unsigned long)ap->a_dvp,
-                     priv_data->vnode_type,
-                     priv_data->nodeID));
-    };
-#endif /* VOLFS_DEBUG */
-
-       /* first check for "." and ".." */
-       if (cnp[0] == '.')
-       {
-               if (namelen == 1)
-               {
+       /* First check for "." and ".." */
+       if (firstchar == '.') {
+               if (namelen == 1) {
                        /* "." requested */
-                   *ap->a_vpp = ap->a_dvp;
-                   VREF(*ap->a_vpp);
-            DBG_VOP_LOCKS_TEST(0);
-            return (0);
-               }
-               else if (cnp[1] == '.' && namelen == 2) 
-               {
+                       isdot_or_dotdot = 1;
+                       *ap->a_vpp = ap->a_dvp;
+                       vnode_get(*ap->a_vpp);
+                       ret_err = 0;
+               } else if (nameptr[1] == '.' && namelen == 2) {
                        /* ".." requested */
-                       ret_err = volfs_root(ap->a_dvp->v_mount, ap->a_vpp);
+                       isdot_or_dotdot = 1;
+                       ret_err = VFS_ROOT(ap->a_dvp->v_mount, ap->a_vpp, ap->a_context);
                }
-       }
-
-       /* then look for special file system root symbol ('@') */
-       else if (cnp[0] == '@')
-       {
+       } else if (firstchar == '@') { /* '@' is alias for system root */
                if ((namelen == 1) && (priv_data->vnode_type != VOLFS_ROOT)) {
-                       parent_fs = priv_data->fs_mount;
-                       if (!(ap->a_cnp->cn_flags & LOCKPARENT) || !(ap->a_cnp->cn_flags & ISLASTCN)) {
-                               VOP_UNLOCK(ap->a_dvp, 0, ap->a_cnp->cn_proc);
-                               unlocked_parent = 1;
-                       };
-                       ret_err = VFS_ROOT(parent_fs, ap->a_vpp);
-        } else {
-            DBG_VOP(("volfs_lookup: pathname = '@' but namelen = %ld and parent vnode_type = %d.\n", namelen, priv_data->vnode_type));
-            *ap->a_vpp = NULL;
-            ret_err = ENOENT;
-        };
-       }
-
-       /* finally, just look for numeric ids... */
-       else if (namelen <= 10 && cnp[0] > '0' && cnp[0] <= '9') /* 10 digits max lead digit must be 1 - 9 */
-       {
+                       /* the following returns with iteration count on mount point */
+                       parent_fs = mount_list_lookupby_fsid(&priv_data->fs_fsid, 0, 1);
+                       if (parent_fs) {
+                               ret_val = vfs_busy(parent_fs, LK_NOWAIT);
+                               mount_iterdrop(parent_fs);
+                               if (ret_val !=0) {
+                                       *ap->a_vpp = NULL;
+                                       ret_err = ENOENT;
+                               } else {
+                                       ret_err = VFS_ROOT(parent_fs, ap->a_vpp, ap->a_context);
+                                       vfs_unbusy(parent_fs);
+                               }
+                       } else {
+                               *ap->a_vpp = NULL;
+                               ret_err = ENOENT;
+                       }
+               } else {
+                       *ap->a_vpp = NULL;
+                       ret_err = ENOENT;
+               }
+       } else if (namelen <= 10 && firstchar > '0' && firstchar <= '9') {
                char    *check_ptr;
                u_long  id;
 
-               id = strtoul(cnp, &check_ptr, 10);
+               id = strtoul(nameptr, &check_ptr, 10);
 
-       /*
+               /*
                 * strtol will leave us at the first non-numeric character.
                 * we've checked to make sure the component name does
                 * begin with a numeric so check_ptr must wind up on
                 * the terminating null or there was other junk following the
                 * number
                 */
-               if ((check_ptr - cnp) == namelen)
-               {
-                   if (priv_data->vnode_type == VOLFS_ROOT)
+               if ((check_ptr - nameptr) == namelen) {
+                       if (priv_data->vnode_type == VOLFS_ROOT) {
+                               /*
+                                * OPTIMIZATION
+                                *
+                                * Obtain the mountpoint and call VFS_VGET in
+                                * one step (ie without creating a vnode for
+                                * the mountpoint).
+                                */
+                               if (check_ptr[0] == '/' &&
+                                   check_ptr[1] > '0' && check_ptr[1] <= '9') {
+                                       struct mount *mp;
+                                       struct vnode *vp;
+                                       u_long  id2;
+                                       char *endptr;
+               
+                                       /* this call will return mount point with vfs_busy held */
+                                       mp = mount_lookupby_volfsid(id, 1);
+                                       if (mp == NULL) {
+                                               *ap->a_vpp = NULL;
+                                               return ENOENT;
+                                       }
+                                       id2 = strtoul(&check_ptr[1], &endptr, 10);
+                                       if ((endptr[0] == '/' || endptr[0] == '\0') &&
+                                           get_filevnode(mp, id2, &vp, ap->a_context) == 0) {
+                                               ap->a_cnp->cn_consume = endptr - check_ptr;
+                                               *ap->a_vpp = vp;
+                                               vfs_unbusy(mp);
+                                               return (0);
+                                       }
+                                       vfs_unbusy(mp);
+                               }
+                               /* Fall through to default behavior... */
+
                                ret_err = get_fsvnode(ap->a_dvp->v_mount, id, ap->a_vpp);
-                   else {
-                       parent_fs = priv_data->fs_mount;
-                               if (!(ap->a_cnp->cn_flags & LOCKPARENT) || !(ap->a_cnp->cn_flags & ISLASTCN)) {
-                                       VOP_UNLOCK(ap->a_dvp, 0, ap->a_cnp->cn_proc);
-                                       unlocked_parent = 1;
-                               };
-                               ret_err = get_filevnode(parent_fs, id, ap->a_vpp);
+
+                       } else {
+                               parent_fs = mount_list_lookupby_fsid(&priv_data->fs_fsid, 0, 1);
+                               if (parent_fs) {
+                                       ret_val = vfs_busy(parent_fs, LK_NOWAIT);
+                                       mount_iterdrop(parent_fs);
+                                       if (ret_val !=0) {
+                                               *ap->a_vpp = NULL;
+                                               ret_err = ENOENT;
+                                       } else {
+                                               ret_err = get_filevnode(parent_fs, id, ap->a_vpp, ap->a_context);
+                                               vfs_unbusy(parent_fs);
+                                       }
+                               } else {
+                                               *ap->a_vpp = NULL;
+                                               ret_err = ENOENT;
+                               }
                        }
                }
-
        }
+       vp = *ap->a_vpp;
 
-       if (!unlocked_parent && (!(ap->a_cnp->cn_flags & LOCKPARENT) || !(ap->a_cnp->cn_flags & ISLASTCN))) {
-               VOP_UNLOCK(ap->a_dvp, 0, ap->a_cnp->cn_proc);
-       };
-
-       /* XXX PPD Should we do something special in case LOCKLEAF isn't set? */
-
-Err_Exit:
-
-       DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
-       DBG_VOP_LOCKS_TEST(ret_err);
-    
-    return (ret_err);
-}
-
-#if DBG_VOP_TEST_LOCKS
+       if ( ret_err == 0 && !isdot_or_dotdot && (vp != NULLVP) && (vp->v_parent == NULLVP))
+               vnode_update_identity(vp, ap->a_dvp, NULL, 0, 0, VNODE_UPDATE_PARENT);
 
 #if 0
-static void DbgLookupTest(     char *funcname, struct componentname  *cnp, struct vnode *dvp, struct vnode *vp)
-{
-    int                flags = cnp->cn_flags;
-    int                nameiop = cnp->cn_nameiop;
-
-    DBG_VOP (("%s: Action:", funcname));
-    switch (nameiop)
-        {
-        case LOOKUP:
-            PRINTIT ("LOOKUP");
-            break;
-        case CREATE:
-            PRINTIT ("CREATE");
-            break;
-        case DELETE:
-            PRINTIT ("DELETE");
-            break;
-        case RENAME:
-            PRINTIT ("RENAME");
-            break;
-        default:
-            PRINTIT ("!!!UNKNOWN!!!!");
-            break;
-            }
-    PRINTIT(" flags: 0x%x ",flags );
-    if (flags & LOCKPARENT)
-        PRINTIT (" Lock Parent");
-    if (flags & ISLASTCN)
-        PRINTIT (" Last Action");
-    PRINTIT("\n");
-
-    if (dvp)
-        {
-        PRINTIT ("%s: Parent vnode exited ", funcname);
-    if (VOP_ISLOCKED(dvp))
-            PRINTIT("LOCKED\n");
-        else
-            PRINTIT("UNLOCKED\n");
-        }
-    if (vp && vp==dvp)
-        {
-        PRINTIT ("%s: Found and Parent are the same\n", funcname);
-        }
-    else if (vp)
-        {
-        PRINTIT ("%s: Found vnode exited ", funcname);
-    if (VOP_ISLOCKED(vp))
-            PRINTIT("LOCKED\n");
-        else
-            PRINTIT("UNLOCKED\n");
-        }
-    else
-        PRINTIT ("%s: Found vnode exited NULL\n", funcname);
-
-
-}
+       KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 8)) | DBG_FUNC_START,
+                    (unsigned int)ap->a_dvp, (unsigned int)ap->a_cnp, (unsigned int)p, ret_err, 0);
 #endif
-
-static void DbgVopTest( int maxSlots,
-                 int retval,
-                 VopDbgStoreRec *VopDbgStore,
-                 char *funcname)
-{
-    int index;
-
-    for (index = 0; index < maxSlots; index++)
-      {
-        if (VopDbgStore[index].id != index) {
-            PRINTIT("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname, VopDbgStore[index].id, index);
-               return;
-        };
-
-        if ((VopDbgStore[index].vp != NULL) &&
-            ((VopDbgStore[index].vp->v_data==NULL)))
-            continue;
-
-        switch (VopDbgStore[index].inState)
-          {
-            case VOPDBG_IGNORE:
-            case VOPDBG_SAME:
-                /* Do Nothing !!! */
-                break;
-            case VOPDBG_LOCKED:
-            case VOPDBG_UNLOCKED:
-            case VOPDBG_LOCKNOTNIL:
-              {
-                  if (VopDbgStore[index].vp == NULL && (VopDbgStore[index].inState != VOPDBG_LOCKNOTNIL)) {
-                      PRINTIT ("%s: InState check: Null vnode ptr in entry #%d\n", funcname, index);
-                  } else if (VopDbgStore[index].vp != NULL) {
-                      switch (VopDbgStore[index].inState)
-                        {
-                          case VOPDBG_LOCKED:
-                          case VOPDBG_LOCKNOTNIL:
-                              if (VopDbgStore[index].inValue == 0)
-                                {
-                                  PRINTIT ("%s: %d Entry: not LOCKED:", funcname, index); DBG_VOP(("\n"));
-                                }
-                              break;
-                          case VOPDBG_UNLOCKED:
-                              if (VopDbgStore[index].inValue != 0)
-                                {
-                                  PRINTIT ("%s: %d Entry: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
-                                }
-                              break;
-                        }
-                  }
-                  break;
-              }
-            default:
-                PRINTIT ("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname, VopDbgStore[index].errState);
-          }
-
-
-        if (retval != 0)
-          {
-            switch (VopDbgStore[index].errState)
-              {
-                case VOPDBG_IGNORE:
-                    /* Do Nothing !!! */
-                    break;
-                case VOPDBG_LOCKED:
-                case VOPDBG_UNLOCKED:
-                case VOPDBG_SAME:
-                  {
-                      if (VopDbgStore[index].vp == NULL) {
-                          PRINTIT ("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname, index);
-                      } else {
-                          VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
-                          switch (VopDbgStore[index].errState)
-                            {
-                              case VOPDBG_LOCKED:
-                                  if (VopDbgStore[index].outValue == 0)
-                                    {
-                                      PRINTIT ("%s: %d Error: not LOCKED:", funcname, index); DBG_VOP(("\n"));
-                                    }
-                                  break;
-                              case VOPDBG_UNLOCKED:
-                                  if (VopDbgStore[index].outValue != 0)
-                                    {
-                                      PRINTIT ("%s: %d Error: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
-                                    }
-                                  break;
-                              case VOPDBG_SAME:
-                                  if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
-                                      PRINTIT ("%s: Error: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue);
-                                  break;
-                            }
-                      }
-                      break;
-                  }
-                case VOPDBG_LOCKNOTNIL:
-                    if (VopDbgStore[index].vp != NULL) {
-                    VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
-                        if (VopDbgStore[index].outValue == 0)
-                            PRINTIT ("%s: Error: %d Not LOCKED: 0x%x\n", funcname, index, (u_int)VopDbgStore[index].vp);
-                    }
-                    break;
-                default:
-                    PRINTIT ("%s: Error: bad lock test value: %d\n", funcname, VopDbgStore[index].errState);
-              }
-          }
-        else
-          {
-            switch (VopDbgStore[index].outState)
-              {
-                case VOPDBG_IGNORE:
-                    /* Do Nothing !!! */
-                    break;
-                case VOPDBG_LOCKED:
-                case VOPDBG_UNLOCKED:
-                case VOPDBG_SAME:
-                    if (VopDbgStore[index].vp == NULL) {
-                        PRINTIT ("%s: OutState: Null vnode ptr in entry #%d\n", funcname, index);
-                    };
-                    if (VopDbgStore[index].vp != NULL)
-                      {
-                    VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
-                        switch (VopDbgStore[index].outState)
-                          {
-                            case VOPDBG_LOCKED:
-                                if (VopDbgStore[index].outValue == 0)
-                                  {
-                                    PRINTIT ("%s: %d Out: not LOCKED:", funcname, index); DBG_VOP(("\n"));
-                                  }
-                                break;
-                            case VOPDBG_UNLOCKED:
-                                if (VopDbgStore[index].outValue != 0)
-                                  {
-                                    PRINTIT ("%s: %d Out: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
-                                  }
-                                break;
-                            case VOPDBG_SAME:
-                                if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
-                                    PRINTIT ("%s: Out: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue);
-                                break;
-                          }
-                      }
-                    break;
-                case VOPDBG_LOCKNOTNIL:
-                    if (VopDbgStore[index].vp != NULL) {
-                    if (&((struct volfs_vndata *)(VopDbgStore[index].vp->v_data))->lock == NULL)
-                            PRINTIT ("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname, (u_int)VopDbgStore[index].vp);
-                        else {
-                        VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
-                            if (VopDbgStore[index].outValue == 0)
-                              {
-                                PRINTIT ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname); DBG_VOP(("\n"));
-                              }
-                        }
-                    }
-                    break;
-                default:
-                    PRINTIT ("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname, VopDbgStore[index].outState);
-              }
-          }
-
-        VopDbgStore[index].id = -1;            /* Invalidate the entry to allow panic-free re-use */
-      }        
+       return (ret_err);
 }
 
-#endif /* DBG_VOP_TEST_LOCKS */
-