fileassoc(9): Fast paths to skip global locks when not in use.

PR kern/57552
This commit is contained in:
riastradh 2023-08-02 07:11:31 +00:00
parent c59176887b
commit 140f7071dd
1 changed files with 62 additions and 5 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_fileassoc.c,v 1.36 2014/07/10 15:00:28 christos Exp $ */
/* $NetBSD: kern_fileassoc.c,v 1.37 2023/08/02 07:11:31 riastradh Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_fileassoc.c,v 1.36 2014/07/10 15:00:28 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_fileassoc.c,v 1.37 2023/08/02 07:11:31 riastradh Exp $");
#include "opt_fileassoc.h"
@ -42,6 +42,8 @@ __KERNEL_RCSID(0, "$NetBSD: kern_fileassoc.c,v 1.36 2014/07/10 15:00:28 christos
#include <sys/hash.h>
#include <sys/kmem.h>
#include <sys/once.h>
#include <sys/mutex.h>
#include <sys/xcall.h>
#define FILEASSOC_INITIAL_TABLESIZE 128
@ -88,6 +90,52 @@ struct fileassoc_table {
(hash32_buf((handle), FHANDLE_SIZE(handle), HASH32_BUF_INIT) \
& ((tbl)->tbl_mask))
/*
* Global usage counting. This is bad for parallelism of updates, but
* good for avoiding calls to fileassoc when it's not in use. Unclear
* if parallelism of updates matters much. If you want to improve
* fileassoc(9) update performance, feel free to rip this out as long
* as you don't cause the fast paths to take any global locks or incur
* memory barriers when fileassoc(9) is not in use.
*/
static struct {
kmutex_t lock;
uint64_t nassocs;
volatile bool inuse;
} fileassoc_global __cacheline_aligned;
static void
fileassoc_incuse(void)
{
mutex_enter(&fileassoc_global.lock);
if (fileassoc_global.nassocs++ == 0) {
KASSERT(!fileassoc_global.inuse);
atomic_store_relaxed(&fileassoc_global.inuse, true);
xc_barrier(0);
}
mutex_exit(&fileassoc_global.lock);
}
static void
fileassoc_decuse(void)
{
mutex_enter(&fileassoc_global.lock);
KASSERT(fileassoc_global.nassocs > 0);
KASSERT(fileassoc_global.inuse);
if (--fileassoc_global.nassocs == 0)
atomic_store_relaxed(&fileassoc_global.inuse, false);
mutex_exit(&fileassoc_global.lock);
}
static bool
fileassoc_inuse(void)
{
return __predict_false(atomic_load_relaxed(&fileassoc_global.inuse));
}
static void *
file_getdata(struct fileassoc_file *faf, const struct fileassoc *assoc)
{
@ -128,6 +176,7 @@ file_free(struct fileassoc_file *faf)
LIST_FOREACH(assoc, &fileassoc_list, assoc_list) {
file_cleanup(faf, assoc);
fileassoc_decuse();
}
vfs_composefh_free(faf->faf_handle);
specificdata_fini(fileassoc_domain, &faf->faf_data);
@ -226,6 +275,9 @@ fileassoc_table_lookup(struct mount *mp)
{
int error;
if (!fileassoc_inuse())
return NULL;
error = RUN_ONCE(&control, fileassoc_init);
if (error) {
return NULL;
@ -437,6 +489,8 @@ fileassoc_table_clear(struct mount *mp, fileassoc_t assoc)
LIST_FOREACH(faf, &tbl->tbl_hash[i], faf_list) {
file_cleanup(faf, assoc);
file_setdata(faf, assoc, NULL);
/* XXX missing faf->faf_nassocs--? */
fileassoc_decuse();
}
}
@ -510,10 +564,9 @@ fileassoc_file_delete(struct vnode *vp)
struct fileassoc_table *tbl;
struct fileassoc_file *faf;
/* Pre-check if fileassoc is used. XXX */
if (!fileassoc_domain) {
if (!fileassoc_inuse())
return ENOENT;
}
KERNEL_LOCK(1, NULL);
faf = fileassoc_file_lookup(vp, NULL);
@ -553,6 +606,8 @@ fileassoc_add(struct vnode *vp, fileassoc_t assoc, void *data)
if (olddata != NULL)
return (EEXIST);
fileassoc_incuse();
file_setdata(faf, assoc, data);
faf->faf_nassocs++;
@ -577,5 +632,7 @@ fileassoc_clear(struct vnode *vp, fileassoc_t assoc)
--(faf->faf_nassocs); /* XXX gc? */
fileassoc_decuse();
return (0);
}