BSD CMs: Don't call nonexistent afs_FlushVS in afs_vop_reclaim
[openafs.git] / src / afs / NBSD / osi_vnodeops.c
index af8e71d..56c42a3 100644 (file)
 /*
- * Copyright 2000, International Business Machines Corporation and others.
- * All Rights Reserved.
- * 
- * This software has been released under the terms of the IBM Public
- * License.  For details, see the LICENSE file in the top-level source
- * directory or online at http://www.openafs.org/dl/license10.html
+ * OpenBSD specific vnodeops + other misc interface glue
+ * Original NetBSD version for Transarc afs by John Kohl <jtk@MIT.EDU>
+ * OpenBSD version by Jim Rees <rees@umich.edu>
+ *
+ * $Id: osi_vnodeops.c,v 1.20 2006/03/09 15:27:17 rees Exp $
  */
 
 /*
- * vnodeops structure and Digital Unix specific ops and support routines.
+copyright 2002
+the regents of the university of michigan
+all rights reserved
+
+permission is granted to use, copy, create derivative works
+and redistribute this software and such derivative works
+for any purpose, so long as the name of the university of
+michigan is not used in any advertising or publicity
+pertaining to the use or distribution of this software
+without specific, written prior authorization.  if the
+above copyright notice or any other identification of the
+university of michigan is included in any copy of any
+portion of this software, then the disclaimer below must
+also be included.
+
+this software is provided as is, without representation
+from the university of michigan as to its fitness for any
+purpose, and without warranty by the university of
+michigan of any kind, either express or implied, including
+without limitation the implied warranties of
+merchantability and fitness for a particular purpose. the
+regents of the university of michigan shall not be liable
+for any damages, including special, indirect, incidental, or
+consequential damages, with respect to any claim arising
+out of or in connection with the use of the software, even
+if it has been or is hereafter advised of the possibility of
+such damages.
+*/
+
+/*
+Copyright 1995 Massachusetts Institute of Technology.  All Rights
+Reserved.
+
+You are hereby granted a worldwide, irrevocable, paid-up, right and
+license to use, execute, display, modify, copy and distribute MIT's
+Modifications, provided that (i) you abide by the terms and conditions
+of your OpenAFS License Agreement, and (ii) you do not use the name
+of MIT in any advertising or publicity without the prior written consent
+of MIT.  MIT disclaims all liability for your use of MIT's
+Modifications.  MIT's Modifications are provided "AS IS" WITHOUT
+WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO,
+ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT.
+*/
+
+/*
+ * A bunch of code cribbed from NetBSD ufs_vnops.c, ffs_vnops.c, and
+ * nfs_vnops.c which carry this copyright:
+ */
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
  */
 
 #include <afsconfig.h>
 #include "afs/param.h"
 
-RCSID
-    ("$Header$");
 
 
 #include "afs/sysincludes.h"   /* Standard vendor system headers */
-#include "afsincludes.h"       /* Afs-based standard headers */
+#include "afs/afsincludes.h"   /* Afs-based standard headers */
 #include "afs/afs_stats.h"     /* statistics */
-#include <vm/vm.h>
-#include <vm/vnode_pager.h>
-#include <vm/vm_map.h>
-/* #include <vm/vm_ubc.h> */
+
+#include <sys/malloc.h>
+#include <sys/namei.h>
+#include <sys/pool.h>
+#include <miscfs/genfs/genfs.h>
+
+
 #include "afs/afs_cbqueue.h"
 #include "afs/nfsclient.h"
 #include "afs/afs_osidnlc.h"
 
+#define M_AFSNODE (M_TEMP-1)   /* XXX */
+
+int afs_nbsd_lookup(void *);
+int afs_nbsd_create(void *);
+int afs_nbsd_mknod(void *);
+int afs_nbsd_open(void *);
+int afs_nbsd_close(void *);
+int afs_nbsd_access(void *);
+int afs_nbsd_getattr(void *);
+int afs_nbsd_setattr(void *);
+int afs_nbsd_read(void *);
+int afs_nbsd_write(void *);
+int afs_nbsd_ioctl(void *);
+int afs_nbsd_select(void *);
+int afs_nbsd_fsync(void *);
+int afs_nbsd_remove(void *);
+int afs_nbsd_link(void *);
+int afs_nbsd_rename(void *);
+int afs_nbsd_mkdir(void *);
+int afs_nbsd_rmdir(void *);
+int afs_nbsd_symlink(void *);
+int afs_nbsd_readdir(void *);
+int afs_nbsd_readlink(void *);
+int afs_nbsd_inactive(void *);
+int afs_nbsd_reclaim(void *);
+int afs_nbsd_lock(void *);
+int afs_nbsd_unlock(void *);
+int afs_nbsd_bmap(void *);
+int afs_nbsd_strategy(void *);
+int afs_nbsd_print(void *);
+int afs_nbsd_islocked(void *);
+int afs_nbsd_pathconf(void *);
+int afs_nbsd_advlock(void *);
+
+#if LATER
+int afs_nbsd_getpages(void*);
+#endif
 
-extern int afs_lookup(), afs_create(), afs_noop(), afs_open(), afs_close();
-extern int afs_access(), afs_getattr(), afs_setattr(), afs_badop();
-extern int afs_fsync(), afs_seek(), afs_remove(), afs_link(), afs_rename();
-extern int afs_mkdir(), afs_rmdir(), afs_symlink(), afs_readdir();
-extern int afs_readlink(), afs_lockctl();
-extern int vn_pathconf_default(), seltrue();
-
-int mp_afs_lookup(), mp_afs_create(), mp_afs_open();
-int mp_afs_access(), mp_afs_getattr(), mp_afs_setattr(), mp_afs_ubcrdwr();
-int mp_afs_ubcrdwr(), mp_afs_mmap();
-int mp_afs_fsync(), mp_afs_seek(), mp_afs_remove(), mp_afs_link();
-int mp_afs_rename(), mp_afs_mkdir(), mp_afs_rmdir(), mp_afs_symlink();
-int mp_afs_readdir(), mp_afs_readlink(), mp_afs_abortop(), mp_afs_inactive();
-int mp_afs_reclaim(), mp_afs_bmap(), mp_afs_strategy(), mp_afs_print();
-int mp_afs_page_read(), mp_afs_page_write(), mp_afs_swap(), mp_afs_bread();
-int mp_afs_brelse(), mp_afs_lockctl(), mp_afs_syncdata(), mp_afs_close();
-int mp_afs_closex();
+/*
+ * Implement:
+ *   vop_getpages (VM)
+ *   vop_putpages (VM)
+ *
+ * Someday:
+ *   vop_mmap_desc (mmap'd IO)
+ *
+ * Skip:
+ *   vop_*xtattr
+ *
+ * Unknown:
+ *   vop_fcntl
+ *
+ */
 
+#define afs_nbsd_opnotsupp \
+       ((int (*) __P((void *)))eopnotsupp)
+#define afs_nbsd_reallocblks afs_nbsd_opnotsupp
+
+/* Global vfs data structures for AFS. */
+int (**afs_vnodeop_p) __P((void *));
+struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
+    {&vop_default_desc, vn_default_error},
+    {&vop_lookup_desc, afs_nbsd_lookup},       /* lookup */
+    {&vop_create_desc, afs_nbsd_create},       /* create */
+    {&vop_mknod_desc, afs_nbsd_mknod},         /* mknod */
+    {&vop_open_desc, afs_nbsd_open},           /* open */
+    {&vop_close_desc, afs_nbsd_close},         /* close */
+    {&vop_access_desc, afs_nbsd_access},       /* access */
+    {&vop_getattr_desc, afs_nbsd_getattr},     /* getattr */
+    {&vop_setattr_desc, afs_nbsd_setattr},     /* setattr */
+    {&vop_read_desc, afs_nbsd_read},           /* read */
+    {&vop_write_desc, afs_nbsd_write},         /* write */
+    {&vop_ioctl_desc, afs_nbsd_ioctl},         /* XXX ioctl */
+    {&vop_poll_desc, afs_nbsd_select},         /* select */
+    {&vop_kqfilter_desc, genfs_kqfilter },     /* kqfilter */
+    {&vop_fsync_desc, afs_nbsd_fsync},         /* fsync */
+    {&vop_remove_desc, afs_nbsd_remove},       /* remove */
+    {&vop_link_desc, afs_nbsd_link},           /* link */
+    {&vop_rename_desc, afs_nbsd_rename},       /* rename */
+    {&vop_mkdir_desc, afs_nbsd_mkdir},         /* mkdir */
+    {&vop_rmdir_desc, afs_nbsd_rmdir},         /* rmdir */
+    {&vop_symlink_desc, afs_nbsd_symlink},     /* symlink */
+    {&vop_readdir_desc, afs_nbsd_readdir},     /* readdir */
+    {&vop_readlink_desc, afs_nbsd_readlink},   /* readlink */
+    {&vop_abortop_desc, genfs_abortop},                /* abortop */
+    {&vop_inactive_desc, afs_nbsd_inactive},   /* inactive */
+    {&vop_reclaim_desc, afs_nbsd_reclaim},     /* reclaim */
+    {&vop_lock_desc, afs_nbsd_lock},           /* lock */
+    {&vop_unlock_desc, afs_nbsd_unlock},       /* unlock */
+    {&vop_bmap_desc, afs_nbsd_bmap},           /* bmap */
+    {&vop_strategy_desc, afs_nbsd_strategy},   /* strategy */
+    {&vop_print_desc, afs_nbsd_print},         /* print */
+    {&vop_islocked_desc, afs_nbsd_islocked},   /* islocked */
+    {&vop_pathconf_desc, afs_nbsd_pathconf},   /* pathconf */
+    {&vop_advlock_desc, afs_nbsd_advlock},     /* advlock */
 #if 0
