summaryrefslogtreecommitdiff
path: root/sys/nnpfs/nnpfs_node-bsd.c
diff options
context:
space:
mode:
authorJanne Johansson <jj@cvs.openbsd.org>2009-06-03 14:45:57 +0000
committerJanne Johansson <jj@cvs.openbsd.org>2009-06-03 14:45:57 +0000
commitea9bbf428f51194a52c45ac274c35dba174a741c (patch)
tree301aa894fd92a097d769b8cac575c8a0fce07329 /sys/nnpfs/nnpfs_node-bsd.c
parent0c52879fa54117b2bd312fe5fff17f310dbdb7eb (diff)
Arla client rename from xfs to nnpfs for later upgrades. Tested on various arches. ok todd@ beck@
Diffstat (limited to 'sys/nnpfs/nnpfs_node-bsd.c')
-rw-r--r--sys/nnpfs/nnpfs_node-bsd.c801
1 files changed, 801 insertions, 0 deletions
diff --git a/sys/nnpfs/nnpfs_node-bsd.c b/sys/nnpfs/nnpfs_node-bsd.c
new file mode 100644
index 00000000000..1f6ace40860
--- /dev/null
+++ b/sys/nnpfs/nnpfs_node-bsd.c
@@ -0,0 +1,801 @@
+/*
+ * Copyright (c) 1995 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * 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. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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 <sys/queue.h>
+#include <nnpfs/nnpfs_locl.h>
+#include <nnpfs/nnpfs_common.h>
+#include <nnpfs/nnpfs_fs.h>
+#include <nnpfs/nnpfs_deb.h>
+#include <nnpfs/nnpfs_vnodeops.h>
+
+RCSID("$arla: nnpfs_node-bsd.c,v 1.70 2003/02/28 02:01:06 lha Exp $");
+
+extern vop_t **nnpfs_vnodeop_p;
+
+#ifndef LK_NOPAUSE
+#define LK_NOPAUSE 0
+#endif
+
+/*
+ * Allocate a new vnode with handle `handle' in `mp' and return it in
+ * `vpp'. Return 0 or error.
+ */
+
+int
+nnpfs_getnewvnode(struct nnpfs *nnpfsp, struct vnode **vpp,
+ struct nnpfs_handle *handle)
+{
+ struct nnpfs_node *result, *check;
+ int error;
+
+ error = getnewvnode(VT_NNPFS, NNPFS_TO_VFS(nnpfsp), nnpfs_vnodeop_p, vpp);
+ if (error)
+ return error;
+
+ result = nnpfs_alloc(sizeof(*result), M_NNPFS_NODE);
+ bzero(result, sizeof(*result));
+
+ (*vpp)->v_data = result;
+ result->vn = *vpp;
+
+ result->handle = *handle;
+ result->flags = 0;
+ result->tokens = 0;
+ result->offset = 0;
+#if defined(HAVE_KERNEL_LOCKMGR) || defined(HAVE_KERNEL_DEBUGLOCKMGR)
+ lockinit (&result->lock, PVFS, "nnpfs_lock", 0, LK_NOPAUSE);
+#else
+ result->vnlocks = 0;
+#endif
+ result->anonrights = 0;
+ result->rd_cred = NULL;
+ result->wr_cred = NULL;
+
+#if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 105280000
+ genfs_node_init(*vpp, &nnpfs_genfsops);
+#endif
+
+ check = nnpfs_node_find(&nnpfsp->nodehead, handle);
+ if (check) {
+ vput(*vpp);
+ *vpp = result->vn;
+ return 0;
+ }
+
+ nnpfs_insert(&nnpfs->nodehead, result);
+
+ return 0;
+}
+
+/*
+ * Create a new nnpfs_node and make a vget
+ *
+ * Also prevents creation of duplicates. This happens
+ * whenever there are more than one name to a file,
+ * "." and ".." are common cases. */
+
+int
+new_nnpfs_node(struct nnpfs *nnpfsp,
+ struct nnpfs_msg_node *node,
+ struct nnpfs_node **xpp,
+ d_thread_t *p)
+{
+ struct nnpfs_node *result;
+
+ NNPFSDEB(XDEBNODE, ("new_nnpfs_node (%d,%d,%d,%d)\n",
+ node->handle.a,
+ node->handle.b,
+ node->handle.c,
+ node->handle.d));
+
+retry:
+ /* Does not allow duplicates */
+ result = nnpfs_node_find(&nnpfsp->nodehead, &node->handle);
+ if (result == 0) {
+ int error;
+ struct vnode *v;
+
+ error = nnpfs_getnewvnode(nnpfsp, &v, &node->handle);
+ if (error)
+ return error;
+
+ result = VNODE_TO_XNODE(v);
+ result->anonrights = node->anonrights;
+
+ nnpfsp->nnodes++;
+ } else {
+ /* Node is already cached */
+ if(nnpfs_do_vget(XNODE_TO_VNODE(result), 0, p))
+ goto retry;
+ }
+
+ /* Init other fields */
+ nnpfs_attr2vattr(&node->attr, &result->attr, 1);
+ result->vn->v_type = result->attr.va_type;
+ result->tokens = node->tokens;
+ bcopy(node->id, result->id, sizeof(result->id));
+ bcopy(node->rights, result->rights, sizeof(result->rights));
+
+#ifdef __APPLE__
+ if (result->vn->v_type == VREG && (!UBCINFOEXISTS(result->vn)))
+ ubc_info_init(result->vn);
+#endif
+
+ *xpp = result;
+ NNPFSDEB(XDEBNODE, ("return: new_nnpfs_node\n"));
+ return 0;
+}
+
+void
+free_nnpfs_node(struct nnpfs_node *node)
+{
+ struct nnpfs *nnpfsp = NNPFS_FROM_XNODE(node);
+
+ NNPFSDEB(XDEBNODE, ("free_nnpfs_node(%lx) (%d,%d,%d,%d)\n",
+ (unsigned long)node,
+ node->handle.a,
+ node->handle.b,
+ node->handle.c,
+ node->handle.d));
+
+ /* XXX Really need to put back dirty data first. */
+
+ if (DATA_FROM_XNODE(node)) {
+ vrele(DATA_FROM_XNODE(node));
+ DATA_FROM_XNODE(node) = NULL;
+ }
+ nnpfsp->nnodes--;
+ XNODE_TO_VNODE(node)->v_data = NULL;
+ if (node->rd_cred) {
+ crfree (node->rd_cred);
+ node->rd_cred = NULL;
+ }
+ if (node->wr_cred) {
+ crfree (node->wr_cred);
+ node->wr_cred = NULL;
+ }
+
+ nnpfs_free(node, sizeof(*node), M_NNPFS_NODE);
+
+ NNPFSDEB(XDEBNODE, ("free_nnpfs_node done\n"));
+}
+
+/*
+ * FreeBSD 4.4 and newer changed to API to vflush around June 2001
+ */
+
+static int
+nnpfs_vflush(struct mount *mp, int flags)
+{
+#if __FreeBSD__ && __FreeBSD_version > 430000
+ return vflush(mp, 0, flags);
+#else
+ return vflush(mp, NULL, flags);
+#endif
+}
+
+int
+free_all_nnpfs_nodes(struct nnpfs *nnpfsp, int flags, int unmountp)
+{
+ int error = 0;
+ struct mount *mp = NNPFS_TO_VFS(nnpfsp);
+
+ if (mp == NULL) {
+ NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes already freed\n"));
+ return 0;
+ }
+
+ NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes starting\n"));
+
+ nnpfs_dnlc_purge_mp(mp);
+
+ if (nnpfsp->root) {
+ NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes now removing root\n"));
+
+ vgone(XNODE_TO_VNODE(nnpfsp->root));
+ nnpfsp->root = NULL;
+ }
+
+ NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes root removed\n"));
+ NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes now killing all remaining nodes\n"));
+
+ /*
+ * If we have a syncer vnode, release it (to emulate dounmount)
+ * and the create it again when if we are going to need it.
+ */
+
+#ifdef HAVE_STRUCT_MOUNT_MNT_SYNCER
+ if (!unmountp) {
+ if (mp->mnt_syncer != NULL) {
+#ifdef HAVE_KERNEL_VFS_DEALLOCATE_SYNCVNODE
+ vfs_deallocate_syncvnode(mp);
+#else
+ /*
+ * FreeBSD and OpenBSD uses different semantics,
+ * FreeBSD does vrele, and OpenBSD does vgone.
+ */
+#if defined(__OpenBSD__)
+ vgone(mp->mnt_syncer);
+#elif defined(__FreeBSD__)
+ vrele(mp->mnt_syncer);
+#else
+#error what os do you use ?
+#endif
+ mp->mnt_syncer = NULL;
+#endif
+ }
+ }
+#endif
+ error = nnpfs_vflush(mp, flags);
+#ifdef HAVE_STRUCT_MOUNT_MNT_SYNCER
+ if (!unmountp) {
+ NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes not flushing syncer vnode\n"));
+ if (mp->mnt_syncer == NULL)
+ if (vfs_allocate_syncvnode(mp))
+ panic("failed to allocate syncer node when nnpfs daemon died");
+ }
+#endif
+
+ if (error) {
+ NNPFSDEB(XDEBNODE, ("xfree_all_nnpfs_nodes: vflush() error == %d\n",
+ error));
+ return error;
+ }
+
+ NNPFSDEB(XDEBNODE, ("free_all_nnpfs_nodes done\n"));
+ return error;
+}
+
+void
+vattr2nnpfs_attr(const struct vattr *va, struct nnpfs_attr *xa)
+{
+ bzero(xa, sizeof(*xa));
+ if (va->va_mode != (mode_t)VNOVAL)
+ XA_SET_MODE(xa, va->va_mode);
+ if (va->va_nlink != VNOVAL)
+ XA_SET_NLINK(xa, va->va_nlink);
+ if (va->va_size != VNOVAL)
+ XA_SET_SIZE(xa, va->va_size);
+ if (va->va_uid != VNOVAL)
+ XA_SET_UID(xa, va->va_uid);
+ if (va->va_gid != VNOVAL)
+ XA_SET_GID(xa, va->va_gid);
+ if (va->va_atime.tv_sec != VNOVAL)
+ XA_SET_ATIME(xa, va->va_atime.tv_sec);
+ if (va->va_mtime.tv_sec != VNOVAL)
+ XA_SET_MTIME(xa, va->va_mtime.tv_sec);
+ if (va->va_ctime.tv_sec != VNOVAL)
+ XA_SET_CTIME(xa, va->va_ctime.tv_sec);
+ if (va->va_fileid != VNOVAL)
+ XA_SET_FILEID(xa, va->va_fileid);
+ switch (va->va_type) {
+ case VNON:
+ xa->xa_type = NNPFS_FILE_NON;
+ break;
+ case VREG:
+ xa->xa_type = NNPFS_FILE_REG;
+ break;
+ case VDIR:
+ xa->xa_type = NNPFS_FILE_DIR;
+ break;
+ case VBLK:
+ xa->xa_type = NNPFS_FILE_BLK;
+ break;
+ case VCHR:
+ xa->xa_type = NNPFS_FILE_CHR;
+ break;
+ case VLNK:
+ xa->xa_type = NNPFS_FILE_LNK;
+ break;
+ case VSOCK:
+ xa->xa_type = NNPFS_FILE_SOCK;
+ break;
+ case VFIFO:
+ xa->xa_type = NNPFS_FILE_FIFO;
+ break;
+ case VBAD:
+ xa->xa_type = NNPFS_FILE_BAD;
+ break;
+ default:
+ panic("nnpfs_attr2attr: bad value");
+ }
+}
+
+#define SET_TIMEVAL(X, S, N) do { (X)->tv_sec = (S); (X)->tv_nsec = (N); } while(0)
+
+void
+nnpfs_attr2vattr(const struct nnpfs_attr *xa, struct vattr *va, int clear_node)
+{
+ if (clear_node)
+ VATTR_NULL(va);
+ if (XA_VALID_MODE(xa))
+ va->va_mode = xa->xa_mode;
+ if (XA_VALID_NLINK(xa))
+ va->va_nlink = xa->xa_nlink;
+ if (XA_VALID_SIZE(xa)) {
+ va->va_size = xa->xa_size;
+ va->va_bytes = va->va_size;
+ }
+ if (XA_VALID_UID(xa))
+ va->va_uid = xa->xa_uid;
+ if (XA_VALID_GID(xa))
+ va->va_gid = xa->xa_gid;
+ if (XA_VALID_ATIME(xa)) {
+ SET_TIMEVAL(&va->va_atime, xa->xa_atime, 0);
+ }
+ if (XA_VALID_MTIME(xa)) {
+ SET_TIMEVAL(&va->va_mtime, xa->xa_mtime, 0);
+ }
+ if (XA_VALID_CTIME(xa)) {
+ SET_TIMEVAL(&va->va_ctime, xa->xa_ctime, 0);
+ }
+ if (XA_VALID_FILEID(xa)) {
+ va->va_fileid = xa->xa_fileid;
+ }
+ if (XA_VALID_TYPE(xa)) {
+ switch (xa->xa_type) {
+ case NNPFS_FILE_NON:
+ va->va_type = VNON;
+ break;
+ case NNPFS_FILE_REG:
+ va->va_type = VREG;
+ break;
+ case NNPFS_FILE_DIR:
+ va->va_type = VDIR;
+ break;
+ case NNPFS_FILE_BLK:
+ va->va_type = VBLK;
+ break;
+ case NNPFS_FILE_CHR:
+ va->va_type = VCHR;
+ break;
+ case NNPFS_FILE_LNK:
+ va->va_type = VLNK;
+ break;
+ case NNPFS_FILE_SOCK:
+ va->va_type = VSOCK;
+ break;
+ case NNPFS_FILE_FIFO:
+ va->va_type = VFIFO;
+ break;
+ case NNPFS_FILE_BAD:
+ va->va_type = VBAD;
+ break;
+ default:
+ panic("nnpfs_attr2vattr: bad value");
+ }
+ }
+ va->va_flags = 0;
+ va->va_blocksize = 8192;
+}
+
+/*
+ * A single entry DNLC for systems for handling long names that don't
+ * get put into the system DNLC.
+ */
+
+struct long_entry {
+ struct vnode *dvp, *vp;
+ char name[MAXNAMLEN + 1];
+ size_t len;
+ u_long dvpid, vpid;
+};
+
+static struct long_entry tbl;
+
+/*
+ * Nuke the `tbl'
+ */
+
+static void
+tbl_clear (void)
+{
+ tbl.dvp = tbl.vp = NULL;
+ tbl.name[0] = '\0';
+ tbl.len = 0;
+ tbl.dvpid = tbl.vpid = 0;
+}
+
+/*
+ * Set the entry in the `tbl'
+ */
+
+static void
+tbl_enter (size_t len, const char *name, struct vnode *dvp, struct vnode *vp)
+{
+ tbl.len = len;
+ bcopy(name, tbl.name, len);
+ tbl.dvp = dvp;
+ tbl.vp = vp;
+ tbl.dvpid = dvp->v_id;
+ tbl.vpid = vp->v_id;
+}
+
+/*
+ * Lookup in tbl (`dvp', `name', `len') and return result in `res'.
+ * Return -1 if successful, otherwise 0.
+ */
+
+static int
+tbl_lookup (struct componentname *cnp,
+ struct vnode *dvp,
+ struct vnode **res)
+{
+ if (tbl.dvp == dvp
+ && tbl.len == cnp->cn_namelen
+ && strncmp(tbl.name, cnp->cn_nameptr, tbl.len) == 0
+ && tbl.dvpid == tbl.dvp->v_id
+ && tbl.vpid == tbl.vp->v_id) {
+
+ *res = tbl.vp;
+ return -1;
+ } else
+ return 0;
+}
+
+/*
+ * Store a componentname in the DNLC
+ */
+
+int
+nnpfs_dnlc_enter(struct vnode *dvp,
+ nnpfs_componentname *cnp,
+ struct vnode *vp)
+{
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_enter_cnp(%lx, %lx, %lx)\n",
+ (unsigned long)dvp,
+ (unsigned long)cnp,
+ (unsigned long)vp));
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_enter: v_id = %lu\n", (u_long)dvp->v_id));
+
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_enter: calling cache_enter:"
+ "dvp = %lx, vp = %lx, cnp = (%s, %ld), "
+ "nameiop = %lu, flags = %lx\n",
+ (unsigned long)dvp,
+ (unsigned long)vp,
+ cnp->cn_nameptr, cnp->cn_namelen,
+ cnp->cn_nameiop, cnp->cn_flags));
+
+#ifdef NCHNAMLEN
+ if (cnp->cn_namelen <= NCHNAMLEN)
+#endif
+ {
+ /*
+ * This is to make sure there's no negative entry already in the dnlc
+ */
+ u_long save_nameiop;
+ u_long save_flags;
+ struct vnode *dummy;
+
+ save_nameiop = cnp->cn_nameiop;
+ save_flags = cnp->cn_flags;
+ cnp->cn_nameiop = CREATE;
+ cnp->cn_flags &= ~MAKEENTRY;
+
+/*
+ * The version number here is not entirely correct, but it's conservative.
+ * The real change is sys/kern/vfs_cache:1.20
+ */
+
+#if __NetBSD_Version__ >= 104120000 || OpenBSD > 200211
+ if (cache_lookup(dvp, &dummy, cnp) != -1) {
+ nnpfs_vfs_unlock(dummy, nnpfs_cnp_to_proc(cnp));
+ printf ("NNPFS PANIC WARNING! nnpfs_dnlc_enter: %s already in cache\n",
+ cnp->cn_nameptr);
+ }
+#else
+ if (cache_lookup(dvp, &dummy, cnp) != 0) {
+ printf ("NNPFS PANIC WARNING! nnpfs_dnlc_enter: %s already in cache\n",
+ cnp->cn_nameptr);
+ }
+#endif
+
+
+ cnp->cn_nameiop = save_nameiop;
+ cnp->cn_flags = save_flags;
+ cache_enter(dvp, vp, cnp);
+ }
+
+ if (vp != NULL)
+ tbl_enter (cnp->cn_namelen, cnp->cn_nameptr, dvp, vp);
+
+ return 0;
+}
+
+
+static void
+nnpfs_cnp_init (struct componentname *cn,
+ const char *name,
+ d_thread_t *proc, struct ucred *cred,
+ int nameiop)
+{
+ bzero(cn, sizeof(*cn));
+ cn->cn_nameptr = (char *)name;
+ cn->cn_namelen = strlen(name);
+ cn->cn_flags = 0;
+#if __APPLE__
+ {
+ const unsigned char *p;
+ int i;
+
+ cn->cn_hash = 0;
+ for (p = cn->cn_nameptr, i = 1; *p; ++p, ++i)
+ cn->cn_hash += *p * i;
+ }
+#elif defined(HAVE_KERNEL_NAMEI_HASH)
+ {
+ const char *cp = name + cn->cn_namelen;
+ cn->cn_hash = namei_hash(name, &cp);
+ }
+#elif defined(HAVE_STRUCT_COMPONENTNAME_CN_HASH)
+ {
+ const unsigned char *p;
+
+ cn->cn_hash = 0;
+ for (p = cn->cn_nameptr; *p; ++p)
+ cn->cn_hash += *p;
+ }
+#endif
+ cn->cn_nameiop = nameiop;
+#ifdef HAVE_FREEBSD_THREAD
+ cn->cn_thread = proc;
+#else
+ cn->cn_proc = proc;
+#endif
+ cn->cn_cred = cred;
+}
+
+
+/*
+ * Store (dvp, name, vp) in the DNLC
+ */
+
+int
+nnpfs_dnlc_enter_name(struct vnode *dvp,
+ const char *name,
+ struct vnode *vp)
+{
+ struct componentname cn;
+
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_enter_name(%lx, \"%s\", %lx)\n",
+ (unsigned long)dvp,
+ name,
+ (unsigned long)vp));
+
+ nnpfs_cnp_init (&cn, name, NULL, NULL, LOOKUP);
+ return nnpfs_dnlc_enter (dvp, &cn, vp);
+}
+
+/*
+ * Lookup (dvp, cnp) in the DNLC and return the result in `res'.
+ * Return the result from cache_lookup.
+ */
+
+static int
+nnpfs_dnlc_lookup_int(struct vnode *dvp,
+ nnpfs_componentname *cnp,
+ struct vnode **res)
+{
+ int error;
+ u_long saved_flags;
+
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_lookup(%lx, \"%s\")\n",
+ (unsigned long)dvp, cnp->cn_nameptr));
+
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_lookup: v_id = %lu\n", (u_long)dvp->v_id));
+
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_lookup: calling cache_lookup:"
+ "dvp = %lx, cnp = (%s, %ld), flags = %lx\n",
+ (unsigned long)dvp,
+ cnp->cn_nameptr, cnp->cn_namelen,
+ cnp->cn_flags));
+
+ saved_flags = cnp->cn_flags;
+ cnp->cn_flags |= MAKEENTRY | LOCKPARENT | ISLASTCN;
+
+ error = cache_lookup(dvp, res, cnp);
+
+ cnp->cn_flags = saved_flags;
+
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_lookup: cache_lookup returned. "
+ "error = %d, *res = %lx\n", error,
+ (unsigned long)*res));
+ return error;
+}
+
+/*
+ * do the last (and locking protocol) portion of xnlc_lookup
+ *
+ * return:
+ * -1 for successful
+ * 0 for failed
+ */
+
+static int
+nnpfs_dnlc_lock(struct vnode *dvp,
+ nnpfs_componentname *cnp,
+ struct vnode **res)
+{
+ int error = 0;
+
+ /*
+ * Try to handle the (complex) BSD locking protocol.
+ */
+
+ if (*res == dvp) { /* "." */
+ VREF(dvp);
+ } else if (cnp->cn_flags & ISDOTDOT) { /* ".." */
+ u_long vpid = dvp->v_id;
+
+#ifdef HAVE_FREEBSD_THREAD
+ nnpfs_vfs_unlock(dvp, nnpfs_cnp_to_thread(cnp));
+ error = nnpfs_do_vget(*res, LK_EXCLUSIVE, nnpfs_cnp_to_thread(cnp));
+ nnpfs_vfs_writelock(dvp, nnpfs_cnp_to_thread(cnp));
+#else
+ nnpfs_vfs_unlock(dvp, nnpfs_cnp_to_proc(cnp));
+ error = nnpfs_do_vget(*res, LK_EXCLUSIVE, nnpfs_cnp_to_proc(cnp));
+ nnpfs_vfs_writelock(dvp, nnpfs_cnp_to_proc(cnp));
+#endif
+
+ if (error == 0 && dvp->v_id != vpid) {
+ vput(*res);
+ return 0;
+ }
+ } else {
+#ifdef HAVE_FREEBSD_THREAD
+ error = nnpfs_do_vget(*res, LK_EXCLUSIVE, nnpfs_cnp_to_thread(cnp));
+#else
+ error = nnpfs_do_vget(*res, LK_EXCLUSIVE, nnpfs_cnp_to_proc(cnp));
+#endif
+ }
+
+ if (error == 0)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+ * Lookup (`dvp', `cnp') in the DNLC (and the local cache).
+ *
+ * Return -1 if successful, 0 if not and ENOENT if the entry is known
+ * not to exist.
+ *
+ * On modern NetBSD, cache_lookup has been changed to return 0 for
+ * successful and -1 for not.
+ * (see the comment above for version information).
+ */
+
+#if __NetBSD_Version__ >= 104120000 || defined(__OpenBSD__)
+
+int
+nnpfs_dnlc_lookup(struct vnode *dvp,
+ nnpfs_componentname *cnp,
+ struct vnode **res)
+{
+ int error = nnpfs_dnlc_lookup_int (dvp, cnp, res);
+
+ if (error == 0)
+ return -1;
+ else if (error == ENOENT)
+ return error;
+
+ error = tbl_lookup (cnp, dvp, res);
+
+ if (error != -1)
+ return error;
+
+ return nnpfs_dnlc_lock (dvp, cnp, res);
+}
+
+#else /* ! __NetBSD_Version__ >= 104120000 && ! OpenBSD > 200211 */
+
+int
+nnpfs_dnlc_lookup(struct vnode *dvp,
+ nnpfs_componentname *cnp,
+ struct vnode **res)
+{
+ int error = nnpfs_dnlc_lookup_int (dvp, cnp, res);
+
+ if (error == 0)
+ error = tbl_lookup (cnp, dvp, res);
+
+ if (error != -1)
+ return error;
+
+ return nnpfs_dnlc_lock (dvp, cnp, res);
+}
+
+#endif /* __NetBSD_Version__ >= 104120000 || OpenBSD > 200211 */
+
+/*
+ * Remove one entry from the DNLC
+ */
+
+void
+nnpfs_dnlc_purge (struct vnode *vp)
+{
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_purge\n"));
+
+ if (tbl.dvp == vp || tbl.vp == vp)
+ tbl_clear ();
+
+ cache_purge(vp);
+}
+
+/*
+ * Remove all entries belong to `mp' from the DNLC
+ */
+
+void
+nnpfs_dnlc_purge_mp(struct mount *mp)
+{
+ NNPFSDEB(XDEBDNLC, ("nnpfs_dnlc_purge_mp()\n"));
+
+ tbl_clear ();
+ cache_purgevfs(mp);
+}
+
+/*
+ * Returns 1 if pag has any rights set in the node
+ */
+
+int
+nnpfs_has_pag(const struct nnpfs_node *xn, nnpfs_pag_t pag)
+{
+ int i;
+
+ for (i = 0; i < MAXRIGHTS; i++)
+ if (xn->id[i] == pag)
+ return 1;
+
+ return 0;
+}
+
+void
+nnpfs_update_write_cred(struct nnpfs_node *xn, struct ucred *cred)
+{
+ if (xn->wr_cred)
+ crfree (xn->wr_cred);
+ crhold (cred);
+ xn->wr_cred = cred;
+}
+
+void
+nnpfs_update_read_cred(struct nnpfs_node *xn, struct ucred *cred)
+{
+ if (xn->rd_cred)
+ crfree (xn->rd_cred);
+ crhold (cred);
+ xn->rd_cred = cred;
+}