kernel - Remove remaining mplock use cases from tmpfs
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 21 Feb 2013 05:07:00 +0000 (21:07 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 21 Feb 2013 05:07:00 +0000 (21:07 -0800)
* Use the per-mount lock for remaining cases, including nremove,
  truncate, and other operations.

* Also fixes machine stalls against pings when removing very
  large files.

Submitted-by: vsrinivas
sys/net/ipfw/ip_fw2.c
sys/vfs/tmpfs/tmpfs.h
sys/vfs/tmpfs/tmpfs_subr.c
sys/vfs/tmpfs/tmpfs_vfsops.c
sys/vfs/tmpfs/tmpfs_vnops.c

index dde4323..39d90a2 100644 (file)
@@ -1618,14 +1618,12 @@ ipfw_match_uid(const struct ipfw_flow_id *fid, struct ifnet *oif,
        *deny = 0;
        gen = ctx->ipfw_gen;
 
-       get_mplock();
        if (gen != ctx->ipfw_gen) {
                /* See the comment in lookup_rule() */
                *deny = 1;
        } else {
                match = _ipfw_match_uid(fid, oif, opcode, uid);
        }
-       rel_mplock();
        return match;
 }
 
index c53d7c1..20a8998 100644 (file)
@@ -62,19 +62,19 @@ MALLOC_DECLARE(M_TMPFSMNT);
  * Internal representation of a tmpfs directory entry.
  */
 struct tmpfs_dirent {
-       RB_ENTRY(tmpfs_dirent) rb_node;
+       RB_ENTRY(tmpfs_dirent)  rb_node;
 
        /* Length of the name stored in this directory entry.  This avoids
         * the need to recalculate it every time the name is used. */
-       uint16_t                        td_namelen;
+       uint16_t                td_namelen;
 
        /* The name of the entry, allocated from a string pool.  This
        * string is not required to be zero-terminated; therefore, the
        * td_namelen field must always be used when accessing its value. */
-       char *                          td_name;
+       char                    *td_name;
 
        /* Pointer to the node this entry refers to. */
-       struct tmpfs_node *             td_node;
+       struct tmpfs_node       *td_node;
 };
 
 struct tmpfs_dirtree;
@@ -173,11 +173,6 @@ tmpfs_dircookie(struct tmpfs_dirent *de)
  * to all file types and the other holds data that is only applicable to
  * a particular type.  The code must be careful to only access those
  * attributes that are actually allowed by the node's type.
- *
- *
- * Below is the key of locks used to protected the fields in the following
- * structures.
- *
  */
 struct tmpfs_node {
        /* Doubly-linked list entry which links all existing nodes for a
@@ -211,7 +206,7 @@ struct tmpfs_node {
        gid_t                   tn_gid;
        mode_t                  tn_mode;
        int                     tn_flags;
-       nlink_t                 tn_links;
+       nlink_t                 tn_links;   /* requires mnt_token protection */
        int32_t                 tn_atime;
        int32_t                 tn_atimensec;
        int32_t                 tn_mtime;
@@ -251,7 +246,7 @@ struct tmpfs_node {
                dev_t                   tn_rdev; /*int32_t ?*/
 
                /* Valid when tn_type == VDIR. */
-               struct tn_dir{
+               struct tn_dir {
                        /* Pointer to the parent directory.  The root
                         * directory has a pointer to itself in this field;
                         * this property identifies the root node. */
@@ -273,7 +268,7 @@ struct tmpfs_node {
                         * point where readdir starts returning values. */
                        off_t                   tn_readdir_lastn;
                        struct tmpfs_dirent *   tn_readdir_lastp;
-               }tn_dir;
+               } tn_dir;
 
                /* Valid when tn_type == VLNK. */
                /* The link's target, allocated from a string pool. */
@@ -293,7 +288,7 @@ struct tmpfs_node {
                        vm_object_t             tn_aobj;
                        size_t                  tn_aobj_pages;
 
-               }tn_reg;
+               } tn_reg;
 
                /* Valid when tn_type = VFIFO */
                struct tn_fifo {
@@ -301,8 +296,8 @@ struct tmpfs_node {
                                struct ucred *cred, int flags);
                        int (*tn_fo_write) (struct file *fp, struct uio *uio,
                                struct ucred *cred, int flags);
-               }tn_fifo;
-       }tn_spec;
+               } tn_fifo;
+       } tn_spec;
 };
 LIST_HEAD(tmpfs_node_list, tmpfs_node);
 