-/* AFS vnodeops */
-struct vnodeops Afs_vnodeops = {
-    mp_afs_lookup,
-    mp_afs_create,
-    afs_noop,                  /* vn_mknod */
-    mp_afs_open,
-    mp_afs_close,
-    mp_afs_access,
-    mp_afs_getattr,
-    mp_afs_setattr,
-    mp_afs_ubcrdwr,
-    mp_afs_ubcrdwr,
-    afs_badop,                 /* vn_ioctl */
-    seltrue,                   /* vn_select */
-    mp_afs_mmap,
-    mp_afs_fsync,
-    mp_afs_seek,
-    mp_afs_remove,
-    mp_afs_link,
-    mp_afs_rename,
-    mp_afs_mkdir,
-    mp_afs_rmdir,
-    mp_afs_symlink,
-    mp_afs_readdir,
-    mp_afs_readlink,
-    mp_afs_abortop,
-    mp_afs_inactive,
-    mp_afs_reclaim,
-    mp_afs_bmap,
-    mp_afs_strategy,
-    mp_afs_print,
-    mp_afs_page_read,
-    mp_afs_page_write,
-    mp_afs_swap,
-    mp_afs_bread,
-    mp_afs_brelse,
-    mp_afs_lockctl,
-    mp_afs_syncdata,
-    afs_noop,                  /* Lock */
-    afs_noop,                  /* unLock */
-    afs_noop,                  /* get ext attrs */
-    afs_noop,                  /* set ext attrs */
-    afs_noop,                  /* del ext attrs */
-    vn_pathconf_default,
-};
-struct vnodeops *afs_ops = &Afs_vnodeops;
-#endif /* 0 */
-
-/* vnode file operations, and our own */
-extern int vn_read();
-extern int vn_write();
-extern int vn_ioctl();
-extern int vn_select();
-extern int afs_closex();
-
-struct fileops afs_fileops = {
-    vn_read,
-    vn_write,
-    vn_ioctl,
-    vn_select,
-    mp_afs_closex,
+    {&vop_reallocblks_desc, afs_nbsd_reallocblks},     /* reallocblks */
+#endif
+    {&vop_bwrite_desc, vn_bwrite},     /* bwrite */
+#if LATER
+    { &vop_getpages_desc, ffs_getpages },       /* getpages */
+    { &vop_putpages_desc, genfs_putpages },    /* putpages */
+#endif
+    {(struct vnodeop_desc *)NULL, (int (*)__P((void *)))NULL}
 };
-
-#if 0
-mp_afs_lookup(adp, ndp)
-     struct vcache *adp;
-     struct nameidata *ndp;
+struct vnodeopv_desc afs_vnodeop_opv_desc =
+    { &afs_vnodeop_p, afs_vnodeop_entries };
+
+#define GETNAME() \
+    struct componentname *cnp = ap->a_cnp; \
+    char *name; \
+    name = PNBUF_GET();        \
+    bcopy(cnp->cn_nameptr, name, cnp->cn_namelen); \
+    name[cnp->cn_namelen] = '\0'
+
+#define DROPNAME() PNBUF_PUT(name)
+#define DROPCNP PNBUF_PUT
+
+/* toss "stale" pages by shrinking the vnode uobj to a 0-length
+ * region (see uvm_vnp_setsize in uvm_vnode.c) */
+#define VNP_UNCACHE(vp) \
+    do {               \
+       struct uvm_object *uobj = &vp->v_uobj; \
+       simple_lock(&uobj->vmobjlock); \
+       VOP_PUTPAGES( (struct vnode *) uobj, 0 /* offlo */, 0 /* offhi */, PGO_FREE | PGO_SYNCIO); \
+       simple_unlock(&uobj->vmobjlock); \
+    } while(0);
+
+/* psuedo-vnop, wherein we learn that obsd and nbsd disagree
+ * about vnode refcounting */
+void
+afs_nbsd_getnewvnode(struct vcache *tvc)
 {
-    int code;
-    AFS_GLOCK();
-    code = afs_lookup(adp, ndp);
-    AFS_GUNLOCK();
-    return code;
+    while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &tvc->v)) {
+       /* no vnodes available, force an alloc (limits be damned)! */
+       desiredvnodes++;
+    }
+    afs_warn("afs_nbsd_getnewvnode: vp %lx refs %d (soon to be 1)\n", tvc->v,
+            tvc->v->v_usecount);
+    simple_lock(&tvc->v->v_interlock);
+    tvc->v->v_data = (void *)tvc;
+    tvc->v->v_usecount = 1; /* !locked, and vref w/v_usecount < 1 panics */
+    simple_unlock(&tvc->v->v_interlock);
 }
 
-mp_afs_create(ndp, attrs)
-     struct nameidata *ndp;
-     struct vattr *attrs;
-{
-    int code;
-    AFS_GLOCK();
-    code = afs_create(ndp, attrs);
-    AFS_GUNLOCK();
-    return code;
-}
+int afs_debug;
 
-mp_afs_open(avcp, aflags, acred)
-     struct vcache **avcp;
-     afs_int32 aflags;
-     struct AFS_UCRED *acred;
+int
+afs_nbsd_lookup(void *v)
 {
+    struct vop_lookup_args     /* {
+                                * struct vnodeop_desc * a_desc;
+                                * struct vnode *a_dvp;
+                                * struct vnode **a_vpp;
+                                * struct componentname *a_cnp;
+                                * } */ *ap = v;
     int code;
+    struct vcache *vcp;
+    struct vnode *vp, *dvp;
+    int flags = ap->a_cnp->cn_flags;
+    int lockparent;            /* 1 => lockparent flag is set */
+
+    afs_warn("afs_nbsd_lookup enter\n");
+
+    GETNAME();
+    lockparent = flags & LOCKPARENT;
+    if (ap->a_dvp->v_type != VDIR) {
+       *ap->a_vpp = NULL;
+       DROPNAME();
+       return ENOTDIR;
+    }
+    dvp = ap->a_dvp;
+    if (afs_debug & AFSDEB_VNLAYER && !(dvp->v_flag & VROOT))
+       printf("nbsd_lookup dvp %p flags %x name %s cnt %d\n", dvp, flags,
+              name, dvp->v_usecount);
     AFS_GLOCK();
-    code = afs_open(avcp, aflags, acred);
+    code = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
     AFS_GUNLOCK();
+    if (code) {
+       if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
+           && (flags & ISLASTCN) && code == ENOENT)
+           code = EJUSTRETURN;
+       if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
+           cnp->cn_flags |= SAVENAME;
+       DROPNAME();
+       *ap->a_vpp = NULL;
+       return (code);
+    }
+    vp = AFSTOV(vcp);          /* always get a node if no error */
+
+    /*
+     * The parent directory comes in locked.  We unlock it on return
+     * unless the caller wants it left locked.
+     * we also always return the vnode locked.
+     */
+
+    if (vp == dvp) {
+       /* they're the same; afs_lookup() already ref'ed the leaf.
+        * It came in locked, so we don't need to ref OR lock it */
+       if (afs_debug & AFSDEB_VNLAYER)
+           printf("ref'ed %p as .\n", dvp);
+    } else {
+       if (!lockparent || !(flags & ISLASTCN)) {
+           VOP_UNLOCK(dvp, 0); /* done with parent. */
+       }
+
+       simple_lock(&vp->v_interlock);
+       vp->v_usecount = (vp->v_usecount < 1) ? 1 : (vp->v_usecount+1);
+       simple_unlock(&vp->v_interlock);
+       if (!VOP_ISLOCKED(vp)) {
+           vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+           afs_warn("h2\n");
+           /* vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); *//* always return the child locked */
+       } else {
+           afs_warn("lookup: vp %lx is locked\n", vp);
+       }
+       afs_warn("lookup: after islocked\n");
+       if (afs_debug & AFSDEB_VNLAYER)
+           printf("locked ret %p from lookup\n", vp);
+    }
+    *ap->a_vpp = vp;
+
+    if (((cnp->cn_nameiop == RENAME && (flags & ISLASTCN))
+        || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
+       cnp->cn_flags |= SAVENAME;
+
+    DROPNAME();
+    if (afs_debug & AFSDEB_VNLAYER && !(dvp->v_flag & VROOT))
+       printf("nbsd_lookup done dvp %p cnt %d\n", dvp, dvp->v_usecount);
     return code;
 }
 
-mp_afs_access(avc, amode, acred)
-     struct vcache *avc;
-     afs_int32 amode;
-     struct AFS_UCRED *acred;
+int
+afs_nbsd_create(void *v)
 {
-    int code;
+    struct vop_create_args     /* {
+                                * struct vnode *a_dvp;
+                                * struct vnode **a_vpp;
+                                * struct componentname *a_cnp;
+                                * struct vattr *a_vap;
+                                * } */ *ap = v;
+    int code = 0;
+    struct vcache *vcp;
+    struct vnode *dvp = ap->a_dvp;
+    GETNAME();
+
+    if (afs_debug & AFSDEB_VNLAYER)
+       printf("nbsd_create dvp %p cnt %d\n", dvp, dvp->v_usecount);
+
+    /* vnode layer handles excl/nonexcl */
+
     AFS_GLOCK();
-    code = afs_access(avc, amode, acred);
+    code =
+       afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
+                  &vcp, cnp->cn_cred);
     AFS_GUNLOCK();
+    if (code) {
+       VOP_ABORTOP(dvp, cnp);
+       vput(dvp);
+       DROPNAME();
+       return (code);
+    }
+
+    if (vcp) {
+       *ap->a_vpp = AFSTOV(vcp);
+       vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY);
+    } else
+       *ap->a_vpp = 0;
+
+    if ((cnp->cn_flags & SAVESTART) == 0)
+       DROPCNP(cnp);
+    vput(dvp);
+    DROPNAME();
+    if (afs_debug & AFSDEB_VNLAYER)
+       printf("nbsd_create done dvp %p cnt %d\n", dvp, dvp->v_usecount);
     return code;
 }
 
