Author: mjg
Date: Sat Jul 25 10:38:44 2020
New Revision: 363521
URL: https://svnweb.freebsd.org/changeset/base/363521

Log:
  tmpfs: add support for lockless lookup
  
  Reviewed by:    kib
  Tested by:      pho (in a patchset)
  Differential Revision:        https://reviews.freebsd.org/D25580

Modified:
  head/sys/fs/tmpfs/tmpfs.h
  head/sys/fs/tmpfs/tmpfs_subr.c
  head/sys/fs/tmpfs/tmpfs_vfsops.c
  head/sys/fs/tmpfs/tmpfs_vnops.c
  head/sys/fs/tmpfs/tmpfs_vnops.h

Modified: head/sys/fs/tmpfs/tmpfs.h
==============================================================================
--- head/sys/fs/tmpfs/tmpfs.h   Sat Jul 25 10:38:05 2020        (r363520)
+++ head/sys/fs/tmpfs/tmpfs.h   Sat Jul 25 10:38:44 2020        (r363521)
@@ -526,6 +526,9 @@ VP_TO_TMPFS_NODE(struct vnode *vp)
        return (node);
 }
 
+#define        VP_TO_TMPFS_NODE_SMR(vp)        \
+       ((struct tmpfs_node *)vn_load_v_data_smr(vp))
+
 static inline struct tmpfs_node *
 VP_TO_TMPFS_DIR(struct vnode *vp)
 {

Modified: head/sys/fs/tmpfs/tmpfs_subr.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_subr.c      Sat Jul 25 10:38:05 2020        
(r363520)
+++ head/sys/fs/tmpfs/tmpfs_subr.c      Sat Jul 25 10:38:44 2020        
(r363521)
@@ -75,6 +75,7 @@ static long tmpfs_pages_reserved = TMPFS_PAGES_MINRESE
 
 static uma_zone_t tmpfs_dirent_pool;
 static uma_zone_t tmpfs_node_pool;
+VFS_SMR_DECLARE;
 
 static int
 tmpfs_node_ctor(void *mem, int size, void *arg, int flags)
@@ -131,6 +132,7 @@ tmpfs_subr_init(void)
        tmpfs_node_pool = uma_zcreate("TMPFS node",
            sizeof(struct tmpfs_node), tmpfs_node_ctor, tmpfs_node_dtor,
            tmpfs_node_init, tmpfs_node_fini, UMA_ALIGN_PTR, 0);
+       VFS_SMR_ZONE_SET(tmpfs_node_pool);
 }
 
 void
@@ -288,7 +290,7 @@ tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount 
        if ((mp->mnt_kern_flag & MNT_RDONLY) != 0)
                return (EROFS);
 
-       nnode = uma_zalloc_arg(tmpfs_node_pool, tmp, M_WAITOK);
+       nnode = uma_zalloc_smr(tmpfs_node_pool, M_WAITOK);
 
        /* Generic initialization. */
        nnode->tn_type = type;
@@ -435,7 +437,7 @@ tmpfs_free_node_locked(struct tmpfs_mount *tmp, struct
                panic("tmpfs_free_node: type %p %d", node, (int)node->tn_type);
        }
 
-       uma_zfree(tmpfs_node_pool, node);
+       uma_zfree_smr(tmpfs_node_pool, node);
        TMPFS_LOCK(tmp);
        tmpfs_free_tmp(tmp);
        return (true);
@@ -1621,8 +1623,10 @@ tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucre
 {
        int error;
        struct tmpfs_node *node;
+       mode_t newmode;
 
        ASSERT_VOP_ELOCKED(vp, "chmod");
+       ASSERT_VOP_IN_SEQC(vp);
 
        node = VP_TO_TMPFS_NODE(vp);
 
@@ -1656,10 +1660,10 @@ tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucre
                        return (error);
        }
 
+       newmode = node->tn_mode & ~ALLPERMS;
+       newmode |= mode & ALLPERMS;
+       atomic_store_short(&node->tn_mode, newmode);
 
