tmpfs: add support for lockless lookup

Reviewed by:    kib
Tested by:      pho (in a patchset)
Differential Revision:	https://reviews.freebsd.org/D25580
This commit is contained in:
Mateusz Guzik 2020-07-25 10:38:44 +00:00
parent 9d5a594f0b
commit 172ffe702c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=363521
5 changed files with 76 additions and 9 deletions

View File

@ -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)
{

View File

@ -75,6 +75,7 @@ static long tmpfs_pages_reserved = TMPFS_PAGES_MINRESERVED;
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 *tmp, enum vtype type,
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 tmpfs_node *node,
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 ucred *cred, struct thread *p)
{
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,9 +1660,9 @@ tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct thread *p)
return (error);
}
node->tn_mode &= ~ALLPERMS;
node->tn_mode |= mode & ALLPERMS;
newmode = node->tn_mode & ~ALLPERMS;
newmode |= mode & ALLPERMS;
atomic_store_short(&node->tn_mode, newmode);
node->tn_status |= TMPFS_NODE_CHANGED;
@ -1682,8 +1686,10 @@ tmpfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred,
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, struct ucred *cred,
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");

View File

@ -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;

View File

@ -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,6 +319,32 @@ 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)
{
@ -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 @@ tmpfs_rename(struct vop_rename_args *v)
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,

View File

@ -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;