The create_dsq test creates and destroys queues, but does not check the
-EEXIST contract for duplicate creation or whether the ID remains
accessible after the failed operation.

Extend the existing lifecycle loop to reject duplicate creation and
check that the empty queue is still accessible. After destruction,
require -ENOENT from the queue lookup, then recreate and destroy the
same ID. Check that all 1024 iterations complete.

This exercises empty queues during initialization, without concurrent
enqueueing or destruction of a nonempty queue. The create_dsq test
passes on a two-CPU matching-kernel VM.

Link: https://lore.kernel.org/all/Z-OZ7tJWhRZbUk1l@gpd3/
Assisted-by: LLM
Signed-off-by: Tianyi Chen <[email protected]>
---
 .../selftests/sched_ext/create_dsq.bpf.c      | 35 +++++++++++++++++++
 .../testing/selftests/sched_ext/create_dsq.c  |  4 ++-
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/sched_ext/create_dsq.bpf.c 
b/tools/testing/selftests/sched_ext/create_dsq.bpf.c
index 2cfc4ffd60e..680cc4b6d8c 100644
--- a/tools/testing/selftests/sched_ext/create_dsq.bpf.c
+++ b/tools/testing/selftests/sched_ext/create_dsq.bpf.c
@@ -10,6 +10,8 @@
 
 char _license[] SEC("license") = "GPL";
 
+u32 nr_lifecycle_tests;
+
 void BPF_STRUCT_OPS(create_dsq_exit_task, struct task_struct *p,
                    struct scx_exit_task_args *args)
 {
@@ -43,7 +45,40 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(create_dsq_init)
        }
 
        bpf_for(i, 0, 1024) {
+               err = scx_bpf_create_dsq(i, -1);
+               if (err != -EEXIST) {
+                       scx_bpf_error("Duplicate DSQ %d creation returned %d", 
i, err);
+                       return -EINVAL;
+               }
+
+               /* A rejected duplicate must leave the original DSQ accessible. 
*/
+               err = scx_bpf_dsq_nr_queued(i);
+               if (err) {
+                       scx_bpf_error("Original DSQ %d queue count is %d", i, 
err);
+                       return -EINVAL;
+               }
+
+               scx_bpf_destroy_dsq(i);
+               err = scx_bpf_dsq_nr_queued(i);
+               if (err != -ENOENT) {
+                       scx_bpf_error("Destroyed DSQ %d queue count is %d", i, 
err);
+                       return -EINVAL;
+               }
+
+               err = scx_bpf_create_dsq(i, -1);
+               if (err) {
+                       scx_bpf_error("Failed to recreate DSQ %d: %d", i, err);
+                       return err;
+               }
+
+               err = scx_bpf_dsq_nr_queued(i);
+               if (err) {
+                       scx_bpf_error("Recreated DSQ %d queue count is %d", i, 
err);
+                       return -EINVAL;
+               }
+
                scx_bpf_destroy_dsq(i);
+               nr_lifecycle_tests++;
        }
 
        return 0;
diff --git a/tools/testing/selftests/sched_ext/create_dsq.c 
b/tools/testing/selftests/sched_ext/create_dsq.c
index d67431f57ac..422e6532ee7 100644
--- a/tools/testing/selftests/sched_ext/create_dsq.c
+++ b/tools/testing/selftests/sched_ext/create_dsq.c
@@ -37,6 +37,8 @@ static enum scx_test_status run(void *ctx)
 
        bpf_link__destroy(link);
 
+       SCX_EQ(skel->bss->nr_lifecycle_tests, 1024);
+
        return SCX_TEST_PASS;
 }
 
@@ -49,7 +51,7 @@ static void cleanup(void *ctx)
 
 struct scx_test create_dsq = {
        .name = "create_dsq",
-       .description = "Create and destroy a dsq in a loop",
+       .description = "Create, reject duplicates, destroy and recreate DSQs",
        .setup = setup,
        .run = run,
        .cleanup = cleanup,
-- 
2.55.0


Reply via email to