The branch main has been updated by rlibby: URL: https://cgit.FreeBSD.org/src/commit/?id=ca8a1c3c27b0d5915e0dcfd02ea4ef703db4fe9a
commit ca8a1c3c27b0d5915e0dcfd02ea4ef703db4fe9a Author: Ryan Libby <[email protected]> AuthorDate: 2026-06-18 03:54:26 +0000 Commit: Ryan Libby <[email protected]> CommitDate: 2026-06-18 04:05:43 +0000 witness: add tunables debug.witness.lock_order_{data_count,hash_size} Add tunable debug.witness.lock_order_data_count to allow adjusting the number of witness lock order data entries (stacks) without recompiling the kernel. This may help to display stacks when a lock order reversal is reported but the number of entries is exhausted before recording the first lock order, by allowing the user to reboot with an adjusted tunable and try again. Tunable debug.witness.lock_order_hash_size is also provided to allow the hash table load factor to be managed, though that is not required. Also tweak witness_lock_order_add to avoid computing a hash when it won't be needed because the lock order data entries are exhausted. Reviewed by: kib, markj Sponsored by: Dell Inc. Differential Revision: https://reviews.freebsd.org/D57600 --- sys/kern/subr_witness.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 2bfd8711eed7..21d015c4f381 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -264,7 +264,7 @@ struct witness_lock_order_data { * (struct witness_lock_order_data). */ struct witness_lock_order_hash { - struct witness_lock_order_data *wloh_array[WITNESS_LO_HASH_SIZE]; + struct witness_lock_order_data **wloh_array; u_int wloh_size; u_int wloh_count; }; @@ -421,6 +421,18 @@ SYSCTL_ULONG(_debug_witness, OID_AUTO, witness_count, "Maximum count of lock type entries"); TUNABLE_ULONG("debug.witness.witness_count", &witness_count); +static u_long witness_lo_data_count = WITNESS_LO_DATA_COUNT; +SYSCTL_ULONG(_debug_witness, OID_AUTO, lock_order_data_count, + CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &witness_lo_data_count, 0, + "Maximum count of lock order data (stacks) to track"); +TUNABLE_ULONG("debug.witness.lock_order_data_count", &witness_lo_data_count); + +static u_long witness_lo_hash_size = WITNESS_LO_HASH_SIZE; +SYSCTL_ULONG(_debug_witness, OID_AUTO, lock_order_hash_size, + CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &witness_lo_hash_size, 0, + "Hash table size for lock order data"); +TUNABLE_ULONG("debug.witness.lock_order_hash_size", &witness_lo_hash_size); + /* * Output channel for witness messages. By default we print to the console. */ @@ -479,7 +491,7 @@ static struct lock_list_entry w_locklistdata[LOCK_CHILDCOUNT]; static struct witness_hash w_hash; /* The witness hash table. */ /* The lock order data hash */ -static struct witness_lock_order_data w_lodata[WITNESS_LO_DATA_COUNT]; +static struct witness_lock_order_data *w_lodata; static struct witness_lock_order_data *w_lofree = NULL; static struct witness_lock_order_hash w_lohash; static int w_max_used_index = 0; @@ -788,6 +800,9 @@ witness_startup_count(void) sz += sizeof(*w_rmatrix) * (witness_count + 1); sz += sizeof(*w_rmatrix[0]) * (witness_count + 1) * (witness_count + 1); + sz += sizeof(void *); + sz += sizeof(w_lodata[0]) * witness_lo_data_count; + sz += sizeof(w_lohash.wloh_array[0]) * witness_lo_hash_size; return (sz); } @@ -818,6 +833,16 @@ witness_startup(void *mem) w_rmatrix[i] = (void *)p; p += sizeof(*w_rmatrix[i]) * (witness_count + 1); } + + /* Fix up alignment */ + p = roundup2(p, sizeof(void *)); + + w_lodata = (void *)p; + p += sizeof(w_lodata[0]) * witness_lo_data_count; + + w_lohash.wloh_array = (void *)p; + p += sizeof(w_lohash.wloh_array[0]) * witness_lo_hash_size; + badstack_sbuf_size = witness_count * 256; /* @@ -3300,14 +3325,14 @@ witness_init_hash_tables(void) /* Initialize the lock order data hash. */ w_lofree = NULL; - for (i = 0; i < WITNESS_LO_DATA_COUNT; i++) { + for (i = 0; i < witness_lo_data_count; i++) { memset(&w_lodata[i], 0, sizeof(w_lodata[i])); w_lodata[i].wlod_next = w_lofree; w_lofree = &w_lodata[i]; } - w_lohash.wloh_size = WITNESS_LO_HASH_SIZE; + w_lohash.wloh_size = witness_lo_hash_size; w_lohash.wloh_count = 0; - for (i = 0; i < WITNESS_LO_HASH_SIZE; i++) + for (i = 0; i < w_lohash.wloh_size; i++) w_lohash.wloh_array[i] = NULL; } @@ -3414,13 +3439,13 @@ witness_lock_order_add(struct witness *parent, struct witness *child) & WITNESS_LOCK_ORDER_KNOWN) return (1); - hash = witness_hash_djb2((const char *)&key, - sizeof(key)) % w_lohash.wloh_size; w_rmatrix[parent->w_index][child->w_index] |= WITNESS_LOCK_ORDER_KNOWN; data = w_lofree; if (data == NULL) return (0); w_lofree = data->wlod_next; + hash = witness_hash_djb2((const char *)&key, + sizeof(key)) % w_lohash.wloh_size; data->wlod_next = w_lohash.wloh_array[hash]; data->wlod_key = key; w_lohash.wloh_array[hash] = data;