@@ -342,6 +337,8 @@ LIST_HEAD(tmpfs_node_list, tmpfs_node);
  * Internal representation of a tmpfs mount point.
  */
 struct tmpfs_mount {
+       struct mount            *tm_mount;
+
        /* Maximum number of memory pages available for use by the file
         * system, set during mount time.  This variable must never be
         * used directly as it may be bigger than the current amount of
@@ -386,9 +383,6 @@ struct tmpfs_mount {
         * file system is unmounted. */
        struct tmpfs_node_list  tm_nodes_used;
 
-       /* All node lock to protect the node list and tmp_pages_used */
-       struct lock              allnode_lock;
-
        /* Per-mount malloc zones for tmpfs nodes, names, and dirents */
        struct malloc_type      *tm_node_zone;
        struct malloc_type      *tm_dirent_zone;
@@ -397,9 +391,7 @@ struct tmpfs_mount {
        struct objcache_malloc_args tm_node_zone_malloc_args;
        struct objcache_malloc_args tm_dirent_zone_malloc_args;
 
-       /* Pools used to store file system meta data.  These are not shared
-        * across several instances of tmpfs for the reasons described in
-        * tmpfs_pool.c. */
+       /* Pools used to store file system meta data. */
        struct objcache         *tm_dirent_pool;
        struct objcache         *tm_node_pool;
 
@@ -407,10 +399,12 @@ struct tmpfs_mount {
        int                     tm_flags;
 
        struct netexport        tm_export;
+
+       struct mount            *tm_mnt;
 };
 
-#define TMPFS_LOCK(tm) lockmgr(&(tm)->allnode_lock, LK_EXCLUSIVE|LK_RETRY)
-#define TMPFS_UNLOCK(tm) lockmgr(&(tm)->allnode_lock, LK_RELEASE)
+#define TMPFS_LOCK(tm) lwkt_gettoken(&(tm)->tm_mount->mnt_token)
+#define TMPFS_UNLOCK(tm) lwkt_reltoken(&(tm)->tm_mount->mnt_token)
 
 /* --------------------------------------------------------------------- */
 
index 0bd807d..191552b 100644 (file)
@@ -290,7 +290,7 @@ tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node)
  */
 int
 tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node,
-    const char *name, uint16_t len, struct tmpfs_dirent **de)
+                  const char *name, uint16_t len, struct tmpfs_dirent **de)
 {
        struct tmpfs_dirent *nde;
 
@@ -308,7 +308,7 @@ tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node,
        nde->td_node = node;
 
        TMPFS_NODE_LOCK(node);
-       node->tn_links++;
+       ++node->tn_links;       /* also requires mnt_token protection */
        TMPFS_NODE_UNLOCK(node);
 
        *de = nde;
@@ -337,7 +337,7 @@ tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de)
        TMPFS_NODE_LOCK(node);
        TMPFS_ASSERT_ELOCKED(node);
        KKASSERT(node->tn_links > 0);
-       node->tn_links--;
+       node->tn_links--;       /* also requires mnt_token protection */
        TMPFS_NODE_UNLOCK(node);
 
        kfree(de->td_name, tmp->tm_name_zone);
@@ -592,10 +592,10 @@ tmpfs_dir_attach(struct tmpfs_node *dnode, struct tmpfs_dirent *de)
        TMPFS_NODE_LOCK(dnode);
        if (node && node->tn_type == VDIR) {
                TMPFS_NODE_LOCK(node);
-               ++node->tn_links;
+               ++node->tn_links;       /* also requires mnt_token protection */
                node->tn_status |= TMPFS_NODE_CHANGED;
                node->tn_dir.tn_parent = dnode;
-               ++dnode->tn_links;
+               ++dnode->tn_links;      /* also requires mnt_token protection */
                TMPFS_NODE_UNLOCK(node);
        }
        RB_INSERT(tmpfs_dirtree, &dnode->tn_dir.tn_dirtree, de);
@@ -643,8 +643,8 @@ tmpfs_dir_detach(struct tmpfs_node *dnode, struct tmpfs_dirent *de)
                TMPFS_NODE_LOCK(dnode);
                TMPFS_NODE_LOCK(node);
                KKASSERT(node->tn_dir.tn_parent == dnode);
-               dnode->tn_links--;
-               node->tn_links--;
+               dnode->tn_links--;      /* also requires mnt_token protection */
+               node->tn_links--;       /* also requires mnt_token protection */
                node->tn_dir.tn_parent = NULL;
                TMPFS_NODE_UNLOCK(node);
                TMPFS_NODE_UNLOCK(dnode);