-mp_afs_close(avc, flags, cred)
-     struct vnode *avc;
-     int flags;
-     struct ucred *cred;
+int
+afs_nbsd_mknod(void *v)
 {
-    int code;
-    AFS_GLOCK();
-    code = afs_close(avc, flags, cred);
-    AFS_GUNLOCK();
-    return code;
+    struct vop_mknod_args      /* {
+                                * struct vnode *a_dvp;
+                                * struct vnode **a_vpp;
+                                * struct componentname *a_cnp;
+                                * struct vattr *a_vap;
+                                * } */ *ap = v;
+    DROPCNP(ap->a_cnp);
+    vput(ap->a_dvp);
+    return (ENODEV);
 }
 
-mp_afs_getattr(avc, attrs, acred)
-     struct vcache *avc;
-     struct vattr *attrs;
-     struct AFS_UCRED *acred;
+int
+afs_nbsd_open(void *v)
 {
+    struct vop_open_args       /* {
+                                * struct vnode *a_vp;
+                                * int  a_mode;
+                                * struct ucred *a_cred;
+                                * struct lwp *a_l;
+                                * } */ *ap = v;
     int code;
+    struct vcache *vc = VTOAFS(ap->a_vp);
+
     AFS_GLOCK();
-    code = afs_getattr(avc, attrs, acred);
+    code = afs_open(&vc, ap->a_mode, ap->a_cred);
+#ifdef DIAGNOSTIC
+    if (AFSTOV(vc) != ap->a_vp)
+       panic("AFS open changed vnode!");
+#endif
     AFS_GUNLOCK();
     return code;
 }
 
-mp_afs_setattr(avc, attrs, acred)
-     struct vcache *avc;
-     struct vattr *attrs;
-     struct AFS_UCRED *acred;
+int
+afs_nbsd_close(void *v)
 {
+    struct vop_close_args      /* {
+                                * struct vnode *a_vp;
+                                * int  a_fflag;
+                                * kauth_cred_t a_cred;
+                                * struct lwp *a_l;
+                                * } */ *ap = v;
     int code;
+
     AFS_GLOCK();
-    code = afs_setattr(avc, attrs, acred);
+    code = afs_close(VTOAFS(ap->a_vp), ap->a_fflag, ap->a_cred);
     AFS_GUNLOCK();
     return code;
 }
 
-mp_afs_fsync(avc, fflags, acred, waitfor)
-     struct vcache *avc;
-     int fflags;
-     struct AFS_UCRED *acred;
-     int waitfor;
+int
+afs_nbsd_access(void *v)
 {
+    struct vop_access_args     /* {
+                                * struct vnode *a_vp;
+                                * int  a_mode;
+                                * kauth_cred_t a_cred;
+                                * struct lwp *a_l;
+                                * } */ *ap = v;
     int code;
+
     AFS_GLOCK();
-    code = afs_fsync(avc, fflags, acred, waitfor);
+    code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
     AFS_GUNLOCK();
     return code;
 }
 
-mp_afs_remove(ndp)
-     struct nameidata *ndp;
+int
+afs_nbsd_getattr(void *v)
 {
+    struct vop_getattr_args    /* {
+                                * struct vnode *a_vp;
+                                * struct vattr *a_vap;
+                                * kauth_cred_t a_cred;
+                                * struct lwp *a_l;
+                                * } */ *ap = v;
     int code;
+
     AFS_GLOCK();
-    code = afs_remove(ndp);
+    code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
     AFS_GUNLOCK();
     return code;
 }
 
-mp_afs_link(avc, ndp)
-     struct vcache *avc;
-     struct nameidata *ndp;
+int
+afs_nbsd_setattr(void *v)
 {
+    struct vop_setattr_args    /* {
+                                * struct vnode *a_vp;
+                                * struct vattr *a_vap;
+                                * kauth_cred_t a_cred;
+                                * struct lwp *a_l;
+                                * } */ *ap = v;
     int code;
+
     AFS_GLOCK();
-    code = afs_link(avc, ndp);
+    code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
     AFS_GUNLOCK();
     return code;
 }
 
-mp_afs_rename(fndp, tndp)
-     struct nameidata *fndp, *tndp;
+int
+afs_nbsd_read(void *v)
 {
+    struct vop_read_args       /* {
+                                * struct vnode *a_vp;
+                                * struct uio *a_uio;
+                                * int a_ioflag;
+                                * kauth_cred_t a_cred;
+                                * } */ *ap = v;
     int code;
+
     AFS_GLOCK();
-    code = afs_rename(fndp, tndp);
+    code =
+       afs_read(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, (daddr_t) 0, NULL,
+                0);
     AFS_GUNLOCK();
     return code;
 }
 
-mp_afs_mkdir(ndp, attrs)
-     struct nameidata *ndp;
-     struct vattr *attrs;
+int
+afs_nbsd_write(void *v)
 {
+    struct vop_write_args      /* {
+                                * struct vnode *a_vp;
+                                * struct uio *a_uio;
+                                * int a_ioflag;
+                                * kauth_cred_t a_cred;
+                                * } */ *ap = v;
     int code;
+
+#if 1
+    /* all pages are really "stale?" */
+    VNP_UNCACHE(ap->a_vp);
+#else
+    (void)uvm_vnp_uncache(ap->a_vp);   /* toss stale pages */
+#endif
     AFS_GLOCK();
-    code = afs_mkdir(ndp, attrs);
+    code =
+       afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
     AFS_GUNLOCK();
     return code;
 }
 
-mp_afs_rmdir(ndp)
-     struct nameidata *ndp;
+int
+afs_nbsd_ioctl(void *v)
 {
+    struct vop_ioctl_args      /* {
+                                * struct vnode *a_vp;
+                                * int  a_command;
+                                * caddr_t  a_data;
+                                * int  a_fflag;
+                                * kauth_cred_t a_cred;
+                                * struct lwp *a_l;
+                                * } */ *ap = v;
     int code;
+
+    /* in case we ever get in here... */
+
+    AFS_STATCNT(afs_ioctl);
     AFS_GLOCK();
-    code = afs_rmdir(ndp);
+    if (((ap->a_command >> 8) & 0xff) == 'V')
+       /* This is a VICEIOCTL call */
+       code =
+           HandleIoctl(VTOAFS(ap->a_vp), ap->a_command,
+                       (struct afs_ioctl *)ap->a_data);
+    else
+       /* No-op call; just return. */
+       code = ENOTTY;
     AFS_GUNLOCK();
     return code;
 }
 
-mp_afs_symlink(ndp, attrs, atargetName)
-     struct nameidata *ndp;
-     struct vattr *attrs;
-     register char *atargetName;
+int
+afs_nbsd_select(void *v)
 {
-    int code;
-    AFS_GLOCK();
-    code = afs_symlink(ndp, attrs, atargetName);
-    AFS_GUNLOCK();
-    return code;
+    return 1;
 }
 