-       node->tn_mode &= ~ALLPERMS;
-       node->tn_mode |= mode & ALLPERMS;
-
        node->tn_status |= TMPFS_NODE_CHANGED;
 
        ASSERT_VOP_ELOCKED(vp, "chmod2");
@@ -1682,8 +1686,10 @@ tmpfs_chown(struct vnode *vp, uid_t uid, gid_t gid, st
        struct tmpfs_node *node;
        uid_t ouid;
        gid_t ogid;
+       mode_t newmode;
 
        ASSERT_VOP_ELOCKED(vp, "chown");
+       ASSERT_VOP_IN_SEQC(vp);
 
        node = VP_TO_TMPFS_NODE(vp);
 
@@ -1729,8 +1735,10 @@ tmpfs_chown(struct vnode *vp, uid_t uid, gid_t gid, st
        node->tn_status |= TMPFS_NODE_CHANGED;
 
        if ((node->tn_mode & (S_ISUID | S_ISGID)) && (ouid != uid || ogid != 
gid)) {
-               if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID))
-                       node->tn_mode &= ~(S_ISUID | S_ISGID);
+               if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) {
+                       newmode = node->tn_mode & ~(S_ISUID | S_ISGID);
+                       atomic_store_short(&node->tn_mode, newmode);
+               }
        }
 
        ASSERT_VOP_ELOCKED(vp, "chown2");

Modified: head/sys/fs/tmpfs/tmpfs_vfsops.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_vfsops.c    Sat Jul 25 10:38:05 2020        
(r363520)
+++ head/sys/fs/tmpfs/tmpfs_vfsops.c    Sat Jul 25 10:38:44 2020        
(r363521)
@@ -462,6 +462,8 @@ tmpfs_mount(struct mount *mp)
        mp->mnt_flag |= MNT_LOCAL;
        mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED |
            MNTK_TEXT_REFS | MNTK_NOMSYNC;
+       if (!nonc)
+               mp->mnt_kern_flag |= MNTK_FPLOOKUP;
        MNT_IUNLOCK(mp);
 
        mp->mnt_data = tmp;

Modified: head/sys/fs/tmpfs/tmpfs_vnops.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_vnops.c     Sat Jul 25 10:38:05 2020        
(r363520)
+++ head/sys/fs/tmpfs/tmpfs_vnops.c     Sat Jul 25 10:38:44 2020        
(r363521)
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 #include <sys/unistd.h>
 #include <sys/vnode.h>
+#include <sys/smr.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -64,6 +65,7 @@ __FBSDID("$FreeBSD$");
 #include <fs/tmpfs/tmpfs.h>
 
 SYSCTL_DECL(_vfs_tmpfs);
+VFS_SMR_DECLARE;
 
 static volatile int tmpfs_rename_restarts;
 SYSCTL_INT(_vfs_tmpfs, OID_AUTO, rename_restarts, CTLFLAG_RD,
@@ -317,7 +319,33 @@ tmpfs_close(struct vop_close_args *v)
        return (0);
 }
 
+/*
+ * VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see
+ * the comment above cache_fplookup for details.
+ */
 int
