git: 23b46b2bbf0a - main - audit: convert audit event class lookup to lockless

From: Andrew Gallatin <gallatin_at_FreeBSD.org>
Date: Mon, 27 Oct 2025 14:15:09 UTC
The branch main has been updated by gallatin:

URL: https://cgit.FreeBSD.org/src/commit/?id=23b46b2bbf0a8f3a740b6e5baf0767816afc339e

commit 23b46b2bbf0a8f3a740b6e5baf0767816afc339e
Author:     Andrew Gallatin <gallatin@FreeBSD.org>
AuthorDate: 2025-10-27 14:05:49 +0000
Commit:     Andrew Gallatin <gallatin@FreeBSD.org>
CommitDate: 2025-10-27 14:15:01 +0000

    audit: convert audit event class lookup to lockless
    
    When system call auditing is enabled, every audited call
    does a lookup in the evclass hash table.  This table
    appears to be insert only (eg, nothing can be removed)
    and protecting it with an rwlock is overkill.  Using
    an rwlock causes just the atomic operations to maintain
    uncontended rwlock state to be responsible for measurable
    overhead on high core count servers making lots of system calls.
    
    Given that the evclass hash table can never have items removed,
    only added, using a mutex to serialize additions and converting
    to ck_list allows sufficient protection for lockless lookups.
    
    In a contrived example of 64 cores, all reading 1 byte from their
    own file, this change increases performance from 5M reads/sec
    to 70M reads/sec on an AMD 7502P.
    
    Reviewed by: markj, mjg, glebius (privately)
    Sponsored by:   Netflix
    Differential Revision: https://reviews.freebsd.org/D53176
---
 sys/security/audit/audit_bsm_db.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/sys/security/audit/audit_bsm_db.c b/sys/security/audit/audit_bsm_db.c
index c9f3d5c8a549..358162544287 100644
--- a/sys/security/audit/audit_bsm_db.c
+++ b/sys/security/audit/audit_bsm_db.c
@@ -56,6 +56,8 @@
 #include <security/audit/audit.h>
 #include <security/audit/audit_private.h>
 
+#include <contrib/ck/include/ck_queue.h>
+
 /*
  * Hash table functions for the audit event number to event class mask
  * mapping.
@@ -64,21 +66,21 @@
 struct evclass_elem {
 	au_event_t event;
 	au_class_t class;
-	LIST_ENTRY(evclass_elem) entry;
+	CK_LIST_ENTRY(evclass_elem) entry;
 };
 struct evclass_list {
-	LIST_HEAD(, evclass_elem) head;
+	CK_LIST_HEAD(, evclass_elem) head;
 };
 
 static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
-static struct rwlock		evclass_lock;
 static struct evclass_list	evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
-
-#define	EVCLASS_LOCK_INIT()	rw_init(&evclass_lock, "evclass_lock")
-#define	EVCLASS_RLOCK()		rw_rlock(&evclass_lock)
-#define	EVCLASS_RUNLOCK()	rw_runlock(&evclass_lock)
-#define	EVCLASS_WLOCK()		rw_wlock(&evclass_lock)
-#define	EVCLASS_WUNLOCK()	rw_wunlock(&evclass_lock)
+static struct mtx evclass_mtx;
+#define	EVCLASS_LOCK_INIT()	mtx_init(&evclass_mtx, "evclass_lock", NULL, MTX_DEF)
+#define	EVCLASS_WLOCK()		mtx_lock(&evclass_mtx);
+#define	EVCLASS_WUNLOCK()	mtx_unlock(&evclass_mtx);
+/* make these do something if we ever remove entries from the hash */
+#define	EVCLASS_RLOCK()		{}
+#define	EVCLASS_RUNLOCK()	{}
 
 /*
  * Hash table maintaining a mapping from audit event numbers to audit event
@@ -118,7 +120,7 @@ au_event_class(au_event_t event)
 	EVCLASS_RLOCK();
 	evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
 	class = 0;
-	LIST_FOREACH(evc, &evcl->head, entry) {
+	CK_LIST_FOREACH(evc, &evcl->head, entry) {
 		if (evc->event == event) {
 			class = evc->class;
 			goto out;
@@ -150,7 +152,7 @@ au_evclassmap_insert(au_event_t event, au_class_t class)
 
 	EVCLASS_WLOCK();
 	evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
-	LIST_FOREACH(evc, &evcl->head, entry) {
+	CK_LIST_FOREACH(evc, &evcl->head, entry) {
 		if (evc->event == event) {
 			evc->class = class;
 			EVCLASS_WUNLOCK();
@@ -161,7 +163,7 @@ au_evclassmap_insert(au_event_t event, au_class_t class)
 	evc = evc_new;
 	evc->event = event;
 	evc->class = class;
-	LIST_INSERT_HEAD(&evcl->head, evc, entry);
+	CK_LIST_INSERT_HEAD(&evcl->head, evc, entry);
 	EVCLASS_WUNLOCK();
 }
 
@@ -172,7 +174,7 @@ au_evclassmap_init(void)
 
 	EVCLASS_LOCK_INIT();
 	for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
-		LIST_INIT(&evclass_hash[i].head);
+		CK_LIST_INIT(&evclass_hash[i].head);
 
 	/*
 	 * Set up the initial event to class mapping for system calls.