@@ -1225,7 +1225,7 @@ tmpfs_chsize(struct vnode *vp, u_quad_t size, struct ucred *cred)
  */
 int
 tmpfs_chtimes(struct vnode *vp, struct timespec *atime, struct timespec *mtime,
-       int vaflags, struct ucred *cred)
+             int vaflags, struct ucred *cred)
 {
        struct tmpfs_node *node;
 
@@ -1261,7 +1261,7 @@ tmpfs_chtimes(struct vnode *vp, struct timespec *atime, struct timespec *mtime,
 /* Sync timestamps */
 void
 tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
-    const struct timespec *mod)
+            const struct timespec *mod)
 {
        struct tmpfs_node *node;
        struct timespec now;
index b2050e7..3a4f338 100644 (file)
 /*
  * Efficient memory file system.
  *
- * tmpfs is a file system that uses NetBSD's virtual memory sub-system
- * (the well-known UVM) to store file data and metadata in an efficient
- * way.  This means that it does not follow the structure of an on-disk
- * file system because it simply does not need to.  Instead, it uses
+ * tmpfs is a file system that uses virtual memory to store file data and
+ * metadata efficiently. It does not follow the structure of an on-disk
+ * file system because it simply does not need to. Instead, it uses
  * memory-specific data structures and algorithms to automatically
  * allocate and release resources.
  */
 #include <vm/vm_object.h>
 #include <vm/vm_param.h>
 
+#if 0
 #include <vfs/tmpfs/tmpfs.h>
+#endif
+#include "tmpfs.h"
 #include <vfs/tmpfs/tmpfs_vnops.h>
 #include <vfs/tmpfs/tmpfs_args.h>
 
@@ -79,7 +81,7 @@ static int    tmpfs_statfs(struct mount *, struct statfs *, struct ucred *cred);
 int
 tmpfs_node_ctor(void *obj, void *privdata, int flags)
 {
-       struct tmpfs_node *node = (struct tmpfs_node *)obj;
+       struct tmpfs_node *node = obj;
 
        node->tn_gen++;
        node->tn_size = 0;
@@ -101,10 +103,10 @@ tmpfs_node_dtor(void *obj, void *privdata)
        node->tn_vpstate = TMPFS_VNODE_DOOMED;
 }
 
-static void*
+static void *
 tmpfs_node_init(void *args, int flags)
 {
-       struct tmpfs_node *node = (struct tmpfs_node *)objcache_malloc_alloc(args, flags);
+       struct tmpfs_node *node = objcache_malloc_alloc(args, flags);
        if (node == NULL)
                return (NULL);
        node->tn_id = 0;
@@ -218,7 +220,7 @@ tmpfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
        /* Allocate the tmpfs mount structure and fill it. */
        tmp = kmalloc(sizeof(*tmp), M_TMPFSMNT, M_WAITOK | M_ZERO);
 
-       lockinit(&(tmp->allnode_lock), "tmpfs allnode lock", 0, LK_CANRECURSE);
+       tmp->tm_mount = mp;
        tmp->tm_nodes_max = nodes;
        tmp->tm_nodes_inuse = 0;
        tmp->tm_maxfilesize = maxfsize;
@@ -270,22 +272,18 @@ tmpfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
            kfree(tmp, M_TMPFSMNT);
            return error;
        }
-       KASSERT(root->tn_id >= 0, ("tmpfs root with invalid ino: %d", (int)root->tn_id));
+       KASSERT(root->tn_id >= 0,
+               ("tmpfs root with invalid ino: %d", (int)root->tn_id));
+
        ++root->tn_links;       /* prevent destruction */
        tmp->tm_root = root;
 
        mp->mnt_flag |= MNT_LOCAL;
-#if 0
-       mp->mnt_kern_flag |= MNTK_RD_MPSAFE | MNTK_WR_MPSAFE | MNTK_GA_MPSAFE  |
-                            MNTK_IN_MPSAFE | MNTK_SG_MPSAFE;
-#endif
-       mp->mnt_kern_flag |= MNTK_RD_MPSAFE | MNTK_GA_MPSAFE | MNTK_SG_MPSAFE;
-       mp->mnt_kern_flag |= MNTK_WR_MPSAFE;
+       mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
        mp->mnt_kern_flag |= MNTK_NOMSYNC;
        mp->mnt_data = (qaddr_t)tmp;
        vfs_getnewfsid(mp);
 
-
        vfs_add_vnodeops(mp, &tmpfs_vnode_vops, &mp->mnt_vn_norm_ops);
        vfs_add_vnodeops(mp, &tmpfs_fifo_vops, &mp->mnt_vn_fifo_ops);
 
@@ -312,12 +310,13 @@ tmpfs_unmount(struct mount *mp, int mntflags)
        struct tmpfs_mount *tmp;
        struct tmpfs_node *node;
 
+       tmp = VFS_TO_TMPFS(mp);
+       TMPFS_LOCK(tmp);
+
        /* Handle forced unmounts. */
        if (mntflags & MNT_FORCE)
                flags |= FORCECLOSE;
 
-       tmp = VFS_TO_TMPFS(mp);
-
        /*
         * Finalize all pending I/O.  In the case of tmpfs we want
         * to throw all the data away so clean out the buffer cache
@@ -325,19 +324,33 @@ tmpfs_unmount(struct mount *mp, int mntflags)
         */
        LIST_FOREACH(node, &tmp->tm_nodes_used, tn_entries) {
                if (node->tn_type == VREG && node->tn_vnode) {
-                       ++node->tn_links;
+                       ++node->tn_links;       /* mnt_token protected */
                        lwkt_yield();
                        TMPFS_NODE_LOCK(node);
+
+                       /*
+                        * vx_get/vx_put and tmpfs_truncate may block,
+                        * releasing the tmpfs mountpoint token.
+                        */
                        vx_get(node->tn_vnode);
                        tmpfs_truncate(node->tn_vnode, 0);
                        vx_put(node->tn_vnode);
+
                        TMPFS_NODE_UNLOCK(node);
-                       --node->tn_links;
+                       --node->tn_links;       /* mnt_token protected */
                }
        }
+       /*
+        * Flush all vnodes on the mount.
+        *
+        * If we fail to flush, we cannot unmount, but all the nodes have
+        * already been truncated. Erroring out is the best we can do.
+        */
        error = vflush(mp, 0, flags);
-       if (error != 0)
-               return error;
+       if (error != 0) {
+               TMPFS_UNLOCK(tmp);
+               return (error);
+       }
 
        /*
         * First pass get rid of all the directory entries and
@@ -348,28 +361,22 @@ tmpfs_unmount(struct mount *mp, int mntflags)
         * No vnodes should remain after the vflush above.
         */
        LIST_FOREACH(node, &tmp->tm_nodes_used, tn_entries) {
-               ++node->tn_links;
+               ++node->tn_links;       /* mnt_token protected */
                lwkt_yield();
                TMPFS_NODE_LOCK(node);
+
                if (node->tn_type == VDIR) {
                        struct tmpfs_dirent *de;
 
-                       while ((de = RB_ROOT(&node->tn_dir.tn_dirtree)) != NULL) {
+                       while ((de = RB_ROOT(&node->tn_dir.tn_dirtree)) != NULL)                        {
                                tmpfs_dir_detach(node, de);
                                tmpfs_free_dirent(tmp, de);
                        }
                }
                KKASSERT(node->tn_vnode == NULL);
-#if 0
-               vp = node->tn_vnode;
-               if (vp != NULL) {
-                       tmpfs_free_vp(vp);
-                       vrecycle(vp);
-                       node->tn_vnode = NULL;
-               }
-#endif
+
                TMPFS_NODE_UNLOCK(node);
-               --node->tn_links;
+               --node->tn_links;       /* mnt_token protected */
        }
 
        /*
@@ -377,7 +384,7 @@ tmpfs_unmount(struct mount *mp, int mntflags)
         * we bumped in the mount code.
         */
        KKASSERT(tmp->tm_root);
-       --tmp->tm_root->tn_links;
+       --tmp->tm_root->tn_links;       /* mnt_token protected */
 
        /*
         * At this point all nodes, including the root node, should have a
@@ -385,7 +392,9 @@ tmpfs_unmount(struct mount *mp, int mntflags)
         */
        while ((node = LIST_FIRST(&tmp->tm_nodes_used)) != NULL) {
                if (node->tn_links)
-                       panic("tmpfs: Dangling nodes during umount (%p)!\n", node);
+                       panic("tmpfs: Dangling nodes during umount (%p)!\n",
+                             node);
+
                TMPFS_NODE_LOCK(node);
                tmpfs_free_node(tmp, node);
                /* eats lock */
@@ -402,10 +411,11 @@ tmpfs_unmount(struct mount *mp, int mntflags)
 
        tmp->tm_node_zone = tmp->tm_dirent_zone = NULL;
 
-       lockuninit(&tmp->allnode_lock);
        KKASSERT(tmp->tm_pages_used == 0);
        KKASSERT(tmp->tm_nodes_inuse == 0);
 
+       TMPFS_UNLOCK(tmp);
+
        /* Throw away the tmpfs_mount structure. */
        kfree(tmp, M_TMPFSMNT);
        mp->mnt_data = NULL;
@@ -439,22 +449,25 @@ tmpfs_root(struct mount *mp, struct vnode **vpp)
 /* --------------------------------------------------------------------- */
 
 static int
-tmpfs_fhtovp(struct mount *mp, struct vnode *rootvp, struct fid *fhp, struct vnode **vpp)
+tmpfs_fhtovp(struct mount *mp, struct vnode *rootvp, struct fid *fhp,
+            struct vnode **vpp)
 {
        boolean_t found;
        struct tmpfs_fid *tfhp;
        struct tmpfs_mount *tmp;
        struct tmpfs_node *node;
+       int rc;
 
        tmp = VFS_TO_TMPFS(mp);
 
-       tfhp = (struct tmpfs_fid *)fhp;
+       tfhp = (struct tmpfs_fid *) fhp;
        if (tfhp->tf_len != sizeof(struct tmpfs_fid))
                return EINVAL;
 
        if (tfhp->tf_id >= tmp->tm_nodes_max)
                return EINVAL;
 
+       rc = EINVAL;
        found = FALSE;
 
        TMPFS_LOCK(tmp);
@@ -465,12 +478,13 @@ tmpfs_fhtovp(struct mount *mp, struct vnode *rootvp, struct fid *fhp, struct vno
                        break;
                }
        }
-       TMPFS_UNLOCK(tmp);
 
        if (found)
-               return (tmpfs_alloc_vp(mp, node, LK_EXCLUSIVE, vpp));
+               rc = tmpfs_alloc_vp(mp, node, LK_EXCLUSIVE, vpp);
+
+       TMPFS_UNLOCK(tmp);
 
-       return (EINVAL);
+       return (rc);
 }
 
 /* --------------------------------------------------------------------- */
@@ -484,6 +498,7 @@ tmpfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
 
        tmp = VFS_TO_TMPFS(mp);
 
+       TMPFS_LOCK(tmp);
        sbp->f_iosize = PAGE_SIZE;
        sbp->f_bsize = PAGE_SIZE;
 
@@ -497,6 +512,8 @@ tmpfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
        sbp->f_ffree = freenodes;
        sbp->f_owner = tmp->tm_root->tn_uid;
 
+       TMPFS_UNLOCK(tmp);
+
        return 0;
 }
 
index 43d7cbd..4196c0e 100644 (file)
 
 #include <vfs/fifofs/fifo.h>
 #include <vfs/tmpfs/tmpfs_vnops.h>
+#if 0
 #include <vfs/tmpfs/tmpfs.h>
-
-MALLOC_DECLARE(M_TMPFS);
+#endif
+#include "tmpfs.h"
 
 static void tmpfs_strategy_done(struct bio *bio);
 
@@ -84,11 +85,15 @@ tmpfs_nresolve(struct vop_nresolve_args *v)
        struct vnode *vp = NULL;
        struct namecache *ncp = v->a_nch->ncp;
        struct tmpfs_node *tnode;
+       struct mount *mp;
 
        int error;
        struct tmpfs_dirent *de;
        struct tmpfs_node *dnode;
 
+       mp = dvp->v_mount;
+       lwkt_gettoken(&mp->mnt_token);
+
        dnode = VP_TO_TMPFS_DIR(dvp);
 
        de = tmpfs_dir_lookup(dnode, NULL, ncp);
@@ -119,7 +124,9 @@ out:
        } else if (error == ENOENT) {
                cache_setvp(v->a_nch, NULL);
        }
-       return error;
+
+       lwkt_reltoken(&mp->mnt_token);
+       return (error);
 }
 
 static int
@@ -129,23 +136,32 @@ tmpfs_nlookupdotdot(struct vop_nlookupdotdot_args *v)
        struct vnode **vpp = v->a_vpp;
        struct tmpfs_node *dnode = VP_TO_TMPFS_NODE(dvp);
        struct ucred *cred = v->a_cred;
+       struct mount *mp;
        int error;
 
        *vpp = NULL;
+
+       mp = dvp->v_mount;
+       lwkt_gettoken(&mp->mnt_token);
+
        /* Check accessibility of requested node as a first step. */
        error = VOP_ACCESS(dvp, VEXEC, cred);
-       if (error != 0)
+       if (error != 0) {
+               lwkt_reltoken(&mp->mnt_token);
                return error;
+       }
 
        if (dnode->tn_dir.tn_parent != NULL) {
                /* Allocate a new vnode on the matching entry. */
                error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent,
-                   LK_EXCLUSIVE | LK_RETRY, vpp);
+                                      LK_EXCLUSIVE | LK_RETRY, vpp);
 
                if (*vpp)
                        vn_unlock(*vpp);
        }
 
+       lwkt_reltoken(&mp->mnt_token);
+
        return (*vpp == NULL) ? ENOENT : 0;
 }
 
