* [PATCH v2 0/2] Introduce in_range_incl() inclusive range check macro
@ 2026-08-16 19:26 Guru Das Srinagesh
2026-08-16 19:26 ` [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh
2026-08-16 19:26 ` [PATCH v2 2/2] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() Guru Das Srinagesh
0 siblings, 2 replies; 8+ messages in thread
From: Guru Das Srinagesh @ 2026-08-16 19: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.
Signed-off-by: Guru Das Srinagesh <linux@gurudas.dev>
---
Changes in v2:
- (Andrew) Rename in_range_incl() to in_range_inclusive()
- (Sashiko) Use __UNIQUE_ID() to fix variable-shadowing bug introduced
by choosing fixed tempval names ("__val", "__start", "__end"). The use
of __UNIQUE_ID() is in line with other macros listed in minmax.h.
- (Sashiko) When @end is the type's max value, len overflows to 0, so
in_range_inclusive(val, 0, UINT32_MAX) rejected every input.
- (Sashiko) Abandon idea of reusing in_range() to avoid integer
promotion of the "+1" always routing sub-32-bit types to in_range64(),
defeating the stated purpose of building on in_range().
- Solve both issues above with a simple, direct "val >= start && val <=
end" instead: an in_range()-style (val-start)<=(end-start) trick was
tried first, but that only works under forced-unsigned arithmetic
(like in_range32()/in_range64() use); with typeof()'s original,
possibly-signed type, it breaks silently instead.
- Verification: exhaustive sweep over all valid u8 (start, end, val)
triples confirms in_range_inclusive() is correct (0 mismatches vs.
2.8M for the abandoned approach). -O2 codegen checked on x86, x86_64,
arm and arm64: branchless on all four, byte-identical to a raw
comparison function on every target - no performance cost from the
switch away from 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 (2):
minmax: Add in_range_inclusive() for inclusive range checks
iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value()
drivers/iio/imu/bmi270/bmi270_core.c | 6 +++---
include/linux/minmax.h | 19 +++++++++++++++++++
2 files changed, 22 insertions(+), 3 deletions(-)
---
base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
change-id: 20260815-minmax-in-range-incl-a25c242be676
Best regards,
--
Guru Das Srinagesh <linux@gurudas.dev>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks
2026-08-16 19:26 [PATCH v2 0/2] Introduce in_range_incl() inclusive range check macro Guru Das Srinagesh
@ 2026-08-16 19:26 ` Guru Das Srinagesh
2026-08-16 21:34 ` Matthew Wilcox
2026-08-17 8:06 ` Andy Shevchenko
2026-08-16 19:26 ` [PATCH v2 2/2] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() Guru Das Srinagesh
1 sibling, 2 replies; 8+ messages in thread
From: Guru Das Srinagesh @ 2026-08-16 19: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
in_range(val, start, len) takes a start and a length, i.e. a half-open
range. Callers that instead have an inclusive [start, end] bound have
no ready helper to reach for and either hand-roll the comparison or
convert it to in_range()'s (start, len) form themselves.
Add in_range_inclusive(val, start, end) as a direct comparison rather
than a wrapper around in_range(): computing len as end - start + 1 and
forwarding it to in_range() subverts in_range()'s 32-bit/64-bit dispatch
for sub-32-bit types via integer promotion, and overflows to 0 when @end
is the type's maximum value, silently rejecting every input instead of
accepting all of them.
val, start and end are each assigned to a __UNIQUE_ID()-generated
temporary before use, matching the __cmp_once()/__cmp_once_unique()
pattern: each argument is evaluated exactly once, and the temporary
can't be shadowed by a caller's own same-named local variable.
Assisted-by: Claude-Code:claude-sonnet-5
Signed-off-by: Guru Das Srinagesh <linux@gurudas.dev>
---
include/linux/minmax.h | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index a0158db54a04..cb042733f253 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -299,6 +299,25 @@ 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))
+#define __in_range_inclusive(val, start, end, uval, ustart, uend) ({ \
+ typeof(val) uval = (val); \
+ typeof(start) ustart = (start); \
+ typeof(end) uend = (end); \
+ uval >= ustart && uval <= uend; \
+})
+
+/**
+ * in_range_inclusive - Determine if a value lies within an inclusive range.
+ * @val: Value to test.
+ * @start: First value in range.
+ * @end: Last value in range.
+ *
+ * @val, @start and @end are each evaluated exactly once.
+ */
+#define in_range_inclusive(val, start, end) \
+ __in_range_inclusive(val, start, end, __UNIQUE_ID(val_), \
+ __UNIQUE_ID(start_), __UNIQUE_ID(end_))
+
/**
* swap - swap values of @a and @b
* @a: first value
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks
2026-08-16 19:26 ` [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh
@ 2026-08-16 21:34 ` Matthew Wilcox
2026-08-31 16:29 ` Guru Das Srinagesh
2026-08-17 8:06 ` Andy Shevchenko
1 sibling, 1 reply; 8+ messages in thread
From: Matthew Wilcox @ 2026-08-16 21:34 UTC (permalink / raw)
To: Guru Das Srinagesh
Cc: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Andrew Morton, Gustavo Silva, linux-kernel,
linux-iio
On Sun, Aug 16, 2026 at 12:26:20PM -0700, Guru Das Srinagesh wrote:
> +++ b/include/linux/minmax.h
> @@ -299,6 +299,25 @@ 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))
>
> +#define __in_range_inclusive(val, start, end, uval, ustart, uend) ({ \
> + typeof(val) uval = (val); \
> + typeof(start) ustart = (start); \
> + typeof(end) uend = (end); \
> + uval >= ustart && uval <= uend; \
By convention, 'end' is used for exclusive ranges while 'max' is used
for inclusive ranges.
Also, this seems completely wrong. How do you think this is unsigned
comparisons? I think you'd do better to follow the example of
in_range() much more closely.
ie this is AI slop. Please learn how C works, and write the code
yourself. Use the AI to check your work, not do it for you, because it
leads to people wasting their time trying to manipulate you into
manipulating your AI to produce good code. That's not a good thing.
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks
2026-08-16 21:34 ` Matthew Wilcox
@ 2026-08-31 16:29 ` Guru Das Srinagesh
0 siblings, 0 replies; 8+ messages in thread
From: Guru Das Srinagesh @ 2026-08-31 16:29 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Andrew Morton, Gustavo Silva, linux-kernel,
linux-iio
On Sun, Aug 16, 2026 at 10:34:59PM +0100, Matthew Wilcox wrote:
> On Sun, Aug 16, 2026 at 12:26:20PM -0700, Guru Das Srinagesh wrote:
> > +++ b/include/linux/minmax.h
> > @@ -299,6 +299,25 @@ 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))
> >
> > +#define __in_range_inclusive(val, start, end, uval, ustart, uend) ({ \
> > + typeof(val) uval = (val); \
> > + typeof(start) ustart = (start); \
> > + typeof(end) uend = (end); \
> > + uval >= ustart && uval <= uend; \
>
> By convention, 'end' is used for exclusive ranges while 'max' is used
> for inclusive ranges.
Changed to use 'min' and 'max' instead.
> Also, this seems completely wrong. How do you think this is unsigned
> comparisons? I think you'd do better to follow the example of
> in_range() much more closely.
Done - v3 now follows in_range() closely.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks
2026-08-16 19:26 ` [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh
2026-08-16 21:34 ` Matthew Wilcox
@ 2026-08-17 8:06 ` Andy Shevchenko
2026-08-31 16:33 ` Guru Das Srinagesh
1 sibling, 1 reply; 8+ messages in thread
From: Andy Shevchenko @ 2026-08-17 8:06 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 Sun, Aug 16, 2026 at 12:26:20PM -0700, Guru Das Srinagesh wrote:
> in_range(val, start, len) takes a start and a length, i.e. a half-open
> range. Callers that instead have an inclusive [start, end] bound have
> no ready helper to reach for and either hand-roll the comparison or
> convert it to in_range()'s (start, len) form themselves.
>
> Add in_range_inclusive(val, start, end) as a direct comparison rather
> than a wrapper around in_range(): computing len as end - start + 1 and
> forwarding it to in_range() subverts in_range()'s 32-bit/64-bit dispatch
> for sub-32-bit types via integer promotion, and overflows to 0 when @end
> is the type's maximum value, silently rejecting every input instead of
> accepting all of them.
>
> val, start and end are each assigned to a __UNIQUE_ID()-generated
> temporary before use, matching the __cmp_once()/__cmp_once_unique()
> pattern: each argument is evaluated exactly once, and the temporary
> can't be shadowed by a caller's own same-named local variable.
No new code to lib/ without test cases.
NAK (until the test cases are not provided).
...
> +/**
> + * in_range_inclusive - Determine if a value lies within an inclusive range.
> + * @val: Value to test.
> + * @start: First value in range.
> + * @end: Last value in range.
> + *
> + * @val, @start and @end are each evaluated exactly once.
This misses the return section (yes, this is not obvious, but needs to add it)
> + */
> +#define in_range_inclusive(val, start, end) \
> + __in_range_inclusive(val, start, end, __UNIQUE_ID(val_), \
> + __UNIQUE_ID(start_), __UNIQUE_ID(end_))
Do you know what __UNIQUE_ID() does and how it will affect the preprocessed
size? It may or may not be needed depending on the (current) use cases.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks
2026-08-17 8:06 ` Andy Shevchenko
@ 2026-08-31 16:33 ` Guru Das Srinagesh
0 siblings, 0 replies; 8+ messages in thread
From: Guru Das Srinagesh @ 2026-08-31 16:33 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Alex Lanzano, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Matthew Wilcox, Andrew Morton, Gustavo Silva,
linux-kernel, linux-iio
On Mon, Aug 17, 2026 at 11:06:35AM +0300, Andy Shevchenko wrote:
> On Sun, Aug 16, 2026 at 12:26:20PM -0700, Guru Das Srinagesh wrote:
> > in_range(val, start, len) takes a start and a length, i.e. a half-open
> > range. Callers that instead have an inclusive [start, end] bound have
> > no ready helper to reach for and either hand-roll the comparison or
> > convert it to in_range()'s (start, len) form themselves.
> >
> > Add in_range_inclusive(val, start, end) as a direct comparison rather
> > than a wrapper around in_range(): computing len as end - start + 1 and
> > forwarding it to in_range() subverts in_range()'s 32-bit/64-bit dispatch
> > for sub-32-bit types via integer promotion, and overflows to 0 when @end
> > is the type's maximum value, silently rejecting every input instead of
> > accepting all of them.
> >
> > val, start and end are each assigned to a __UNIQUE_ID()-generated
> > temporary before use, matching the __cmp_once()/__cmp_once_unique()
> > pattern: each argument is evaluated exactly once, and the temporary
> > can't be shadowed by a caller's own same-named local variable.
>
> No new code to lib/ without test cases.
> NAK (until the test cases are not provided).
Done, added KUnit test cases to v3.
> > +/**
> > + * in_range_inclusive - Determine if a value lies within an inclusive range.
> > + * @val: Value to test.
> > + * @start: First value in range.
> > + * @end: Last value in range.
> > + *
> > + * @val, @start and @end are each evaluated exactly once.
>
> This misses the return section (yes, this is not obvious, but needs to add it)
Done, added return section to v3 kernel-doc.
> > + */
> > +#define in_range_inclusive(val, start, end) \
> > + __in_range_inclusive(val, start, end, __UNIQUE_ID(val_), \
> > + __UNIQUE_ID(start_), __UNIQUE_ID(end_))
>
> Do you know what __UNIQUE_ID() does and how it will affect the preprocessed
> size? It may or may not be needed depending on the (current) use cases.
Sorry, __UNIQUE_ID() has been dropped in v3 as v3 follows in_range() more closely and
does not need any temporary variables.
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 2/2] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value()
2026-08-16 19:26 [PATCH v2 0/2] Introduce in_range_incl() inclusive range check macro Guru Das Srinagesh
2026-08-16 19:26 ` [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh
@ 2026-08-16 19:26 ` Guru Das Srinagesh
2026-08-17 3:00 ` Jonathan Cameron
1 sibling, 1 reply; 8+ messages in thread
From: Guru Das Srinagesh @ 2026-08-16 19: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 change.
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] 8+ messages in thread* Re: [PATCH v2 2/2] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value()
2026-08-16 19:26 ` [PATCH v2 2/2] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() Guru Das Srinagesh
@ 2026-08-17 3:00 ` Jonathan Cameron
0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Cameron @ 2026-08-17 3:00 UTC (permalink / raw)
To: Guru Das Srinagesh
Cc: Alex Lanzano, David Lechner, Nuno Sá, Andy Shevchenko,
Matthew Wilcox, Andrew Morton, Gustavo Silva, linux-kernel,
linux-iio
On Sun, 16 Aug 2026 12:26:21 -0700
Guru Das Srinagesh <linux@gurudas.dev> 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 change.
>
> Assisted-by: Claude-Code:claude-sonnet-5
> Signed-off-by: Guru Das Srinagesh <linux@gurudas.dev>
I like the improved readability of this, so if you get the implementation
issues resolved, this patch is fine by me.
Jonathan
> ---
> 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,
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-31 16:54 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-16 19:26 [PATCH v2 0/2] Introduce in_range_incl() inclusive range check macro Guru Das Srinagesh
2026-08-16 19:26 ` [PATCH v2 1/2] minmax: Add in_range_inclusive() for inclusive range checks Guru Das Srinagesh
2026-08-16 21:34 ` Matthew Wilcox
2026-08-31 16:29 ` Guru Das Srinagesh
2026-08-17 8:06 ` Andy Shevchenko
2026-08-31 16:33 ` Guru Das Srinagesh
2026-08-16 19:26 ` [PATCH v2 2/2] iio: imu: bmi270: Use in_range_inclusive() in bmi270_write_event_value() Guru Das Srinagesh
2026-08-17 3:00 ` Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox