* [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample
@ 2026-09-27 7:28 Enze Li
2026-09-27 7:28 ` [RFC PATCH 1/4] rust: add bindings for linux/damon.h Enze Li
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Enze Li @ 2026-09-27 7:28 UTC (permalink / raw)
To: ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, sj
Cc: linux-kernel, rust-for-linux, damon, linux-mm, enze.li, lienze
Hi SJ, hi all,
Almost a year ago, right after a memory-leak fix discussion on this list, I
asked whether introducing Rust for some DAMON modules could be worth
exploring as a proactive measure. SJ's answer was positive: he was open to
Rust adoption in DAMON, both in kernel and user space, and even mentioned
he had been wanting to write a Rust sample DAMON module himself since LPC,
but had not found the time yet [1].
So, here is my attempt at making that start happen. This RFC is
intentionally small: it adds just enough Rust support for DAMON to port the
proactive reclamation sample (prcl.c), and nothing more.
The series has four patches:
1. Generate Rust bindings for include/linux/damon.h.
2. Add thin safe wrappers in a new rust::kernel::damon module: contexts,
targets, access patterns, quotas, watermarks, schemes, plus
start/stop. Everything FFI-related is confined to the wrappers, with
the usual SAFETY comments; error codes are returned as kernel::Result.
3. Add samples/damon/rust_prcl.rs, a Rust port of prcl.c. It watches the
virtual address space of a target process and pages out cold regions
with the DAMOS_PAGEOUT action, same access-pattern filter as the C
version.
4. Add a MAINTAINERS entry for the two new files.
Two differences from the C sample are worth noting.
First, the control interface. The C prcl sample is driven through
runtime-writable module parameters (target_pid and enabled, the latter via
module_param_cb), neither of which Rust can express yet -- its module
parameters are load-time only and do not show up under /sys/module/, and
there is no general sysfs abstraction in mainline or the RfL rust-next
tree. The debugfs abstraction, however, already provides the safe
read/write wrappers we need, so the Rust sample exposes the same two knobs
under /sys/kernel/debug/rust_prcl/. This is a temporary detour, not a
design preference: the sample will be switched over to match the C
interface once Rust supports sysfs-backed module parameters.
Second, the functional scope. The C sample also repeatedly reports the
estimated working set size via a repeating damon_call() callback. This
initial Rust version covers only the core monitoring/reclamation path
(context, target, PAGEOUT scheme, start/stop); wss reporting needs safe
wrappers for damon_call() and region iteration, which will come in a
follow-up series that also makes the Rust sample's output match the C
one's.
A quick word on the longer-term plan, so the design discussion here can
happen with the destination in mind:
- Over roughly the next year, I would like to port the other two DAMON
samples (wsse and mtier) to Rust as well, and let the DAMON Rust
compatibility layer grow together with them, wrapping only what real
in-tree users need.
- Once that layer has matured, I would be happy to try Rust for the
production modules - damon/reclaim, damon/lru_sort and damon/stat.
That is a much bigger step, of course, and it only happens if SJ is
comfortable with it. Consider it a willingness statement, not a
promise.
Regarding the MAINTAINERS patch: I listed myself for the new files, but did
not add SJ as a reviewer yet, since he mentioned limited bandwidth for Rust
work in that earlier discussion. The existing DAMON entry already covers
samples/damon/, so the sample reaches him regardless; adding him to the
RUST [DAMON] entry would only additionally route future changes to
rust/kernel/damon.rs his way. Happy to add the R: line if he wants it, or
leave it out if he prefers.
Testing: build test kernel with CONFIG_RUST=y and
CONFIG_SAMPLE_DAMON_RUST_PRCL=y. Functionally exercised via debugfs:
# echo <pid> > /sys/kernel/debug/rust_prcl/target_pid
# echo y > /sys/kernel/debug/rust_prcl/enabled
... cold regions of the target get paged out ...
# echo n > /sys/kernel/debug/rust_prcl/enabled
This is an RFC, so comments on the wrapper API shape, naming and the
debugfs detour are especially welcome.
[1] https://lore.kernel.org/all/20251015150701.68087-1-sj@kernel.org/
Enze Li (4):
rust: add bindings for linux/damon.h
rust: damon: add basic DAMON abstractions
samples/damon: add Rust sample for DAMON access-aware proactive reclamation
MAINTAINERS: add entry for the DAMON Rust abstractions
MAINTAINERS | 8 +
rust/bindings/bindings_helper.h | 1 +
rust/kernel/damon.rs | 292 ++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 2 +
samples/Makefile | 1 +
samples/damon/Kconfig | 12 ++
samples/damon/Makefile | 1 +
samples/damon/rust_prcl.rs | 158 +++++++++++++++++
8 files changed, 475 insertions(+)
create mode 100644 rust/kernel/damon.rs
create mode 100644 samples/damon/rust_prcl.rs
--
2.25.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC PATCH 1/4] rust: add bindings for linux/damon.h
2026-09-27 7:28 [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample Enze Li
@ 2026-09-27 7:28 ` Enze Li
2026-09-27 7:28 ` [RFC PATCH 2/4] rust: damon: add basic DAMON abstractions Enze Li
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Enze Li @ 2026-09-27 7:28 UTC (permalink / raw)
To: ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, sj
Cc: linux-kernel, rust-for-linux, damon, linux-mm, enze.li, lienze
Include linux/damon.h in bindings_helper.h so that DAMON APIs become
available to Rust code. This is in preparation for the DAMON abstractions
added in the next patch.
Signed-off-by: Enze Li <lienze@kylinos.cn>
---
rust/bindings/bindings_helper.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 4b31aa7f432f..0951dfe8e3e5 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -50,6 +50,7 @@
#include <linux/cpufreq.h>
#include <linux/cpumask.h>
#include <linux/cred.h>
+#include <linux/damon.h>
#include <linux/debugfs.h>
#include <linux/device/faux.h>
#include <linux/dma-direction.h>
base-commit: 1c2b8d2725f84b43fabe3b3e9628c91db8ca6c65
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC PATCH 2/4] rust: damon: add basic DAMON abstractions
2026-09-27 7:28 [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample Enze Li
2026-09-27 7:28 ` [RFC PATCH 1/4] rust: add bindings for linux/damon.h Enze Li
@ 2026-09-27 7:28 ` Enze Li
2026-09-27 7:28 ` [RFC PATCH 3/4] samples/damon: add Rust sample for DAMON access-aware proactive reclamation Enze Li
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Enze Li @ 2026-09-27 7:28 UTC (permalink / raw)
To: ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, sj
Cc: linux-kernel, rust-for-linux, damon, linux-mm, enze.li, lienze
Wrap the basic DAMON C API in a new rust/kernel/damon module, exposing
contexts, targets, schemes, and the types that configure them, so Rust
modules can drive DAMON without calling the raw C functions directly.
This initial support will then be used by a subsequent sample module.
Signed-off-by: Enze Li <lienze@kylinos.cn>
---
rust/kernel/damon.rs | 292 +++++++++++++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 2 +
2 files changed, 294 insertions(+)
create mode 100644 rust/kernel/damon.rs
diff --git a/rust/kernel/damon.rs b/rust/kernel/damon.rs
new file mode 100644
index 000000000000..80e6609132e7
--- /dev/null
+++ b/rust/kernel/damon.rs
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2026 KylinSoft Corporation.
+// Author: Enze Li <lienze@kylinos.cn>
+
+//! DAMON (Data Access MONitor) abstractions.
+//!
+//! C header: [`include/linux/damon.h`](srctree/include/linux/damon.h)
+
+use core::ptr::NonNull;
+
+use kernel::bindings;
+use kernel::error::code::*;
+use kernel::error::Error;
+use kernel::error::Result;
+
+/// Return if DAMON is ready to be used.
+pub fn damon_initialized() -> bool {
+ // SAFETY: It is a simple pure query function.
+ unsafe { bindings::damon_initialized() }
+}
+
+/// DAMON operations.
+pub struct OpsID {
+ ops_id: bindings::damon_ops_id,
+}
+
+impl OpsID {
+ /// Monitoring operations for virtual address spaces.
+ pub const VADDR: Self = Self {
+ ops_id: bindings::damon_ops_id_DAMON_OPS_VADDR,
+ };
+}
+
+/// Represents a monitoring target.
+pub struct Target {
+ target: NonNull<bindings::damon_target>,
+}
+
+impl Target {
+ /// Construct a damon_target struct.
+ pub fn damon_new_target() -> Result<Self> {
+ // SAFETY: damon_new_target returns a valid pointer to new allocated
+ // damon_target or NULL if allocation failure, which will be checked
+ // by the subsequent NonNull::new.
+ let raw = unsafe { bindings::damon_new_target() };
+ let t = NonNull::new(raw).ok_or(ENOMEM)?;
+ Ok(Self { target: t })
+ }
+
+ /// Set the PID of monitoring target.
+ pub fn damon_set_target_pid(&mut self, pid: i32) -> Result {
+ // SAFETY: slef.target is a valid, non-null 'damon_target *' by the
+ // Target invariant, and the '&mut self' borrow keeps it alive for
+ // the duration of the call. The returned errno is checked below.
+ let ret = unsafe { bindings::damon_set_target_pid(self.target.as_ptr(), pid) };
+ if ret < 0 {
+ Err(Error::from_errno(ret))
+ } else {
+ Ok(())
+ }
+ }
+}
+
+impl Drop for Target {
+ fn drop(&mut self) {
+ let t = self.target.as_ptr();
+
+ // SAFETY: t is a valid, non-null 'damon_target *' by the Target
+ // invariant, and release the pid refcount taken by find_get_pid
+ // with a matching put_pid, then free the target once in Drop.
+ unsafe {
+ if !(*t).pid.is_null() {
+ bindings::put_pid((*t).pid);
+ }
+ bindings::damon_free_target(t)
+ };
+ }
+}
+
+/// Target access pattern of the given scheme.
+pub struct DamosAccessPattern {
+ damos_access_pattern: bindings::damos_access_pattern,
+}
+
+impl DamosAccessPattern {
+ /// Create a new damos_access_pattern.
+ pub const fn new(
+ min_sz_region: usize,
+ max_sz_region: usize,
+ min_nr_accesses: u32,
+ max_nr_accesses: u32,
+ min_age_region: u32,
+ max_age_region: u32,
+ ) -> Self {
+ Self {
+ damos_access_pattern: bindings::damos_access_pattern {
+ min_sz_region,
+ max_sz_region,
+ min_nr_accesses,
+ max_nr_accesses,
+ min_age_region,
+ max_age_region,
+ },
+ }
+ }
+}
+
+/// Controls the aggressiveness of the given scheme.
+pub struct DamosQuota {
+ damos_quota: bindings::damos_quota,
+}
+
+impl DamosQuota {
+ /// Create a zero-initialized damos_quota sturct.
+ pub fn zeroed() -> Self {
+ Self {
+ // SAFETY: All-zero is a valid bit pattern for damos_quota.
+ damos_quota: unsafe { core::mem::zeroed() },
+ }
+ }
+}
+
+/// Controls when a given scheme should be activated.
+pub struct DamosWatermarks {
+ damos_watermarks: bindings::damos_watermarks,
+}
+
+impl DamosWatermarks {
+ /// Create a zero-initialized damos_watermarks sturct.
+ pub fn zeroed() -> Self {
+ Self {
+ // SAFETY: All-zero is a valid bit pattern for damos_watermarks.
+ damos_watermarks: unsafe { core::mem::zeroed() },
+ }
+ }
+}
+
+/// Represents an action of a Data Access Monitoring-based Operation Scheme.
+pub struct DamosAction {
+ /// Reclaim the region.
+ damos_action: bindings::damos_action,
+}
+
+impl DamosAction {
+ /// PAGEOUT action.
+ pub const PAGEOUT: Self = Self {
+ damos_action: bindings::damos_action_DAMOS_PAGEOUT,
+ };
+}
+
+/// Represents a Data Access Monitoring-based Operation Scheme.
+pub struct Damos {
+ damos: NonNull<bindings::damos>,
+}
+
+impl Damos {
+ /// Create new Damos.
+ pub fn new(
+ pattern: &mut DamosAccessPattern,
+ action: DamosAction,
+ apply_interval_us: usize,
+ quota: &mut DamosQuota,
+ wmarks: &mut DamosWatermarks,
+ target_nid: i32,
+ ) -> Result<Self> {
+ // SAFETY: All pointer arguments come from local variables that
+ // stay alive during the call; the rest are just numbers. The
+ // return value is checked for NULL right after.
+ let ptr = unsafe {
+ bindings::damon_new_scheme(
+ &mut pattern.damos_access_pattern,
+ action.damos_action,
+ apply_interval_us,
+ &mut quota.damos_quota,
+ &mut wmarks.damos_watermarks,
+ target_nid,
+ )
+ };
+ NonNull::new(ptr).map(|p| Self { damos: p }).ok_or(ENOMEM)
+ }
+}
+
+/// DAMON monitoring context.
+pub struct DamonCtx {
+ ctx: NonNull<bindings::damon_ctx>,
+}
+
+impl DamonCtx {
+ /// Create a new DAMON monitoring context.
+ pub fn damon_new_ctx() -> Result<Self> {
+ // SAFETY: damon_new_ctx returns a valid pointer to new allocated
+ // damon_ctx or NULL if allocation failure, which will be checked
+ // by the subsequent NonNull::new.
+ let raw = unsafe { bindings::damon_new_ctx() };
+ let c = NonNull::new(raw).ok_or(ENOMEM)?;
+ Ok(Self { ctx: c })
+ }
+
+ /// Select a monitoring operations to use with the context.
+ pub fn damon_select_ops(&self, id: OpsID) -> Result {
+ // SAFETY: self.ctx was created by a successful damon_new_ctx()
+ // call, so it points to a valid damon_ctx. id.ops_id comes from a
+ // known-good constant, so it is a value the C side understands.
+ let ret = unsafe { bindings::damon_select_ops(self.ctx.as_ptr(), id.ops_id) };
+ if ret < 0 {
+ Err(Error::from_errno(ret))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Add a new DAMON monitoring target.
+ pub fn damon_add_target(&self, target: Target) {
+ // SAFETY: Both arguments are valid: self.ctx is non-null by
+ // construction, and target.target points to an unique owned
+ // damon_target. The C function takes ownership of the target
+ // that is why rust slide should forget it.
+ unsafe { bindings::damon_add_target(self.ctx.as_ptr(), target.target.as_ptr()) };
+ core::mem::forget(target);
+ }
+
+ /// Add a scheme to context.
+ pub fn damon_add_scheme(&self, scheme: Damos) {
+ // SAFETY: self.ctx is a valid 'damon_ctx *' and scheme.damos is a
+ // valid 'damos *', both by the type invariants of Ctx and Damos.
+ // damon_add_scheme takes ownership of the scheme, so the rust
+ // side should forget it to avoid a double free.
+ unsafe { bindings::damon_add_scheme(self.ctx.as_ptr(), scheme.damos.as_ptr()) };
+ core::mem::forget(scheme);
+ }
+
+ /// Starts the monitorings for a given group of contexts.
+ pub fn damon_start(&self) -> Result {
+ let mut ctxs = [self.ctx.as_ptr()];
+ // SAFETY: ctxs is a stack-allocated array of length 1 whose only
+ // element is a valid 'damon_ctx *'. The pointer remains valid
+ // for the duration of the call. The length argument 1 matches the
+ // array size, and true is a valid bool value for the exclusive
+ // parameter.
+ let ret = unsafe { bindings::damon_start(ctxs.as_mut_ptr(), 1, true) };
+ if ret < 0 {
+ Err(Error::from_errno(ret))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Transfers ownership of the underlying damon_ctx to the caller.
+ /// After this call, the DamonCtx is consumed and will not call
+ /// damon_destroy_ctx on drop. The caller becomes responsible for
+ /// eventually calling damon_destroy_ctx.
+ pub fn into_raw(self) -> *mut bindings::damon_ctx {
+ let ptr = self.ctx.as_ptr();
+ core::mem::forget(self);
+ ptr
+ }
+
+ /// Reconstructs a DamonCtx from a raw pointer returned by into_raw.
+ /// Note that the ptr must be the non-null pointer obtained from
+ /// into_raw(), and returned once -- the caller must not use ptr
+ /// afterwards, and no other owner may remain.
+ pub unsafe fn from_raw(ptr: *mut bindings::damon_ctx) -> Self {
+ // SAFETY: ptr is a valid, non-null 'damon_ctx *'.
+ Self {
+ ctx: unsafe { NonNull::new_unchecked(ptr) },
+ }
+ }
+
+ /// Stops the monitorings for a given group of contexts.
+ fn damon_stop(&self, nr_ctxs: i32) {
+ let mut ctxs = [self.ctx.as_ptr()];
+ // SAFETY: ctxs is a stack buffer whose element is a valid
+ // 'damon_ctx *' by the DamonCtx invariant.
+ unsafe { bindings::damon_stop(ctxs.as_mut_ptr(), nr_ctxs) };
+ }
+
+ /// Destroys the contexts and frees all associated resources.
+ fn damon_destroy_ctx(&self) {
+ // SAFETY: self.ctx is a valid, non-null 'damon_ctx *' by the
+ // DamonCtx invariant, and it is only destroyed once from drop()
+ // that execute after damon_stop().
+ unsafe { bindings::damon_destroy_ctx(self.ctx.as_ptr()) };
+ }
+}
+
+impl Drop for DamonCtx {
+ fn drop(&mut self) {
+ self.damon_stop(1);
+ self.damon_destroy_ctx();
+ }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 4d5c96ddc49c..7e9e748cd0b9 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -62,6 +62,8 @@
pub mod cpufreq;
pub mod cpumask;
pub mod cred;
+#[cfg(CONFIG_DAMON)]
+pub mod damon;
pub mod debugfs;
pub mod device;
pub mod device_id;
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC PATCH 3/4] samples/damon: add Rust sample for DAMON access-aware proactive reclamation
2026-09-27 7:28 [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample Enze Li
2026-09-27 7:28 ` [RFC PATCH 1/4] rust: add bindings for linux/damon.h Enze Li
2026-09-27 7:28 ` [RFC PATCH 2/4] rust: damon: add basic DAMON abstractions Enze Li
@ 2026-09-27 7:28 ` Enze Li
2026-09-27 7:28 ` [RFC PATCH 4/4] MAINTAINERS: add entry for the DAMON Rust abstractions Enze Li
2026-09-27 10:07 ` [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample SJ Park
4 siblings, 0 replies; 8+ messages in thread
From: Enze Li @ 2026-09-27 7:28 UTC (permalink / raw)
To: ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, sj
Cc: linux-kernel, rust-for-linux, damon, linux-mm, enze.li, lienze
Add a Rust implementation of the DAMON-based proactive reclamation sample
module, porting the logic from prcl.c to demonstrate using Rust bindings
for DAMON C APIs.
The module monitors the virtual address space of a target process via DAMON
vaddr operations and proactively reclaims cold memory regions using the
DAMOS_PAGEOUT action with an access pattern filter.
Unlike the C version (prcl.c), which is configured through module
parameters, the Rust version provides debugfs-based runtime control under
/sys/kernel/debug/rust_prcl/. Monitoring can be enabled or disabled by
writing to the enabled file, while the target process to monitor is
selected by writing its PID to target_pid.
Signed-off-by: Enze Li <lienze@kylinos.cn>
---
samples/Makefile | 1 +
samples/damon/Kconfig | 12 +++
samples/damon/Makefile | 1 +
samples/damon/rust_prcl.rs | 158 +++++++++++++++++++++++++++++++++++++
4 files changed, 172 insertions(+)
create mode 100644 samples/damon/rust_prcl.rs
diff --git a/samples/Makefile b/samples/Makefile
index 07641e177bd8..df726c0653cd 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -43,5 +43,6 @@ obj-$(CONFIG_SAMPLES_RUST) += rust/
obj-$(CONFIG_SAMPLE_DAMON_WSSE) += damon/
obj-$(CONFIG_SAMPLE_DAMON_PRCL) += damon/
obj-$(CONFIG_SAMPLE_DAMON_MTIER) += damon/
+obj-$(CONFIG_SAMPLE_DAMON_RUST_PRCL) += damon/
obj-$(CONFIG_SAMPLE_HUNG_TASK) += hung_task/
obj-$(CONFIG_SAMPLE_TSM_MR) += tsm-mr/
diff --git a/samples/damon/Kconfig b/samples/damon/Kconfig
index 00be3e6bdd65..654b62e186c9 100644
--- a/samples/damon/Kconfig
+++ b/samples/damon/Kconfig
@@ -40,4 +40,16 @@ config SAMPLE_DAMON_MTIER
If unsure, say N.
+config SAMPLE_DAMON_RUST_PRCL
+ bool "Rust sample module for DAMON-based access-aware proactive reclamation"
+ depends on DAMON && DAMON_VADDR && RUST && DEBUG_FS
+ help
+ This option builds the Rust implementation of DAMON-based prcl sample.
+
+ The module exposes two debugfs interfaces under
+ /sys/kernel/debug/rust_prcl/ for starting/stopping monitoring
+ and setting the target PID.
+
+ If unsure, say N.
+
endmenu
diff --git a/samples/damon/Makefile b/samples/damon/Makefile
index 72f68cbf422a..2e3ed8d9dd5d 100644
--- a/samples/damon/Makefile
+++ b/samples/damon/Makefile
@@ -3,3 +3,4 @@
obj-$(CONFIG_SAMPLE_DAMON_WSSE) += wsse.o
obj-$(CONFIG_SAMPLE_DAMON_PRCL) += prcl.o
obj-$(CONFIG_SAMPLE_DAMON_MTIER) += mtier.o
+obj-$(CONFIG_SAMPLE_DAMON_RUST_PRCL) += rust_prcl.o
diff --git a/samples/damon/rust_prcl.rs b/samples/damon/rust_prcl.rs
new file mode 100644
index 000000000000..1e6c820311e2
--- /dev/null
+++ b/samples/damon/rust_prcl.rs
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust prcl sample.
+
+use core::ptr::null_mut;
+use kernel::bindings;
+use kernel::damon;
+use kernel::debugfs::Scope;
+use kernel::prelude::*;
+use kernel::sync::atomic::{Atomic, Relaxed};
+use kernel::uaccess::UserSliceReader;
+
+module! {
+ type: RustPrcl,
+ name: "rust_prcl",
+ authors: ["Enze Li <lienze@kylinos.cn>"],
+ description: "DAMON-based proactive reclamation module for rust edition",
+ license: "GPL",
+}
+
+struct RustPrcl {
+ _data: Pin<KBox<Scope<ModuleData>>>,
+}
+
+struct ModuleData {
+ enabled: Atomic<bool>,
+ target_pid: Atomic<i32>,
+}
+
+impl Drop for ModuleData {
+ fn drop(&mut self) {
+ if self.enabled.load(Relaxed) {
+ damon_sample_rust_prcl_stop();
+ }
+ }
+}
+
+static CTX: Atomic<*mut bindings::damon_ctx> = Atomic::new(null_mut());
+
+fn damon_sample_rust_prcl_start(target_pid: i32) -> Result {
+ let ctx = damon::DamonCtx::damon_new_ctx()?;
+ ctx.damon_select_ops(damon::OpsID::VADDR)?;
+
+ let mut target = damon::Target::damon_new_target()?;
+ target.damon_set_target_pid(target_pid)?;
+ ctx.damon_add_target(target);
+
+ let mut pattern =
+ damon::DamosAccessPattern::new(bindings::PAGE_SIZE, usize::MAX, 0, 0, 50, u32::MAX);
+
+ let mut quota = damon::DamosQuota::zeroed();
+ let mut watermarks = damon::DamosWatermarks::zeroed();
+ let scheme = damon::Damos::new(
+ &mut pattern,
+ damon::DamosAction::PAGEOUT,
+ 0,
+ &mut quota,
+ &mut watermarks,
+ bindings::NUMA_NO_NODE,
+ )?;
+
+ ctx.damon_add_scheme(scheme);
+
+ let ret = ctx.damon_start();
+ match ret {
+ Ok(_) => {
+ CTX.store(ctx.into_raw(), Relaxed);
+ }
+ Err(e) => {
+ pr_err!("damon_start failed, error: {:?}\n", e);
+ return Err(e);
+ }
+ }
+ Ok(())
+}
+
+fn damon_sample_rust_prcl_stop() {
+ pr_info!("stop\n");
+ let raw = CTX.xchg(null_mut(), Relaxed);
+ if !raw.is_null() {
+ // SAFETY: raw came from into_raw() at damon_start(), and xchg()
+ // makes its sole remaining owner, so moving it back once is safe.
+ let _ctx = unsafe { damon::DamonCtx::from_raw(raw) };
+ // _ctx drops at the end of this scope, it runs damon_stop(1) and
+ // damon_destroy_ctx().
+ }
+}
+
+fn damon_sample_rust_parse_bool(s: &str) -> Result<bool> {
+ let s = s.trim();
+ if s.eq_ignore_ascii_case("y") {
+ Ok(true)
+ } else if s.eq_ignore_ascii_case("n") {
+ Ok(false)
+ } else {
+ Err(EINVAL)
+ }
+}
+
+fn enabled_read(data: &ModuleData, f: &mut kernel::fmt::Formatter<'_>) -> kernel::fmt::Result {
+ writeln!(f, "{}", if data.enabled.load(Relaxed) { 'Y' } else { 'N' })
+}
+
+fn enabled_write(data: &ModuleData, reader: &mut UserSliceReader) -> Result {
+ let mut buf = [0u8; 32];
+ if reader.len() > buf.len() {
+ return Err(EINVAL);
+ }
+ let n = reader.len();
+ reader.read_slice(&mut buf[..n])?;
+
+ let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?;
+ let enabled = damon_sample_rust_parse_bool(s)?;
+
+ let is_enabled = data.enabled.load(Relaxed);
+ if enabled == is_enabled {
+ return Ok(());
+ }
+
+ if !damon::damon_initialized() {
+ return Ok(());
+ }
+
+ data.enabled.store(enabled, Relaxed);
+
+ if enabled {
+ let target_pid = data.target_pid.load(Relaxed);
+ if let Err(e) = damon_sample_rust_prcl_start(target_pid) {
+ data.enabled.store(false, Relaxed);
+ return Err(e);
+ }
+ } else {
+ damon_sample_rust_prcl_stop();
+ }
+
+ Ok(())
+}
+
+impl kernel::Module for RustPrcl {
+ fn init(_module: &'static kernel::ThisModule) -> Result<Self> {
+ let data = KBox::pin_init(
+ Scope::dir(
+ ModuleData {
+ enabled: Atomic::new(false),
+ target_pid: Atomic::new(0),
+ },
+ c"rust_prcl",
+ |data, dir| {
+ dir.read_write_callback_file(c"enabled", data, &enabled_read, &enabled_write);
+ dir.read_write_file(c"target_pid", &data.target_pid);
+ },
+ ),
+ GFP_KERNEL,
+ )?;
+
+ Ok(Self { _data: data })
+ }
+}
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC PATCH 4/4] MAINTAINERS: add entry for the DAMON Rust abstractions
2026-09-27 7:28 [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample Enze Li
` (2 preceding siblings ...)
2026-09-27 7:28 ` [RFC PATCH 3/4] samples/damon: add Rust sample for DAMON access-aware proactive reclamation Enze Li
@ 2026-09-27 7:28 ` Enze Li
2026-09-27 10:07 ` [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample SJ Park
4 siblings, 0 replies; 8+ messages in thread
From: Enze Li @ 2026-09-27 7:28 UTC (permalink / raw)
To: ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl,
tmgross, dakr, daniel.almeida, tamird, acourbot, work, sj
Cc: linux-kernel, rust-for-linux, damon, linux-mm, enze.li, lienze
Add a RUST [DAMON] entry covering rust/kernel/damon.rs and
samples/damon/rust_prcl.rs so those files are maintained by Enze Li and
routed to the rust-for-linux and DAMON lists.
Signed-off-by: Enze Li <lienze@kylinos.cn>
---
MAINTAINERS | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 1fc1cb1d1c49..37136171f08d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24007,6 +24007,14 @@ L: rust-for-linux@vger.kernel.org
S: Maintained
F: rust/kernel/bitfield.rs
+RUST [DAMON]
+M: Enze Li <lienze@kylinos.cn>
+L: rust-for-linux@vger.kernel.org
+L: damon@lists.linux.dev
+S: Maintained
+F: rust/kernel/damon.rs
+F: samples/damon/rust_prcl.rs
+
RUST [INTEROP]
M: Joel Fernandes <joelagnelf@nvidia.com>
M: Alexandre Courbot <acourbot@nvidia.com>
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample
2026-09-27 7:28 [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample Enze Li
` (3 preceding siblings ...)
2026-09-27 7:28 ` [RFC PATCH 4/4] MAINTAINERS: add entry for the DAMON Rust abstractions Enze Li
@ 2026-09-27 10:07 ` SJ Park
2026-09-28 12:59 ` Enze Li
4 siblings, 1 reply; 8+ messages in thread
From: SJ Park @ 2026-09-27 10:07 UTC (permalink / raw)
To: Enze Li
Cc: SJ Park, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
aliceryhl, tmgross, dakr, daniel.almeida, tamird, acourbot, work,
linux-kernel, rust-for-linux, damon, linux-mm, enze.li
Hi Enze,
On Sun, 27 Sep 2026 15:28:08 +0800 Enze Li <lienze@kylinos.cn> wrote:
> Hi SJ, hi all,
>
> Almost a year ago, right after a memory-leak fix discussion on this list, I
> asked whether introducing Rust for some DAMON modules could be worth
> exploring as a proactive measure. SJ's answer was positive: he was open to
> Rust adoption in DAMON, both in kernel and user space, and even mentioned
> he had been wanting to write a Rust sample DAMON module himself since LPC,
> but had not found the time yet [1].
>
> So, here is my attempt at making that start happen. This RFC is
> intentionally small: it adds just enough Rust support for DAMON to port the
> proactive reclamation sample (prcl.c), and nothing more.
Thank you for this patch series! Yes, I'm interested in Rust, though I didn't
have sufficient time to dig in yet. I'm planning to attend Rust for Linux
training day [1] on next Sunday.
TLDR: I feel like we might need to wait or focus on module parameter support in
Rust, ongoing DAMON extension works before adopting Rust in DAMON. Also, I'd
suggest starting with wsse, which is simpler.
>
> The series has four patches:
>
> 1. Generate Rust bindings for include/linux/damon.h.
> 2. Add thin safe wrappers in a new rust::kernel::damon module: contexts,
> targets, access patterns, quotas, watermarks, schemes, plus
> start/stop. Everything FFI-related is confined to the wrappers, with
> the usual SAFETY comments; error codes are returned as kernel::Result.
> 3. Add samples/damon/rust_prcl.rs, a Rust port of prcl.c. It watches the
> virtual address space of a target process and pages out cold regions
> with the DAMOS_PAGEOUT action, same access-pattern filter as the C
> version.
I'd suggest starting from porting wsse, because it is simplest. By scoping
down to it, you could drop the wrappers for DAMOS.
> 4. Add a MAINTAINERS entry for the two new files.
>
> Two differences from the C sample are worth noting.
>
> First, the control interface. The C prcl sample is driven through
> runtime-writable module parameters (target_pid and enabled, the latter via
> module_param_cb), neither of which Rust can express yet -- its module
> parameters are load-time only and do not show up under /sys/module/, and
> there is no general sysfs abstraction in mainline or the RfL rust-next
> tree. The debugfs abstraction, however, already provides the safe
> read/write wrappers we need, so the Rust sample exposes the same two knobs
> under /sys/kernel/debug/rust_prcl/. This is a temporary detour, not a
> design preference: the sample will be switched over to match the C
> interface once Rust supports sysfs-backed module parameters.
Do we have a timeline for module parameters support in Rust? I'd prefer to
avoid use of debugfs and directly start with sysfs.
>
> Second, the functional scope. The C sample also repeatedly reports the
> estimated working set size via a repeating damon_call() callback. This
> initial Rust version covers only the core monitoring/reclamation path
> (context, target, PAGEOUT scheme, start/stop); wss reporting needs safe
> wrappers for damon_call() and region iteration, which will come in a
> follow-up series that also makes the Rust sample's output match the C
> one's.
As I abovely mentioned, I'd prefer porting wsse first, and later extend to
DAMOS-based samples like prcl and mtier.
>
> A quick word on the longer-term plan, so the design discussion here can
> happen with the destination in mind:
>
> - Over roughly the next year, I would like to port the other two DAMON
> samples (wsse and mtier) to Rust as well, and let the DAMON Rust
> compatibility layer grow together with them, wrapping only what real
> in-tree users need.
> - Once that layer has matured, I would be happy to try Rust for the
> production modules - damon/reclaim, damon/lru_sort and damon/stat.
> That is a much bigger step, of course, and it only happens if SJ is
> comfortable with it. Consider it a willingness statement, not a
> promise.
I think that's a good plan. However, I'd like to call out we will also need to
make each step with good and sufficient discussions. That is, for each step,
we will discuss if the previous step change was helpful and therefore make
sense to proceed to the next step. If the conclusion is oppostie, we could
even revert the previous changes. It would be great if we could make it driven
by data.
>
> Regarding the MAINTAINERS patch: I listed myself for the new files, but did
> not add SJ as a reviewer yet, since he mentioned limited bandwidth for Rust
> work in that earlier discussion. The existing DAMON entry already covers
> samples/damon/, so the sample reaches him regardless; adding him to the
> RUST [DAMON] entry would only additionally route future changes to
> rust/kernel/damon.rs his way. Happy to add the R: line if he wants it, or
> leave it out if he prefers.
I think I should at least review the patches. Also I feel I am responsible to
the maintenance of the code.
We are extending DAMON to work for not only data access but general data
attributes. I'm also planning to refactor DAMON API quite a lot in near
future. Some interfaces will be added and removed. DAMON API callers
including sample modules would also need to be changed a lot. If we make the
Rust sample module with the current API, we may need to make changes not only
in C but also Rust parts. I concern if it can introduce more breakages that
require unnecessarily long time to fix. Among all, my lack of Rust
understanding is a big concern.
I understand this patch series is a kind of experiment rather than for a real
use case that has a hard deadline. If I'm not incorrect, I feel like this
might not be the best time to start the experiment. Could we wait until
fundamental parts including module parameters support in Rust and ongoing DAMON
reconstruction, or my learning of Rust are done and stabilized?
I may missing many things. I might simply rejecting this great opportunity
only due to my laziness. Please push back if you find so.
[1] https://lore.kernel.org/all/rust-at-lpc2026@google.com/
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample
2026-09-27 10:07 ` [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample SJ Park
@ 2026-09-28 12:59 ` Enze Li
2026-09-28 16:56 ` SJ Park
0 siblings, 1 reply; 8+ messages in thread
From: Enze Li @ 2026-09-28 12:59 UTC (permalink / raw)
To: SJ Park
Cc: ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl,
tmgross, dakr, daniel.almeida, tamird, acourbot, work,
linux-kernel, rust-for-linux, damon, linux-mm, enze.li
Hi SJ,
Thank you for the detailed reply. Comments inline below.
On 9/27/26 18:07, SJ Park wrote:
> Hi Enze,
>
> On Sun, 27 Sep 2026 15:28:08 +0800 Enze Li <lienze@kylinos.cn> wrote:
>
>> Hi SJ, hi all,
>>
>> Almost a year ago, right after a memory-leak fix discussion on this list, I
>> asked whether introducing Rust for some DAMON modules could be worth
>> exploring as a proactive measure. SJ's answer was positive: he was open to
>> Rust adoption in DAMON, both in kernel and user space, and even mentioned
>> he had been wanting to write a Rust sample DAMON module himself since LPC,
>> but had not found the time yet [1].
>>
>> So, here is my attempt at making that start happen. This RFC is
>> intentionally small: it adds just enough Rust support for DAMON to port the
>> proactive reclamation sample (prcl.c), and nothing more.
>
> Thank you for this patch series! Yes, I'm interested in Rust, though I didn't
> have sufficient time to dig in yet. I'm planning to attend Rust for Linux
> training day [1] on next Sunday.
>
> TLDR: I feel like we might need to wait or focus on module parameter support in
> Rust, ongoing DAMON extension works before adopting Rust in DAMON. Also, I'd
> suggest starting with wsse, which is simpler.
Agreed, and after thinking it over I am fine with deferring the series.
For context, the original goal was never really the sample itself: what
I was hoping to start was a thin Rust compatibility layer for DAMON --
the damon.rs wrappers -- with prcl serving only as its first in-tree
user, to validate that the wrappers are usable so that others can build
their own DAMON-based modules on top of them. It is therefore a bit
unfortunate that the first step ends up blocked partly by something
outside of DAMON, namely the lack of writable/sysfs-backed module
parameters in Rust.
That said, I understand the position and I do not think waiting is the
wrong outcome: the parameters have no committed timeline, and the DAMON
API reconstruction is actively changing the interfaces the wrappers
would sit on, so starting now with a debugfs-only interface we already
know we want to replace would just add churn to moving APIs.
>
>>
>> The series has four patches:
>>
>> 1. Generate Rust bindings for include/linux/damon.h.
>> 2. Add thin safe wrappers in a new rust::kernel::damon module: contexts,
>> targets, access patterns, quotas, watermarks, schemes, plus
>> start/stop. Everything FFI-related is confined to the wrappers, with
>> the usual SAFETY comments; error codes are returned as kernel::Result.
>> 3. Add samples/damon/rust_prcl.rs, a Rust port of prcl.c. It watches the
>> virtual address space of a target process and pages out cold regions
>> with the DAMOS_PAGEOUT action, same access-pattern filter as the C
>> version.
>
> I'd suggest starting from porting wsse, because it is simplest. By scoping
> down to it, you could drop the wrappers for DAMOS.
>
>> 4. Add a MAINTAINERS entry for the two new files.
>>
>> Two differences from the C sample are worth noting.
>>
>> First, the control interface. The C prcl sample is driven through
>> runtime-writable module parameters (target_pid and enabled, the latter via
>> module_param_cb), neither of which Rust can express yet -- its module
>> parameters are load-time only and do not show up under /sys/module/, and
>> there is no general sysfs abstraction in mainline or the RfL rust-next
>> tree. The debugfs abstraction, however, already provides the safe
>> read/write wrappers we need, so the Rust sample exposes the same two knobs
>> under /sys/kernel/debug/rust_prcl/. This is a temporary detour, not a
>> design preference: the sample will be switched over to match the C
>> interface once Rust supports sysfs-backed module parameters.
>
> Do we have a timeline for module parameters support in Rust? I'd prefer to
> avoid use of debugfs and directly start with sysfs.
I am not aware of one. rust-next still registers Rust module
parameters with perm 0 (load-time only). I will keep an eye on the
rust-for-linux list; if anyone picks it up, I would appreciate being
Cc'd.
>
>>
>> Second, the functional scope. The C sample also repeatedly reports the
>> estimated working set size via a repeating damon_call() callback. This
>> initial Rust version covers only the core monitoring/reclamation path
>> (context, target, PAGEOUT scheme, start/stop); wss reporting needs safe
>> wrappers for damon_call() and region iteration, which will come in a
>> follow-up series that also makes the Rust sample's output match the C
>> one's.
>
> As I abovely mentioned, I'd prefer porting wsse first, and later extend to
> DAMOS-based samples like prcl and mtier.
Noted -- when this restarts, it will be the wsse-scoped version, without
the DAMOS wrappers, and the compatibility layer will grow around only
what that sample actually needs.
>
>>
>> A quick word on the longer-term plan, so the design discussion here can
>> happen with the destination in mind:
>>
>> - Over roughly the next year, I would like to port the other two DAMON
>> samples (wsse and mtier) to Rust as well, and let the DAMON Rust
>> compatibility layer grow together with them, wrapping only what real
>> in-tree users need.
>> - Once that layer has matured, I would be happy to try Rust for the
>> production modules - damon/reclaim, damon/lru_sort and damon/stat.
>> That is a much bigger step, of course, and it only happens if SJ is
>> comfortable with it. Consider it a willingness statement, not a
>> promise.
>
> I think that's a good plan. However, I'd like to call out we will also need to
> make each step with good and sufficient discussions. That is, for each step,
> we will discuss if the previous step change was helpful and therefore make
> sense to proceed to the next step. If the conclusion is oppostie, we could
> even revert the previous changes. It would be great if we could make it driven
> by data.
>
>>
>> Regarding the MAINTAINERS patch: I listed myself for the new files, but did
>> not add SJ as a reviewer yet, since he mentioned limited bandwidth for Rust
>> work in that earlier discussion. The existing DAMON entry already covers
>> samples/damon/, so the sample reaches him regardless; adding him to the
>> RUST [DAMON] entry would only additionally route future changes to
>> rust/kernel/damon.rs his way. Happy to add the R: line if he wants it, or
>> leave it out if he prefers.
>
> I think I should at least review the patches. Also I feel I am responsible to
> the maintenance of the code.
>
> We are extending DAMON to work for not only data access but general data
> attributes. I'm also planning to refactor DAMON API quite a lot in near
> future. Some interfaces will be added and removed. DAMON API callers
> including sample modules would also need to be changed a lot. If we make the
> Rust sample module with the current API, we may need to make changes not only
> in C but also Rust parts. I concern if it can introduce more breakages that
> require unnecessarily long time to fix. Among all, my lack of Rust
> understanding is a big concern.
>
> I understand this patch series is a kind of experiment rather than for a real
> use case that has a hard deadline. If I'm not incorrect, I feel like this
> might not be the best time to start the experiment. Could we wait until
> fundamental parts including module parameters support in Rust and ongoing DAMON
> reconstruction, or my learning of Rust are done and stabilized?
Yes. I will park the patches and restart once both are true:
1. Rust supports writable/sysfs-backed module parameters.
2. the DAMON API reconstruction has settled enough that wrappers can
target the new interfaces directly.
Meanwhile I will keep working on DAMON in C as usual.
Enjoy the training day, and good luck with the Rust learning.
Thanks,
Enze
<...>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample
2026-09-28 12:59 ` Enze Li
@ 2026-09-28 16:56 ` SJ Park
0 siblings, 0 replies; 8+ messages in thread
From: SJ Park @ 2026-09-28 16:56 UTC (permalink / raw)
To: Enze Li
Cc: SJ Park, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
aliceryhl, tmgross, dakr, daniel.almeida, tamird, acourbot, work,
linux-kernel, rust-for-linux, damon, linux-mm, enze.li
On Mon, 28 Sep 2026 20:59:45 +0800 Enze Li <lienze@kylinos.cn> wrote:
> Hi SJ,
>
> Thank you for the detailed reply. Comments inline below.
>
> On 9/27/26 18:07, SJ Park wrote:
[...]
> > I understand this patch series is a kind of experiment rather than for a real
> > use case that has a hard deadline. If I'm not incorrect, I feel like this
> > might not be the best time to start the experiment. Could we wait until
> > fundamental parts including module parameters support in Rust and ongoing DAMON
> > reconstruction, or my learning of Rust are done and stabilized?
>
> Yes. I will park the patches and restart once both are true:
>
> 1. Rust supports writable/sysfs-backed module parameters.
> 2. the DAMON API reconstruction has settled enough that wrappers can
> target the new interfaces directly.
>
> Meanwhile I will keep working on DAMON in C as usual.
Thank you for accepting my humble suggestion, Enze. If anybody has different
optinions, please feel free to weigh in, though.
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-28 16:56 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-27 7:28 [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample Enze Li
2026-09-27 7:28 ` [RFC PATCH 1/4] rust: add bindings for linux/damon.h Enze Li
2026-09-27 7:28 ` [RFC PATCH 2/4] rust: damon: add basic DAMON abstractions Enze Li
2026-09-27 7:28 ` [RFC PATCH 3/4] samples/damon: add Rust sample for DAMON access-aware proactive reclamation Enze Li
2026-09-27 7:28 ` [RFC PATCH 4/4] MAINTAINERS: add entry for the DAMON Rust abstractions Enze Li
2026-09-27 10:07 ` [RFC PATCH 0/4] rust: damon: a first small step, plus a Rust prcl sample SJ Park
2026-09-28 12:59 ` Enze Li
2026-09-28 16:56 ` SJ Park
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®