@@ -159,8 +175,12 @@ tmpfs_ncreate(struct vop_ncreate_args *v)
        struct namecache *ncp = v->a_nch->ncp;
        struct vattr *vap = v->a_vap;
        struct ucred *cred = v->a_cred;
+       struct mount *mp;
        int error;
 
+       mp = dvp->v_mount;
+       lwkt_gettoken(&mp->mnt_token);
+
        KKASSERT(vap->va_type == VREG || vap->va_type == VSOCK);
 
        error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, NULL);
@@ -170,7 +190,9 @@ tmpfs_ncreate(struct vop_ncreate_args *v)
                tmpfs_knote(dvp, NOTE_WRITE);
        }
 
-       return error;
+       lwkt_reltoken(&mp->mnt_token);
+
+       return (error);
 }
 /* --------------------------------------------------------------------- */
 
@@ -182,11 +204,16 @@ tmpfs_nmknod(struct vop_nmknod_args *v)
        struct namecache *ncp = v->a_nch->ncp;
        struct vattr *vap = v->a_vap;
        struct ucred *cred = v->a_cred;
+       struct mount *mp = dvp->v_mount;
        int error;
 
+       lwkt_gettoken(&mp->mnt_token);
+
        if (vap->va_type != VBLK && vap->va_type != VCHR &&
-           vap->va_type != VFIFO)
-               return EINVAL;
+           vap->va_type != VFIFO) {
+               lwkt_reltoken(&mp->mnt_token);
+               return (EINVAL);
+       }
 
        error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, NULL);
        if (error == 0) {
@@ -195,6 +222,8 @@ tmpfs_nmknod(struct vop_nmknod_args *v)
                tmpfs_knote(dvp, NOTE_WRITE);
        }
 
+       lwkt_reltoken(&mp->mnt_token);
+
        return error;
 }
 