-mp_afs_readdir(avc, auio, acred, eofp)
-     struct vcache *avc;
-     struct uio *auio;
-     struct AFS_UCRED *acred;
-     int *eofp;
+int
+afs_nbsd_fsync(void *v)
 {
-    int code;
+    struct vop_fsync_args      /* {
+                                * struct vnode *a_vp;
+                                * kauth_cred_t a_cred;
+                                * int a_waitfor;
+                                * struct lwp *a_l;
+                                * } */ *ap = v;
+    struct vnode *vp = ap->a_vp;
+    int code, wait;
+
+    wait = (ap->a_flags & FSYNC_WAIT) != 0;
+
     AFS_GLOCK();
-    code = afs_readdir(avc, auio, acred, eofp);
+    vflushbuf(vp, wait);
+    code = afs_fsync(VTOAFS(vp), ap->a_cred);
     AFS_GUNLOCK();
+
     return code;
 }
 
-mp_afs_readlink(avc, auio, acred)
-     struct vcache *avc;
-     struct uio *auio;
-     struct AFS_UCRED *acred;
+int
+afs_nbsd_remove(void *v)
 {
+    struct vop_remove_args     /* {
+                                * struct vnode *a_dvp;
+                                * struct vnode *a_vp;
+                                * struct componentname *a_cnp;
+                                * } */ *ap = v;
     int code;
+    struct vnode *vp = ap->a_vp;
+    struct vnode *dvp = ap->a_dvp;
+
+    GETNAME();
     AFS_GLOCK();
-    code = afs_readlink(avc, auio, acred);
+    code = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
     AFS_GUNLOCK();
+    if (dvp == vp)
+       vrele(vp);
+    else
+       vput(vp);
+    vput(dvp);
+    DROPCNP(cnp);
+    DROPNAME();
     return code;
 }
 
-mp_afs_lockctl(avc, af, flag, acred, clid, offset)
-     struct vcache *avc;
-     struct eflock *af;
-     struct AFS_UCRED *acred;
-     int flag;
-     pid_t clid;
-     off_t offset;
+int
+afs_nbsd_link(void *v)
 {
+    struct vop_link_args       /* {
+                                * struct vnode *a_vp;
+                                * struct vnode *a_tdvp;
+                                * struct componentname *a_cnp;
+                                * } */ *ap = v;
     int code;
+    struct vnode *dvp = ap->a_dvp;
+    struct vnode *vp = ap->a_vp;
+
+    GETNAME();
+    if (dvp->v_mount != vp->v_mount) {
+       VOP_ABORTOP(vp, cnp);
+       code = EXDEV;
+       goto out;
+    }
+    if (vp->v_type == VDIR) {
+       VOP_ABORTOP(vp, cnp);
+       code = EISDIR;
+       goto out;
+    }
+    if ((code = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY))) {
+       VOP_ABORTOP(dvp, cnp);
+       goto out;
+    }
+
     AFS_GLOCK();
-    code = afs_lockctl(avc, af, flag, acred, clid, offset);
+    code = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
     AFS_GUNLOCK();
+    DROPCNP(cnp);
+    if (dvp != vp)
+       VOP_UNLOCK(vp, 0);
+
+  out:
+    vput(dvp);
+    DROPNAME();
     return code;
 }
 
-mp_afs_closex(afd)
-     struct file *afd;
+int
+afs_nbsd_rename(void *v)
 {
-    int code;
+    struct vop_rename_args     /* {
+                                * struct vnode *a_fdvp;
+                                * struct vnode *a_fvp;
+                                * struct componentname *a_fcnp;
+                                * struct vnode *a_tdvp;
+                                * struct vnode *a_tvp;
+                                * struct componentname *a_tcnp;
+                                * } */ *ap = v;
+    int code = 0;
+    struct componentname *fcnp = ap->a_fcnp;
+    char *fname;
+    struct componentname *tcnp = ap->a_tcnp;
+    char *tname;
+    struct vnode *tvp = ap->a_tvp;
+    struct vnode *tdvp = ap->a_tdvp;
+    struct vnode *fvp = ap->a_fvp;
+    struct vnode *fdvp = ap->a_fdvp;
+
+    /*
+     * Check for cross-device rename.
+     */
+    if ((fvp->v_mount != tdvp->v_mount)
+       || (tvp && (fvp->v_mount != tvp->v_mount))) {
+       code = EXDEV;
+      abortit:
+       VOP_ABORTOP(tdvp, tcnp);        /* XXX, why not in NFS? */
+       if (tdvp == tvp)
+           vrele(tdvp);
+       else
+           vput(tdvp);
+       if (tvp)
+           vput(tvp);
+       VOP_ABORTOP(fdvp, fcnp);        /* XXX, why not in NFS? */
+       vrele(fdvp);
+       vrele(fvp);
+       return (code);
+    }
+    /*
+     * if fvp == tvp, we're just removing one name of a pair of
+     * directory entries for the same element.  convert call into rename.
+     ( (pinched from NetBSD 1.0's ufs_rename())
+     */
+    if (fvp == tvp) {
+       if (fvp->v_type == VDIR) {
+           code = EINVAL;
+           goto abortit;
+       }
+
+       /* Release destination completely. */
+       VOP_ABORTOP(tdvp, tcnp);
+       vput(tdvp);
+       vput(tvp);
+
+       /* Delete source. */
+       vrele(fdvp);
+       vrele(fvp);
+       fcnp->cn_flags &= ~MODMASK;
+       fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
+       if ((fcnp->cn_flags & SAVESTART) == 0)
+           panic("afs_rename: lost from startdir");
+       fcnp->cn_nameiop = DELETE;
+       (void)relookup(fdvp, &fvp, fcnp);
+       return (VOP_REMOVE(fdvp, fvp, fcnp));
+    }
+
+    if ((code = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY)))
+       goto abortit;
+
+    /* XXX GETNAME() ? */
+    MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
+    bcopy(fcnp->cn_nameptr, fname, fcnp->cn_namelen);
+    fname[fcnp->cn_namelen] = '\0';
+    MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
+    bcopy(tcnp->cn_nameptr, tname, tcnp->cn_namelen);
+    tname[tcnp->cn_namelen] = '\0';
+
+
     AFS_GLOCK();
-    code = afs_closex(afd);
+    /* XXX use "from" or "to" creds? NFS uses "to" creds */
+    code =
+       afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname,
+                  tcnp->cn_cred);
     AFS_GUNLOCK();
-    return code;
-}
 
-mp_afs_seek(avc, oldoff, newoff, cred)
-     struct vcache *avc;
-     off_t oldoff, newoff;
-     struct ucred *cred;
-{
-    if ((int)newoff < 0)
-       return (EINVAL);
+    VOP_UNLOCK(fvp, 0);
+    FREE(fname, M_TEMP);
+    FREE(tname, M_TEMP);
+    if (code)
+       goto abortit;           /* XXX */
+    if (tdvp == tvp)
+       vrele(tdvp);
     else
-       return (0);
+       vput(tdvp);
+    if (tvp)
+       vput(tvp);
+    vrele(fdvp);
+    vrele(fvp);
+    return code;
 }
 
-mp_afs_abortop(ndp)
-     struct nameidata *ndp;
+int
+afs_nbsd_mkdir(void *v)
 {
-    return (0);
-}
+    struct vop_mkdir_args      /* {
+                                * struct vnode *a_dvp;
+                                * struct vnode **a_vpp;
+                                * struct componentname *a_cnp;
+                                * struct vattr *a_vap;
+                                * } */ *ap = v;
+    struct vnode *dvp = ap->a_dvp;
+    struct vattr *vap = ap->a_vap;
+    int code;
+    struct vcache *vcp;
 
-mp_afs_inactive(avc, acred)
-     register struct vcache *avc;
-     struct AFS_UCRED *acred;
-{
+    GETNAME();
+#ifdef DIAGNOSTIC
+    if ((cnp->cn_flags & HASBUF) == 0)
+       panic("afs_nbsd_mkdir: no name");
+#endif
     AFS_GLOCK();
-    afs_InactiveVCache(avc, acred);
+    code = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
     AFS_GUNLOCK();
+    if (code) {
+       VOP_ABORTOP(dvp, cnp);
+       vput(dvp);
+       DROPNAME();
+       return (code);
+    }
+    if (vcp) {
+       *ap->a_vpp = AFSTOV(vcp);
+       vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY);
+    } else
+       *ap->a_vpp = 0;
+    DROPCNP(cnp);
+    DROPNAME();
+    vput(dvp);
+    return code;
 }
 
