* [PATCH v3 0/3] Introduce in_range_incl() inclusive range check macro
@ 2026-08-31 16:26 Guru Das Srinagesh
2026-08-31 16:26 ` [PATCH v3 1/3] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Guru Das Srinagesh @ 2026-08-31 16:26 UTC (permalink / raw)
To: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Matthew Wilcox, Andrew Morton, Gustavo Silva
Cc: linux-kernel, linux-iio, Guru Das Srinagesh
Extend the existing in_range() API to provide a user-friendly inclusive
range check and add one illustrative in-tree example of its use.
The in_range() API lends itself easily to callers who care about a
half-open range, but has no straightforward equivalent for callers that
want to check for an inclusive range. Such callers have to resort to
this pattern:
in_range(val, start, (end - start + 1))
which is quite clunky and easy to mess up. Examples of such callers:
- fs/btrfs/extent-io-tree.c hand-computes the inclusive check by
passing "state->end - state->start + 1" as in_range()'s len argument.
- drivers/md/dm-raid.c has its own file-local __within_range(v, min, max)
helper, independently invented, with almost a dozen call sites in
that one file.
- drivers/iio/imu/bmi270/bmi270_core.c has three "in_range(val, 0,
MAX + 1)" checks in bmi270_write_event_value(), computing the +1 by
hand for the same reason.
This series converts only bmi270_core.c as a first step, as an exemplar
for the usage of the new API. Note that similar conversions in other
call sites are not drop-in replacements and have to be reviewed
carefully to ensure the behaviour of the check does not change.
Signed-off-by: Guru Das Srinagesh <linux@gurudas.dev>
---
Changes in v3:
- (Matthew) Go back to in_range() approach which was earlier incorrectly
abandoned in v2 to avoid the overflow problem with v1's plain wrapper of
in_range() with len = (max - min + 1)
- (Andy) Add Kunit test for in_range_inclusive() covering both u32 and
u64 test cases. Tested with:
./tools/testing/kunit/kunit.py run --arch=x86_64 "in_range*"
- (Andy) Added return value kernel-doc description
- in_range_inclusive() deliberately does not add a BUILD_BUG_ON for
@min > @max nor a signedness check in keeping with the in_range() example.
- AI assistance (Claude, sashiko using Claude CLI as backend) was used
to improve precision in kernel-doc description, refining test cases
and adding more test case classes.
- Rebased to v7.2
- Link to v2: https://patch.msgid.link/20260816-minmax-in-range-incl-v2-0-766f737dd6bf@gurudas.dev
Changes in v2:
- (Andrew) Rename in_range_incl() to in_range_inclusive()
- Wholly incorrect approach abandoning in_range()
Link to v1: https://patch.msgid.link/20260815-minmax-in-range-incl-v1-0-a75f7d9ae92e@gurudas.dev
To: Alex Lanzano <lanzano.alex@gmail.com>
To: Jonathan Cameron <jic23@kernel.org>
To: David Lechner <dlechner@baylibre.com>
To: Nuno Sá <nuno.sa@analog.com>
To: Andy Shevchenko <andy@kernel.org>
Cc: linux-kernel@vger.kernel.org
Cc: linux-iio@vger.kernel.org
---
Guru Das Srinagesh (3):
minmax: Add in_range_inclusive() for inclusive range checks
lib/tests: Add in_range_inclusive() KUnit test
iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value()
drivers/iio/imu/bmi270/bmi270_core.c | 6 +-
include/linux/minmax.h | 39 ++++++
lib/Kconfig.debug | 18 +++
lib/tests/Makefile | 1 +
lib/tests/in_range_inclusive_kunit.c | 249 +++++++++++++++++++++++++++++++++++
5 files changed, 310 insertions(+), 3 deletions(-)
---
base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
change-id: 20260815-minmax-in-range-incl-a25c242be676
Best regards,
--
Guru Das Srinagesh <linux@gurudas.dev>
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v3 1/3] minmax: Add in_range_inclusive() for inclusive range checks 2026-08-31 16:26 [PATCH v3 0/3] Introduce in_range_incl() inclusive range check macro Guru Das Srinagesh @ 2026-08-31 16:26 ` Guru Das Srinagesh 2026-09-01 7:26 ` Andy Shevchenko 2026-08-31 16:26 ` [PATCH v3 2/3] lib/tests: Add in_range_inclusive() KUnit test Guru Das Srinagesh 2026-08-31 16:26 ` [PATCH v3 3/3] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() Guru Das Srinagesh 2 siblings, 1 reply; 7+ messages in thread From: Guru Das Srinagesh @ 2026-08-31 16:26 UTC (permalink / raw) To: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko, Matthew Wilcox, Andrew Morton, Gustavo Silva Cc: linux-kernel, linux-iio, Guru Das Srinagesh Extend the logic in in_range() to support checking for an inclusive range [min, max]. The condition in the check is derived as follows, starting from the in_range() macro with len = (max - min + 1): (val - min) < (max - min + 1) // overflows for [0, U32/U64_MAX] (val - min) <= (max - min) // no overflow The behaviour of the macro from the signedness perspective is documented in the kernel-doc and in the in_range_inclusive KUnit test suite. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Guru Das Srinagesh <linux@gurudas.dev> --- include/linux/minmax.h | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/include/linux/minmax.h b/include/linux/minmax.h index a0158db54a04..dce3a8bea9e2 100644 --- a/include/linux/minmax.h +++ b/include/linux/minmax.h @@ -299,6 +299,45 @@ static inline bool in_range32(u32 val, u32 start, u32 len) ((sizeof(start) | sizeof(len) | sizeof(val)) <= sizeof(u32) ? \ in_range32(val, start, len) : in_range64(val, start, len)) +static inline bool in_range_inclusive64(u64 val, u64 min, u64 max) +{ + return (val - min) <= (max - min); +} + +static inline bool in_range_inclusive32(u32 val, u32 min, u32 max) +{ + return (val - min) <= (max - min); +} + +/** + * in_range_inclusive - Determine if a value lies within an inclusive range. + * @val: Value to test. + * @min: First value in range. + * @max: Last value in range. + * + * This checks if a value lies within the closed range of [@min, @max]. Note that + * "range" refers to values counting up from @min with wraparound at + * unsigned-datatype max if encountered, continuing on till @max is reached. + * + * This macro is not a drop-in replacement for "if (val >= min && val <= max)". + * Unsigned arithmetic determines what the 'true' range exactly is depending on + * whether @min <= @max holds, and in which reading (signed vs unsigned) as follows:: + * + * Valid in reading Example 'True' range is + * Both readings [5, 10] interval as written in either reading + * Signed only [-10, 5] signed interval + * Unsigned only [5, -10] unsigned interval + * Neither reading [-5, -10] neither; all values except [unsigned(-9), unsigned(-6)] + * + * The last two cases provide "surprising" results and are to be used carefully, if + * at all. Further, if @max = @min - 1, every @val is in range. + * + * Return: true or false as described above. + */ +#define in_range_inclusive(val, min, max) \ + ((sizeof(val) | sizeof(min) | sizeof(max)) <= sizeof(u32) ? \ + in_range_inclusive32(val, min, max) : in_range_inclusive64(val, min, max)) + /** * swap - swap values of @a and @b * @a: first value -- 2.55.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v3 1/3] minmax: Add in_range_inclusive() for inclusive range checks 2026-08-31 16:26 ` [PATCH v3 1/3] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh @ 2026-09-01 7:26 ` Andy Shevchenko 0 siblings, 0 replies; 7+ messages in thread From: Andy Shevchenko @ 2026-09-01 7:26 UTC (permalink / raw) To: Guru Das Srinagesh Cc: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko, Matthew Wilcox, Andrew Morton, Gustavo Silva, linux-kernel, linux-iio On Mon, Aug 31, 2026 at 09:26:28AM -0700, Guru Das Srinagesh wrote: > Extend the logic in in_range() to support checking for an inclusive > range [min, max]. > > The condition in the check is derived as follows, starting from the > in_range() macro with len = (max - min + 1): > > (val - min) < (max - min + 1) // overflows for [0, U32/U64_MAX] > (val - min) <= (max - min) // no overflow > > The behaviour of the macro from the signedness perspective is documented > in the kernel-doc and in the in_range_inclusive KUnit test suite. ... > +/** > + * in_range_inclusive - Determine if a value lies within an inclusive range. > + * @val: Value to test. > + * @min: First value in range. > + * @max: Last value in range. We have macros named min() and max(), since this is a macro as well it might give an interesting outcome when two collide. Suggestion is to rename the parameters to avoid potential collisions. > + * This checks if a value lies within the closed range of [@min, @max]. Note that > + * "range" refers to values counting up from @min with wraparound at > + * unsigned-datatype max if encountered, continuing on till @max is reached. > + * > + * This macro is not a drop-in replacement for "if (val >= min && val <= max)". > + * Unsigned arithmetic determines what the 'true' range exactly is depending on > + * whether @min <= @max holds, and in which reading (signed vs unsigned) as follows:: > + * > + * Valid in reading Example 'True' range is > + * Both readings [5, 10] interval as written in either reading > + * Signed only [-10, 5] signed interval > + * Unsigned only [5, -10] unsigned interval > + * Neither reading [-5, -10] neither; all values except [unsigned(-9), unsigned(-6)] > + * > + * The last two cases provide "surprising" results and are to be used carefully, if > + * at all. Further, if @max = @min - 1, every @val is in range. > + * > + * Return: true or false as described above. > + */ Imagine something like in_range_inclusive(value, min(A, B), max(C, D)) case which I consider plausible to happen (in some form). -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 2/3] lib/tests: Add in_range_inclusive() KUnit test 2026-08-31 16:26 [PATCH v3 0/3] Introduce in_range_incl() inclusive range check macro Guru Das Srinagesh 2026-08-31 16:26 ` [PATCH v3 1/3] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh @ 2026-08-31 16:26 ` Guru Das Srinagesh 2026-09-01 7:38 ` Andy Shevchenko 2026-08-31 16:26 ` [PATCH v3 3/3] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() Guru Das Srinagesh 2 siblings, 1 reply; 7+ messages in thread From: Guru Das Srinagesh @ 2026-08-31 16:26 UTC (permalink / raw) To: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko, Matthew Wilcox, Andrew Morton, Gustavo Silva Cc: linux-kernel, linux-iio, Guru Das Srinagesh Add a KUnit test for the minmax.h in_range_inclusive() logic. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Guru Das Srinagesh <linux@gurudas.dev> --- lib/Kconfig.debug | 18 +++ lib/tests/Makefile | 1 + lib/tests/in_range_inclusive_kunit.c | 249 +++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 1244dcac2294..88f5abc70266 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -3031,6 +3031,24 @@ config MIN_HEAP_KUNIT_TEST If unsure, say N +config IN_RANGE_INCLUSIVE_KUNIT_TEST + tristate "Test minmax in_range_inclusive() logic" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + Enable this option to build the in_range_inclusive KUnit module. + It tests the in_range_inclusive() logic. + + KUnit tests run during boot and output the results to the debug log + in TAP format (http://testanything.org/). Only useful for kernel devs + running the KUnit test harness, and not intended for inclusion into a + production build. + + For more information on KUnit and unit tests in general please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. + config IS_SIGNED_TYPE_KUNIT_TEST tristate "Test is_signed_type() macro" if !KUNIT_ALL_TESTS depends on KUNIT diff --git a/lib/tests/Makefile b/lib/tests/Makefile index 4ead57602eac..866b6006413d 100644 --- a/lib/tests/Makefile +++ b/lib/tests/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_GLOB_KUNIT_TEST) += glob_kunit.o obj-$(CONFIG_HASHTABLE_KUNIT_TEST) += hashtable_test.o obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o obj-$(CONFIG_TEST_IOV_ITER) += kunit_iov_iter.o +obj-$(CONFIG_IN_RANGE_INCLUSIVE_KUNIT_TEST) += in_range_inclusive_kunit.o obj-$(CONFIG_IS_SIGNED_TYPE_KUNIT_TEST) += is_signed_type_kunit.o obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o diff --git a/lib/tests/in_range_inclusive_kunit.c b/lib/tests/in_range_inclusive_kunit.c new file mode 100644 index 000000000000..83e8d48684f2 --- /dev/null +++ b/lib/tests/in_range_inclusive_kunit.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test cases for minmax in_range_inclusive() helpers. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <kunit/test.h> +#include <linux/minmax.h> + +/* + * When @min <= @max is valid in: + * Valid in reading Example 'True' range is + * Case 1 Both readings [5, 10] interval as written in either reading + * Case 2 Signed only [-10, 5] signed interval + * Case 3 Unsigned only [5, -10] unsigned interval + * Case 4 Neither reading [-5, -10] neither; all values except [unsigned(-9), unsigned(-6)] + * + * Visualizing the wraparound-continuous unsigned number scale as a full circle with + * 0 at 12 o'clock and S32_MAX/S64_MAX at 6 o'clock, with ranges being calculated + * only clockwise starting from @min until @max might help greatly in understanding + * the following true and false ranges. + */ +static void u32_tests(struct kunit *test) +{ + /* Case 1 first true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(5, 5, 10)); + /* Case 1 last true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(10, 5, 10)); + /* Case 1 first false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(11, 5, 10)); + /* Case 1 last false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(4, 5, 10)); + /* Case 1 0 not in range */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(0, 5, 10)); + /* Case 1 U32_MAX not in range */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(U32_MAX, 5, 10)); + + /* Case 2 first true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(-10, -10, 5)); + /* Case 2 last true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(5, -10, 5)); + /* Case 2 first false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(6, -10, 5)); + /* Case 2 last false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(-11, -10, 5)); + /* Case 2 0 in range */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(0, -10, 5)); + /* Case 2 U32_MAX in range */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(U32_MAX, -10, 5)); + + /* Case 3 first true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(5, 5, -10)); + /* Case 3 last true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(-10, 5, -10)); + /* Case 3 first false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(-9, 5, -10)); + /* Case 3 last false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(4, 5, -10)); + /* Case 3 0 not in range */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(0, 5, -10)); + /* Case 3 U32_MAX not in range */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(U32_MAX, 5, -10)); + + /* Case 4 first true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(-5, -5, -10)); + /* Case 4 last true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(-10, -5, -10)); + /* Case 4 first false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(-9, -5, -10)); + /* Case 4 last false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(-6, -5, -10)); + /* Case 4 0 in range */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(0, -5, -10)); + /* Case 4 U32_MAX in range */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(U32_MAX, -5, -10)); +} + +static void u64_tests(struct kunit *test) +{ + /* Case 1 first true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(5ULL, 5ULL, 10ULL)); + /* Case 1 last true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(10ULL, 5ULL, 10ULL)); + /* Case 1 first false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(11ULL, 5ULL, 10ULL)); + /* Case 1 last false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(4ULL, 5ULL, 10ULL)); + /* Case 1 0 not in range */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(0ULL, 5ULL, 10ULL)); + /* Case 1 U64_MAX not in range */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(U64_MAX, 5ULL, 10ULL)); + + /* Case 2 first true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(-10ULL, -10ULL, 5ULL)); + /* Case 2 last true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(5ULL, -10ULL, 5ULL)); + /* Case 2 first false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(6ULL, -10ULL, 5ULL)); + /* Case 2 last false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(-11ULL, -10ULL, 5ULL)); + /* Case 2 0 in range */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(0ULL, -10ULL, 5ULL)); + /* Case 2 U64_MAX in range */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(U64_MAX, -10ULL, 5ULL)); + + /* Case 3 first true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(5ULL, 5ULL, -10ULL)); + /* Case 3 last true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(-10ULL, 5ULL, -10ULL)); + /* Case 3 first false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(-9ULL, 5ULL, -10ULL)); + /* Case 3 last false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(4ULL, 5ULL, -10ULL)); + /* Case 3 0 not in range */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(0ULL, 5ULL, -10ULL)); + /* Case 3 U64_MAX not in range */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(U64_MAX, 5ULL, -10ULL)); + + /* Case 4 first true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(-5ULL, -5ULL, -10ULL)); + /* Case 4 last true value */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(-10ULL, -5ULL, -10ULL)); + /* Case 4 first false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(-9ULL, -5ULL, -10ULL)); + /* Case 4 last false value */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(-6ULL, -5ULL, -10ULL)); + /* Case 4 0 in range */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(0ULL, -5ULL, -10ULL)); + /* Case 4 U64_MAX in range */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(U64_MAX, -5ULL, -10ULL)); +} + +/* Check whether sizeof logic to select 32- vs 64-bit comparisons works */ +static void sizeof_logic_tests(struct kunit *test) +{ + u64 u64_val = BIT_ULL(32) | 7; + u64 u64_minval = BIT_ULL(32) | 5; + u64 u64_maxval = BIT_ULL(32) | 10; + u32 u32_minval = 5, u32_maxval = 10, u32_val = 100; + + /* If sizeof trick does not work: + * - u64_val will get truncated to 7 + * - 7 is in [5, 10] so test should pass. + */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(u64_val, u32_minval, u32_maxval)); + + /* + * If sizeof trick does not work: + * - u64_maxval will get truncated to 10 + * - 100 is not in [5, 10], so test should fail. + */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(u32_val, u32_minval, u64_maxval)); + + /* + * If sizeof trick does not work: + * - u64_minval gets truncated to 5 + * - 0 is not in [5, 10], so test should fail. + * Otherwise: + * - @min > @max here, so this is Case 4 + * - 0 should be in range and test should pass. + */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(0, u64_minval, u32_maxval)); +} + +/* + * Each argument is widened to the selected width according to its own type: + * signed arguments sign-extend, unsigned ones zero-extend. The same written + * values can therefore give opposite answers depending on the declared types. + */ +static void sign_extension_tests(struct kunit *test) +{ + u32 u32_val = -9; + s32 s32_val = -9; + s32 s32_minval = 5, s32_maxval = -10; + s64 s64_minval = 5, s64_maxval = -10; + + /* Case 3 range. -9 is out of range in both readings */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(u32_val, s32_minval, s32_maxval)); + KUNIT_EXPECT_FALSE(test, in_range_inclusive(s32_val, s32_minval, s32_maxval)); + + /* + * Sign extension kicks in due to sizeof logic. minval "stays in place" + * because it is positive and maxval "moves" because it is negative and + * signed, thereby increasing the True range. + * Negative unsigned -9 "stays in place", so it becomes in range. + * Negative signed -9 "moves", so it still remains out of range. + */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(u32_val, s64_minval, s64_maxval)); + KUNIT_EXPECT_FALSE(test, in_range_inclusive(s32_val, s64_minval, s64_maxval)); +} + +#define TEST_RANGE_MIN 0 +#define TEST_RANGE_MAX 100 +static void misc_tests(struct kunit *test) +{ + s32 s32_val = -5; + + /* + * Test common device driver use case of rejecting negative input from + * userspace. + */ + KUNIT_EXPECT_FALSE(test, in_range_inclusive(s32_val, TEST_RANGE_MIN, TEST_RANGE_MAX)); + + /* If min == max, only one true solution exists, val = min */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(5, 5, 5)); + KUNIT_EXPECT_FALSE(test, in_range_inclusive(0, 5, 5)); + KUNIT_EXPECT_FALSE(test, in_range_inclusive(U32_MAX, 5, 5)); + KUNIT_EXPECT_FALSE(test, in_range_inclusive(U64_MAX, 5, 5)); + + /* + * When max = (min - 1), Case 4 kicks in, and there is no 'false' range, + * i.e. all values of val result in 'true'. + */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(5, 5, 4)); + KUNIT_EXPECT_TRUE(test, in_range_inclusive(4, 5, 4)); + KUNIT_EXPECT_TRUE(test, in_range_inclusive(0, 5, 4)); + KUNIT_EXPECT_TRUE(test, in_range_inclusive(U32_MAX, 5, 4)); + KUNIT_EXPECT_TRUE(test, in_range_inclusive(U64_MAX, 5, 4)); + + /* + * [0, U32_MAX] and [0, U64_MAX] are both the same case as above with + * min = 0 and max = (min - 1) + */ + KUNIT_EXPECT_TRUE(test, in_range_inclusive(0, 0, U32_MAX)); + KUNIT_EXPECT_TRUE(test, in_range_inclusive(U32_MAX, 0, U32_MAX)); + KUNIT_EXPECT_TRUE(test, in_range_inclusive(0, 0, U64_MAX)); + KUNIT_EXPECT_TRUE(test, in_range_inclusive(U64_MAX, 0, U64_MAX)); +} + +static struct kunit_case in_range_incl_test_cases[] = { + KUNIT_CASE(u32_tests), + KUNIT_CASE(u64_tests), + KUNIT_CASE(sizeof_logic_tests), + KUNIT_CASE(sign_extension_tests), + KUNIT_CASE(misc_tests), + {} +}; + +static struct kunit_suite in_range_incl_test_suite = { + .name = "in_range_inclusive", + .test_cases = in_range_incl_test_cases, +}; + +kunit_test_suites(&in_range_incl_test_suite); + +MODULE_AUTHOR("Guru Das Srinagesh <linux@gurudas.dev>"); +MODULE_DESCRIPTION("Test cases for in_range_inclusive()"); +MODULE_LICENSE("GPL"); -- 2.55.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v3 2/3] lib/tests: Add in_range_inclusive() KUnit test 2026-08-31 16:26 ` [PATCH v3 2/3] lib/tests: Add in_range_inclusive() KUnit test Guru Das Srinagesh @ 2026-09-01 7:38 ` Andy Shevchenko 0 siblings, 0 replies; 7+ messages in thread From: Andy Shevchenko @ 2026-09-01 7:38 UTC (permalink / raw) To: Guru Das Srinagesh Cc: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko, Matthew Wilcox, Andrew Morton, Gustavo Silva, linux-kernel, linux-iio On Mon, Aug 31, 2026 at 09:26:29AM -0700, Guru Das Srinagesh wrote: > Add a KUnit test for the minmax.h in_range_inclusive() logic. Please, name it after the whole header, id est minmax_kunit.c. ... Also would be nice to have a couple of tests that combine this macro with others from minmax.h (see previous reply on the possible name collision). -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 3/3] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() 2026-08-31 16:26 [PATCH v3 0/3] Introduce in_range_incl() inclusive range check macro Guru Das Srinagesh 2026-08-31 16:26 ` [PATCH v3 1/3] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh 2026-08-31 16:26 ` [PATCH v3 2/3] lib/tests: Add in_range_inclusive() KUnit test Guru Das Srinagesh @ 2026-08-31 16:26 ` Guru Das Srinagesh 2026-09-01 7:47 ` Andy Shevchenko 2 siblings, 1 reply; 7+ messages in thread From: Guru Das Srinagesh @ 2026-08-31 16:26 UTC (permalink / raw) To: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko, Matthew Wilcox, Andrew Morton, Gustavo Silva Cc: linux-kernel, linux-iio, Guru Das Srinagesh Replace the three "in_range(val, 0, MAX + 1)" checks with the new in_range_inclusive() helper, expressing each as the inclusive [0, MAX] range it actually validates. No functional changes are introduced by this change because @min <= @max in the inclusive range in both signed and unsigned readings and hence the check correctly continues to hold and is unchanged in behaviour. Assisted-by: Claude-Code:claude-sonnet-5 Signed-off-by: Guru Das Srinagesh <linux@gurudas.dev> --- drivers/iio/imu/bmi270/bmi270_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c index 2ad230788532..7f386a615b39 100644 --- a/drivers/iio/imu/bmi270/bmi270_core.c +++ b/drivers/iio/imu/bmi270/bmi270_core.c @@ -1132,7 +1132,7 @@ static int bmi270_write_event_value(struct iio_dev *indio_dev, guard(mutex)(&data->mutex); if (type == IIO_EV_TYPE_CHANGE) { - if (!in_range(val, 0, BMI270_STEP_COUNTER_MAX + 1)) + if (!in_range_inclusive(val, 0, BMI270_STEP_COUNTER_MAX)) return -EINVAL; raw = val / BMI270_STEP_COUNTER_FACTOR; @@ -1152,7 +1152,7 @@ static int bmi270_write_event_value(struct iio_dev *indio_dev, if (ret) return ret; - if (!in_range(val, 0, (BMI270_G_MICRO_M_S_2 / uscale) + 1)) + if (!in_range_inclusive(val, 0, BMI270_G_MICRO_M_S_2 / uscale)) return -EINVAL; tmp = (u64)val * BMI270_MOTION_THRES_FULL_SCALE * uscale; @@ -1161,7 +1161,7 @@ static int bmi270_write_event_value(struct iio_dev *indio_dev, regval = FIELD_PREP(BMI270_FEAT_MOTION_THRESHOLD_MSK, raw); return bmi270_update_feature_reg(data, reg, mask, regval); case IIO_EV_INFO_PERIOD: - if (!in_range(val, 0, BMI270_MOTION_DURAT_MAX + 1)) + if (!in_range_inclusive(val, 0, BMI270_MOTION_DURAT_MAX)) return -EINVAL; raw = BMI270_INT_MICRO_TO_RAW(val, val2, -- 2.55.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v3 3/3] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() 2026-08-31 16:26 ` [PATCH v3 3/3] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() Guru Das Srinagesh @ 2026-09-01 7:47 ` Andy Shevchenko 0 siblings, 0 replies; 7+ messages in thread From: Andy Shevchenko @ 2026-09-01 7:47 UTC (permalink / raw) To: Guru Das Srinagesh Cc: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko, Matthew Wilcox, Andrew Morton, Gustavo Silva, linux-kernel, linux-iio On Mon, Aug 31, 2026 at 09:26:30AM -0700, Guru Das Srinagesh wrote: > Replace the three "in_range(val, 0, MAX + 1)" checks with the new > in_range_inclusive() helper, expressing each as the inclusive [0, MAX] > range it actually validates. > > No functional changes are introduced by this change because @min <= @max > in the inclusive range in both signed and unsigned readings and hence > the check correctly continues to hold and is unchanged in behaviour. Yes, this change makes code better (not only shorter, it makes it robust against theoretical wrap-around). Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com> -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-01 7:48 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-31 16:26 [PATCH v3 0/3] Introduce in_range_incl() inclusive range check macro Guru Das Srinagesh 2026-08-31 16:26 ` [PATCH v3 1/3] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh 2026-09-01 7:26 ` Andy Shevchenko 2026-08-31 16:26 ` [PATCH v3 2/3] lib/tests: Add in_range_inclusive() KUnit test Guru Das Srinagesh 2026-09-01 7:38 ` Andy Shevchenko 2026-08-31 16:26 ` [PATCH v3 3/3] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() Guru Das Srinagesh 2026-09-01 7:47 ` Andy Shevchenko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox