From eac22dd48079d5cccecb07f4e60b44bb692167f8 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Mon, 15 Feb 2021 05:24:17 +0100 Subject: [PATCH] lockmgr: shrink struct lock by 8 bytes on LP64 Currently the struct has a 4 byte padding stemming from 3 ints. 1. prio comfortably fits in short, unfortunately there is no dedicated type for it and plumbing it throughout the codebase is not worth it right now, instead an assert is added which covers also flags for safety 2. lk_exslpfail can in principle exceed u_short, but the count is already not considered reliable and it only ever gets modified straight to 0. In other words it can be incrementing with an upper bound of USHRT_MAX With these in place struct lock shrinks from 48 to 40 bytes. Reviewed by: kib (previous version) Differential Revision: https://reviews.freebsd.org/D28680 --- sys/kern/kern_lock.c | 18 +++++++++++++----- sys/kern/subr_lock.c | 1 + sys/sys/_lockmgr.h | 4 ++-- sys/sys/param.h | 7 ++++--- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 091abcda2a1..5cefcf7a597 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -61,6 +62,12 @@ __FBSDID("$FreeBSD$"); PMC_SOFT_DECLARE( , , lock, failed); #endif +/* + * Hack. There should be prio_t or similar so that this is not necessary. + */ +_Static_assert((PRILASTFLAG * 2) - 1 <= USHRT_MAX, + "prio flags wont fit in u_short pri in struct lock"); + CTASSERT(LK_UNLOCKED == (LK_UNLOCKED & ~(LK_ALL_WAITERS | LK_EXCLUSIVE_SPINNERS))); @@ -280,8 +287,10 @@ sleeplk(struct lock *lk, u_int flags, struct lock_object *ilk, if (flags & LK_INTERLOCK) class->lc_unlock(ilk); - if (queue == SQ_EXCLUSIVE_QUEUE && (flags & LK_SLEEPFAIL) != 0) - lk->lk_exslpfail++; + if (queue == SQ_EXCLUSIVE_QUEUE && (flags & LK_SLEEPFAIL) != 0) { + if (lk->lk_exslpfail < USHRT_MAX) + lk->lk_exslpfail++; + } GIANT_SAVE(); sleepq_add(&lk->lock_object, NULL, wmesg, SLEEPQ_LK | (catch ? SLEEPQ_INTERRUPTIBLE : 0), queue); @@ -345,7 +354,7 @@ retry_sleepq: realexslp = sleepq_sleepcnt(&lk->lock_object, SQ_EXCLUSIVE_QUEUE); if ((x & LK_EXCLUSIVE_WAITERS) != 0 && realexslp != 0) { - if (lk->lk_exslpfail < realexslp) { + if (lk->lk_exslpfail != USHRT_MAX && lk->lk_exslpfail < realexslp) { lk->lk_exslpfail = 0; queue = SQ_EXCLUSIVE_QUEUE; v |= (x & LK_SHARED_WAITERS); @@ -362,7 +371,6 @@ retry_sleepq: SLEEPQ_LK, 0, SQ_EXCLUSIVE_QUEUE); queue = SQ_SHARED_QUEUE; } - } else { /* * Exclusive waiters sleeping with LK_SLEEPFAIL on @@ -1170,7 +1178,7 @@ lockmgr_xunlock_hard(struct lock *lk, uintptr_t x, u_int flags, struct lock_obje MPASS((x & LK_EXCLUSIVE_SPINNERS) == 0); realexslp = sleepq_sleepcnt(&lk->lock_object, SQ_EXCLUSIVE_QUEUE); if ((x & LK_EXCLUSIVE_WAITERS) != 0 && realexslp != 0) { - if (lk->lk_exslpfail < realexslp) { + if (lk->lk_exslpfail != USHRT_MAX && lk->lk_exslpfail < realexslp) { lk->lk_exslpfail = 0; queue = SQ_EXCLUSIVE_QUEUE; v |= (x & LK_SHARED_WAITERS); diff --git a/sys/kern/subr_lock.c b/sys/kern/subr_lock.c index b69ee349482..a74f7e62db4 100644 --- a/sys/kern/subr_lock.c +++ b/sys/kern/subr_lock.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include diff --git a/sys/sys/_lockmgr.h b/sys/sys/_lockmgr.h index 62e50df1ac4..b0d164bdb4d 100644 --- a/sys/sys/_lockmgr.h +++ b/sys/sys/_lockmgr.h @@ -40,9 +40,9 @@ struct lock { struct lock_object lock_object; volatile uintptr_t lk_lock; - u_int lk_exslpfail; + u_short lk_exslpfail; + u_short lk_pri; int lk_timo; - int lk_pri; #ifdef DEBUG_LOCKS struct stack lk_stack; #endif diff --git a/sys/sys/param.h b/sys/sys/param.h index 058aef99e07..fa02b55d1f1 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -227,9 +227,10 @@ ((off_t)(db) << DEV_BSHIFT) #endif -#define PRIMASK 0x0ff -#define PCATCH 0x100 /* OR'd with pri for tsleep to check signals */ -#define PDROP 0x200 /* OR'd with pri to stop re-entry of interlock mutex */ +#define PRIMASK 0x0ff +#define PCATCH 0x100 /* OR'd with pri for tsleep to check signals */ +#define PDROP 0x200 /* OR'd with pri to stop re-entry of interlock mutex */ +#define PRILASTFLAG 0x200 /* Last flag defined above */ #define NZERO 0 /* default "nice" */