Index: head/sys/fs/tmpfs/tmpfs.h =================================================================== --- head/sys/fs/tmpfs/tmpfs.h +++ head/sys/fs/tmpfs/tmpfs.h @@ -526,6 +526,9 @@ 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) { Index: head/sys/fs/tmpfs/tmpfs_subr.c =================================================================== --- head/sys/fs/tmpfs/tmpfs_subr.c +++ head/sys/fs/tmpfs/tmpfs_subr.c @@ -75,6 +75,7 @@ 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_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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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"); Index: head/sys/fs/tmpfs/tmpfs_vfsops.c =================================================================== --- head/sys/fs/tmpfs/tmpfs_vfsops.c +++ head/sys/fs/tmpfs/tmpfs_vfsops.c @@ -462,6 +462,8 @@ 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; Index: head/sys/fs/tmpfs/tmpfs_vnops.h =================================================================== --- head/sys/fs/tmpfs/tmpfs_vnops.h +++ head/sys/fs/tmpfs/tmpfs_vnops.h @@ -49,6 +49,7 @@ 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; Index: head/sys/fs/tmpfs/tmpfs_vnops.c =================================================================== --- head/sys/fs/tmpfs/tmpfs_vnops.c +++ head/sys/fs/tmpfs/tmpfs_vnops.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,7 @@ #include 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 @@ 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 @@ int error; MPASS(VOP_ISLOCKED(vp)); + ASSERT_VOP_IN_SEQC(vp); error = 0; @@ -497,6 +526,7 @@ 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 @@ 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 @@ 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 @@ } } + 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 @@ 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 @@ .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,