-
-mp_afs_reclaim(avc)
-     struct vcache *avc;
-{
-    return (0);
-}
-
-mp_afs_print(avc)
-     struct vcache *avc;
-{
-    return (0);
-}
-
-mp_afs_page_read(avc, uio, acred)
-     struct vcache *avc;
-     struct uio *uio;
-     struct ucred *acred;
+int
+afs_nbsd_rmdir(void *v)
 {
-    int error;
-    struct vrequest treq;
+    struct vop_rmdir_args      /* {
+                                * struct vnode *a_dvp;
+                                * struct vnode *a_vp;
+                                * struct componentname *a_cnp;
+                                * } */ *ap = v;
+    int code;
+    struct vnode *vp = ap->a_vp;
+    struct vnode *dvp = ap->a_dvp;
+
+    GETNAME();
+    if (dvp == vp) {
+       vrele(dvp);
+       vput(vp);
+       DROPCNP(cnp);
+       DROPNAME();
+       return (EINVAL);
+    }
 
     AFS_GLOCK();
-    error = afs_rdwr(avc, uio, UIO_READ, 0, acred);
-    afs_Trace3(afs_iclSetp, CM_TRACE_PAGE_READ, ICL_TYPE_POINTER, avc,
-              ICL_TYPE_INT32, error, ICL_TYPE_INT32, avc->f.states);
-    if (error) {
-       error = EIO;
-    } else if ((avc->f.states) == 0) {
-       afs_InitReq(&treq, acred);
-       ObtainWriteLock(&avc->lock, 161);
-       afs_Wire(avc, &treq);
-       ReleaseWriteLock(&avc->lock);
-    }
+    code = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
     AFS_GUNLOCK();
-    return (error);
+    DROPNAME();
+    vput(dvp);
+    vput(vp);
+    return code;
 }
 
-
-mp_afs_page_write(avc, uio, acred, pager, offset)
-     struct vcache *avc;
-     struct uio *uio;
-     struct ucred *acred;
-     memory_object_t pager;
-     vm_offset_t offset;
+int
+afs_nbsd_symlink(void *v)
 {
-    int error;
+    struct vop_symlink_args    /* {
+                                * struct vnode *a_dvp;
+                                * struct vnode **a_vpp;
+                                * struct componentname *a_cnp;
+                                * struct vattr *a_vap;
+                                * char *a_target;
+                                * } */ *ap = v;
+    struct vnode *dvp = ap->a_dvp;
+    int code;
+    /* NFS ignores a_vpp; so do we. */
 
+    GETNAME();
     AFS_GLOCK();
-    error = afs_rdwr(avc, uio, UIO_WRITE, 0, acred);
-    afs_Trace3(afs_iclSetp, CM_TRACE_PAGE_WRITE, ICL_TYPE_POINTER, avc,
-              ICL_TYPE_INT32, error, ICL_TYPE_INT32, avc->f.states);
-    if (error) {
-       error = EIO;
-    }
+    code =
+       afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target,
+                   cnp->cn_cred);
     AFS_GUNLOCK();
-    return (error);
+    DROPCNP(cnp);
+    DROPNAME();
+    vput(dvp);
+    return code;
 }
 
-
-int DO_FLUSH = 1;
-mp_afs_ubcrdwr(avc, uio, ioflag, cred)
-     struct vcache *avc;
-     struct uio *uio;
-     int ioflag;
-     struct ucred *cred;
+int
+afs_nbsd_readdir(void *v)
 {
-    register afs_int32 code;
-    register char *data;
-    afs_int32 fileBase, size, cnt = 0;
-    afs_int32 pageBase;
-    register afs_int32 tsize;
-    register afs_int32 pageOffset;
-    int eof;
-    struct vrequest treq;
-    int rw = uio->uio_rw;
-    int rv, flags;
-    int newpage = 0;
-    vm_page_t page;
-    afs_int32 save_resid;
-    struct dcache *tdc;
-    int didFakeOpen = 0;
-    int counter = 0;
+    struct vop_readdir_args    /* {
+                                * struct vnode *a_vp;
+                                * struct uio *a_uio;
+                                * kauth_cred_t a_cred;
+                                * int *a_eofflag;
+                                * int *a_ncookies;
+                                * u_long **a_cookies;
+                                * } */ *ap = v;
+    int code;
 
     AFS_GLOCK();
-    afs_InitReq(&treq, cred);
-    if (AFS_NFSXLATORREQ(cred) && rw == UIO_READ) {
-       if (!afs_AccessOK
-           (avc, PRSFS_READ, &treq,
-            CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
-           AFS_GUNLOCK();
-           return EACCES;
-       }
-    }
-    afs_Trace4(afs_iclSetp, CM_TRACE_VMRW, ICL_TYPE_POINTER, avc,
-              ICL_TYPE_INT32, (rw == UIO_WRITE ? 1 : 0), ICL_TYPE_LONG,
-              uio->uio_offset, ICL_TYPE_LONG, uio->uio_resid);
-    code = afs_VerifyVCache(avc, &treq);
-    if (code) {
-       code = afs_CheckCode(code, &treq, 35);
-       AFS_GUNLOCK();
-       return code;
-    }
-    if (vType(avc) != VREG) {
-       AFS_GUNLOCK();
-       return EISDIR;          /* can't read or write other things */
-    }
-    osi_FlushPages(avc);       /* hold bozon lock, but not basic vnode lock */
-    ObtainWriteLock(&avc->lock, 162);
-    /* adjust parameters when appending files */
-    if ((ioflag & IO_APPEND) && uio->uio_rw == UIO_WRITE)
-       uio->uio_offset = avc->f.m.Length;      /* write at EOF position */
-    if (uio->uio_rw == UIO_WRITE) {
-       avc->f.states |= CDirty;
-       afs_FakeOpen(avc);
-       didFakeOpen = 1;
-       /*
-        * before starting any I/O, we must ensure that the file is big enough
-        * to hold the results (since afs_putpage will be called to force
-        * the I/O.
-        */
-       size = uio->afsio_resid + uio->afsio_offset;    /* new file size */
-       if (size > avc->f.m.Length)
-           avc->f.m.Length = size;     /* file grew */
-       avc->f.m.Date = osi_Time();     /* Set file date (for ranlib) */
-       if (uio->afsio_resid > PAGE_SIZE)
-           cnt = uio->afsio_resid / PAGE_SIZE;
-       save_resid = uio->afsio_resid;
-    }
-
-    while (1) {
-       /*
-        * compute the amount of data to move into this block,
-        * based on uio->afsio_resid.
-        */
-       size = uio->afsio_resid;        /* transfer size */
-       fileBase = uio->afsio_offset;   /* start file position */
-       pageBase = fileBase & ~(PAGE_SIZE - 1); /* file position of the page */
-       pageOffset = fileBase & (PAGE_SIZE - 1);        /* start offset within page */
-       tsize = PAGE_SIZE - pageOffset; /* amount left in this page */
-       /*
-        * we'll read tsize bytes,
-        * but first must make sure tsize isn't too big
-        */
-       if (tsize > size)
-           tsize = size;       /* don't read past end of request */
-       eof = 0;                /* flag telling us if we hit the EOF on the read */
-       if (uio->uio_rw == UIO_READ) {  /* we're doing a read operation */
-           /* don't read past EOF */
-           if (tsize + fileBase > avc->f.m.Length) {
-               tsize = avc->f.m.Length - fileBase;
-               eof = 1;        /* we did hit the EOF */
-               if (tsize < 0)
-                   tsize = 0;  /* better safe than sorry */
-           }
-       }
-       if (tsize <= 0)
-           break;              /* nothing to transfer, we're done */
-
-       /* Purge dirty chunks of file if there are too many dirty chunks.
-        * Inside the write loop, we only do this at a chunk boundary.
-        * Clean up partial chunk if necessary at end of loop.
-        */
-       if (uio->uio_rw == UIO_WRITE && counter > 0
-           && AFS_CHUNKOFFSET(fileBase) == 0) {
-           code = afs_DoPartialWrite(avc, &treq);
-           avc->f.states |= CDirty;
-       }
-
-       if (code) {
-           break;
-       }
-
-       flags = 0;
-       ReleaseWriteLock(&avc->lock);
-       AFS_GUNLOCK();
-       code =
-           ubc_lookup(((struct vnode *)avc)->v_object, pageBase, PAGE_SIZE,
-                      PAGE_SIZE, &page, &flags);
-       AFS_GLOCK();
-       ObtainWriteLock(&avc->lock, 163);
-
-       if (code) {
-           break;
-       }
-       if (flags & B_NOCACHE) {
-           /*
-            * No page found. We should not read the page in if
-            * 1. the write starts on a page edge (ie, pageoffset == 0)
-            * and either
-            * 1. we will fill the page  (ie, size == PAGESIZE), or
-            * 2. we are writing past eof
-            */
-           if ((uio->uio_rw == UIO_WRITE)
-               &&
-               ((pageOffset == 0
-                 && (size == PAGE_SIZE || fileBase >= avc->f.m.Length)))) {
-               struct vnode *vp = (struct vnode *)avc;
-               /* we're doing a write operation past eof; no need to read it */
-               newpage = 1;
-               AFS_GUNLOCK();
-               ubc_page_zero(page, 0, PAGE_SIZE);
-               ubc_page_release(page, B_DONE);
-               AFS_GLOCK();
-           } else {
-               /* page wasn't cached, read it in. */
-               struct buf *bp;
-
-               AFS_GUNLOCK();
-               bp = ubc_bufalloc(page, 1, PAGE_SIZE, 1, B_READ);
-               AFS_GLOCK();
-               bp->b_dev = 0;
-               bp->b_vp = (struct vnode *)avc;
-               bp->b_blkno = btodb(pageBase);
-               ReleaseWriteLock(&avc->lock);
-               code = afs_ustrategy(bp, cred); /* do the I/O */
-               ObtainWriteLock(&avc->lock, 164);
-               AFS_GUNLOCK();
-               ubc_sync_iodone(bp);
-               AFS_GLOCK();
-               if (code) {
-                   AFS_GUNLOCK();
-                   ubc_page_release(page, 0);
-                   AFS_GLOCK();
-                   break;
-               }
-           }
-       }
-       AFS_GUNLOCK();
-       ubc_page_wait(page);
-       data = (char *)page->pg_addr;   /* DUX 4.0D */
-       if (data == 0)
-           data = (char *)PHYS_TO_KSEG(page->pg_phys_addr);    /* DUX 4.0E */
-       AFS_GLOCK();
-       ReleaseWriteLock(&avc->lock);   /* uiomove may page fault */
-       AFS_GUNLOCK();
-       code = uiomove(data + pageOffset, tsize, uio);
-       ubc_unload(page, pageOffset, page_size);
-       if (uio->uio_rw == UIO_WRITE) {
-           vm_offset_t toffset;
-
-           /* Mark the page dirty and release it to avoid a deadlock
-            * in ubc_dirty_kluster when more than one process writes
-            * this page at the same time. */
-           toffset = page->pg_offset;
-           flags |= B_DIRTY;
-           ubc_page_release(page, flags);
-
-           if (cnt > 10) {
-               vm_page_t pl;
-               int kpcnt;
-               struct buf *bp;
-
-               /* We released the page, so we can get a null page
-                * list if another thread calls the strategy routine.
-                */
-               pl = ubc_dirty_kluster(((struct vnode *)avc)->v_object, NULL,
-                                      toffset, 0, B_WANTED, FALSE, &kpcnt);
-               if (pl) {
-                   bp = ubc_bufalloc(pl, 1, PAGE_SIZE, 1, B_WRITE);
-                   bp->b_dev = 0;
-                   bp->b_vp = (struct vnode *)avc;
-                   bp->b_blkno = btodb(pageBase);
-                   AFS_GLOCK();
-                   code = afs_ustrategy(bp, cred);     /* do the I/O */
-                   AFS_GUNLOCK();
-                   ubc_sync_iodone(bp);
-                   if (code) {
-                       AFS_GLOCK();
-                       ObtainWriteLock(&avc->lock, 415);
-                       break;
-                   }
-               }
-           }
-       } else {
-           ubc_page_release(page, flags);
-       }
-       AFS_GLOCK();
-       ObtainWriteLock(&avc->lock, 165);
-       /*
-        * If reading at a chunk boundary, start prefetch of next chunk.
-        */
-       if (uio->uio_rw == UIO_READ
-           && (counter == 0 || AFS_CHUNKOFFSET(fileBase) == 0)) {
-           tdc = afs_FindDCache(avc, fileBase);
-           if (tdc) {
-               if (!(tdc->mflags & DFNextStarted))
-                   afs_PrefetchChunk(avc, tdc, cred, &treq);
-               afs_PutDCache(tdc);
-           }
-       }
-       counter++;
-       if (code)
-           break;
-    }
-    if (didFakeOpen)
-       afs_FakeClose(avc, cred);
-    if (uio->uio_rw == UIO_WRITE && code == 0 && (avc->f.states & CDirty)) {
-       code = afs_DoPartialWrite(avc, &treq);
-    }
-    ReleaseWriteLock(&avc->lock);
-    if (DO_FLUSH || (!newpage && (cnt < 10))) {
-       AFS_GUNLOCK();
-       ubc_flush_dirty(((struct vnode *)avc)->v_object, flags);
-       AFS_GLOCK();
-    }
-
-    ObtainSharedLock(&avc->lock, 409);
-    if (!code) {
-       if (avc->vc_error) {
-           code = avc->vc_error;
-       }
-    }
-    /* This is required since we may still have dirty pages after the write.
-     * I could just let close do the right thing, but stat's before the close
-     * return the wrong length.
-     */
-    if (code == EDQUOT || code == ENOSPC) {
-       uio->uio_resid = save_resid;
-       UpgradeSToWLock(&avc->lock, 410);
-       osi_ReleaseVM(avc, cred);
-       ConvertWToSLock(&avc->lock);
-    }
-    ReleaseSharedLock(&avc->lock);
-
-    if (!code && (ioflag & IO_SYNC) && (uio->uio_rw == UIO_WRITE)
-       && !AFS_NFSXLATORREQ(cred)) {
-       code = afs_fsync(avc, 0, cred, 0);
-    }
-  out:
-    code = afs_CheckCode(code, &treq, 36);
+#ifdef AFS_HAVE_COOKIES
+    printf("readdir %p cookies %p ncookies %d\n", ap->a_vp, ap->a_cookies,
+          ap->a_ncookies);
+    code =
+       afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag,
+                   ap->a_ncookies, ap->a_cookies);
+#else
+    code =
+       afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
+#endif
     AFS_GUNLOCK();
     return code;
 }
 