@@ -205,10 +234,11 @@ tmpfs_open(struct vop_open_args *v)
 {
        struct vnode *vp = v->a_vp;
        int mode = v->a_mode;
-
-       int error;
+       struct mount *mp = vp->v_mount;
        struct tmpfs_node *node;
+       int error;
 
+       lwkt_gettoken(&mp->mnt_token);
        node = VP_TO_TMPFS_NODE(vp);
 
 #if 0
@@ -224,9 +254,11 @@ tmpfs_open(struct vop_open_args *v)
            (mode & (FWRITE | O_APPEND)) == FWRITE) {
                error = EPERM;
        } else {
-               return (vop_stdopen(v));
+               error = (vop_stdopen(v));
        }
-       return error;
+
+       lwkt_reltoken(&mp->mnt_token);
+       return (error);
 }
 
 /* --------------------------------------------------------------------- */
@@ -236,7 +268,9 @@ tmpfs_close(struct vop_close_args *v)
 {
        struct vnode *vp = v->a_vp;
        struct tmpfs_node *node;
+       int error;
 
+       lwkt_gettoken(&vp->v_mount->mnt_token);
        node = VP_TO_TMPFS_NODE(vp);
 
        if (node->tn_links > 0) {
@@ -247,7 +281,11 @@ tmpfs_close(struct vop_close_args *v)
                tmpfs_update(vp);
        }
 
-       return vop_stdclose(v);
+       error = vop_stdclose(v);
+
+       lwkt_reltoken(&vp->v_mount->mnt_token);
+
+       return (error);
 }
 
 /* --------------------------------------------------------------------- */
@@ -259,6 +297,7 @@ tmpfs_access(struct vop_access_args *v)
        int error;
        struct tmpfs_node *node;
 
+       lwkt_gettoken(&vp->v_mount->mnt_token);
        node = VP_TO_TMPFS_NODE(vp);
 
        switch (vp->v_type) {
@@ -267,7 +306,8 @@ tmpfs_access(struct vop_access_args *v)
        case VLNK:
                /* FALLTHROUGH */
        case VREG:
-               if ((v->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
+               if ((v->a_mode & VWRITE) &&
+                   (vp->v_mount->mnt_flag & MNT_RDONLY)) {
                        error = EROFS;
                        goto out;
                }
@@ -292,10 +332,11 @@ tmpfs_access(struct vop_access_args *v)
                goto out;
        }
 
-       error = vop_helper_access(v, node->tn_uid, node->tn_gid, node->tn_mode, 0);
+       error = vop_helper_access(v, node->tn_uid, node->tn_gid,
+                                 node->tn_mode, 0);
 
 out:
-
+       lwkt_reltoken(&vp->v_mount->mnt_token);
        return error;
 }
 
@@ -308,9 +349,9 @@ tmpfs_getattr(struct vop_getattr_args *v)
        struct vattr *vap = v->a_vap;
        struct tmpfs_node *node;
 
+       lwkt_gettoken(&vp->v_mount->mnt_token);
        node = VP_TO_TMPFS_NODE(vp);
 
-       lwkt_gettoken(&vp->v_mount->mnt_token);
        tmpfs_update(vp);
 
        vap->va_type = vp->v_type;
@@ -355,6 +396,7 @@ tmpfs_setattr(struct vop_setattr_args *v)
        int error = 0;
        int kflags = 0;
 
+       lwkt_gettoken(&vp->v_mount->mnt_token);
        if (error == 0 && (vap->va_flags != VNOVAL)) {
                error = tmpfs_chflags(vp, vap->va_flags, cred);
                kflags |= NOTE_ATTRIB;
@@ -394,7 +436,9 @@ tmpfs_setattr(struct vop_setattr_args *v)
        tmpfs_update(vp);
        tmpfs_knote(vp, kflags);
 
-       return error;
+       lwkt_reltoken(&vp->v_mount->mnt_token);
+
+       return (error);
 }
 
 /* --------------------------------------------------------------------- */
@@ -409,6 +453,7 @@ tmpfs_fsync(struct vop_fsync_args *v)
        struct tmpfs_node *node;
        struct vnode *vp = v->a_vp;
 
+       lwkt_gettoken(&vp->v_mount->mnt_token);
        node = VP_TO_TMPFS_NODE(vp);
 
        tmpfs_update(vp);
@@ -420,6 +465,8 @@ tmpfs_fsync(struct vop_fsync_args *v)
                                vfsync(v->a_vp, v->a_waitfor, 1, NULL, NULL);
                }
        }
+
+       lwkt_reltoken(&vp->v_mount->mnt_token);
        return 0;
 }
 
@@ -489,7 +536,7 @@ tmpfs_read (struct vop_read_args *ap)
        node->tn_status |= TMPFS_NODE_ACCESSED;
        TMPFS_NODE_UNLOCK(node);
 
-       return(error);
+       return (error);
 }
 
 static int
@@ -656,7 +703,6 @@ done:
 
        tmpfs_knote(vp, kflags);
 
-
        lwkt_reltoken(&vp->v_mount->mnt_token);
        return(error);
 }
