* [PATCH v3 1/3] rust: time: rename the rem_nanos() divisor
2026-10-17 11:11 [PATCH v3 0/3] rust: time: fix Delta arithmetic and add math helpers chenhan
@ 2026-10-17 11:11 ` chenhan
2026-10-21 7:33 ` FUJITA Tomonori
2026-10-17 11:11 ` [PATCH v3 2/3] rust: time: make Delta division and remainder fail consistently chenhan
2026-10-17 11:11 ` [PATCH v3 3/3] rust: math: add signed division and remainder helpers chenhan
2 siblings, 1 reply; 8+ messages in thread
From: chenhan @ 2026-10-17 11:11 UTC (permalink / raw)
To: rust-for-linux
Cc: a.hindborg, boqun, fujita.tomonori, frederic, lyude, tglx,
anna-maria, jstultz, sboyd, ojeda, gary, bjorn3_gh, lossin,
aliceryhl, tmgross, dakr, daniel.almeida, tamird, acourbot, work,
miguel.ojeda.sandonis, tomo, georgeandrout13, linux-kernel,
stable
The argument to rem_nanos() is the divisor, while self holds the
dividend. Rename the argument and correct the documentation. Drop the
architecture-specific implementation explanation from the public API
documentation; the argument type already states the divisor's width.
This does not change the function's type or behavior. It is a preparation
for documenting and checking the invalid divisors in the next patch.
Cc: stable@vger.kernel.org # prerequisite for the Delta division/remainder fix
Assisted-by: LLM
Signed-off-by: chenhan <chenhan0017.work@gmail.com>
---
rust/kernel/time.rs | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index 5ae377e70dd8..16b44e82d2ac 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -614,16 +614,13 @@ pub fn to_jiffies_timeout(self) -> Delta<Jiffy> {
Delta::<Jiffy>::from_jiffies(jiffies)
}
- /// Return `self % dividend` where `dividend` is in nanoseconds.
- ///
- /// The kernel doesn't have any emulation for `s64 % s64` on 32 bit platforms, so this is
- /// limited to 32 bit dividends.
+ /// Return `self % divisor` where `divisor` is in nanoseconds.
#[inline]
- pub fn rem_nanos(self, dividend: i32) -> Self {
+ pub fn rem_nanos(self, divisor: i32) -> Self {
#[cfg(CONFIG_64BIT)]
{
Self {
- value: self.as_nanos() % i64::from(dividend),
+ value: self.as_nanos() % i64::from(divisor),
}
}
@@ -632,7 +629,7 @@ pub fn rem_nanos(self, dividend: i32) -> Self {
let mut rem = 0;
// SAFETY: `rem` is in the stack, so we can always provide a valid pointer to it.
- unsafe { bindings::div_s64_rem(self.as_nanos(), dividend, &mut rem) };
+ unsafe { bindings::div_s64_rem(self.as_nanos(), divisor, &mut rem) };
Self {
value: i64::from(rem),
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH v3 1/3] rust: time: rename the rem_nanos() divisor
2026-10-17 11:11 ` [PATCH v3 1/3] rust: time: rename the rem_nanos() divisor chenhan
@ 2026-10-21 7:33 ` FUJITA Tomonori
0 siblings, 0 replies; 8+ messages in thread
From: FUJITA Tomonori @ 2026-10-21 7:33 UTC (permalink / raw)
To: chenhan0017.work
Cc: rust-for-linux, a.hindborg, boqun, fujita.tomonori, frederic,
lyude, tglx, anna-maria, jstultz, sboyd, ojeda, gary, bjorn3_gh,
lossin, aliceryhl, tmgross, dakr, daniel.almeida, tamird,
acourbot, work, miguel.ojeda.sandonis, tomo, georgeandrout13,
linux-kernel, stable
On Sat, 17 Oct 2026 19:11:32 +0800
chenhan <chenhan0017.work@gmail.com> wrote:
> The argument to rem_nanos() is the divisor, while self holds the
> dividend. Rename the argument and correct the documentation. Drop the
> architecture-specific implementation explanation from the public API
> documentation; the argument type already states the divisor's width.
>
> This does not change the function's type or behavior. It is a preparation
> for documenting and checking the invalid divisors in the next patch.
>
> Cc: stable@vger.kernel.org # prerequisite for the Delta division/remainder fix
> Assisted-by: LLM
> Signed-off-by: chenhan <chenhan0017.work@gmail.com>
Reviewed-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 2/3] rust: time: make Delta division and remainder fail consistently
2026-10-17 11:11 [PATCH v3 0/3] rust: time: fix Delta arithmetic and add math helpers chenhan
2026-10-17 11:11 ` [PATCH v3 1/3] rust: time: rename the rem_nanos() divisor chenhan
@ 2026-10-17 11:11 ` chenhan
2026-10-17 11:11 ` [PATCH v3 3/3] rust: math: add signed division and remainder helpers chenhan
2 siblings, 0 replies; 8+ messages in thread
From: chenhan @ 2026-10-17 11:11 UTC (permalink / raw)
To: rust-for-linux
Cc: a.hindborg, boqun, fujita.tomonori, frederic, lyude, tglx,
anna-maria, jstultz, sboyd, ojeda, gary, bjorn3_gh, lossin,
aliceryhl, tmgross, dakr, daniel.almeida, tamird, acourbot, work,
miguel.ojeda.sandonis, tomo, georgeandrout13, linux-kernel,
stable
Delta's division and rem_nanos() use Rust operators on 64-bit and C
helpers on 32-bit. The report shows that rem_nanos(0) can return 10 for
a 10 ns dividend on ARMv7, while the same call panics on x86-64. The
i64::MIN / -1 case also differs, and neither API documents these inputs.
Check for zero divisors and i64::MIN with -1 before the architecture-
specific code, and document the panic conditions on each method. This
matches Rust's signed division and remainder operators, including when
overflow checks are disabled. Valid-input results and API signatures
are unchanged; invalid inputs now panic on 32-bit too.
No in-tree calls to either API were found at the base commit. The checks
stay in the existing methods so the fix does not depend on introducing
a math module.
Fixes: 4521438fb076 ("rust: time: Implement basic arithmetic operations for Delta")
Reported-by: Georgios Androutsopoulos <georgeandrout13@gmail.com>
Closes: https://github.com/Rust-for-Linux/linux/issues/1254
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: chenhan <chenhan0017.work@gmail.com>
---
rust/kernel/time.rs | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index 16b44e82d2ac..4415e91a5227 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -412,8 +412,20 @@ fn mul_assign(&mut self, rhs: i64) {
impl ops::Div for Delta {
type Output = i64;
+ /// # Panics
+ ///
+ /// Panics if `rhs` is zero, or if `self` represents [`i64::MIN`] nanoseconds
+ /// and `rhs` represents `-1` nanosecond.
#[inline]
fn div(self, rhs: Self) -> Self::Output {
+ if rhs.value == 0 {
+ panic!("attempt to divide by zero");
+ }
+
+ if self.value == i64::MIN && rhs.value == -1 {
+ panic!("attempt to divide with overflow");
+ }
+
#[cfg(CONFIG_64BIT)]
{
self.value / rhs.value
@@ -421,7 +433,7 @@ fn div(self, rhs: Self) -> Self::Output {
#[cfg(not(CONFIG_64BIT))]
{
- // SAFETY: This function is always safe to call regardless of the input values
+ // SAFETY: The checks above exclude a zero divisor and `i64::MIN / -1`.
unsafe { bindings::div64_s64(self.value, rhs.value) }
}
}
@@ -615,8 +627,21 @@ pub fn to_jiffies_timeout(self) -> Delta<Jiffy> {
}
/// Return `self % divisor` where `divisor` is in nanoseconds.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `divisor` is zero, or if `self` represents [`i64::MIN`]
+ /// nanoseconds and `divisor` is `-1`.
#[inline]
pub fn rem_nanos(self, divisor: i32) -> Self {
+ if divisor == 0 {
+ panic!("attempt to calculate the remainder with a divisor of zero");
+ }
+
+ if self.value == i64::MIN && divisor == -1 {
+ panic!("attempt to calculate the remainder with overflow");
+ }
+
#[cfg(CONFIG_64BIT)]
{
Self {
@@ -628,7 +653,8 @@ pub fn rem_nanos(self, divisor: i32) -> Self {
{
let mut rem = 0;
- // SAFETY: `rem` is in the stack, so we can always provide a valid pointer to it.
+ // SAFETY: The checks above exclude a zero divisor and `i64::MIN / -1`.
+ // `&mut rem` provides a valid, aligned, writable pointer for this call.
unsafe { bindings::div_s64_rem(self.as_nanos(), divisor, &mut rem) };
Self {
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v3 3/3] rust: math: add signed division and remainder helpers
2026-10-17 11:11 [PATCH v3 0/3] rust: time: fix Delta arithmetic and add math helpers chenhan
2026-10-17 11:11 ` [PATCH v3 1/3] rust: time: rename the rem_nanos() divisor chenhan
2026-10-17 11:11 ` [PATCH v3 2/3] rust: time: make Delta division and remainder fail consistently chenhan
@ 2026-10-17 11:11 ` chenhan
2026-10-21 9:16 ` FUJITA Tomonori
2026-10-21 9:37 ` FUJITA Tomonori
2 siblings, 2 replies; 8+ messages in thread
From: chenhan @ 2026-10-17 11:11 UTC (permalink / raw)
To: rust-for-linux
Cc: a.hindborg, boqun, fujita.tomonori, frederic, lyude, tglx,
anna-maria, jstultz, sboyd, ojeda, gary, bjorn3_gh, lossin,
aliceryhl, tmgross, dakr, daniel.almeida, tamird, acourbot, work,
miguel.ojeda.sandonis, tomo, georgeandrout13, linux-kernel
Delta's division and remainder implementations operate on integers and
do not depend on time units. Move them into a math module to provide a
common home for arithmetic helpers, with Delta as the initial user.
Expose div64_s64() and rem_s64() so driver crates can use these operations
without constructing time values. The division helper takes two i64
operands; the remainder helper takes an i64 dividend and an i32 divisor
and returns an i64. Both keep Rust's signed operator semantics, including
the unconditional panic checks, and use the existing C helpers on 32-bit.
Keep the Delta API and its panic documentation unchanged. This is separate
from the preceding behavior fix so that introducing the math module is
not required for a backport.
Assisted-by: LLM
Signed-off-by: chenhan <chenhan0017.work@gmail.com>
---
rust/kernel/lib.rs | 1 +
rust/kernel/math.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++
rust/kernel/time.rs | 49 ++++------------------------------
3 files changed, 70 insertions(+), 44 deletions(-)
create mode 100644 rust/kernel/math.rs
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 4d5c96ddc49c..60c2af705b47 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -98,6 +98,7 @@
pub mod kunit;
pub mod list;
pub mod maple_tree;
+pub mod math;
pub mod miscdevice;
pub mod mm;
pub mod module;
diff --git a/rust/kernel/math.rs b/rust/kernel/math.rs
new file mode 100644
index 000000000000..34ca097caac9
--- /dev/null
+++ b/rust/kernel/math.rs
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Integer arithmetic helpers.
+
+/// Divides an [`i64`] dividend by an [`i64`] divisor, rounding towards zero.
+///
+/// # Panics
+///
+/// Panics if `divisor` is zero, or if `dividend` is [`i64::MIN`] and `divisor` is `-1`.
+#[inline]
+pub fn div64_s64(dividend: i64, divisor: i64) -> i64 {
+ if divisor == 0 {
+ panic!("attempt to divide by zero");
+ }
+
+ if dividend == i64::MIN && divisor == -1 {
+ panic!("attempt to divide with overflow");
+ }
+
+ #[cfg(CONFIG_64BIT)]
+ {
+ dividend / divisor
+ }
+
+ #[cfg(not(CONFIG_64BIT))]
+ {
+ // SAFETY: The checks above exclude a zero divisor and `i64::MIN / -1`.
+ unsafe { bindings::div64_s64(dividend, divisor) }
+ }
+}
+
+/// Returns the remainder of an [`i64`] dividend divided by an [`i32`] divisor.
+///
+/// A non-zero remainder has the sign of `dividend`.
+///
+/// # Panics
+///
+/// Panics if `divisor` is zero, or if `dividend` is [`i64::MIN`] and `divisor` is `-1`.
+#[inline]
+pub fn rem_s64(dividend: i64, divisor: i32) -> i64 {
+ if divisor == 0 {
+ panic!("attempt to calculate the remainder with a divisor of zero");
+ }
+
+ if dividend == i64::MIN && divisor == -1 {
+ panic!("attempt to calculate the remainder with overflow");
+ }
+
+ #[cfg(CONFIG_64BIT)]
+ {
+ dividend % i64::from(divisor)
+ }
+
+ #[cfg(not(CONFIG_64BIT))]
+ {
+ let mut rem = 0;
+
+ // SAFETY: The checks above exclude a zero divisor and `i64::MIN / -1`.
+ // `&mut rem` provides a valid, aligned, writable pointer for this call.
+ unsafe { bindings::div_s64_rem(dividend, divisor, &mut rem) };
+
+ i64::from(rem)
+ }
+}
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index 4415e91a5227..e297d327953f 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -27,6 +27,8 @@
use core::marker::PhantomData;
use core::ops;
+use crate::math;
+
pub mod delay;
pub mod hrtimer;
@@ -418,24 +420,7 @@ impl ops::Div for Delta {
/// and `rhs` represents `-1` nanosecond.
#[inline]
fn div(self, rhs: Self) -> Self::Output {
- if rhs.value == 0 {
- panic!("attempt to divide by zero");
- }
-
- if self.value == i64::MIN && rhs.value == -1 {
- panic!("attempt to divide with overflow");
- }
-
- #[cfg(CONFIG_64BIT)]
- {
- self.value / rhs.value
- }
-
- #[cfg(not(CONFIG_64BIT))]
- {
- // SAFETY: The checks above exclude a zero divisor and `i64::MIN / -1`.
- unsafe { bindings::div64_s64(self.value, rhs.value) }
- }
+ math::div64_s64(self.value, rhs.value)
}
}
@@ -634,32 +619,8 @@ pub fn to_jiffies_timeout(self) -> Delta<Jiffy> {
/// nanoseconds and `divisor` is `-1`.
#[inline]
pub fn rem_nanos(self, divisor: i32) -> Self {
- if divisor == 0 {
- panic!("attempt to calculate the remainder with a divisor of zero");
- }
-
- if self.value == i64::MIN && divisor == -1 {
- panic!("attempt to calculate the remainder with overflow");
- }
-
- #[cfg(CONFIG_64BIT)]
- {
- Self {
- value: self.as_nanos() % i64::from(divisor),
- }
- }
-
- #[cfg(not(CONFIG_64BIT))]
- {
- let mut rem = 0;
-
- // SAFETY: The checks above exclude a zero divisor and `i64::MIN / -1`.
- // `&mut rem` provides a valid, aligned, writable pointer for this call.
- unsafe { bindings::div_s64_rem(self.as_nanos(), divisor, &mut rem) };
-
- Self {
- value: i64::from(rem),
- }
+ Self {
+ value: math::rem_s64(self.as_nanos(), divisor),
}
}
}
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH v3 3/3] rust: math: add signed division and remainder helpers
2026-10-17 11:11 ` [PATCH v3 3/3] rust: math: add signed division and remainder helpers chenhan
@ 2026-10-21 9:16 ` FUJITA Tomonori
2026-10-21 9:37 ` FUJITA Tomonori
1 sibling, 0 replies; 8+ messages in thread
From: FUJITA Tomonori @ 2026-10-21 9:16 UTC (permalink / raw)
To: chenhan0017.work
Cc: rust-for-linux, a.hindborg, boqun, fujita.tomonori, frederic,
lyude, tglx, anna-maria, jstultz, sboyd, ojeda, gary, bjorn3_gh,
lossin, aliceryhl, tmgross, dakr, daniel.almeida, tamird,
acourbot, work, miguel.ojeda.sandonis, tomo, georgeandrout13,
linux-kernel
On Sat, 17 Oct 2026 19:11:34 +0800
chenhan <chenhan0017.work@gmail.com> wrote:
> Delta's division and remainder implementations operate on integers and
> do not depend on time units. Move them into a math module to provide a
> common home for arithmetic helpers, with Delta as the initial user.
>
> Expose div64_s64() and rem_s64() so driver crates can use these operations
> without constructing time values. The division helper takes two i64
> operands; the remainder helper takes an i64 dividend and an i32 divisor
> and returns an i64. Both keep Rust's signed operator semantics, including
> the unconditional panic checks, and use the existing C helpers on 32-bit.
>
> Keep the Delta API and its panic documentation unchanged. This is separate
> from the preceding behavior fix so that introducing the math module is
> not required for a backport.
>
> Assisted-by: LLM
> Signed-off-by: chenhan <chenhan0017.work@gmail.com>
Reviewed-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 3/3] rust: math: add signed division and remainder helpers
2026-10-17 11:11 ` [PATCH v3 3/3] rust: math: add signed division and remainder helpers chenhan
2026-10-21 9:16 ` FUJITA Tomonori
@ 2026-10-21 9:37 ` FUJITA Tomonori
2026-10-23 13:06 ` chenhan
1 sibling, 1 reply; 8+ messages in thread
From: FUJITA Tomonori @ 2026-10-21 9:37 UTC (permalink / raw)
To: chenhan0017.work
Cc: rust-for-linux, a.hindborg, boqun, fujita.tomonori, frederic,
lyude, tglx, anna-maria, jstultz, sboyd, ojeda, gary, bjorn3_gh,
lossin, aliceryhl, tmgross, dakr, daniel.almeida, tamird,
acourbot, work, miguel.ojeda.sandonis, tomo, georgeandrout13,
linux-kernel
On Sat, 17 Oct 2026 19:11:34 +0800
chenhan <chenhan0017.work@gmail.com> wrote:
> Delta's division and remainder implementations operate on integers and
> do not depend on time units. Move them into a math module to provide a
> common home for arithmetic helpers, with Delta as the initial user.
>
> Expose div64_s64() and rem_s64() so driver crates can use these operations
> without constructing time values. The division helper takes two i64
> operands; the remainder helper takes an i64 dividend and an i32 divisor
> and returns an i64. Both keep Rust's signed operator semantics, including
> the unconditional panic checks, and use the existing C helpers on 32-bit.
>
> Keep the Delta API and its panic documentation unchanged. This is separate
> from the preceding behavior fix so that introducing the math module is
> not required for a backport.
>
> Assisted-by: LLM
> Signed-off-by: chenhan <chenhan0017.work@gmail.com>
> ---
> rust/kernel/lib.rs | 1 +
> rust/kernel/math.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++
> rust/kernel/time.rs | 49 ++++------------------------------
> 3 files changed, 70 insertions(+), 44 deletions(-)
> create mode 100644 rust/kernel/math.rs
>
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 4d5c96ddc49c..60c2af705b47 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -98,6 +98,7 @@
> pub mod kunit;
> pub mod list;
> pub mod maple_tree;
> +pub mod math;
> pub mod miscdevice;
> pub mod mm;
> pub mod module;
> diff --git a/rust/kernel/math.rs b/rust/kernel/math.rs
> new file mode 100644
> index 000000000000..34ca097caac9
> --- /dev/null
> +++ b/rust/kernel/math.rs
> @@ -0,0 +1,64 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Integer arithmetic helpers.
//! C header: [`include/linux/math64.h`](srctree/include/linux/math64.h).
?
> +/// Returns the remainder of an [`i64`] dividend divided by an [`i32`] divisor.
> +///
> +/// A non-zero remainder has the sign of `dividend`.
> +///
> +/// # Panics
> +///
> +/// Panics if `divisor` is zero, or if `dividend` is [`i64::MIN`] and `divisor` is `-1`.
> +#[inline]
> +pub fn rem_s64(dividend: i64, divisor: i32) -> i64 {
How about matching the C function? Something like:
pub fn div_s64_rem(dividend: i64, divisor: i32) -> (i64, i32)
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH v3 3/3] rust: math: add signed division and remainder helpers
2026-10-21 9:37 ` FUJITA Tomonori
@ 2026-10-23 13:06 ` chenhan
0 siblings, 0 replies; 8+ messages in thread
From: chenhan @ 2026-10-23 13:06 UTC (permalink / raw)
To: tomo
Cc: rust-for-linux, a.hindborg, boqun, fujita.tomonori, frederic,
lyude, tglx, anna-maria, jstultz, sboyd, ojeda, gary, bjorn3_gh,
lossin, aliceryhl, tmgross, dakr, daniel.almeida, tamird,
acourbot, work, miguel.ojeda.sandonis, georgeandrout13,
linux-kernel
Hi Tomonori,
Thanks for the review and the follow-up suggestions.
I've sent v4 here:
https://lore.kernel.org/rust-for-linux/20261023130413.178487-1-chenhan0017.work@gmail.com/
> //! C header: [`include/linux/math64.h`](srctree/include/linux/math64.h).
Added the module-level link and checked its generated rustdoc target.
> How about matching the C function? Something like:
>
> pub fn div_s64_rem(dividend: i64, divisor: i32) -> (i64, i32)
V4 uses this interface. The 32-bit path returns both the C helper's
quotient and remainder. The 64-bit path uses Rust's signed operators,
with a comment explaining why the remainder fits in i32. The
documentation specifies the tuple order, truncation towards zero and
the remainder's sign.
Delta::rem_nanos() takes the remainder and converts it to i64, preserving
its public signature and panic conditions. div64_s64() remains available
for full-width divisors. Both helpers still reject zero and MIN/-1
regardless of the overflow-check setting.
The updated validation module calls both public helpers directly, checks
both tuple elements, and retains the Delta regression cases. It includes
i64::MIN divided by i32::MIN, whose quotient is 4294967296.
I have carried your Reviewed-by on patch 1. Since patch 3 now changes the
public interface, I have left its v3 Reviewed-by out of this revision and
noted why below the commit message. Could you confirm whether it also
applies to the updated patch?
Best regards,
chenhan
^ permalink raw reply [flat|nested] 8+ messages in thread