[PATCH v4 5/7] linux/log2.h: Add 64-bit roundup/down_pow_of_two64() variants
From: Ilpo Järvinen
Date: Wed Oct 21 2026 - 08:52:41 EST
Generic sounding roundup_pow_of_two() and rounddown_pow_of_two() are
internally based on fls() that limits types to unsigned long. The type
limitation is unexpected and undocumented.
Worse yet, the typing seems also inconsistent between
__builtin_constant_p() and __roundup/down_pow_of_two() branches, the
former using full 64-bit size and the latter truncating type.
The most sensible way seems to be eventually changing types such that
the return type for roundup/down_pow_of_two() is same as input but it
requires auditing all the existing callers that have mixed input/output
types.
As a stop gap solution, add roundup/down_pow_of_two64() that do not
unexpectedly truncate 64-bit input.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>
---
include/linux/log2.h | 52 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/include/linux/log2.h b/include/linux/log2.h
index e17ceb32e0c9..180e5702f677 100644
--- a/include/linux/log2.h
+++ b/include/linux/log2.h
@@ -57,6 +57,16 @@ unsigned long __roundup_pow_of_two(unsigned long n)
return 1UL << fls_long(n - 1);
}
+/**
+ * __roundup_pow_of_two64() - round up to nearest power of two
+ * @n: value to round up
+ */
+static inline __attribute__((const))
+u64 __roundup_pow_of_two64(u64 n)
+{
+ return 1ULL << fls64(n - 1);
+}
+
/**
* __rounddown_pow_of_two() - round down to nearest power of two
* @n: value to round down
@@ -67,6 +77,16 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
return 1UL << (fls_long(n) - 1);
}
+/**
+ * __rounddown_pow_of_two64() - round down to nearest power of two
+ * @n: value to round down
+ */
+static inline __attribute__((const))
+u64 __rounddown_pow_of_two64(u64 n)
+{
+ return 1ULL << (fls64(n) - 1);
+}
+
/**
* const_ilog2 - log base 2 of 32-bit or a 64-bit constant unsigned value
* @n: parameter
@@ -163,6 +183,23 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
__ilog2_u64(n) \
)
+/**
+ * roundup_pow_of_two64 - round the given value up to nearest power of two
+ * @n: parameter
+ *
+ * round the given value up to the nearest power of two
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define roundup_pow_of_two64(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ ((n) == 1) ? 1 : \
+ (1UL << (ilog2((n) - 1) + 1)) \
+ ) : \
+ __roundup_pow_of_two64(n) \
+ )
+
/**
* roundup_pow_of_two - round the given value up to nearest power of two
* @n: parameter
@@ -180,6 +217,21 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
__roundup_pow_of_two(n) \
)
+/**
+ * rounddown_pow_of_two64 - round the given value down to nearest power of two
+ * @n: parameter
+ *
+ * round the given value down to the nearest power of two
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define rounddown_pow_of_two64(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ (1UL << ilog2(n))) : \
+ __rounddown_pow_of_two64(n) \
+ )
+
/**
* rounddown_pow_of_two - round the given value down to nearest power of two
* @n: parameter
--
2.47.3