From 4601f5f5ee10e6ea093c6c7289a7157ed527d9d8 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Tue, 15 Sep 2020 22:13:21 +0000 Subject: Microoptimize tmpfs node ref/unref by using atomics. Avoid tmpfs mount and node locks when ref count is greater than zero, which is the case until node is being destroyed by unlink or unmount. Reviewed by: markj Tested by: pho Sponsored by: The FreeBSD Foundation Differential revision: https://reviews.freebsd.org/D26346 --- sys/fs/tmpfs/tmpfs.h | 3 +-- sys/fs/tmpfs/tmpfs_subr.c | 35 ++++++++++++++++------------------- sys/fs/tmpfs/tmpfs_vnops.c | 2 +- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h index b15a83af7eba9..ac8fe0c1c2d66 100644 --- a/sys/fs/tmpfs/tmpfs.h +++ b/sys/fs/tmpfs/tmpfs.h @@ -228,7 +228,7 @@ struct tmpfs_node { int tn_vpstate; /* (i) */ /* Transient refcounter on this node. */ - u_int tn_refcount; /* (m) + (i) */ + u_int tn_refcount; /* 0<->1 (m) + (i) */ /* misc data field for different tn_type node */ union { @@ -412,7 +412,6 @@ struct tmpfs_dir_cursor { */ void tmpfs_ref_node(struct tmpfs_node *node); -void tmpfs_ref_node_locked(struct tmpfs_node *node); int tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *, enum vtype, uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *, const char *, dev_t, struct tmpfs_node **); diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index 7d5d719001486..d9844bc3c7c9b 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -211,21 +212,15 @@ tmpfs_pages_check_avail(struct tmpfs_mount *tmp, size_t req_pages) void tmpfs_ref_node(struct tmpfs_node *node) { +#ifdef INVARIANTS + u_int old; - TMPFS_NODE_LOCK(node); - tmpfs_ref_node_locked(node); - TMPFS_NODE_UNLOCK(node); -} - -void -tmpfs_ref_node_locked(struct tmpfs_node *node) -{ - - TMPFS_NODE_ASSERT_LOCKED(node); - KASSERT(node->tn_refcount > 0, ("node %p zero refcount", node)); - KASSERT(node->tn_refcount < UINT_MAX, ("node %p refcount %u", node, - node->tn_refcount)); - node->tn_refcount++; + old = +#endif + refcount_acquire(&node->tn_refcount); +#ifdef INVARIANTS + KASSERT(old > 0, ("node %p zero refcount", node)); +#endif } /* @@ -370,6 +365,8 @@ tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *tmp, enum vtype type, void tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node) { + if (refcount_release_if_not_last(&node->tn_refcount)) + return; TMPFS_LOCK(tmp); TMPFS_NODE_LOCK(node); @@ -384,19 +381,19 @@ tmpfs_free_node_locked(struct tmpfs_mount *tmp, struct tmpfs_node *node, bool detach) { vm_object_t uobj; + bool last; TMPFS_MP_ASSERT_LOCKED(tmp); TMPFS_NODE_ASSERT_LOCKED(node); - KASSERT(node->tn_refcount > 0, ("node %p refcount zero", node)); - node->tn_refcount--; - if (node->tn_attached && (detach || node->tn_refcount == 0)) { + last = refcount_release(&node->tn_refcount); + if (node->tn_attached && (detach || last)) { MPASS(tmp->tm_nodes_inuse > 0); tmp->tm_nodes_inuse--; LIST_REMOVE(node, tn_entries); node->tn_attached = false; } - if (node->tn_refcount > 0) + if (!last) return (false); #ifdef INVARIANTS @@ -596,7 +593,7 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag, error = 0; tm = VFS_TO_TMPFS(mp); TMPFS_NODE_LOCK(node); - tmpfs_ref_node_locked(node); + tmpfs_ref_node(node); loop: TMPFS_NODE_ASSERT_LOCKED(node); if ((vp = node->tn_vnode) != NULL) { diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 61dd148c73051..c5d0702801e95 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -1663,7 +1663,7 @@ restart: if (tnp->tn_type != VDIR) continue; TMPFS_NODE_LOCK(tnp); - tmpfs_ref_node_locked(tnp); + tmpfs_ref_node(tnp); /* * tn_vnode cannot be instantiated while we hold the -- cgit v1.2.3