From: sashiko-bot@kernel.org
To: "Enze Li" <lienze@kylinos.cn>
Cc: ojeda@kernel.org, gary@garyguo.net, damon@lists.linux.dev
Subject: Re: [RFC PATCH 2/4] rust: damon: add basic DAMON abstractions
Date: Sun, 27 Sep 2026 07:40:07 +0000 [thread overview]
Message-ID: <20260927074007.8C75C1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260927072812.2393456-3-lienze@kylinos.cn>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] damon: data race in damon_add_target() and damon_add_scheme() via shared reference
- [High] damon: PID refcount leak in damon_add_target() when cleanup_target is NULL
- [High] damon: memory leak of struct damos due to missing Drop
- [Low] damon: missing #[inline] on C binding wrappers like damon_initialized()
--
commit d3e2e841f98a461b836da0fb19644c82a53dc09d
Author: Enze Li <lienze@kylinos.cn>
rust: damon: add basic DAMON abstractions
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.
diff --git a/rust/kernel/damon.rs b/rust/kernel/damon.rs
new file mode 100644
index 0000000000000..80e6609132e75
--- /dev/null
+++ b/rust/kernel/damon.rs
@@ -0,0 +1,292 @@
[ ... ]
> +/// 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() }
> +}
[Severity: Low]
This isn't a bug, but should this C binding wrapper have an #[inline]
annotation? The Rust subsystem guidelines recommend that small abstraction
functions forwarding to C bindings use #[inline].
[ ... ]
> +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)
[Severity: High]
Does this code leak the allocated struct damos?
If a user calls Damos::new() but returns early (for example, via the ? operator
during error handling) before passing ownership to DamonCtx::damon_add_scheme(),
it appears the memory allocated by damon_new_scheme() is never freed because
the Damos struct does not implement the Drop trait.
> + }
> +}
[ ... ]
> + /// 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);
[Severity: High]
Can this data race with the kdamond thread iterating over the same lists
locklessly?
Because damon_add_target() takes a shared &self reference, safe Rust code
can call it concurrently, or after damon_start() spawns the background C kernel
thread. This does not enforce mutual exclusion.
[Severity: High]
Does this code leak the struct pid refcount when cleanup_target is NULL?
Target::damon_set_target_pid() takes a refcount on a struct pid. Here,
core::mem::forget(target) bypasses the Rust Drop handler. If a user drops the
context without successfully selecting operations (like OpsID::VADDR), the C
fallback damon_destroy_ctx() leaves cleanup_target as NULL and put_pid() is
never called, leaking the refcount.
> + }
> +
> + /// 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()) };
[Severity: High]
Can this data race with the background thread for the same reasons as
damon_add_target()?
This method also takes a shared &self reference, allowing concurrent mutation
of the context's scheme list while the kthread locklessly accesses it.
> + 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) };
[Severity: High]
Can this allow data races by only requiring a shared reference?
damon_start() spawns the kdamond background thread. Because it takes &self
instead of an exclusive reference or consuming the context, it fails to
statically prevent safe Rust code from calling mutating methods like
damon_add_target() or damon_add_scheme() concurrently.
> + if ret < 0 {
> + Err(Error::from_errno(ret))
> + } else {
> + Ok(())
> + }
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260927072812.2393456-1-lienze@kylinos.cn?part=2
next prev parent reply other threads:[~2026-09-27 7:40 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
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:29 ` sashiko-bot
2026-09-27 7:28 ` [RFC PATCH 2/4] rust: damon: add basic DAMON abstractions Enze Li
2026-09-27 7:40 ` sashiko-bot [this message]
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:37 ` sashiko-bot
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260927074007.8C75C1F000FF@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=damon@lists.linux.dev \
--cc=gary@garyguo.net \
--cc=lienze@kylinos.cn \
--cc=ojeda@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox