[RFC PATCH v3 9/9] mm/damon/core: allow both primitives disabled when a perf probe is present
From: Ravi Jonnalagadda
Date: Sat Oct 03 2026 - 17:12:38 EST
The sample control validation requires exactly one software access check
primitive, page_table or page_fault, to be enabled. A context carrying a
perf-event probe needs neither: the probe drives the access signal
through its report ring and the drain, so region access rates and ages
update with both primitives off.
That check runs in damon_commit_sample_control(), which sees only the
sample control and cannot tell whether the context has such a probe.
Move it to __damon_commit_ctx(), skip it for a context with event-driven
probes, and run it with the other validation of @src before anything is
committed to @dst, so a rejected configuration cannot leave a live commit
with its PMU events already armed.
Add damon_test_both_primitives_disabled_with_probe(), which commits a
context with both primitives off and an event-driven probe and asserts the
commit succeeds.
Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@xxxxxxxxx>
---
mm/damon/core.c | 11 ++++++++---
mm/damon/tests/drain-kunit.h | 37 +++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index c2c74d0daf95..04a1cccbc2f5 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -2357,9 +2357,6 @@ static int damon_commit_sample_control(
struct damon_sample_control *dst,
struct damon_sample_control *src)
{
- if (damon_primitives_enabled_invalid(&src->primitives_enabled))
- return -EINVAL;
-
dst->primitives_enabled = src->primitives_enabled;
return damon_commit_sample_filters(dst, src);
}
@@ -2390,6 +2387,14 @@ static int __damon_commit_ctx(struct damon_ctx *dst, struct damon_ctx *src,
if (!damon_valid_probe_params(src))
return -EINVAL;
+ /*
+ * A probe-driven context needs no software primitive. Validate this
+ * before anything is committed to @dst, so a rejected configuration
+ * cannot leave a live commit with its PMU events already armed.
+ */
+ if (!damon_has_event_driven_probes(src) &&
+ damon_primitives_enabled_invalid(&src->sample_control.primitives_enabled))
+ return -EINVAL;
err = damon_commit_schemes(dst, src);
if (err)
diff --git a/mm/damon/tests/drain-kunit.h b/mm/damon/tests/drain-kunit.h
index 8e5023ebf6df..be44311617fc 100644
--- a/mm/damon/tests/drain-kunit.h
+++ b/mm/damon/tests/drain-kunit.h
@@ -722,6 +722,42 @@ static void damon_test_bsearch_unsorted_regions(struct kunit *test)
damon_destroy_ctx(ctx);
}
+/*
+ * Test that damon_primitives_enabled_invalid() accepts the both-disabled
+ * configuration when an event-driven probe is present (this commit's
+ * relaxation).
+ *
+ * Before this commit this configuration was rejected (-EINVAL). After it,
+ * it is valid: the probe drives access-rate updates directly via the report
+ * ring, so neither software primitive is required.
+ */
+static void damon_test_both_primitives_disabled_with_probe(struct kunit *test)
+{
+ struct damon_ctx *ctx;
+ int ret;
+
+ ctx = damon_new_ctx();
+ if (!ctx)
+ kunit_skip(test, "ctx alloc failed");
+
+ if (damon_test_attach_perf_probe(ctx)) {
+ damon_destroy_ctx(ctx);
+ kunit_skip(test, "perf probe alloc failed");
+ }
+
+ /*
+ * Explicitly disable both primitives. With an event-driven probe
+ * present, damon_commit_ctx() must now succeed outright.
+ */
+ ctx->sample_control.primitives_enabled.page_table = false;
+ ctx->sample_control.primitives_enabled.page_fault = false;
+
+ ret = damon_commit_ctx(ctx, ctx);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ damon_destroy_ctx(ctx);
+}
+
static struct kunit_case damon_drain_test_cases[] = {
KUNIT_CASE(damon_test_unified_vaddr_match),
KUNIT_CASE(damon_test_unified_vaddr_tgid_mismatch),
@@ -733,6 +769,7 @@ static struct kunit_case damon_drain_test_cases[] = {
KUNIT_CASE(damon_test_report_addr_space_keyed),
KUNIT_CASE(damon_test_ring_full_counter_increments),
KUNIT_CASE(damon_test_bsearch_unsorted_regions),
+ KUNIT_CASE(damon_test_both_primitives_disabled_with_probe),
{}
};
--
Git-157)