-
-/*
- * Now for some bad news.  Since we artificially hold on to vnodes by doing
- * and extra VNHOLD in afs_NewVCache(), there is no way for us to know
- * when we need to flush the pages when a program exits.  Particularly
- * if it closes the file after mapping it R/W.
- *
- */
-
-mp_afs_mmap(avc, offset, map, addrp, len, prot, maxprot, flags, cred)
-     register struct vcache *avc;
-     vm_offset_t offset;
-     vm_map_t map;
-     vm_offset_t *addrp;
-     vm_size_t len;
-     vm_prot_t prot;
-     vm_prot_t maxprot;
-     int flags;
-     struct ucred *cred;
+int
+afs_nbsd_readlink(void *v)
 {
-    struct vp_mmap_args args;
-    register struct vp_mmap_args *ap = &args;
-    struct vnode *vp = (struct vnode *)avc;
+    struct vop_readlink_args   /* {
+                                * struct vnode *a_vp;
+                                * struct uio *a_uio;
+                                * kauth_cred_t a_cred;
+                                * } */ *ap = v;
     int code;
-    struct vrequest treq;
-#if    !defined(DYNEL)
-    extern kern_return_t u_vp_create();
-#endif
 
     AFS_GLOCK();
-    afs_InitReq(&treq, cred);
-    code = afs_VerifyVCache(avc, &treq);
-    if (code) {
-       code = afs_CheckCode(code, &treq, 37);
-       AFS_GUNLOCK();
-       return code;
-    }
-    osi_FlushPages(avc);       /* ensure old pages are gone */
-    ObtainWriteLock(&avc->lock, 166);
-    avc->f.states |= CMAPPED;
-    ReleaseWriteLock(&avc->lock);
-    ap->a_offset = offset;
-    ap->a_vaddr = addrp;
-    ap->a_size = len;
-    ap->a_prot = prot, ap->a_maxprot = maxprot;
-    ap->a_flags = flags;
-    AFS_GUNLOCK();
-    code = u_vp_create(map, vp->v_object, (vm_offset_t) ap);
-    AFS_GLOCK();
-    code = afs_CheckCode(code, &treq, 38);
+    code = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
     AFS_GUNLOCK();
     return code;
 }
 
+extern int prtactive;
 
 int
