* [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions
@ 2026-08-30 10:33 David Gow
2026-08-30 10:33 ` [PATCH v2 2/3] drm_buddy: fix power-of-2 rounding errs David Gow
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: David Gow @ 2026-08-30 10:33 UTC (permalink / raw)
To: Jim Cromie, Maciej W . Rozycki, Andrew Morton, Matthew Auld,
Arun Pravin, Joel Fernandes, David Airlie, Simona Vetter,
Chris Mason, David Sterba
Cc: David Gow, dri-devel, linux-btrfs, linux-kernel
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.
To avoid conflicts, the i915 implementation is also removed here. The btrfs
one (which has a different name) is replaced in a separate patch.
Signed-off-by: David Gow <david@davidgow.net>
---
This patch adds u64 helpers, and the following two use them. And v2 also
has the i915 change to remove the conflicting implementation.
So I'm not sure who best wants to take these. Ultimately it's an include/linux
change, but it touches i915, patch 2 touches GPU/DRM, and patch 3 btrfs.
Personally, I'm keen to get patch 2 in, as it fixes a real issue, so if taking
1 and 2 via DRM makes more sense, that's fine by me.
Changes since v1:
https://lore.kernel.org/all/20260821091918.1902032-1-david@ingeniumdigital.com/
- Include is_power_of_2_u64() as well, and remove the i915 version
(Thanks, Matthew)
- Use _u64 as a suffix for the 64-bit versions, not just 64
(This is a much nicer name, and matches what everone else was doing)
- Fix some comment typos.
- Add a third patch which removes a similar is_power_of_two_u64() helper
from btrfs.
---
drivers/gpu/drm/i915/i915_utils.h | 5 ---
include/linux/log2.h | 73 +++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
index ecc20e0528f4..1cec51984d8c 100644
--- a/drivers/gpu/drm/i915/i915_utils.h
+++ b/drivers/gpu/drm/i915/i915_utils.h
@@ -75,11 +75,6 @@ struct drm_i915_private;
__idx; \
})
-static inline bool is_power_of_2_u64(u64 n)
-{
- return (n != 0 && ((n & (n - 1)) == 0));
-}
-
void add_taint_for_CI(struct drm_i915_private *i915, unsigned int taint);
static inline void __add_taint_for_CI(unsigned int taint)
{
diff --git a/include/linux/log2.h b/include/linux/log2.h
index e17ceb32e0c9..fc44e59f5732 100644
--- a/include/linux/log2.h
+++ b/include/linux/log2.h
@@ -47,6 +47,22 @@ bool is_power_of_2(unsigned long n)
return n - 1 < (n ^ (n - 1));
}
+/**
+ * is_power_of_2_u64() - check if a 64-bit value is a power of two
+ * @n: the value to check
+ *
+ * Determine whether some value is a power of two, where zero is
+ * *not* considered a power of two. Unlike is_power_of_2, this version
+ * always operates on 64-bit values, even on 32-bit architectures where
+ * long is 32-bit.
+ * Return: true if @n is a power of 2, otherwise false.
+ */
+static __always_inline __attribute_const__
+bool is_power_of_2_u64(u64 n)
+{
+ return n - 1 < (n ^ (n - 1));
+}
+
/**
* __roundup_pow_of_two() - round up to nearest power of two
* @n: value to round up
@@ -195,6 +211,63 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
__rounddown_pow_of_two(n) \
)
+/**
+ * __rounddown_pow_of_two_64() - round a 64-bit value down to nearest power of two
+ * @n: value to round down
+ */
+static inline __attribute_const__
+u64 __rounddown_pow_of_two_u64(u64 n)
+{
+ return 1ULL << ilog2(n);
+}
+
+/**
+ * rounddown_pow_of_two_u64 - round a 64-bit value down to nearest power of two
+ * @n: parameter
+ *
+ * round the given value down to the nearest power of two
+ * - this always operates on 64-bit values, even on 32-bit systems
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define rounddown_pow_of_two_u64(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ ((n) == 1) ? 1ULL : \
+ (1ULL << ilog2((n))) \
+ ) : \
+ __rounddown_pow_of_two_u64(n) \
+)
+
+
+/**
+ * __roundup_pow_of_two_u64() - round a 64-bit value up to nearest power of two
+ * @n: value to round up
+ */
+static inline __attribute_const__
+u64 __roundup_pow_of_two_u64(u64 n)
+{
+ return 1ULL << (ilog2(n - 1) + 1);
+}
+
+/**
+ * roundup_pow_of_two_u64 - round a 64-bit value up to nearest power of two
+ * @n: parameter
+ *
+ * round the given value up to the nearest power of two
+ * - this always operates on 64-bit values, even on 32-bit systems
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define roundup_pow_of_two_u64(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ ((n) == 1) ? 1ULL : \
+ (1ULL << (ilog2((n) - 1) + 1)) \
+ ) : \
+ __roundup_pow_of_two_u64(n) \
+)
+
static inline __attribute_const__
int __order_base_2(unsigned long n)
{
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 2/3] drm_buddy: fix power-of-2 rounding errs
2026-08-30 10:33 [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions David Gow
@ 2026-08-30 10:33 ` David Gow
2026-08-30 10:33 ` [PATCH v2 3/3] fs:btrfs: Use the new global is_power_of_2_u64() helper David Gow
2026-08-30 11:43 ` [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions David Laight
2 siblings, 0 replies; 4+ messages in thread
From: David Gow @ 2026-08-30 10:33 UTC (permalink / raw)
To: Jim Cromie, Maciej W . Rozycki, Andrew Morton, Matthew Auld,
Arun Pravin, Joel Fernandes, David Airlie, Simona Vetter
Cc: dri-devel, linux-kernel, David Gow
From: Jim Cromie <jim.cromie@gmail.com>
The standard roundup_pow_of_two() and rounddown_pow_of_two() macros use
unsigned long internally, which on 32-bit architectures (like arm32) is
a 32-bit type.
drm_test_buddy_alloc_exceeds_max_order() uses these on a u64 value,
where they silently truncate the 10GB allocation, giving unexpected
success in DRM-CI. (see below the snip).
Fix this by replacing the those macros with the safe 64-bit power-of-two
equivalents added in the previous patch.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/all/20260326185413.1205870-40-jim.cromie@gmail.com/
Signed-off-by: David Gow <david@davidgow.net>
---
This should actually be version 13 or 14, I think, as it's just a rebase
of v12 here, where it was part of a large series of fixups:
https://lore.kernel.org/all/20260326185413.1205870-40-jim.cromie@gmail.com/
There are probably some other places where this is not perfectly 32-bit safe,
but this is at least enough to fix the KUnit tests.
The major changes since that version are:
- Add the helper functions rounddown_pow_of_two_u64() and
roundup_pow_of_two_u64() (see patch 1) instead of open-coding them
- Rebase now that the buddy allocator lives in drivers/gpu/buddy.c
instead of drivers/gpu/drm/drm_buddy.c
This is still breaking the gpu_test_buddy_alloc_exceeds_max_order
KUnit test on 32-bit systems:
[09:01:26] # gpu_test_buddy_alloc_exceeds_max_order: EXPECTATION FAILED at drivers/gpu/tests/gpu_buddy_test.c:1429
[09:01:26] Expected err == -22, but
[09:01:26] err == 0 (0x0)
[09:01:26] WARNING: drivers/gpu/buddy.c:508 at gpu_buddy_fini+0x244/0x2e0, CPU#0: kunit_try_catch/1595
[09:01:26] # gpu_test_buddy_alloc_exceeds_max_order: drivers/gpu/buddy.c:508: gpu_buddy_assert(gpu_buddy_block_is_free(mm->roots[i]))
[09:01:26] WARNING: drivers/gpu/buddy.c:516 at gpu_buddy_fini+0x284/0x2e0, CPU#0: kunit_try_catch/1595
[09:01:26] # gpu_test_buddy_alloc_exceeds_max_order: drivers/gpu/buddy.c:508: gpu_buddy_assert(gpu_buddy_block_is_free(mm->roots[i]))
[09:01:26] WARNING: drivers/gpu/buddy.c:516 at gpu_buddy_fini+0x284/0x2e0, CPU#0: kunit_try_catch/1595
[09:01:26] # gpu_test_buddy_alloc_exceeds_max_order: drivers/gpu/buddy.c:519: gpu_buddy_assert(!mm->used_scoreboard[i])
[09:01:26] [FAILED] gpu_test_buddy_alloc_exceeds_max_order
Changes since v1:
https://lore.kernel.org/all/20260821091918.1902032-2-david@ingeniumdigital.com/
- Rename round{up,down}_pow_of_two64() -> round{up,down_pow_of_two_u64()
(This seems nicer and more consistent with what everyone else is doing)
---
drivers/gpu/buddy.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c
index a5553fcec28c..0c432719f8f1 100644
--- a/drivers/gpu/buddy.c
+++ b/drivers/gpu/buddy.c
@@ -1193,7 +1193,7 @@ static int __alloc_contig_try_harder(struct gpu_buddy *mm,
u64 modify_size;
int err;
- modify_size = rounddown_pow_of_two(size);
+ modify_size = rounddown_pow_of_two_u64(size);
order = ilog2(modify_size) - ilog2(mm->chunk_size);
if (order == 0)
return -ENOSPC;
@@ -1440,7 +1440,7 @@ int gpu_buddy_alloc_blocks(struct gpu_buddy *mm,
/* Roundup the size to power of 2 */
if (flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION) {
- size = roundup_pow_of_two(size);
+ size = roundup_pow_of_two_u64(size);
min_block_size = size;
/*
* Normalize the requested size to min_block_size for regular allocations.
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] fs:btrfs: Use the new global is_power_of_2_u64() helper
2026-08-30 10:33 [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions David Gow
2026-08-30 10:33 ` [PATCH v2 2/3] drm_buddy: fix power-of-2 rounding errs David Gow
@ 2026-08-30 10:33 ` David Gow
2026-08-30 11:43 ` [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions David Laight
2 siblings, 0 replies; 4+ messages in thread
From: David Gow @ 2026-08-30 10:33 UTC (permalink / raw)
To: Jim Cromie, Maciej W . Rozycki, Andrew Morton, Matthew Auld,
Arun Pravin, Joel Fernandes, David Airlie, Simona Vetter,
Chris Mason, David Sterba
Cc: David Gow, dri-devel, linux-btrfs, linux-kernel
btrfs currently provides its own 64-bit safe version of
is_power_of_2(), in order to handle 64-bit values on 32-bit systems.
Since other subsystems also have similar helpers, a new implementation
has been added to linux/log2.h. Use this instead of the btrfs-specific
one.
Signed-off-by: David Gow <david@davidgow.net>
---
This basically just replaces a btrfs helper with the version in patch 1.
It probably doesn't make sense for this series to go in via the btrfs
tree, so it's probably worth either accepting the posssibility for a
conflict, or sending this patch in separately after the first one lands.
Cheers,
-- David
[This patch was introduced in v2 of the series.]
---
fs/btrfs/misc.h | 7 +------
fs/btrfs/zoned.c | 2 +-
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/fs/btrfs/misc.h b/fs/btrfs/misc.h
index 802060943180..e8be78341dc0 100644
--- a/fs/btrfs/misc.h
+++ b/fs/btrfs/misc.h
@@ -110,15 +110,10 @@ static inline u64 mult_perc(u64 num, u32 percent)
{
return div_u64(num * percent, 100);
}
-/* Copy of is_power_of_two that is 64bit safe */
-static inline bool is_power_of_two_u64(u64 n)
-{
- return n != 0 && (n & (n - 1)) == 0;
-}
static inline bool has_single_bit_set(u64 n)
{
- return is_power_of_two_u64(n);
+ return is_power_of_2_u64(n);
}
/*
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index a016cb471beb..b90ac4ff71b8 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -421,7 +421,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
zone_sectors = bdev_zone_sectors(bdev);
}
- ASSERT(is_power_of_two_u64(zone_sectors));
+ ASSERT(is_power_of_2_u64(zone_sectors));
zone_info->zone_size = zone_sectors << SECTOR_SHIFT;
/* We reject devices with a zone size larger than 8GB */
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions
2026-08-30 10:33 [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions David Gow
2026-08-30 10:33 ` [PATCH v2 2/3] drm_buddy: fix power-of-2 rounding errs David Gow
2026-08-30 10:33 ` [PATCH v2 3/3] fs:btrfs: Use the new global is_power_of_2_u64() helper David Gow
@ 2026-08-30 11:43 ` David Laight
2 siblings, 0 replies; 4+ messages in thread
From: David Laight @ 2026-08-30 11:43 UTC (permalink / raw)
To: David Gow
Cc: Jim Cromie, Maciej W . Rozycki, Andrew Morton, Matthew Auld,
Arun Pravin, Joel Fernandes, David Airlie, Simona Vetter,
Chris Mason, David Sterba, dri-devel, linux-btrfs, linux-kernel
On Sun, 30 Aug 2026 18:33:15 +0800
David Gow <david@davidgow.net> 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.
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.
David
>
> To avoid conflicts, the i915 implementation is also removed here. The btrfs
> one (which has a different name) is replaced in a separate patch.
>
> Signed-off-by: David Gow <david@davidgow.net>
> ---
>
> This patch adds u64 helpers, and the following two use them. And v2 also
> has the i915 change to remove the conflicting implementation.
>
> So I'm not sure who best wants to take these. Ultimately it's an include/linux
> change, but it touches i915, patch 2 touches GPU/DRM, and patch 3 btrfs.
> Personally, I'm keen to get patch 2 in, as it fixes a real issue, so if taking
> 1 and 2 via DRM makes more sense, that's fine by me.
>
> Changes since v1:
> https://lore.kernel.org/all/20260821091918.1902032-1-david@ingeniumdigital.com/
> - Include is_power_of_2_u64() as well, and remove the i915 version
> (Thanks, Matthew)
> - Use _u64 as a suffix for the 64-bit versions, not just 64
> (This is a much nicer name, and matches what everone else was doing)
> - Fix some comment typos.
> - Add a third patch which removes a similar is_power_of_two_u64() helper
> from btrfs.
>
> ---
> drivers/gpu/drm/i915/i915_utils.h | 5 ---
> include/linux/log2.h | 73 +++++++++++++++++++++++++++++++
> 2 files changed, 73 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
> index ecc20e0528f4..1cec51984d8c 100644
> --- a/drivers/gpu/drm/i915/i915_utils.h
> +++ b/drivers/gpu/drm/i915/i915_utils.h
> @@ -75,11 +75,6 @@ struct drm_i915_private;
> __idx; \
> })
>
> -static inline bool is_power_of_2_u64(u64 n)
> -{
> - return (n != 0 && ((n & (n - 1)) == 0));
> -}
> -
> void add_taint_for_CI(struct drm_i915_private *i915, unsigned int taint);
> static inline void __add_taint_for_CI(unsigned int taint)
> {
> diff --git a/include/linux/log2.h b/include/linux/log2.h
> index e17ceb32e0c9..fc44e59f5732 100644
> --- a/include/linux/log2.h
> +++ b/include/linux/log2.h
> @@ -47,6 +47,22 @@ bool is_power_of_2(unsigned long n)
> return n - 1 < (n ^ (n - 1));
> }
>
> +/**
> + * is_power_of_2_u64() - check if a 64-bit value is a power of two
> + * @n: the value to check
> + *
> + * Determine whether some value is a power of two, where zero is
> + * *not* considered a power of two. Unlike is_power_of_2, this version
> + * always operates on 64-bit values, even on 32-bit architectures where
> + * long is 32-bit.
> + * Return: true if @n is a power of 2, otherwise false.
> + */
> +static __always_inline __attribute_const__
> +bool is_power_of_2_u64(u64 n)
> +{
> + return n - 1 < (n ^ (n - 1));
> +}
> +
> /**
> * __roundup_pow_of_two() - round up to nearest power of two
> * @n: value to round up
> @@ -195,6 +211,63 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
> __rounddown_pow_of_two(n) \
> )
>
> +/**
> + * __rounddown_pow_of_two_64() - round a 64-bit value down to nearest power of two
> + * @n: value to round down
> + */
> +static inline __attribute_const__
> +u64 __rounddown_pow_of_two_u64(u64 n)
> +{
> + return 1ULL << ilog2(n);
> +}
> +
> +/**
> + * rounddown_pow_of_two_u64 - round a 64-bit value down to nearest power of two
> + * @n: parameter
> + *
> + * round the given value down to the nearest power of two
> + * - this always operates on 64-bit values, even on 32-bit systems
> + * - the result is undefined when n == 0
> + * - this can be used to initialise global variables from constant data
> + */
> +#define rounddown_pow_of_two_u64(n) \
> +( \
> + __builtin_constant_p(n) ? ( \
> + ((n) == 1) ? 1ULL : \
> + (1ULL << ilog2((n))) \
> + ) : \
> + __rounddown_pow_of_two_u64(n) \
> +)
> +
> +
> +/**
> + * __roundup_pow_of_two_u64() - round a 64-bit value up to nearest power of two
> + * @n: value to round up
> + */
> +static inline __attribute_const__
> +u64 __roundup_pow_of_two_u64(u64 n)
> +{
> + return 1ULL << (ilog2(n - 1) + 1);
> +}
> +
> +/**
> + * roundup_pow_of_two_u64 - round a 64-bit value up to nearest power of two
> + * @n: parameter
> + *
> + * round the given value up to the nearest power of two
> + * - this always operates on 64-bit values, even on 32-bit systems
> + * - the result is undefined when n == 0
> + * - this can be used to initialise global variables from constant data
> + */
> +#define roundup_pow_of_two_u64(n) \
> +( \
> + __builtin_constant_p(n) ? ( \
> + ((n) == 1) ? 1ULL : \
> + (1ULL << (ilog2((n) - 1) + 1)) \
> + ) : \
> + __roundup_pow_of_two_u64(n) \
> +)
> +
> static inline __attribute_const__
> int __order_base_2(unsigned long n)
> {
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-30 11:43 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-30 10:33 [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions David Gow
2026-08-30 10:33 ` [PATCH v2 2/3] drm_buddy: fix power-of-2 rounding errs David Gow
2026-08-30 10:33 ` [PATCH v2 3/3] fs:btrfs: Use the new global is_power_of_2_u64() helper David Gow
2026-08-30 11:43 ` [PATCH v2 1/3] linux/log2.h: Add 64-bit safe variants of power-of-two functions David Laight
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®