+tmpfs_fplookup_vexec(struct vop_fplookup_vexec_args *v)
+{
+       struct vnode *vp;
+       struct tmpfs_node *node;
+       struct ucred *cred;
+       mode_t all_x, mode;
+
+       vp = v->a_vp;
+       node = VP_TO_TMPFS_NODE_SMR(vp);
+       if (__predict_false(node == NULL))
+               return (EAGAIN);
+
+       all_x = S_IXUSR | S_IXGRP | S_IXOTH;
+       mode = atomic_load_short(&node->tn_mode);
+       if (__predict_true((mode & all_x) == all_x))
+               return (0);
+
+       cred = v->a_cred;
+       return (vaccess_vexec_smr(mode, node->tn_uid, node->tn_gid, cred));
+}
+
+int
 tmpfs_access(struct vop_access_args *v)
 {
        struct vnode *vp = v->a_vp;
@@ -427,6 +455,7 @@ tmpfs_setattr(struct vop_setattr_args *v)
        int error;
 
        MPASS(VOP_ISLOCKED(vp));
+       ASSERT_VOP_IN_SEQC(vp);
 
        error = 0;
 
@@ -497,6 +526,7 @@ tmpfs_write(struct vop_write_args *v)
        struct tmpfs_node *node;
        off_t oldsize;
        int error, ioflag;
+       mode_t newmode;
 
        vp = v->a_vp;
        uio = v->a_uio;
@@ -527,8 +557,12 @@ tmpfs_write(struct vop_write_args *v)
        node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
            TMPFS_NODE_CHANGED;
        if (node->tn_mode & (S_ISUID | S_ISGID)) {
-               if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID))
-                       node->tn_mode &= ~(S_ISUID | S_ISGID);
+               if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID)) {
+                       newmode = node->tn_mode & ~(S_ISUID | S_ISGID);
+                       vn_seqc_write_begin(vp);
+                       atomic_store_short(&node->tn_mode, newmode);
+                       vn_seqc_write_end(vp);
+               }
        }
        if (error != 0)
                (void)tmpfs_reg_resize(vp, oldsize, TRUE);
@@ -806,12 +840,15 @@ tmpfs_rename(struct vop_rename_args *v)
        struct tmpfs_node *tnode;
        struct tmpfs_node *tdnode;
        int error;
+       bool want_seqc_end;
 
        MPASS(VOP_ISLOCKED(tdvp));
        MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp)));
        MPASS(fcnp->cn_flags & HASBUF);
        MPASS(tcnp->cn_flags & HASBUF);
 
+       want_seqc_end = false;
+
        /*
         * Disallow cross-device renames.
         * XXX Why isn't this done by the caller?
@@ -852,6 +889,13 @@ tmpfs_rename(struct vop_rename_args *v)
                }
        }
 
+       if (tvp != NULL)
+               vn_seqc_write_begin(tvp);
+       vn_seqc_write_begin(tdvp);
+       vn_seqc_write_begin(fvp);
+       vn_seqc_write_begin(fdvp);
+       want_seqc_end = true;
+
        tmp = VFS_TO_TMPFS(tdvp->v_mount);
        tdnode = VP_TO_TMPFS_DIR(tdvp);
        tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
@@ -1065,6 +1109,14 @@ out_locked:
                VOP_UNLOCK(fdvp);
 
 out:
+       if (want_seqc_end) {
+               if (tvp != NULL)
+                       vn_seqc_write_end(tvp);
+               vn_seqc_write_end(tdvp);
+               vn_seqc_write_end(fvp);
+               vn_seqc_write_end(fdvp);
+       }
+
        /*
         * Release target nodes.
         * XXX: I don't understand when tdvp can be the same as tvp, but
@@ -1621,6 +1673,7 @@ struct vop_vector tmpfs_vnodeop_entries = {
        .vop_mknod =                    tmpfs_mknod,
        .vop_open =                     tmpfs_open,
        .vop_close =                    tmpfs_close,
+       .vop_fplookup_vexec =           tmpfs_fplookup_vexec,
        .vop_access =                   tmpfs_access,
        .vop_getattr =                  tmpfs_getattr,
        .vop_setattr =                  tmpfs_setattr,

Modified: head/sys/fs/tmpfs/tmpfs_vnops.h
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_vnops.h     Sat Jul 25 10:38:05 2020        
(r363520)
+++ head/sys/fs/tmpfs/tmpfs_vnops.h     Sat Jul 25 10:38:44 2020        
(r363521)
@@ -49,6 +49,7 @@ extern struct vop_vector tmpfs_vnodeop_entries;
 extern struct vop_vector tmpfs_vnodeop_nonc_entries;
 
 vop_access_t   tmpfs_access;
+vop_fplookup_vexec_t tmpfs_fplookup_vexec;
 vop_getattr_t  tmpfs_getattr;
 vop_setattr_t  tmpfs_setattr;
 vop_pathconf_t tmpfs_pathconf;
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to