-mp_afs_getpage(vop, offset, len, protp, pl, plsz, mape, addr, rw, cred)
-     vm_ubc_object_t vop;
-     vm_offset_t offset;
-     vm_size_t len;
-     vm_prot_t *protp;
-     vm_page_t *pl;
-     int plsz;
-     vm_map_entry_t mape;
-     vm_offset_t addr;
-     int rw;
-     struct ucred *cred;
+afs_nbsd_inactive(void *v)
 {
-    register afs_int32 code;
-    struct vrequest treq;
-    int flags = 0;
-    int i, pages = (len + PAGE_SIZE - 1) >> page_shift;
-    vm_page_t *pagep;
-    vm_offset_t off;
+    struct vop_inactive_args   /* {
+                                * struct vnode *a_vp;
+                                * } */ *ap = v;
+    struct vnode *vp = ap->a_vp;
+    struct vcache *vc = VTOAFS(vp);
+    int haveGlock = ISAFS_GLOCK();
 
-    struct vcache *avc = VTOAFS(vop->vu_vp);
+    AFS_STATCNT(afs_inactive);
 
-    /* first, obtain the proper lock for the VM system */
+    if (prtactive && vp->v_usecount != 0)
+       vprint("afs_nbsd_inactive(): pushing active", vp);
 
-    AFS_GLOCK();
-    afs_InitReq(&treq, cred);
-    code = afs_VerifyVCache(avc, &treq);
-    if (code) {
-       *pl = VM_PAGE_NULL;
-       code = afs_CheckCode(code, &treq, 39);  /* failed to get it */
+    if (!haveGlock)
+       AFS_GLOCK();
+    afs_InactiveVCache(vc, 0); /* decrs ref counts */
+    if (!haveGlock)
        AFS_GUNLOCK();
-       return code;
-    }
 
-    /* clean all dirty pages for this vnode */
-    AFS_GUNLOCK();
-    ubc_flush_dirty(vop, 0);
-    AFS_GLOCK();
-
-    ObtainWriteLock(&avc->lock, 167);
-    afs_Trace4(afs_iclSetp, CM_TRACE_PAGEIN, ICL_TYPE_POINTER, avc,
-              ICL_TYPE_LONG, offset, ICL_TYPE_LONG, len, ICL_TYPE_INT32,
-              (int)rw);
-    for (i = 0; i < pages; i++) {
-       pagep = &pl[i];
-       off = offset + PAGE_SIZE * i;
-       if (protp)
-           protp[i] = 0;
-       flags = 0;
-       ReleaseWriteLock(&avc->lock);
-       AFS_GUNLOCK();
-       code =
-           ubc_lookup(((struct vnode *)avc)->v_object, off, PAGE_SIZE,
-                      PAGE_SIZE, pagep, &flags);
-       AFS_GLOCK();
-       ObtainWriteLock(&avc->lock, 168);
-       if (code) {
-           goto out;
-       }
-       if (flags & B_NOCACHE) {        /* if (page) */
-           if ((rw & B_WRITE) && (offset + len >= avc->f.m.Length)) {
-               struct vnode *vp = (struct vnode *)avc;
-               /* we're doing a write operation past eof; no need to read it */
-               AFS_GUNLOCK();
-               ubc_page_zero(*pagep, 0, PAGE_SIZE);
-               ubc_page_release(*pagep, B_DONE);
-               AFS_GLOCK();
-           } else {
-               /* page wasn't cached, read it in. */
-               struct buf *bp;
-
-               AFS_GUNLOCK();
-               bp = ubc_bufalloc(*pagep, 1, PAGE_SIZE, 1, B_READ);
-               AFS_GLOCK();
-               bp->b_dev = 0;
-               bp->b_vp = (struct vnode *)avc;
-               bp->b_blkno = btodb(off);
-               ReleaseWriteLock(&avc->lock);
-               code = afs_ustrategy(bp, cred); /* do the I/O */
-               ObtainWriteLock(&avc->lock, 169);
-               AFS_GUNLOCK();
-               ubc_sync_iodone(bp);
-               AFS_GLOCK();
-               if (code) {
-                   AFS_GUNLOCK();
-                   ubc_page_release(pl[i], 0);
-                   AFS_GLOCK();
-                   goto out;
-               }
-           }
-       }
-       if ((rw & B_READ) == 0) {
-           AFS_GUNLOCK();
-           ubc_page_dirty(pl[i]);
-           AFS_GLOCK();
-       } else {
-           if (protp && (flags & B_DIRTY) == 0) {
-               protp[i] = VM_PROT_WRITE;
-           }
-       }
-    }
-  out:
-    pl[i] = VM_PAGE_NULL;
-    ReleaseWriteLock(&avc->lock);
-    afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_INT32, code,
-              ICL_TYPE_POINTER, *pagep, ICL_TYPE_INT32, flags);
-    code = afs_CheckCode(code, &treq, 40);
-    AFS_GUNLOCK();
-    return code;
+    lockinit(&vc->rwlock, PINOD, "vcache", 0, 0);
+    return 0;
 }
 
-
 int
-mp_afs_putpage(vop, pl, pcnt, flags, cred)
-     vm_ubc_object_t vop;
-     vm_page_t *pl;
-     int pcnt;
-     int flags;
-     struct ucred *cred;
+afs_nbsd_reclaim(void *v)
 {
-    register afs_int32 code = 0;
-    struct vcache *avc = VTOAFS(vop->vu_vp);
-    struct vnode *vp = (struct vnode *)avc;
-    int i;
-
-    AFS_GLOCK();
-    afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUT, ICL_TYPE_POINTER, avc,
-              ICL_TYPE_INT32, pcnt, ICL_TYPE_INT32, vp->v_flag,
-              ICL_TYPE_INT32, flags);
-    if (flags & B_UBC) {
-       AFS_GUNLOCK();
-       VN_LOCK(vp);
-       if (vp->v_flag & VXLOCK) {
-           VN_UNLOCK(vp);
-           for (i = 0; i < pcnt; i++) {
-               ubc_page_release(pl[i], B_DONE | B_DIRTY);
-               pl[i] = VM_PAGE_NULL;
-           }
-           return (0);
-       } else {
-           VN_UNLOCK(vp);
-       }
-       AFS_GLOCK();
-    }
-
-    /* first, obtain the proper lock for the VM system */
-    ObtainWriteLock(&avc->lock, 170);
-    for (i = 0; i < pcnt; i++) {
-       vm_page_t page = pl[i];
-       struct buf *bp;
+    struct vop_reclaim_args    /* {
+                                * struct vnode *a_vp;
+                                * } */ *ap = v;
+    int code, slept;
+    struct vnode *vp = ap->a_vp;
+    struct vcache *avc = VTOAFS(vp);
+    int haveGlock = ISAFS_GLOCK();
+    int haveVlock = CheckLock(&afs_xvcache);
 
-       /* write it out */
-       AFS_GUNLOCK();
-       bp = ubc_bufalloc(page, 1, PAGE_SIZE, 1, B_WRITE);
+#if 0
+    printf("reclaim usecount %d\n", vp->v_usecount);
+    /* OK, there are no internal vrefCounts, so there shouldn't
+     * be any more refs here. */
+    vp->v_data = NULL;         /* remove from vnode */
+    avc->v = NULL;             /* also drop the ptr to vnode */
+    return 0;
+#else
+    if (!haveGlock)
        AFS_GLOCK();
-       bp->b_dev = 0;
-       bp->b_vp = (struct vnode *)avc;
-       bp->b_blkno = btodb(page->pg_offset);
-       ReleaseWriteLock(&avc->lock);
-       code = afs_ustrategy(bp, cred); /* do the I/O */
-       ObtainWriteLock(&avc->lock, 171);
+    if (!haveVlock)
+       ObtainWriteLock(&afs_xvcache, 901);
+    /* reclaim the vnode and the in-memory vcache, but keep the on-disk vcache */
+    code = afs_FlushVCache(avc, &slept);
+    if (!haveVlock)
+       ReleaseWriteLock(&afs_xvcache);
+    if (!haveGlock)
        AFS_GUNLOCK();
-       ubc_sync_iodone(bp);
-       AFS_GLOCK();
-       if (code) {
-           goto done;
-       } else {
-           pl[i] = VM_PAGE_NULL;
-       }
-    }
-  done:
-    ReleaseWriteLock(&avc->lock);
-    afs_Trace2(afs_iclSetp, CM_TRACE_PAGEOUTDONE, ICL_TYPE_INT32, code,
-              ICL_TYPE_INT32, avc->f.m.Length);
-    AFS_GUNLOCK();
     return code;
+#endif
 }
 
-
 int
-mp_afs_swap(avc, swapop, argp)
-     struct vcache *avc;
-     vp_swap_op_t swapop;
-     vm_offset_t argp;
+afs_nbsd_lock(void *v)
 {
-    return EIO;
+    struct vop_lock_args       /* {
+                                * struct vnode *a_vp;
+                                * int a_flags;
+                                * struct lwp *a_l;
+                                * } */ *ap = v;
+
+    return (genfs_lock(v));
 }
 
 int
-mp_afs_syncdata(avc, flag, offset, length, cred)
-     struct vcache *avc;
-     int flag;
-     vm_offset_t offset;
-     vm_size_t length;
-     struct ucred *cred;
+afs_nbsd_unlock(void *v)
 {
-    /* NFS V3 makes this call, ignore it. We'll sync the data in afs_fsync. */
-    if (AFS_NFSXLATORREQ(cred))
-       return 0;
-    else
-       return EINVAL;
-}
+    struct vop_unlock_args     /* {
+                                * struct vnode *a_vp;
+                                * int a_flags;
+                                * struct lwp *a_l;
+                                * } */ *ap = v;
 
-/* a freelist of one */
-struct buf *afs_bread_freebp = 0;
+    return (genfs_unlock(v));
+}
 
-/*
- *  Only rfs_read calls this, and it only looks at bp->b_un.b_addr.
- *  Thus we can use fake bufs (ie not from the real buffer pool).
- */
-mp_afs_bread(vp, lbn, bpp, cred)
-     struct ucred *cred;
-     struct vnode *vp;
-     daddr_t lbn;
-     struct buf **bpp;
+int
+afs_nbsd_bmap(void *v)
 {
-    int offset, fsbsize, error;
-    struct buf *bp;
-    struct iovec iov;
-    struct uio uio;
+    struct vop_bmap_args       /* {
+                                * struct vnode *a_vp;
+                                * daddr_t  a_bn;
+                                * struct vnode **a_vpp;
+                                * daddr_t *a_bnp;
+                                * int *a_runp;
+                                * } */ *ap = v;
+    struct vcache *vcp = VTOAFS(ap->a_vp);
 
-    AFS_GLOCK();
-    AFS_STATCNT(afs_bread);
-    fsbsize = vp->v_vfsp->vfs_bsize;
-    offset = lbn * fsbsize;
-    if (afs_bread_freebp) {
-       bp = afs_bread_freebp;
-       afs_bread_freebp = 0;
-    } else {
-       bp = (struct buf *)AFS_KALLOC(sizeof(*bp));
-       bp->b_un.b_addr = (caddr_t) AFS_KALLOC(fsbsize);
-    }
+    AFS_STATCNT(afs_bmap);
 
-    iov.iov_base = bp->b_un.b_addr;
-    iov.iov_len = fsbsize;
-    uio.afsio_iov = &iov;
-    uio.afsio_iovcnt = 1;
-    uio.afsio_seg = AFS_UIOSYS;
-    uio.afsio_offset = offset;
-    uio.afsio_resid = fsbsize;
-    *bpp = 0;
-    error = afs_read(VTOAFS(vp), &uio, cred, lbn, bpp, 0);
-    if (error) {
-       afs_bread_freebp = bp;
-       AFS_GUNLOCK();
-       return error;
+    /* borrowed from DARWIN--why notyet? */
+    if (ap->a_bnp) {
+       *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
     }
-    if (*bpp) {
-       afs_bread_freebp = bp;
-    } else {
-       *(struct buf **)&bp->b_vp = bp; /* mark as fake */
-       *bpp = bp;
+    if (ap->a_vpp) {
+       *ap->a_vpp = ap->a_vp;
     }
-    AFS_GUNLOCK();
-    return 0;
-}
-
+    if (ap->a_runp != NULL)
+       *ap->a_runp = 0;
+#ifdef notyet
+    if (ap->a_runb != NULL)
+       *ap->a_runb = 0;
+#endif
 
-mp_afs_brelse(vp, bp)
-     struct vnode *vp;
-     struct buf *bp;
-{
-    AFS_GLOCK();
-    AFS_STATCNT(afs_brelse);
-    if ((struct buf *)bp->b_vp != bp) {        /* not fake */
-       brelse(bp);
-    } else if (afs_bread_freebp) {
-       AFS_KFREE(bp->b_un.b_addr, vp->v_vfsp->vfs_bsize);
-       AFS_KFREE(bp, sizeof(*bp));
-    } else {
-       afs_bread_freebp = bp;
-    }
-    AFS_GUNLOCK();
+    return 0;
 }
 
-
-mp_afs_bmap(avc, abn, anvp, anbn)
-     register struct vcache *avc;
-     afs_int32 abn, *anbn;
-     struct vcache **anvp;
+int
+afs_nbsd_strategy(void *v)
 {
-    AFS_GLOCK();
-    AFS_STATCNT(afs_bmap);
-    if (anvp)
-       *anvp = avc;
-    if (anbn)
-       *anbn = abn * (8192 / DEV_BSIZE);       /* in 512 byte units */
-    AFS_GUNLOCK();
-    return 0;
-}
+    struct vop_strategy_args   /* {
+                                * struct buf *a_bp;
+                                * } */ *ap = v;
+    struct buf *abp = ap->a_bp;
+    struct uio tuio;
+    struct iovec tiovec[1];
+    struct vcache *tvc = VTOAFS(abp->b_vp);
+    afs_ucred_t credp = osi_curcred();
+    long len = abp->b_bcount;
+    int code;
 
+    AFS_STATCNT(afs_strategy);
 
-/* real strategy */
-mp_afs_strategy(abp)
-     register struct buf *abp;
-{
-    register afs_int32 code;
+    tuio.afsio_iov = tiovec;
+    tuio.afsio_iovcnt = 1;
+    tuio.afsio_resid = len;
+    tiovec[0].iov_base = abp->b_un.b_addr;
+    tiovec[0].iov_len = len;
+    UIO_SETUP_SYSSPACE(&tuio);
 
     AFS_GLOCK();
-    AFS_STATCNT(afs_strategy);
-    code = afs_osi_MapStrategy(afs_ustrategy, abp);
+    if ((abp->b_flags & B_READ) == B_READ) {
+       code = afs_rdwr(tvc, &tuio, UIO_READ, 0, credp);
+       if (code == 0 && tuio.afsio_resid > 0)
+           bzero(abp->b_un.b_addr + len - tuio.afsio_resid,
+                 tuio.afsio_resid);
+    } else
+       code = afs_rdwr(tvc, &tuio, UIO_WRITE, 0, credp);
     AFS_GUNLOCK();
+
+    ReleaseWriteLock(&tvc->lock);
+    AFS_RELE(AFSTOV(tvc));
     return code;
 }
 
-
-mp_afs_refer(vm_ubc_object_t vop)
+int
+afs_nbsd_print(void *v)
 {
-    VREF(vop->vu_vp);
+    struct vop_print_args      /* {
+                                * struct vnode *a_vp;
+                                * } */ *ap = v;
+    struct vnode *vp = ap->a_vp;
+    struct vcache *vc = VTOAFS(ap->a_vp);
+
+    printf("tag %d, fid: %d.%x.%x.%x, ", vp->v_tag, vc->f.fid.Cell,
+          (int)vc->f.fid.Fid.Volume, (int)vc->f.fid.Fid.Vnode,
+          (int)vc->f.fid.Fid.Unique);
+    lockmgr_printinfo(&vc->rwlock);
+    printf("\n");
+    return 0;
 }
 
-
-mp_afs_release(vm_ubc_object_t vop)
+int
+afs_nbsd_islocked(void *v)
 {
-    vrele(vop->vu_vp);
+    struct vop_islocked_args   /* {
+                                * struct vnode *a_vp;
+                                * } */ *ap = v;
+    return (genfs_islocked(v));
 }
 
-
-mp_afs_write_check(vm_ubc_object_t vop, vm_page_t pp)
+/*
+ * Return POSIX pathconf information applicable to ufs filesystems.
+ */
+int
+afs_nbsd_pathconf(void *v)
 {
-    return TRUE;
+    struct vop_pathconf_args   /* {
+                                * struct vnode *a_vp;
+                                * int a_name;
+                                * int *a_retval;
+                                * } */ *ap = v;
+    AFS_STATCNT(afs_cntl);
+    switch (ap->a_name) {
+    case _PC_LINK_MAX:
+       *ap->a_retval = LINK_MAX;
+       break;
+    case _PC_NAME_MAX:
+       *ap->a_retval = NAME_MAX;
+       break;
+    case _PC_PATH_MAX:
+       *ap->a_retval = PATH_MAX;
+       break;
+    case _PC_CHOWN_RESTRICTED:
+       *ap->a_retval = 1;
+       break;
+    case _PC_NO_TRUNC:
+       *ap->a_retval = 1;
+       break;
+    case _PC_PIPE_BUF:
+       return EINVAL;
+       break;
+    default:
+       return EINVAL;
+    }
+    return 0;
 }
 
-
-
-struct vfs_ubcops afs_ubcops = {
-    mp_afs_refer,              /* refer vnode */
-    mp_afs_release,            /* release vnode */
-    mp_afs_getpage,            /* get page */
-    mp_afs_putpage,            /* put page */
-    mp_afs_write_check,                /* check writablity */
-};
-#endif /* 0 */
+extern int
+  afs_lockctl(struct vcache *avc, struct AFS_FLOCK *af, int acmd,
+             afs_ucred_t *acred, pid_t clid);
 
 /*
- * Cover function for lookup name using OSF equivalent, namei()
- *
- * Note, the result vnode (ni_vp) in the namei data structure is remains
- * locked after return.
+ * Advisory record locking support (fcntl() POSIX style)
  */
-lookupname(namep, seg, follow, dvpp, cvpp)
-     char *namep;              /* path name */
-     int seg;                  /* address space containing name */
-     int follow;               /* follow symbolic links */
-     struct vnode **dvpp;      /* result, containing parent vnode */
-     struct vnode **cvpp;      /* result, containing final component vnode */
+int
+afs_nbsd_advlock(void *v)
 {
-    /* Should I use free-bee in u-area? */
-    struct nameidata *ndp = &u.u_nd;
-    int error;
-
-    ndp->ni_nameiop = ((follow) ? (LOOKUP | FOLLOW) : (LOOKUP));
-    ndp->ni_segflg = seg;
-    ndp->ni_dirp = namep;
-    error = namei(ndp);
-    if (dvpp != NULL)
-       *dvpp = ndp->ni_dvp;
-    if (cvpp != NULL)
-       *cvpp = ndp->ni_vp;
-    return (error);
+    struct vop_advlock_args    /* {
+                                * struct vnode *a_vp;
+                                * caddr_t  a_id;
+                                * int  a_op;
+                                * struct flock *a_fl;
+                                * int  a_flags;
+                                * } */ *ap = v;
+    int code;
+
+    AFS_GLOCK();
+    code =
+       afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, osi_curcred(),
+                   (int)ap->a_id);
+    AFS_GUNLOCK();
+    return code;
 }