Add a KUnit test to verify that damos_walk() rejects
new requests when walk_control_obsolete is set.

Commit 33c3f6c2b48c ("mm/damon/core: fix damos_walk() vs
kdamond_fn() exit race") introduced walk_control_obsolete
to prevent a race condition where new requests could be
registered during kdamond shutdown and never handled.

This test simulates the shutdown condition by setting
walk_control_obsolete and verifies that damos_walk()
returns -ECANCELED immediately.

This validates the invariant introduced by the fix and
helps prevent regressions.

Suggested-by: SeongJae Park <[email protected]>
Signed-off-by: Sailesh Nandanavanam <[email protected]>
---

Changes since v2 
(https://lore.kernel.org/[email protected]):
- Dropped the userspace selftest approach entirely. SeongJae tested
  v2 100 times on a kernel with the fix reverted and it always
  passed, confirming the microsecond-wide race window cannot be
  reliably hit from userspace due to syscall overhead.
- Added a KUnit test for damos_walk() + walk_control_obsolete
  instead, as suggested by SeongJae. This directly sets the
  obsolete flag and verifies damos_walk() returns -ECANCELED
  immediately, without timing dependency.

Changes since v1 
(https://lore.kernel.org/[email protected]):
- Addressed sashiko bot review comments (execute bit, threading,
  dynamic sysfs path, OSError handling) - superseded by the v3
  approach above.

 mm/damon/tests/core-kunit.h | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/mm/damon/tests/core-kunit.h b/mm/damon/tests/core-kunit.h
index 9e5904c2beeb..599aac056b73 100644
--- a/mm/damon/tests/core-kunit.h
+++ b/mm/damon/tests/core-kunit.h
@@ -1336,6 +1336,33 @@ static void damon_test_is_last_region(struct kunit *test)
        damon_free_target(t);
 }
 
+/*
+ * Verify that damos_walk() rejects new requests when
+ * walk_control_obsolete is set.
+ *
+ * This tests the invariant introduced by:
+ * commit 33c3f6c2b48c ("mm/damon/core: fix damos_walk() vs kdamond_fn() exit 
race")
+ */
+static void damon_test_walk_control_obsolete(struct kunit *test)
+{
+       struct damon_ctx *ctx;
+       struct damos_walk_control control = {};
+       int ret;
+
+       ctx = damon_new_ctx();
+       if (!ctx)
+               kunit_skip(test, "ctx alloc fail");
+
+       /* Simulate shutdown phase */
+       ctx->walk_control_obsolete = true;
+
+       ret = damos_walk(ctx, &control);
+
+       KUNIT_EXPECT_EQ(test, ret, -ECANCELED);
+
+       damon_destroy_ctx(ctx);
+}
+
 static struct kunit_case damon_test_cases[] = {
        KUNIT_CASE(damon_test_target),
        KUNIT_CASE(damon_test_regions),
@@ -1365,6 +1392,7 @@ static struct kunit_case damon_test_cases[] = {
        KUNIT_CASE(damon_test_set_filters_default_reject),
        KUNIT_CASE(damon_test_apply_min_nr_regions),
        KUNIT_CASE(damon_test_is_last_region),
+       KUNIT_CASE(damon_test_walk_control_obsolete),
        {},
 };
 
-- 
2.34.1


Reply via email to