@@ -666,10 +712,15 @@ tmpfs_advlock (struct vop_advlock_args *ap)
 {
        struct tmpfs_node *node;
        struct vnode *vp = ap->a_vp;
+       int error;
 
+       lwkt_gettoken(&vp->v_mount->mnt_token);
        node = VP_TO_TMPFS_NODE(vp);
 
-       return (lf_advlock(ap, &node->tn_advlock, node->tn_size));
+       error = (lf_advlock(ap, &node->tn_advlock, node->tn_size));
+       lwkt_reltoken(&vp->v_mount->mnt_token);
+
+       return (error);
 }
 
 /*
@@ -784,6 +835,11 @@ tmpfs_nremove(struct vop_nremove_args *v)
        struct tmpfs_mount *tmp;
        struct tmpfs_node *dnode;
        struct tmpfs_node *node;
+       struct mount *mp;
+
+       mp = dvp->v_mount;
+
+       lwkt_gettoken(&mp->mnt_token);
 
        /*
         * We have to acquire the vp from v->a_nch because we will likely
@@ -795,6 +851,7 @@ tmpfs_nremove(struct vop_nremove_args *v)
         * will not get called when we release it.
         */
        error = cache_vget(v->a_nch, v->a_cred, LK_SHARED, &vp);
+       KKASSERT(vp->v_mount == dvp->v_mount);
        KKASSERT(error == 0);
        vn_unlock(vp);
 
@@ -842,6 +899,7 @@ tmpfs_nremove(struct vop_nremove_args *v)
 
 out:
        vrele(vp);
+       lwkt_reltoken(&mp->mnt_token);
 
        return error;
 }
@@ -857,8 +915,13 @@ tmpfs_nlink(struct vop_nlink_args *v)
        struct tmpfs_dirent *de;
        struct tmpfs_node *node;
        struct tmpfs_node *dnode;
+       struct mount *mp;
        int error;
 
+       mp = dvp->v_mount;
+       KKASSERT(dvp->v_mount == vp->v_mount);
+
+       lwkt_gettoken(&mp->mnt_token);
        KKASSERT(dvp != vp); /* XXX When can this be false? */
 
        node = VP_TO_TMPFS_NODE(vp);
@@ -894,7 +957,7 @@ tmpfs_nlink(struct vop_nlink_args *v)
 
        /* Allocate a new directory entry to represent the node. */
        error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
-           ncp->nc_name, ncp->nc_nlen, &de);
+                                  ncp->nc_name, ncp->nc_nlen, &de);
        if (error != 0)
                goto out;
 
@@ -915,6 +978,7 @@ tmpfs_nlink(struct vop_nlink_args *v)
        error = 0;
 
 out:
+       lwkt_reltoken(&mp->mnt_token);
        return error;
 }
 
@@ -935,10 +999,15 @@ tmpfs_nrename(struct vop_nrename_args *v)
        struct tmpfs_node *fnode;
        struct tmpfs_node *tnode;
        struct tmpfs_node *tdnode;
+       struct mount *mp;
        char *newname;
        char *oldname;
        int error;
 
+       mp = fdvp->v_mount;
+       KKASSERT(fdvp->v_mount == fvp->v_mount);
+
+       lwkt_gettoken(&mp->mnt_token);
        /*
         * Because tvp can get overwritten we have to vget it instead of
         * just vref or use it, otherwise it's VINACTIVE flag may not get
@@ -1121,6 +1190,8 @@ out:
        if (tvp)
                vrele(tvp);
 
+       lwkt_reltoken(&mp->mnt_token);
+
        return error;
 }
 
@@ -1134,8 +1205,12 @@ tmpfs_nmkdir(struct vop_nmkdir_args *v)
        struct namecache *ncp = v->a_nch->ncp;
        struct vattr *vap = v->a_vap;
        struct ucred *cred = v->a_cred;
+       struct mount *mp;
        int error;
 
+       mp = dvp->v_mount;
+
+       lwkt_gettoken(&mp->mnt_token);
        KKASSERT(vap->va_type == VDIR);
 
        error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, NULL);
@@ -1145,6 +1220,8 @@ tmpfs_nmkdir(struct vop_nmkdir_args *v)
                tmpfs_knote(dvp, NOTE_WRITE | NOTE_LINK);
        }
 
+       lwkt_reltoken(&mp->mnt_token);
+
        return error;
 }
 
@@ -1160,8 +1237,12 @@ tmpfs_nrmdir(struct vop_nrmdir_args *v)
        struct tmpfs_mount *tmp;
        struct tmpfs_node *dnode;
        struct tmpfs_node *node;
+       struct mount *mp;
        int error;
 
+       mp = dvp->v_mount;
+       lwkt_gettoken(&mp->mnt_token);
+
        /*
         * We have to acquire the vp from v->a_nch because we will likely
         * unresolve the namecache entry, and a vrele/vput is needed to
@@ -1261,6 +1342,8 @@ tmpfs_nrmdir(struct vop_nrmdir_args *v)
 out:
        vrele(vp);
 
+       lwkt_reltoken(&mp->mnt_token);
+
        return error;
 }
 
@@ -1275,8 +1358,10 @@ tmpfs_nsymlink(struct vop_nsymlink_args *v)
        struct vattr *vap = v->a_vap;
        struct ucred *cred = v->a_cred;
        char *target = v->a_target;
+       struct mount *mp = dvp->v_mount;
        int error;
 
+       lwkt_gettoken(&mp->mnt_token);
        vap->va_type = VLNK;
        error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, target);
        if (error == 0) {
@@ -1285,6 +1370,8 @@ tmpfs_nsymlink(struct vop_nsymlink_args *v)
                cache_setvp(v->a_nch, *vpp);
        }
 
+       lwkt_reltoken(&mp->mnt_token);
+
        return error;
 }
 
@@ -1303,10 +1390,15 @@ tmpfs_readdir(struct vop_readdir_args *v)
        off_t startoff;
        off_t cnt = 0;
        struct tmpfs_node *node;
+       struct mount *mp = vp->v_mount;
+
+       lwkt_gettoken(&mp->mnt_token);
 
        /* This operation only makes sense on directory nodes. */
-       if (vp->v_type != VDIR)
+       if (vp->v_type != VDIR) {
+               lwkt_reltoken(&mp->mnt_token);
                return ENOTDIR;
+       }
 
        tmp = VFS_TO_TMPFS(vp->v_mount);
        node = VP_TO_TMPFS_DIR(vp);
@@ -1373,6 +1465,8 @@ outok:
                KKASSERT(uio->uio_offset == off);
        }
 
+       lwkt_reltoken(&mp->mnt_token);
+
        return error;
 }
 
@@ -1383,10 +1477,12 @@ tmpfs_readlink(struct vop_readlink_args *v)
 {
        struct vnode *vp = v->a_vp;
        struct uio *uio = v->a_uio;
-
+       struct mount *mp = vp->v_mount;
        int error;
        struct tmpfs_node *node;
 
+       lwkt_gettoken(&mp->mnt_token);
+
        KKASSERT(uio->uio_offset == 0);
        KKASSERT(vp->v_type == VLNK);
 
@@ -1398,6 +1494,8 @@ tmpfs_readlink(struct vop_readlink_args *v)
        node->tn_status |= TMPFS_NODE_ACCESSED;
        TMPFS_NODE_UNLOCK(node);
 
+       lwkt_reltoken(&mp->mnt_token);
+
        return error;
 }
 
@@ -1408,7 +1506,10 @@ tmpfs_inactive(struct vop_inactive_args *v)
 {
        struct vnode *vp = v->a_vp;
        struct tmpfs_node *node;
+       struct mount *mp;
 
+       mp = vp->v_mount;
+       lwkt_gettoken(&mp->mnt_token);
        node = VP_TO_TMPFS_NODE(vp);
 
        /*
@@ -1416,6 +1517,7 @@ tmpfs_inactive(struct vop_inactive_args *v)
         */
        if (node == NULL) {
                vrecycle(vp);
+               lwkt_reltoken(&mp->mnt_token);
                return(0);
        }
 
@@ -1438,13 +1540,12 @@ tmpfs_inactive(struct vop_inactive_args *v)
        } else {
                TMPFS_NODE_UNLOCK(node);
        }
+       lwkt_reltoken(&mp->mnt_token);
 
        return 0;
 }
 
 /* --------------------------------------------------------------------- */
-#include <vm/vm_object.h>
-#include <vm/vm_page.h>
 
 int
 tmpfs_reclaim(struct vop_reclaim_args *v)
@@ -1452,9 +1553,14 @@ tmpfs_reclaim(struct vop_reclaim_args *v)
        struct vnode *vp = v->a_vp;
        struct tmpfs_mount *tmp;
        struct tmpfs_node *node;
+       struct mount *mp;
+
+       mp = vp->v_mount;
+       lwkt_gettoken(&mp->mnt_token);
 
        node = VP_TO_TMPFS_NODE(vp);
        tmp = VFS_TO_TMPFS(vp->v_mount);
+       KKASSERT(mp == tmp->tm_mount);
 
        tmpfs_free_vp(vp);
 
@@ -1474,6 +1580,7 @@ tmpfs_reclaim(struct vop_reclaim_args *v)
        } else {
                TMPFS_NODE_UNLOCK(node);
        }
+       lwkt_reltoken(&mp->mnt_token);
 
        KKASSERT(vp->v_data == NULL);
        return 0;
@@ -1488,9 +1595,11 @@ tmpfs_mountctl(struct vop_mountctl_args *ap)
        struct mount *mp; 
        int rc; 
 
+       mp = ap->a_head.a_ops->head.vv_mount;
+       lwkt_gettoken(&mp->mnt_token);
+
        switch (ap->a_op) { 
        case (MOUNTCTL_SET_EXPORT): 
-               mp = ap->a_head.a_ops->head.vv_mount; 
                tmp = (struct tmpfs_mount *) mp->mnt_data; 
  
                if (ap->a_ctllen != sizeof(struct export_args)) 
@@ -1503,6 +1612,8 @@ tmpfs_mountctl(struct vop_mountctl_args *ap)
                rc = vop_stdmountctl(ap); 
                break; 
        } 
+
+       lwkt_reltoken(&mp->mnt_token);
        return (rc); 
 }