Re: [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions
From: David Gow
Date: Sun Sep 13 2026 - 04:49:00 EST
Le 30/08/2026 à 19:43, David Laight a écrit :
On Sun, 30 Aug 2026 18:33:15 +0800
David Gow <david@xxxxxxxxxxxx> wrote:
The existing roundup_pow_of_two() and rounddown_pow_of_two() functions work
on values of type unsigned long, which is 32-bit on 32-bit systems.
Equally, is_power_of_2() operates on an unsigned long.
There are several instances where 64-bit safe versions of these (which
operate on a 64-bit value regardless of sizeof(long)) are required. Most
particularly, some hardware (especially GPUs) have 64-bit address spaces,
and some formats (such as filesystems) use 64-bit offsets. Some of these
(such as i915 and btrfs) have already implemented their own 64-bit
is_power_of_2() helpers.
Add a version of these which always operate on a 64-bit value. These have
the (unimaginative) names:
- is_power_of_2_u64()
- roundup_pow_of_two_u64(), and
- rounddown_pow_of_two_u64()
and otherwise work identically to their unsigned long counterparts.
Why not just change the definitions (back?) to #defines.
Then they can be size neutral and you don't have to guess the correct one.
You may need to use __builtin_constant_p(x <= ~0u) to select between 32 and
64 bit versions.
I've given this a go, and (with some ugly typeof() casting) something like this works:
---
#define rounddown_pow_of_two(n) \
__builtin_constant_p(n) ? ( \
((typeof(n)1UL << ilog2(n)) : \
(sizeof(n) <= 4) ? \
1UL << (fls(n) - 1) : \
(typeof(n))1UL << (fls64(n) - 1)\
)
---
Unfortunately, there are enough random places where the function __round{up,down}_pow_of_two() is called directly that it's turning this into a more involved series than I'd want to push through for a simple fix.
I'll re-send patch 2 in it's original form (without the helper changes) so we can at least fix the buddy allocator breakage, and then put together a more complete version of this series with all of the various callsite fixes, and a KUnit test to verify it works properly across both 32-bit and 64-bit values.
My quick look suggested that gcc and clang were not doing anything excessively stupid here. The only really dubious case was for the roundup variant, which does end up doing the 64-bit subtraction. That being said, I wasn't able to come up with anything significantly better (particularly given that we're already pretty register constrained).
It is also worth checking what gcc/clang generate for the 64bit versions
on 32bit when passed a 32bit variable.
It might be that they optimise the code and avoid all the 64bit maths.
Regardless, I'll take another look at this before sending the full series.
Cheers,
-- David