All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] rust: time: fix Delta arithmetic and add math helpers
@ 2026-10-17 11:11 chenhan
  2026-10-17 11:11 ` [PATCH v3 1/3] rust: time: rename the rem_nanos() divisor chenhan
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ 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

Hi,

This revision separates the Delta arithmetic fix from establishing the
math module, following the v2 discussion.

Patch 1 corrects the rem_nanos() parameter name and documentation, as
Miguel requested. Patch 2 adds the panic checks in the existing methods.
Patch 3 moves that implementation to public math::div64_s64() and
math::rem_s64() helpers and uses them from Delta.

For stable, patch 2 depends on patch 1; both carry stable Cc, and patch 1
is marked as a prerequisite. The math refactor is not marked for stable.
The first two patches can be taken without the third. Backport suitability
remains for the maintainers to decide; I have not audited all stable trees.

Each signed helper still has one production call site, in Delta. The
current pwm_th1520 conversions use unsigned arithmetic and are not users
of these helpers. Patch 3 follows Andreas' request to establish math.rs.
Tomonori, it adds no unsigned helpers or PWM changes; if your math module
lands first, I can rebase this patch onto it. The helpers are public so
they are available to driver crates as well as the kernel crate.

Changes since v2:
- Split the parameter correction, behavior fix and math extraction.
- Explain in SAFETY why the conditions hold: the checks above exclude
  zero and i64::MIN / -1, and &mut rem supplies the valid writable pointer.
- Drop the redundant issue-comment Link trailers, retaining Closes.
- Remove the unrelated "a number of" wording, C implementation details
  from public documentation, and the "even though ..." panic explanation.

No in-tree calls to Delta's division or rem_nanos() were found at the
base or rust-next 7c306f00835a. This covered tracked Rust files, named
calls and division expressions in Delta/Instant users, including elapsed()
results. Fixed-divisor time conversions, unsigned jiffies arithmetic and
generic bounded-integer operations are not extra users of these helpers.

Testing used a built-in Rust module whose init function passes black_box
operands to the actual Delta APIs (a and b are i64, d is i32):

    Delta::from_nanos(black_box(a)) / Delta::from_nanos(black_box(b))
    Delta::from_nanos(black_box(a)).rem_nanos(black_box(d)).as_nanos()

A boot-parameter selector chooses the test. One boot compares 26 valid
divisions and 21 valid remainders against literal expected values; four
separate boots exercise the invalid inputs because each panic stops its
test. Core expectations are:

    dividend    divisor    division    remainder (nanoseconds)
    10          0          panic       panic
    i64::MIN    -1         panic       panic
    10          3          3           1
    -10         3          -3          -1

Other valid cases cover signed extrema, i32::MIN divisors and full-width
i64 division operands. Patches 1-2 passed on x86-64 and ARMv7 QEMU with
CONFIG_RUST_OVERFLOW_CHECKS=y. The full series passed on both architectures
with that option enabled and disabled: 30 boots, 282 valid comparisons and
24 expected panics in total. Kernel builds and rustdoc passed on both
architectures. The test module is validation code, not part of this series.

Base: timekeeping-next 2ea0119f72dba597aa8a98cbdb72c564bfc5cb38.
Rechecked on October 17: this is still the timekeeping-next tip, and
neither it nor rust-next has a math module. When applying patch 3 to
rust-next 7c306f00835a, the new "pub mod mem;" line overlaps the module
registration hunk. Keep both modules, with math between maple_tree and
mem. Patches 1 and 2 apply there unchanged. Runtime testing above is on
the stated timekeeping-next base.

V2: https://lore.kernel.org/rust-for-linux/20261001042942.109012-1-chenhan0017.work@gmail.com/

Best regards,
chenhan

chenhan (3):
  rust: time: rename the rem_nanos() divisor
  rust: time: make Delta division and remainder fail consistently
  rust: math: add signed division and remainder helpers

 rust/kernel/lib.rs  |  1 +
 rust/kernel/math.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++
 rust/kernel/time.rs | 46 +++++++++++---------------------
 3 files changed, 80 insertions(+), 31 deletions(-)
 create mode 100644 rust/kernel/math.rs


base-commit: 2ea0119f72dba597aa8a98cbdb72c564bfc5cb38
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [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-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, 0 replies; 4+ 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 related	[flat|nested] 4+ 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; 4+ 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 related	[flat|nested] 4+ 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
  2 siblings, 0 replies; 4+ 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 related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-17 11:12 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH v3 3/3] rust: math: add signed division and remainder helpers chenhan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.