From 0cb302c9c9b702efe09398c8a591beffe083b742 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 6 Nov 2025 09:02:50 +0100 Subject: [PATCH 01/32] bitops: Add missed file to MAINTAINERS In accordance with the history and nature of the operation add lib/hweight.c to the BITOPS record in MAINTAINERS. Signed-off-by: Andy Shevchenko Signed-off-by: Yury Norov (NVIDIA) --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 807820f7a1a9..be6a4217caa5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4381,6 +4381,7 @@ F: arch/*/lib/bitops.c F: include/asm-generic/bitops F: include/asm-generic/bitops.h F: include/linux/bitops.h +F: lib/hweight.c F: lib/test_bitops.c F: tools/*/bitops* From 6f15c3d715f1bf1025f88890eec7f3da210097a9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 6 Nov 2025 09:02:51 +0100 Subject: [PATCH 02/32] bitops: Update kernel-doc in hweight.c to fix the issues with it The kernel-doc in lib/hweight.c is global to the file and currently has issues: Warning: lib/hweight.c:13 expecting prototype for hweightN(). Prototype was for __sw_hweight32() instead Warning: lib/hweight.c:13 function parameter 'w' not described in '__sw_hweight32' Update it accordingly. Signed-off-by: Andy Shevchenko Signed-off-by: Yury Norov (NVIDIA) --- lib/hweight.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/hweight.c b/lib/hweight.c index c94586b62551..0dfcafc3fd39 100644 --- a/lib/hweight.c +++ b/lib/hweight.c @@ -4,8 +4,8 @@ #include /** - * hweightN - returns the hamming weight of a N-bit word - * @x: the word to weigh + * DOC: __sw_hweightN - returns the hamming weight of a N-bit word + * @w: the word to weigh * * The Hamming Weight of a number is the total number of bits set in it. */ From d1cadd4bfc2802c6f73b1739dbceef7513afc591 Mon Sep 17 00:00:00 2001 From: David Laight Date: Wed, 19 Nov 2025 22:41:28 +0000 Subject: [PATCH 03/32] nodemask: use min() instead of min_t() min_t(unsigned int, a, b) casts an 'unsigned long' to 'unsigned int'. Use min(a, b) instead as it promotes any 'unsigned int' to 'unsigned long' and so cannot discard significant bits. In this case the 'unsigned long' value is small enough that the result is ok. Detected by an extra check added to min_t(). Signed-off-by: David Laight Signed-off-by: Yury Norov (NVIDIA) --- include/linux/nodemask.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 7ad1f5c7407e..bd38648c998d 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -245,18 +245,18 @@ static __always_inline int __nodes_weight(const nodemask_t *srcp, unsigned int n } /* FIXME: better would be to fix all architectures to never return - > MAX_NUMNODES, then the silly min_ts could be dropped. */ + > MAX_NUMNODES, then the silly min()s could be dropped. */ #define first_node(src) __first_node(&(src)) static __always_inline unsigned int __first_node(const nodemask_t *srcp) { - return min_t(unsigned int, MAX_NUMNODES, find_first_bit(srcp->bits, MAX_NUMNODES)); + return min(MAX_NUMNODES, find_first_bit(srcp->bits, MAX_NUMNODES)); } #define next_node(n, src) __next_node((n), &(src)) static __always_inline unsigned int __next_node(int n, const nodemask_t *srcp) { - return min_t(unsigned int, MAX_NUMNODES, find_next_bit(srcp->bits, MAX_NUMNODES, n+1)); + return min(MAX_NUMNODES, find_next_bit(srcp->bits, MAX_NUMNODES, n+1)); } /* @@ -293,8 +293,7 @@ static __always_inline void init_nodemask_of_node(nodemask_t *mask, int node) #define first_unset_node(mask) __first_unset_node(&(mask)) static __always_inline unsigned int __first_unset_node(const nodemask_t *maskp) { - return min_t(unsigned int, MAX_NUMNODES, - find_first_zero_bit(maskp->bits, MAX_NUMNODES)); + return min(MAX_NUMNODES, find_first_zero_bit(maskp->bits, MAX_NUMNODES)); } #define NODE_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(MAX_NUMNODES) From dbfe51513aae6bace00cc390e11cb486a64a63d2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:33:49 +0100 Subject: [PATCH 04/32] clk: at91: pmc: #undef field_{get,prep}() before definition Prepare for the advent of globally available common field_get() and field_prep() macros by undefining the symbols before defining local variants. This prevents redefinition warnings from the C preprocessor when introducing the common macros later. Suggested-by: Yury Norov Signed-off-by: Geert Uytterhoeven Acked-by: Alexandre Belloni Acked-by: Stephen Boyd Acked-by: Claudiu Beznea Signed-off-by: Yury Norov (NVIDIA) --- drivers/clk/at91/pmc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 5daa32c4cf25..78a87d31463e 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -117,7 +117,9 @@ struct at91_clk_pms { unsigned int parent; }; +#undef field_get #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#undef field_prep #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) #define ndck(a, s) (a[s - 1].id + 1) From 7996cbdb3f8472bc4286c776d3fa39cf0c20237a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:33:50 +0100 Subject: [PATCH 05/32] crypto: qat - #undef field_get() before local definition Prepare for the advent of a globally available common field_get() macro by undefining the symbol before defining a local variant. This prevents redefinition warnings from the C preprocessor when introducing the common macro later. Suggested-by: Yury Norov Signed-off-by: Geert Uytterhoeven Acked-by: Giovanni Cabiddu Signed-off-by: Yury Norov (NVIDIA) --- drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c b/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c index 69295a9ddf0a..6186fafb4a7b 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c +++ b/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c @@ -11,6 +11,7 @@ * pm_scnprint_table(), making it not compile time constant, so the compile * asserts from FIELD_GET() or u32_get_bits() won't be fulfilled. */ +#undef field_get #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) #define PM_INFO_MAX_KEY_LEN 21 From d51b09a0feb63029be64226502cbcf53adc434b0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:33:51 +0100 Subject: [PATCH 06/32] EDAC/ie31200: #undef field_get() before local definition Prepare for the advent of a globally available common field_get() macro by undefining the symbol before defining a local variant. This prevents redefinition warnings from the C preprocessor when introducing the common macro later. Suggested-by: Yury Norov Signed-off-by: Geert Uytterhoeven Reviewed-by: Qiuxu Zhuo Signed-off-by: Yury Norov (NVIDIA) --- drivers/edac/ie31200_edac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c index 5a080ab65476..72290f430126 100644 --- a/drivers/edac/ie31200_edac.c +++ b/drivers/edac/ie31200_edac.c @@ -140,6 +140,7 @@ #define IE31200_CAPID0_ECC BIT(1) /* Non-constant mask variant of FIELD_GET() */ +#undef field_get #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) static int nr_channels; From d1e1a7271e97bf679d355777a10fa8c0dc259b86 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:33:52 +0100 Subject: [PATCH 07/32] gpio: aspeed: #undef field_{get,prep}() before local definition Prepare for the advent of globally available common field_get() and field_prep() macros by undefining the symbols before defining local variants. This prevents redefinition warnings from the C preprocessor when introducing the common macros later. Suggested-by: Yury Norov Signed-off-by: Geert Uytterhoeven Acked-by: Bartosz Golaszewski Signed-off-by: Yury Norov (NVIDIA) --- drivers/gpio/gpio-aspeed.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 7953a9c4e36d..ef4ccaf74a5b 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -32,7 +32,9 @@ #include "gpiolib.h" /* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ +#undef field_get #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#undef field_prep #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) #define GPIO_G7_IRQ_STS_BASE 0x100 From 27856d2b2b0f259ba261a3e3e028cc75a70ae817 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:33:53 +0100 Subject: [PATCH 08/32] iio: dac: ad3530r: #undef field_prep() before local definition Prepare for the advent of a globally available common field_prep() macro by undefining the symbol before defining a local variant. This prevents redefinition warnings from the C preprocessor when introducing the common macro later. Suggested-by: Yury Norov Signed-off-by: Geert Uytterhoeven Acked-by: Jonathan Cameron Signed-off-by: Yury Norov (NVIDIA) --- drivers/iio/dac/ad3530r.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c index 6134613777b8..5684d11137f2 100644 --- a/drivers/iio/dac/ad3530r.c +++ b/drivers/iio/dac/ad3530r.c @@ -54,6 +54,7 @@ #define AD3531R_MAX_CHANNELS 4 /* Non-constant mask variant of FIELD_PREP() */ +#undef field_prep #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) enum ad3530r_mode { From 8a838dabf145818e67b304997c21a055dd5943dc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:33:54 +0100 Subject: [PATCH 09/32] iio: mlx90614: #undef field_{get,prep}() before local definition Prepare for the advent of globally available common field_get() and field_prep() macros by undefining the symbols before defining local variants. This prevents redefinition warnings from the C preprocessor when introducing the common macros later. Suggested-by: Yury Norov Signed-off-by: Geert Uytterhoeven Acked-by: Jonathan Cameron Signed-off-by: Yury Norov (NVIDIA) --- drivers/iio/temperature/mlx90614.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 8a44a00bfd5e..de5615fdb396 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -69,7 +69,9 @@ #define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */ /* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ +#undef field_get #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#undef field_prep #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) struct mlx_chip_info { From 2fc00c008e9043ca66b711cc0df78a4d94da2e34 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:33:55 +0100 Subject: [PATCH 10/32] pinctrl: ma35: #undef field_{get,prep}() before local definition Prepare for the advent of globally available common field_get() and field_prep() macros by undefining the symbols before defining local variants. This prevents redefinition warnings from the C preprocessor when introducing the common macros later. Suggested-by: Yury Norov Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Yury Norov (NVIDIA) --- drivers/pinctrl/nuvoton/pinctrl-ma35.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.c b/drivers/pinctrl/nuvoton/pinctrl-ma35.c index cdad01d68a37..925dd717c9de 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.c @@ -82,7 +82,9 @@ #define MVOLT_3300 1 /* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ +#undef field_get #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#undef field_prep #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) static const char * const gpio_group_name[] = { From 138ab44108fad96c22b381ebfb6936ab9787aedc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:33:56 +0100 Subject: [PATCH 11/32] soc: renesas: rz-sysc: #undef field_get() before local definition Prepare for the advent of a globally available common field_get() macro by undefining the symbol before defining a local variant. This prevents redefinition warnings from the C preprocessor when introducing the common macro later. Suggested-by: Yury Norov Signed-off-by: Geert Uytterhoeven Reviewed-by: Claudiu Beznea Signed-off-by: Yury Norov (NVIDIA) --- drivers/soc/renesas/rz-sysc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c index 9f79e299e6f4..b9880085d363 100644 --- a/drivers/soc/renesas/rz-sysc.c +++ b/drivers/soc/renesas/rz-sysc.c @@ -16,6 +16,7 @@ #include "rz-sysc.h" +#undef field_get #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) /** From 85a8ff11853110e59396f97b3239db40cc89e08c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:33:57 +0100 Subject: [PATCH 12/32] ALSA: usb-audio: #undef field_{get,prep}() before local definition Prepare for the advent of globally available common field_get() and field_prep() macros by undefining the symbols before defining local variants. This prevents redefinition warnings from the C preprocessor when introducing the common macros later. Suggested-by: Yury Norov Signed-off-by: Geert Uytterhoeven Acked-by: Takashi Iwai Signed-off-by: Yury Norov (NVIDIA) --- sound/usb/mixer_quirks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 828af3095b86..713a8498b975 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3312,7 +3312,9 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) #define RME_DIGIFACE_INVERT BIT(31) /* Nonconst helpers */ +#undef field_get #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#undef field_prep #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) static int snd_rme_digiface_write_reg(struct snd_kcontrol *kcontrol, int item, u16 mask, u16 val) From 2a6c045640c38a407a39cd40c3c4d8dd2fd89aa8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:00 +0100 Subject: [PATCH 13/32] bitfield: Add less-checking __FIELD_{GET,PREP}() The BUILD_BUG_ON_MSG() check against "~0ull" works only with "unsigned (long) long" _mask types. For constant masks, that condition is usually met, as GENMASK() yields an UL value. The few places where the constant mask is stored in an intermediate variable were fixed by changing the variable type to u64 (see e.g. [1] and [2]). However, for non-constant masks, smaller unsigned types should be valid, too, but currently lead to "result of comparison of constant 18446744073709551615 with expression of type ... is always false"-warnings with clang and W=1. Hence refactor the __BF_FIELD_CHECK() helper, and factor out __FIELD_{GET,PREP}(). The later lack the single problematic check, but are otherwise identical to FIELD_{GET,PREP}(), and are intended to be used in the fully non-const variants later. [1] commit 5c667d5a5a3ec166 ("clk: sp7021: Adjust width of _m in HWM_FIELD_PREP()") [2] commit cfd6fb45cfaf46fa ("crypto: ccree - avoid out-of-range warnings from clang") Signed-off-by: Geert Uytterhoeven Link: https://git.kernel.org/torvalds/c/5c667d5a5a3ec166 [1] Signed-off-by: Yury Norov (NVIDIA) --- include/linux/bitfield.h | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index 5355f8f806a9..bf8e0ae4b5b4 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -60,7 +60,7 @@ #define __bf_cast_unsigned(type, x) ((__unsigned_scalar_typeof(type))(x)) -#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \ +#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \ ({ \ BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \ _pfx "mask is not constant"); \ @@ -69,13 +69,33 @@ ~((_mask) >> __bf_shf(_mask)) & \ (0 + (_val)) : 0, \ _pfx "value too large for the field"); \ - BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) > \ - __bf_cast_unsigned(_reg, ~0ull), \ - _pfx "type of reg too small for mask"); \ __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ (1ULL << __bf_shf(_mask))); \ }) +#define __BF_FIELD_CHECK_REG(mask, reg, pfx) \ + BUILD_BUG_ON_MSG(__bf_cast_unsigned(mask, mask) > \ + __bf_cast_unsigned(reg, ~0ull), \ + pfx "type of reg too small for mask") + +#define __BF_FIELD_CHECK(mask, reg, val, pfx) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, val, pfx); \ + __BF_FIELD_CHECK_REG(mask, reg, pfx); \ + }) + +#define __FIELD_PREP(mask, val, pfx) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, val, pfx); \ + ((typeof(mask))(val) << __bf_shf(mask)) & (mask); \ + }) + +#define __FIELD_GET(mask, reg, pfx) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, 0U, pfx); \ + (typeof(mask))(((reg) & (mask)) >> __bf_shf(mask)); \ + }) + /** * FIELD_MAX() - produce the maximum value representable by a field * @_mask: shifted mask defining the field's length and position @@ -112,8 +132,8 @@ */ #define FIELD_PREP(_mask, _val) \ ({ \ - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ - ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ + __BF_FIELD_CHECK_REG(_mask, 0ULL, "FIELD_PREP: "); \ + __FIELD_PREP(_mask, _val, "FIELD_PREP: "); \ }) #define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0) @@ -152,8 +172,8 @@ */ #define FIELD_GET(_mask, _reg) \ ({ \ - __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ - (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ + __BF_FIELD_CHECK_REG(_mask, _reg, "FIELD_GET: "); \ + __FIELD_GET(_mask, _reg, "FIELD_GET: "); \ }) /** From c1c6ab80b25c8db1e2ef5ae3ac8075d2c242ae13 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:01 +0100 Subject: [PATCH 14/32] bitfield: Add non-constant field_{prep,get}() helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing FIELD_{GET,PREP}() macros are limited to compile-time constants. However, it is very common to prepare or extract bitfield elements where the bitfield mask is not a compile-time constant. To avoid this limitation, the AT91 clock driver and several other drivers already have their own non-const field_{prep,get}() macros. Make them available for general use by adding them to , and improve them slightly: 1. Avoid evaluating macro parameters more than once, 2. Replace "ffs() - 1" by "__ffs()", 3. Support 64-bit use on 32-bit architectures, 4. Wire field_{get,prep}() to FIELD_{GET,PREP}() when mask is actually constant. This is deliberately not merged into the existing FIELD_{GET,PREP}() macros, as people expressed the desire to keep stricter variants for increased safety, or for performance critical paths. Yury: use __mask withing new macros. Signed-off-by: Geert Uytterhoeven Acked-by: Alexandre Belloni Acked-by: Jonathan Cameron Acked-by: Crt Mori Acked-by: Nuno Sá Acked-by: Richard Genoud Reviewed-by: Andy Shevchenko Reviewed-by: Yury Norov (NVIDIA) Signed-off-by: Yury Norov (NVIDIA) --- include/linux/bitfield.h | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index bf8e0ae4b5b4..126dc5b380af 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -17,6 +17,7 @@ * FIELD_{GET,PREP} macros take as first parameter shifted mask * from which they extract the base mask and shift amount. * Mask must be a compilation time constant. + * field_{get,prep} are variants that take a non-const mask. * * Example: * @@ -240,4 +241,62 @@ __MAKE_OP(64) #undef __MAKE_OP #undef ____MAKE_OP +#define __field_prep(mask, val) \ + ({ \ + __auto_type __mask = (mask); \ + typeof(__mask) __val = (val); \ + unsigned int __shift = BITS_PER_TYPE(__mask) <= 32 ? \ + __ffs(__mask) : __ffs64(__mask); \ + (__val << __shift) & __mask; \ + }) + +#define __field_get(mask, reg) \ + ({ \ + __auto_type __mask = (mask); \ + typeof(__mask) __reg = (reg); \ + unsigned int __shift = BITS_PER_TYPE(__mask) <= 32 ? \ + __ffs(__mask) : __ffs64(__mask); \ + (__reg & __mask) >> __shift; \ + }) + +/** + * field_prep() - prepare a bitfield element + * @mask: shifted mask defining the field's length and position, must be + * non-zero + * @val: value to put in the field + * + * Return: field value masked and shifted to its final destination + * + * field_prep() masks and shifts up the value. The result should be + * combined with other fields of the bitfield using logical OR. + * Unlike FIELD_PREP(), @mask is not limited to a compile-time constant. + * Typical usage patterns are a value stored in a table, or calculated by + * shifting a constant by a variable number of bits. + * If you want to ensure that @mask is a compile-time constant, please use + * FIELD_PREP() directly instead. + */ +#define field_prep(mask, val) \ + (__builtin_constant_p(mask) ? __FIELD_PREP(mask, val, "field_prep: ") \ + : __field_prep(mask, val)) + +/** + * field_get() - extract a bitfield element + * @mask: shifted mask defining the field's length and position, must be + * non-zero + * @reg: value of entire bitfield + * + * Return: extracted field value + * + * field_get() extracts the field specified by @mask from the + * bitfield passed in as @reg by masking and shifting it down. + * Unlike FIELD_GET(), @mask is not limited to a compile-time constant. + * Typical usage patterns are a value stored in a table, or calculated by + * shifting a constant by a variable number of bits. + * If you want to ensure that @mask is a compile-time constant, please use + * FIELD_GET() directly instead. + */ +#define field_get(mask, reg) \ + (__builtin_constant_p(mask) ? __FIELD_GET(mask, reg, "field_get: ") \ + : __field_get(mask, reg)) + #endif From 0f8407a1f1c795c417e4c7750654a6024a3ec68b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:02 +0100 Subject: [PATCH 15/32] clk: at91: Convert to common field_{get,prep}() helpers Drop the driver-specific field_get() and field_prep() macros, in favor of the globally available variants from . Signed-off-by: Geert Uytterhoeven Acked-by: Alexandre Belloni Acked-by: Stephen Boyd Acked-by: Claudiu Beznea Signed-off-by: Yury Norov (NVIDIA) --- drivers/clk/at91/clk-peripheral.c | 1 + drivers/clk/at91/pmc.h | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index e700f40fd87f..e7208c47268b 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -3,6 +3,7 @@ * Copyright (C) 2013 Boris BREZILLON */ +#include #include #include #include diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 78a87d31463e..543d7aee8d24 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -117,11 +117,6 @@ struct at91_clk_pms { unsigned int parent; }; -#undef field_get -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#undef field_prep -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - #define ndck(a, s) (a[s - 1].id + 1) #define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) From 350f06c9e2c97aca009fa10e8636ecf297ccd330 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:03 +0100 Subject: [PATCH 16/32] crypto: qat - convert to common field_get() helper Drop the driver-specific field_get() macro, in favor of the globally available variant from . Signed-off-by: Geert Uytterhoeven Acked-by: Giovanni Cabiddu Signed-off-by: Yury Norov (NVIDIA) --- drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c b/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c index 6186fafb4a7b..4ccc94ed9493 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c +++ b/drivers/crypto/intel/qat/qat_common/adf_pm_dbgfs_utils.c @@ -1,19 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2025 Intel Corporation */ +#include #include #include #include #include "adf_pm_dbgfs_utils.h" -/* - * This is needed because a variable is used to index the mask at - * pm_scnprint_table(), making it not compile time constant, so the compile - * asserts from FIELD_GET() or u32_get_bits() won't be fulfilled. - */ -#undef field_get -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - #define PM_INFO_MAX_KEY_LEN 21 static int pm_scnprint_table(char *buff, const struct pm_status_row *table, From 331a1457d8d5d233435633fcea116abeb775c4b4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:04 +0100 Subject: [PATCH 17/32] EDAC/ie31200: Convert to common field_get() helper Drop the driver-specific field_get() macro, in favor of the globally available variant from . Signed-off-by: Geert Uytterhoeven Reviewed-by: Qiuxu Zhuo Signed-off-by: Yury Norov (NVIDIA) --- drivers/edac/ie31200_edac.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c index 72290f430126..dfc9a9cecd74 100644 --- a/drivers/edac/ie31200_edac.c +++ b/drivers/edac/ie31200_edac.c @@ -44,6 +44,7 @@ * but lo_hi_readq() ensures that we are safe across all e3-1200 processors. */ +#include #include #include #include @@ -139,10 +140,6 @@ #define IE31200_CAPID0_DDPCD BIT(6) #define IE31200_CAPID0_ECC BIT(1) -/* Non-constant mask variant of FIELD_GET() */ -#undef field_get -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - static int nr_channels; static struct pci_dev *mci_pdev; static int ie31200_registered = 1; From 2ef26ba8192c6ef49dd9ed1a95f990c438085517 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:05 +0100 Subject: [PATCH 18/32] gpio: aspeed: Convert to common field_{get,prep}() helpers Drop the driver-specific field_get() and field_prep() macros, in favor of the globally available variants from . Signed-off-by: Geert Uytterhoeven Signed-off-by: Yury Norov (NVIDIA) --- drivers/gpio/gpio-aspeed.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index ef4ccaf74a5b..3da999334971 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -5,6 +5,7 @@ * Joel Stanley */ +#include #include #include #include @@ -31,12 +32,6 @@ #include #include "gpiolib.h" -/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ -#undef field_get -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#undef field_prep -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - #define GPIO_G7_IRQ_STS_BASE 0x100 #define GPIO_G7_IRQ_STS_OFFSET(x) (GPIO_G7_IRQ_STS_BASE + (x) * 0x4) #define GPIO_G7_CTRL_REG_BASE 0x180 From 54bfd90ca3b41567cbfdac2f633ae329eb3a665a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:06 +0100 Subject: [PATCH 19/32] iio: dac: Convert to common field_prep() helper Drop the driver-specific field_prep() macro, in favor of the globally available variant from . Signed-off-by: Geert Uytterhoeven Acked-by: Jonathan Cameron Signed-off-by: Yury Norov (NVIDIA) --- drivers/iio/dac/ad3530r.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c index 5684d11137f2..b97b46090d80 100644 --- a/drivers/iio/dac/ad3530r.c +++ b/drivers/iio/dac/ad3530r.c @@ -53,10 +53,6 @@ #define AD3530R_MAX_CHANNELS 8 #define AD3531R_MAX_CHANNELS 4 -/* Non-constant mask variant of FIELD_PREP() */ -#undef field_prep -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - enum ad3530r_mode { AD3530R_NORMAL_OP, AD3530R_POWERDOWN_1K, From 1fe1c28a108e4953f083c0106575ee0eccc296ae Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:07 +0100 Subject: [PATCH 20/32] iio: mlx90614: Convert to common field_{get,prep}() helpers Drop the driver-specific field_get() and field_prep() macros, in favor of the globally available variants from . Signed-off-by: Geert Uytterhoeven Acked-by: Jonathan Cameron Acked-by: Crt Mori Signed-off-by: Yury Norov (NVIDIA) --- drivers/iio/temperature/mlx90614.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index de5615fdb396..1ad21b73e1b4 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -22,6 +22,7 @@ * the "wakeup" GPIO is not given, power management will be disabled. */ +#include #include #include #include @@ -68,12 +69,6 @@ #define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */ #define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */ -/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ -#undef field_get -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#undef field_prep -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - struct mlx_chip_info { /* EEPROM offsets with 16-bit data, MSB first */ /* emissivity correction coefficient */ From bb0e7fda87753a973cb4a86c22905b1177f00d4e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:08 +0100 Subject: [PATCH 21/32] pinctrl: ma35: Convert to common field_{get,prep}() helpers Drop the driver-specific field_get() and field_prep() macros, in favor of the globally available variants from . Signed-off-by: Geert Uytterhoeven Reviewed-by: Linus Walleij Signed-off-by: Yury Norov (NVIDIA) --- drivers/pinctrl/nuvoton/pinctrl-ma35.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.c b/drivers/pinctrl/nuvoton/pinctrl-ma35.c index 925dd717c9de..8d71dc53cc1d 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.c @@ -81,12 +81,6 @@ #define MVOLT_1800 0 #define MVOLT_3300 1 -/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ -#undef field_get -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#undef field_prep -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - static const char * const gpio_group_name[] = { "gpioa", "gpiob", "gpioc", "gpiod", "gpioe", "gpiof", "gpiog", "gpioh", "gpioi", "gpioj", "gpiok", "gpiol", "gpiom", "gpion", From 610c4408a2f7a09a00f656459e762ee1e21bbd7b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:09 +0100 Subject: [PATCH 22/32] soc: renesas: rz-sysc: Convert to common field_get() helper Drop the driver-specific field_get() macro, in favor of the globally available variant from . Signed-off-by: Geert Uytterhoeven Reviewed-by: Claudiu Beznea Signed-off-by: Yury Norov (NVIDIA) --- drivers/soc/renesas/rz-sysc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c index b9880085d363..73eaf8b9d69f 100644 --- a/drivers/soc/renesas/rz-sysc.c +++ b/drivers/soc/renesas/rz-sysc.c @@ -5,6 +5,7 @@ * Copyright (C) 2024 Renesas Electronics Corp. */ +#include #include #include #include @@ -16,9 +17,6 @@ #include "rz-sysc.h" -#undef field_get -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - /** * struct rz_sysc - RZ SYSC private data structure * @base: SYSC base address From b1cff2f4b2391a13bd3e9263502072df1ee5d035 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:10 +0100 Subject: [PATCH 23/32] ALSA: usb-audio: Convert to common field_{get,prep}() helpers Drop the driver-specific field_get() and field_prep() macros, in favor of the globally available variants from . Signed-off-by: Geert Uytterhoeven Acked-by: Takashi Iwai Signed-off-by: Yury Norov (NVIDIA) --- sound/usb/mixer_quirks.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 713a8498b975..6eee89cbc086 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3311,12 +3311,6 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) #define RME_DIGIFACE_REGISTER(reg, mask) (((reg) << 16) | (mask)) #define RME_DIGIFACE_INVERT BIT(31) -/* Nonconst helpers */ -#undef field_get -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#undef field_prep -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - static int snd_rme_digiface_write_reg(struct snd_kcontrol *kcontrol, int item, u16 mask, u16 val) { struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); From 3937b05bb78f3ad1e8887b91b9a97ea05ac0a4a8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:13 +0100 Subject: [PATCH 24/32] clk: renesas: Use bitfield helpers Use the FIELD_{GET,PREP}() and field_{get,prep}() helpers for const respective non-const bitfields, instead of open-coding the same operations. Signed-off-by: Geert Uytterhoeven Reviewed-by: Stephen Boyd Signed-off-by: Yury Norov (NVIDIA) --- drivers/clk/renesas/clk-div6.c | 6 +++--- drivers/clk/renesas/rcar-gen3-cpg.c | 15 +++++---------- drivers/clk/renesas/rcar-gen4-cpg.c | 9 +++------ 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c index 3abd6e5400ad..f7b827b5e9b2 100644 --- a/drivers/clk/renesas/clk-div6.c +++ b/drivers/clk/renesas/clk-div6.c @@ -7,6 +7,7 @@ * Contact: Laurent Pinchart */ +#include #include #include #include @@ -171,8 +172,7 @@ static u8 cpg_div6_clock_get_parent(struct clk_hw *hw) if (clock->src_mask == 0) return 0; - hw_index = (readl(clock->reg) & clock->src_mask) >> - __ffs(clock->src_mask); + hw_index = field_get(clock->src_mask, readl(clock->reg)); for (i = 0; i < clk_hw_get_num_parents(hw); i++) { if (clock->parents[i] == hw_index) return i; @@ -191,7 +191,7 @@ static int cpg_div6_clock_set_parent(struct clk_hw *hw, u8 index) if (index >= clk_hw_get_num_parents(hw)) return -EINVAL; - src = clock->parents[index] << __ffs(clock->src_mask); + src = field_prep(clock->src_mask, clock->parents[index]); writel((readl(clock->reg) & ~clock->src_mask) | src, clock->reg); return 0; } diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 10ae20489df9..b954278ddd9d 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -54,10 +54,8 @@ static unsigned long cpg_pll_clk_recalc_rate(struct clk_hw *hw, { struct cpg_pll_clk *pll_clk = to_pll_clk(hw); unsigned int mult; - u32 val; - val = readl(pll_clk->pllcr_reg) & CPG_PLLnCR_STC_MASK; - mult = (val >> __ffs(CPG_PLLnCR_STC_MASK)) + 1; + mult = FIELD_GET(CPG_PLLnCR_STC_MASK, readl(pll_clk->pllcr_reg)) + 1; return parent_rate * mult * pll_clk->fixed_mult; } @@ -94,7 +92,7 @@ static int cpg_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, val = readl(pll_clk->pllcr_reg); val &= ~CPG_PLLnCR_STC_MASK; - val |= (mult - 1) << __ffs(CPG_PLLnCR_STC_MASK); + val |= FIELD_PREP(CPG_PLLnCR_STC_MASK, mult - 1); writel(val, pll_clk->pllcr_reg); for (i = 1000; i; i--) { @@ -176,11 +174,7 @@ static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct cpg_z_clk *zclk = to_z_clk(hw); - unsigned int mult; - u32 val; - - val = readl(zclk->reg) & zclk->mask; - mult = 32 - (val >> __ffs(zclk->mask)); + unsigned int mult = 32 - field_get(zclk->mask, readl(zclk->reg)); return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, 32 * zclk->fixed_div); @@ -231,7 +225,8 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) return -EBUSY; - cpg_reg_modify(zclk->reg, zclk->mask, (32 - mult) << __ffs(zclk->mask)); + cpg_reg_modify(zclk->reg, zclk->mask, + field_prep(zclk->mask, 32 - mult)); /* * Set KICK bit in FRQCRB to update hardware setting and wait for diff --git a/drivers/clk/renesas/rcar-gen4-cpg.c b/drivers/clk/renesas/rcar-gen4-cpg.c index fb9a876aaba5..db3a0b8ef2b9 100644 --- a/drivers/clk/renesas/rcar-gen4-cpg.c +++ b/drivers/clk/renesas/rcar-gen4-cpg.c @@ -279,11 +279,7 @@ static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct cpg_z_clk *zclk = to_z_clk(hw); - unsigned int mult; - u32 val; - - val = readl(zclk->reg) & zclk->mask; - mult = 32 - (val >> __ffs(zclk->mask)); + unsigned int mult = 32 - field_get(zclk->mask, readl(zclk->reg)); return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, 32 * zclk->fixed_div); @@ -334,7 +330,8 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) return -EBUSY; - cpg_reg_modify(zclk->reg, zclk->mask, (32 - mult) << __ffs(zclk->mask)); + cpg_reg_modify(zclk->reg, zclk->mask, + field_prep(zclk->mask, 32 - mult)); /* * Set KICK bit in FRQCRB to update hardware setting and wait for From c604cb5fdf0f569a9ce344a37a79958c3841396e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Nov 2025 14:34:14 +0100 Subject: [PATCH 25/32] soc: renesas: Use bitfield helpers Use the field_get() helper, instead of open-coding the same operation. Signed-off-by: Geert Uytterhoeven Signed-off-by: Yury Norov (NVIDIA) --- drivers/soc/renesas/renesas-soc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 1eb52356b996..ee4f17bb4db4 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -5,6 +5,7 @@ * Copyright (C) 2014-2016 Glider bvba */ +#include #include #include #include @@ -524,8 +525,7 @@ static int __init renesas_soc_init(void) eshi, eslo); } - if (soc->id && - ((product & id->mask) >> __ffs(id->mask)) != soc->id) { + if (soc->id && field_get(id->mask, product) != soc->id) { pr_warn("SoC mismatch (product = 0x%x)\n", product); ret = -ENODEV; goto free_soc_dev_attr; From 4bd68e475300bc97b33a7f1ef9bd112970018789 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 24 Nov 2025 21:39:59 +0100 Subject: [PATCH 26/32] cpumask: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Note that kernel.h is discouraged to be included as it's written at the top of that file. Signed-off-by: Andy Shevchenko Signed-off-by: Yury Norov (NVIDIA) --- arch/x86/include/asm/cpumask.h | 2 ++ include/linux/cpumask.h | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/cpumask.h b/arch/x86/include/asm/cpumask.h index 70f6b60ad67b..9df9e9cde670 100644 --- a/arch/x86/include/asm/cpumask.h +++ b/arch/x86/include/asm/cpumask.h @@ -2,6 +2,8 @@ #ifndef _ASM_X86_CPUMASK_H #define _ASM_X86_CPUMASK_H #ifndef __ASSEMBLER__ + +#include #include extern void setup_cpu_local_masks(void); diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index ff8f41ab7ce6..df89eedc6e91 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -7,14 +7,16 @@ * set of CPUs in a system, one bit position per CPU number. In general, * only nr_cpu_ids (<= NR_CPUS) bits are valid. */ -#include -#include -#include -#include #include -#include +#include +#include +#include #include #include +#include +#include + +#include /** * cpumask_pr_args - printf args to output a cpumask From f5535d78e12600deb30a9fb3c628c425f0caec21 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 25 Nov 2025 13:59:37 +0000 Subject: [PATCH 27/32] rust: bitmap: add MAX_LEN and MAX_INLINE_LEN constants To avoid hard-coding these values in drivers, define constants for them that drivers can reference. Also, update all instances in bitmap.rs and id_pool.rs that use these values to use the new constants. Signed-off-by: Alice Ryhl Reviewed-by: Burak Emir Signed-off-by: Yury Norov (NVIDIA) --- rust/kernel/bitmap.rs | 33 +++++++++++++++++++-------------- rust/kernel/id_pool.rs | 39 ++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/rust/kernel/bitmap.rs b/rust/kernel/bitmap.rs index aa8fc7bf06fc..0705646c6251 100644 --- a/rust/kernel/bitmap.rs +++ b/rust/kernel/bitmap.rs @@ -12,8 +12,6 @@ use crate::bindings; use crate::pr_err; use core::ptr::NonNull; -const BITS_PER_LONG: usize = bindings::BITS_PER_LONG as usize; - /// Represents a C bitmap. Wraps underlying C bitmap API. /// /// # Invariants @@ -149,14 +147,14 @@ macro_rules! bitmap_assert_return { /// /// # Invariants /// -/// * `nbits` is `<= i32::MAX` and never changes. -/// * if `nbits <= bindings::BITS_PER_LONG`, then `repr` is a `usize`. +/// * `nbits` is `<= MAX_LEN`. +/// * if `nbits <= MAX_INLINE_LEN`, then `repr` is a `usize`. /// * otherwise, `repr` holds a non-null pointer to an initialized /// array of `unsigned long` that is large enough to hold `nbits` bits. pub struct BitmapVec { /// Representation of bitmap. repr: BitmapRepr, - /// Length of this bitmap. Must be `<= i32::MAX`. + /// Length of this bitmap. Must be `<= MAX_LEN`. nbits: usize, } @@ -164,7 +162,7 @@ impl core::ops::Deref for BitmapVec { type Target = Bitmap; fn deref(&self) -> &Bitmap { - let ptr = if self.nbits <= BITS_PER_LONG { + let ptr = if self.nbits <= BitmapVec::MAX_INLINE_LEN { // SAFETY: Bitmap is represented inline. #[allow(unused_unsafe, reason = "Safe since Rust 1.92.0")] unsafe { @@ -183,7 +181,7 @@ impl core::ops::Deref for BitmapVec { impl core::ops::DerefMut for BitmapVec { fn deref_mut(&mut self) -> &mut Bitmap { - let ptr = if self.nbits <= BITS_PER_LONG { + let ptr = if self.nbits <= BitmapVec::MAX_INLINE_LEN { // SAFETY: Bitmap is represented inline. #[allow(unused_unsafe, reason = "Safe since Rust 1.92.0")] unsafe { @@ -213,7 +211,7 @@ unsafe impl Sync for BitmapVec {} impl Drop for BitmapVec { fn drop(&mut self) { - if self.nbits <= BITS_PER_LONG { + if self.nbits <= BitmapVec::MAX_INLINE_LEN { return; } // SAFETY: `self.ptr` was returned by the C `bitmap_zalloc`. @@ -226,23 +224,29 @@ impl Drop for BitmapVec { } impl BitmapVec { + /// The maximum possible length of a `BitmapVec`. + pub const MAX_LEN: usize = i32::MAX as usize; + + /// The maximum length that uses the inline representation. + pub const MAX_INLINE_LEN: usize = usize::BITS as usize; + /// Constructs a new [`BitmapVec`]. /// /// Fails with [`AllocError`] when the [`BitmapVec`] could not be allocated. This - /// includes the case when `nbits` is greater than `i32::MAX`. + /// includes the case when `nbits` is greater than `MAX_LEN`. #[inline] pub fn new(nbits: usize, flags: Flags) -> Result { - if nbits <= BITS_PER_LONG { + if nbits <= BitmapVec::MAX_INLINE_LEN { return Ok(BitmapVec { repr: BitmapRepr { bitmap: 0 }, nbits, }); } - if nbits > i32::MAX.try_into().unwrap() { + if nbits > Self::MAX_LEN { return Err(AllocError); } let nbits_u32 = u32::try_from(nbits).unwrap(); - // SAFETY: `BITS_PER_LONG < nbits` and `nbits <= i32::MAX`. + // SAFETY: `MAX_INLINE_LEN < nbits` and `nbits <= MAX_LEN`. let ptr = unsafe { bindings::bitmap_zalloc(nbits_u32, flags.as_raw()) }; let ptr = NonNull::new(ptr).ok_or(AllocError)?; // INVARIANT: `ptr` returned by C `bitmap_zalloc` and `nbits` checked. @@ -495,9 +499,10 @@ mod tests { #[test] fn bitmap_borrow() { let fake_bitmap: [usize; 2] = [0, 0]; + let fake_bitmap_len = 2 * usize::BITS as usize; // SAFETY: `fake_c_bitmap` is an array of expected length. - let b = unsafe { Bitmap::from_raw(fake_bitmap.as_ptr(), 2 * BITS_PER_LONG) }; - assert_eq!(2 * BITS_PER_LONG, b.len()); + let b = unsafe { Bitmap::from_raw(fake_bitmap.as_ptr(), fake_bitmap_len) }; + assert_eq!(fake_bitmap_len, b.len()); assert_eq!(None, b.next_bit(0)); } diff --git a/rust/kernel/id_pool.rs b/rust/kernel/id_pool.rs index a41a3404213c..0b1f720a1f7d 100644 --- a/rust/kernel/id_pool.rs +++ b/rust/kernel/id_pool.rs @@ -7,8 +7,6 @@ use crate::alloc::{AllocError, Flags}; use crate::bitmap::BitmapVec; -const BITS_PER_LONG: usize = bindings::BITS_PER_LONG as usize; - /// Represents a dynamic ID pool backed by a [`BitmapVec`]. /// /// Clients acquire and release IDs from unset bits in a bitmap. @@ -97,13 +95,12 @@ impl ReallocRequest { impl IdPool { /// Constructs a new [`IdPool`]. /// - /// A capacity below [`BITS_PER_LONG`] is adjusted to - /// [`BITS_PER_LONG`]. + /// A capacity below [`MAX_INLINE_LEN`] is adjusted to [`MAX_INLINE_LEN`]. /// - /// [`BITS_PER_LONG`]: srctree/include/asm-generic/bitsperlong.h + /// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN #[inline] pub fn new(num_ids: usize, flags: Flags) -> Result { - let num_ids = core::cmp::max(num_ids, BITS_PER_LONG); + let num_ids = usize::max(num_ids, BitmapVec::MAX_INLINE_LEN); let map = BitmapVec::new(num_ids, flags)?; Ok(Self { map }) } @@ -116,28 +113,34 @@ impl IdPool { /// Returns a [`ReallocRequest`] if the [`IdPool`] can be shrunk, [`None`] otherwise. /// - /// The capacity of an [`IdPool`] cannot be shrunk below [`BITS_PER_LONG`]. + /// The capacity of an [`IdPool`] cannot be shrunk below [`MAX_INLINE_LEN`]. /// - /// [`BITS_PER_LONG`]: srctree/include/asm-generic/bitsperlong.h + /// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN /// /// # Examples /// /// ``` - /// use kernel::alloc::{AllocError, flags::GFP_KERNEL}; - /// use kernel::id_pool::{ReallocRequest, IdPool}; + /// use kernel::{ + /// alloc::AllocError, + /// bitmap::BitmapVec, + /// id_pool::{ + /// IdPool, + /// ReallocRequest, + /// }, + /// }; /// /// let mut pool = IdPool::new(1024, GFP_KERNEL)?; /// let alloc_request = pool.shrink_request().ok_or(AllocError)?; /// let resizer = alloc_request.realloc(GFP_KERNEL)?; /// pool.shrink(resizer); - /// assert_eq!(pool.capacity(), kernel::bindings::BITS_PER_LONG as usize); + /// assert_eq!(pool.capacity(), BitmapVec::MAX_INLINE_LEN); /// # Ok::<(), AllocError>(()) /// ``` #[inline] pub fn shrink_request(&self) -> Option { let cap = self.capacity(); - // Shrinking below [`BITS_PER_LONG`] is never possible. - if cap <= BITS_PER_LONG { + // Shrinking below `MAX_INLINE_LEN` is never possible. + if cap <= BitmapVec::MAX_INLINE_LEN { return None; } // Determine if the bitmap can shrink based on the position of @@ -146,13 +149,13 @@ impl IdPool { // bitmap should shrink to half its current size. let Some(bit) = self.map.last_bit() else { return Some(ReallocRequest { - num_ids: BITS_PER_LONG, + num_ids: BitmapVec::MAX_INLINE_LEN, }); }; if bit >= (cap / 4) { return None; } - let num_ids = usize::max(BITS_PER_LONG, cap / 2); + let num_ids = usize::max(BitmapVec::MAX_INLINE_LEN, cap / 2); Some(ReallocRequest { num_ids }) } @@ -177,11 +180,13 @@ impl IdPool { /// Returns a [`ReallocRequest`] for growing this [`IdPool`], if possible. /// - /// The capacity of an [`IdPool`] cannot be grown above [`i32::MAX`]. + /// The capacity of an [`IdPool`] cannot be grown above [`MAX_LEN`]. + /// + /// [`MAX_LEN`]: BitmapVec::MAX_LEN #[inline] pub fn grow_request(&self) -> Option { let num_ids = self.capacity() * 2; - if num_ids > i32::MAX.try_into().unwrap() { + if num_ids > BitmapVec::MAX_LEN { return None; } Some(ReallocRequest { num_ids }) From d0cf6512bbcf77afb6102f886fcd7fd48b7ae043 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 25 Nov 2025 13:59:38 +0000 Subject: [PATCH 28/32] rust: bitmap: add BitmapVec::new_inline() This constructor is useful when you just want to create a BitmapVec without allocating but don't care how large it is. Acked-by: Yury Norov (NVIDIA) Reviewed-by: Burak Emir Reviewed-by: Danilo Krummrich Signed-off-by: Alice Ryhl Signed-off-by: Yury Norov (NVIDIA) --- rust/kernel/bitmap.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rust/kernel/bitmap.rs b/rust/kernel/bitmap.rs index 0705646c6251..83d7dea99137 100644 --- a/rust/kernel/bitmap.rs +++ b/rust/kernel/bitmap.rs @@ -230,6 +230,16 @@ impl BitmapVec { /// The maximum length that uses the inline representation. pub const MAX_INLINE_LEN: usize = usize::BITS as usize; + /// Construct a longest possible inline [`BitmapVec`]. + #[inline] + pub fn new_inline() -> Self { + // INVARIANT: `nbits <= MAX_INLINE_LEN`, so an inline bitmap is the right repr. + BitmapVec { + repr: BitmapRepr { bitmap: 0 }, + nbits: BitmapVec::MAX_INLINE_LEN, + } + } + /// Constructs a new [`BitmapVec`]. /// /// Fails with [`AllocError`] when the [`BitmapVec`] could not be allocated. This From 6297fb3863d81b0970fd435476b837739c0ea4e7 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 25 Nov 2025 13:59:39 +0000 Subject: [PATCH 29/32] rust: id_pool: rename IdPool::new() to with_capacity() We want to change ::new() to take no parameters and produce a pool that is as large as possible while also being inline because that is the constructor that Rust Binder actually needs. However, to avoid complications in examples, we still need the current constructor. So rename it to with_capacity(), which is the idiomatic Rust name for this kind constructor. Reviewed-by: Burak Emir Signed-off-by: Alice Ryhl Signed-off-by: Yury Norov (NVIDIA) --- rust/kernel/id_pool.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/kernel/id_pool.rs b/rust/kernel/id_pool.rs index 0b1f720a1f7d..7968b6c5566b 100644 --- a/rust/kernel/id_pool.rs +++ b/rust/kernel/id_pool.rs @@ -26,7 +26,7 @@ use crate::bitmap::BitmapVec; /// use kernel::alloc::{AllocError, flags::GFP_KERNEL}; /// use kernel::id_pool::IdPool; /// -/// let mut pool = IdPool::new(64, GFP_KERNEL)?; +/// let mut pool = IdPool::with_capacity(64, GFP_KERNEL)?; /// for i in 0..64 { /// assert_eq!(i, pool.acquire_next_id(i).ok_or(ENOSPC)?); /// } @@ -93,13 +93,13 @@ impl ReallocRequest { } impl IdPool { - /// Constructs a new [`IdPool`]. + /// Constructs a new [`IdPool`] with space for a specific number of bits. /// /// A capacity below [`MAX_INLINE_LEN`] is adjusted to [`MAX_INLINE_LEN`]. /// /// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN #[inline] - pub fn new(num_ids: usize, flags: Flags) -> Result { + pub fn with_capacity(num_ids: usize, flags: Flags) -> Result { let num_ids = usize::max(num_ids, BitmapVec::MAX_INLINE_LEN); let map = BitmapVec::new(num_ids, flags)?; Ok(Self { map }) @@ -129,7 +129,7 @@ impl IdPool { /// }, /// }; /// - /// let mut pool = IdPool::new(1024, GFP_KERNEL)?; + /// let mut pool = IdPool::with_capacity(1024, GFP_KERNEL)?; /// let alloc_request = pool.shrink_request().ok_or(AllocError)?; /// let resizer = alloc_request.realloc(GFP_KERNEL)?; /// pool.shrink(resizer); From 69ec6a1bed3017293a3430e2f8e3c01b29496446 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 25 Nov 2025 13:59:40 +0000 Subject: [PATCH 30/32] rust: id_pool: do not supply starting capacity Rust Binder wants to use inline bitmaps whenever possible to avoid allocations, so introduce a constructor for an IdPool with arbitrary capacity that stores the bitmap inline. The existing constructor could be renamed to with_capacity() to match constructors for other similar types, but it is removed as there is currently no user for it. [Miguel: rust: id_pool: fix broken intra-doc link] Acked-by: Yury Norov (NVIDIA) Reviewed-by: Burak Emir Reviewed-by: Danilo Krummrich Signed-off-by: Alice Ryhl Signed-off-by: Yury Norov (NVIDIA) --- rust/kernel/id_pool.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/rust/kernel/id_pool.rs b/rust/kernel/id_pool.rs index 7968b6c5566b..afde05f53588 100644 --- a/rust/kernel/id_pool.rs +++ b/rust/kernel/id_pool.rs @@ -93,6 +93,18 @@ impl ReallocRequest { } impl IdPool { + /// Constructs a new [`IdPool`]. + /// + /// The pool will have a capacity of [`MAX_INLINE_LEN`]. + /// + /// [`MAX_INLINE_LEN`]: BitmapVec::MAX_INLINE_LEN + #[inline] + pub fn new() -> Self { + Self { + map: BitmapVec::new_inline(), + } + } + /// Constructs a new [`IdPool`] with space for a specific number of bits. /// /// A capacity below [`MAX_INLINE_LEN`] is adjusted to [`MAX_INLINE_LEN`]. @@ -229,3 +241,10 @@ impl IdPool { self.map.clear_bit(id); } } + +impl Default for IdPool { + #[inline] + fn default() -> Self { + Self::new() + } +} From f523d110a63b5b38ab5d54df1d06f1e0988c9b74 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 25 Nov 2025 13:59:41 +0000 Subject: [PATCH 31/32] rust: id_pool: do not immediately acquire new ids When Rust Binder assigns a new ID, it performs various fallible operations before it "commits" to actually using the new ID. To support this pattern, change acquire_next_id() so that it does not immediately call set_bit(), but instead returns an object that may be used to call set_bit() later. The UnusedId type holds a exclusive reference to the IdPool, so it's guaranteed that nobody else can call find_unused_id() while the UnusedId object is live. [Miguel: rust: id_pool: fix example] Reviewed-by: Burak Emir Reviewed-by: Danilo Krummrich Signed-off-by: Alice Ryhl Signed-off-by: Yury Norov (NVIDIA) --- rust/kernel/id_pool.rs | 77 +++++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/rust/kernel/id_pool.rs b/rust/kernel/id_pool.rs index afde05f53588..384753fe0e44 100644 --- a/rust/kernel/id_pool.rs +++ b/rust/kernel/id_pool.rs @@ -23,22 +23,22 @@ use crate::bitmap::BitmapVec; /// Basic usage /// /// ``` -/// use kernel::alloc::{AllocError, flags::GFP_KERNEL}; -/// use kernel::id_pool::IdPool; +/// use kernel::alloc::AllocError; +/// use kernel::id_pool::{IdPool, UnusedId}; /// /// let mut pool = IdPool::with_capacity(64, GFP_KERNEL)?; /// for i in 0..64 { -/// assert_eq!(i, pool.acquire_next_id(i).ok_or(ENOSPC)?); +/// assert_eq!(i, pool.find_unused_id(i).ok_or(ENOSPC)?.acquire()); /// } /// /// pool.release_id(23); -/// assert_eq!(23, pool.acquire_next_id(0).ok_or(ENOSPC)?); +/// assert_eq!(23, pool.find_unused_id(0).ok_or(ENOSPC)?.acquire()); /// -/// assert_eq!(None, pool.acquire_next_id(0)); // time to realloc. +/// assert!(pool.find_unused_id(0).is_none()); // time to realloc. /// let resizer = pool.grow_request().ok_or(ENOSPC)?.realloc(GFP_KERNEL)?; /// pool.grow(resizer); /// -/// assert_eq!(pool.acquire_next_id(0), Some(64)); +/// assert_eq!(pool.find_unused_id(0).ok_or(ENOSPC)?.acquire(), 64); /// # Ok::<(), Error>(()) /// ``` /// @@ -52,8 +52,8 @@ use crate::bitmap::BitmapVec; /// fn get_id_maybe_realloc(guarded_pool: &SpinLock) -> Result { /// let mut pool = guarded_pool.lock(); /// loop { -/// match pool.acquire_next_id(0) { -/// Some(index) => return Ok(index), +/// match pool.find_unused_id(0) { +/// Some(index) => return Ok(index.acquire()), /// None => { /// let alloc_request = pool.grow_request(); /// drop(pool); @@ -221,18 +221,18 @@ impl IdPool { self.map = resizer.new; } - /// Acquires a new ID by finding and setting the next zero bit in the - /// bitmap. + /// Finds an unused ID in the bitmap. /// /// Upon success, returns its index. Otherwise, returns [`None`] /// to indicate that a [`Self::grow_request`] is needed. #[inline] - pub fn acquire_next_id(&mut self, offset: usize) -> Option { - let next_zero_bit = self.map.next_zero_bit(offset); - if let Some(nr) = next_zero_bit { - self.map.set_bit(nr); - } - next_zero_bit + #[must_use] + pub fn find_unused_id(&mut self, offset: usize) -> Option> { + // INVARIANT: `next_zero_bit()` returns None or an integer less than `map.len()` + Some(UnusedId { + id: self.map.next_zero_bit(offset)?, + pool: self, + }) } /// Releases an ID. @@ -242,6 +242,51 @@ impl IdPool { } } +/// Represents an unused id in an [`IdPool`]. +/// +/// # Invariants +/// +/// The value of `id` is less than `pool.map.len()`. +pub struct UnusedId<'pool> { + id: usize, + pool: &'pool mut IdPool, +} + +impl<'pool> UnusedId<'pool> { + /// Get the unused id as an usize. + /// + /// Be aware that the id has not yet been acquired in the pool. The + /// [`acquire`] method must be called to prevent others from taking the id. + /// + /// [`acquire`]: UnusedId::acquire() + #[inline] + #[must_use] + pub fn as_usize(&self) -> usize { + self.id + } + + /// Get the unused id as an u32. + /// + /// Be aware that the id has not yet been acquired in the pool. The + /// [`acquire`] method must be called to prevent others from taking the id. + /// + /// [`acquire`]: UnusedId::acquire() + #[inline] + #[must_use] + pub fn as_u32(&self) -> u32 { + // CAST: By the type invariants: + // `self.id < pool.map.len() <= BitmapVec::MAX_LEN = i32::MAX`. + self.id as u32 + } + + /// Acquire the unused id. + #[inline] + pub fn acquire(self) -> usize { + self.pool.map.set_bit(self.id); + self.id + } +} + impl Default for IdPool { #[inline] fn default() -> Self { From 5ba71195a9cb8bb573c7165685a63654af4d7401 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 25 Nov 2025 13:59:42 +0000 Subject: [PATCH 32/32] rust_binder: use bitmap for allocation of handles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To find an unused Binder handle, Rust Binder currently iterates the red/black tree from the beginning until it finds a gap in the keys. This is extremely slow. To improve the performance, add a bitmap that keeps track of which indices are actually in use. This allows us to quickly find an unused key in the red/black tree. For a benchmark, please see the below numbers that were obtained from modifying binderThroughputTest to send a node with each transaction and stashing it in the server. This results in the number of nodes increasing by one for every transaction sent. I got the following table of roundtrip latencies (in µs): Transaction Range │ Baseline (Rust) │ Bitmap (Rust) │ Comparison (C) 0 - 10,000 │ 176.88 │ 92.93 │ 99.41 10,000 - 20,000 │ 437.37 │ 87.74 │ 98.55 20,000 - 30,000 │ 677.49 │ 76.24 │ 96.37 30,000 - 40,000 │ 901.76 │ 83.39 │ 96.73 40,000 - 50,000 │ 1126.62 │ 100.44 │ 94.57 50,000 - 60,000 │ 1288.98 │ 94.38 │ 96.64 60,000 - 70,000 │ 1588.74 │ 88.27 │ 96.36 70,000 - 80,000 │ 1812.97 │ 93.97 │ 91.24 80,000 - 90,000 │ 2062.95 │ 92.22 │ 102.01 90,000 - 100,000 │ 2330.03 │ 97.18 │ 100.31 It should be clear that the current Rust code becomes linearly slower per insertion as the number of calls to rb_next() per transaction increases. After this change, the time to find an ID number appears constant. (Technically it is not constant-time as both insertion and removal scan the entire bitmap. However, quick napkin math shows that scanning the entire bitmap with N=100k takes ~1.5µs, which is neglible in a benchmark where the rountrip latency is 100µs.) I've included a comparison to the C driver, which uses the same bitmap algorithm as this patch since commit 15d9da3f818c ("binder: use bitmap for faster descriptor lookup"). This currently checks if the bitmap should be shrunk after every removal. One potential future change is introducing a shrinker to make this operation O(1), but based on the benchmark above this does not seem required at this time. Reviewed-by: Burak Emir Reviewed-by: Yury Norov (NVIDIA) Acked-by: Carlos Llamas Signed-off-by: Alice Ryhl Signed-off-by: Yury Norov (NVIDIA) --- drivers/android/binder/process.rs | 64 +++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index 7607353a5e92..39c5cb365c9e 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -19,6 +19,7 @@ use kernel::{ cred::Credential, error::Error, fs::file::{self, File}, + id_pool::IdPool, list::{List, ListArc, ListArcField, ListLinks}, mm, prelude::*, @@ -394,6 +395,8 @@ kernel::list::impl_list_item! { struct ProcessNodeRefs { /// Used to look up nodes using the 32-bit id that this process knows it by. by_handle: RBTree>, + /// Used to quickly find unused ids in `by_handle`. + handle_is_present: IdPool, /// Used to look up nodes without knowing their local 32-bit id. The usize is the address of /// the underlying `Node` struct as returned by `Node::global_id`. by_node: RBTree, @@ -408,6 +411,7 @@ impl ProcessNodeRefs { fn new() -> Self { Self { by_handle: RBTree::new(), + handle_is_present: IdPool::new(), by_node: RBTree::new(), freeze_listeners: RBTree::new(), } @@ -802,7 +806,7 @@ impl Process { pub(crate) fn insert_or_update_handle( self: ArcBorrow<'_, Process>, node_ref: NodeRef, - is_mananger: bool, + is_manager: bool, ) -> Result { { let mut refs = self.node_refs.lock(); @@ -821,7 +825,33 @@ impl Process { let reserve2 = RBTreeNodeReservation::new(GFP_KERNEL)?; let info = UniqueArc::new_uninit(GFP_KERNEL)?; - let mut refs = self.node_refs.lock(); + let mut refs_lock = self.node_refs.lock(); + let mut refs = &mut *refs_lock; + + let (unused_id, by_handle_slot) = loop { + // ID 0 may only be used by the manager. + let start = if is_manager { 0 } else { 1 }; + + if let Some(res) = refs.handle_is_present.find_unused_id(start) { + match refs.by_handle.entry(res.as_u32()) { + rbtree::Entry::Vacant(entry) => break (res, entry), + rbtree::Entry::Occupied(_) => { + pr_err!("Detected mismatch between handle_is_present and by_handle"); + res.acquire(); + kernel::warn_on!(true); + return Err(EINVAL); + } + } + } + + let grow_request = refs.handle_is_present.grow_request().ok_or(ENOMEM)?; + drop(refs_lock); + let resizer = grow_request.realloc(GFP_KERNEL)?; + refs_lock = self.node_refs.lock(); + refs = &mut *refs_lock; + refs.handle_is_present.grow(resizer); + }; + let handle = unused_id.as_u32(); // Do a lookup again as node may have been inserted before the lock was reacquired. if let Some(handle_ref) = refs.by_node.get(&node_ref.node.global_id()) { @@ -831,20 +861,9 @@ impl Process { return Ok(handle); } - // Find id. - let mut target: u32 = if is_mananger { 0 } else { 1 }; - for handle in refs.by_handle.keys() { - if *handle > target { - break; - } - if *handle == target { - target = target.checked_add(1).ok_or(ENOMEM)?; - } - } - let gid = node_ref.node.global_id(); let (info_proc, info_node) = { - let info_init = NodeRefInfo::new(node_ref, target, self.into()); + let info_init = NodeRefInfo::new(node_ref, handle, self.into()); match info.pin_init_with(info_init) { Ok(info) => ListArc::pair_from_pin_unique(info), // error is infallible @@ -865,9 +884,10 @@ impl Process { // `info_node` into the right node's `refs` list. unsafe { info_proc.node_ref2().node.insert_node_info(info_node) }; - refs.by_node.insert(reserve1.into_node(gid, target)); - refs.by_handle.insert(reserve2.into_node(target, info_proc)); - Ok(target) + refs.by_node.insert(reserve1.into_node(gid, handle)); + by_handle_slot.insert(info_proc, reserve2); + unused_id.acquire(); + Ok(handle) } pub(crate) fn get_transaction_node(&self, handle: u32) -> BinderResult { @@ -932,6 +952,16 @@ impl Process { let id = info.node_ref().node.global_id(); refs.by_handle.remove(&handle); refs.by_node.remove(&id); + refs.handle_is_present.release_id(handle as usize); + + if let Some(shrink) = refs.handle_is_present.shrink_request() { + drop(refs); + // This intentionally ignores allocation failures. + if let Ok(new_bitmap) = shrink.realloc(GFP_KERNEL) { + refs = self.node_refs.lock(); + refs.handle_is_present.shrink(new_bitmap); + } + } } } else { // All refs are cleared in process exit, so this warning is expected in that case.