This commit introduces a new selftest for the BPF wakeup_source iterator
to verify the functionality of open-coded iteration.

The test adds:
- A new BPF map `test_ws_hash` to track iterated wakeup source names.
- A BPF program `iter_ws_for_each` that iterates over wakeup sources and
  updates the `test_ws_hash` map with the names of found sources.
- A new subtest `subtest_ws_iter_check_open_coded` to trigger the BPF
  program and assert that the expected wakeup sources are marked in the
  map.

Signed-off-by: Samuel Wu <[email protected]>
---
 .../testing/selftests/bpf/bpf_experimental.h  |  5 ++
 .../bpf/prog_tests/wakeup_source_iter.c       | 42 +++++++++++++++++
 .../selftests/bpf/progs/wakeup_source_iter.c  | 47 +++++++++++++++++++
 3 files changed, 94 insertions(+)

diff --git a/tools/testing/selftests/bpf/bpf_experimental.h 
b/tools/testing/selftests/bpf/bpf_experimental.h
index 2cd9165c7348..e532999b91ca 100644
--- a/tools/testing/selftests/bpf/bpf_experimental.h
+++ b/tools/testing/selftests/bpf/bpf_experimental.h
@@ -598,6 +598,11 @@ extern void bpf_iter_dmabuf_destroy(struct bpf_iter_dmabuf 
*it) __weak __ksym;
 
 extern int bpf_cgroup_read_xattr(struct cgroup *cgroup, const char *name__str,
                                 struct bpf_dynptr *value_p) __weak __ksym;
+struct bpf_iter_wakeup_source;
+extern int bpf_iter_wakeup_source_new(struct bpf_iter_wakeup_source *it) 
__weak __ksym;
+extern struct wakeup_source *bpf_iter_wakeup_source_next(
+               struct bpf_iter_wakeup_source *it) __weak __ksym;
+extern void bpf_iter_wakeup_source_destroy(struct bpf_iter_wakeup_source *it) 
__weak __ksym;
 
 #define PREEMPT_BITS   8
 #define SOFTIRQ_BITS   8
diff --git a/tools/testing/selftests/bpf/prog_tests/wakeup_source_iter.c 
b/tools/testing/selftests/bpf/prog_tests/wakeup_source_iter.c
index 5cea4d4458f3..b2eaba38cc68 100644
--- a/tools/testing/selftests/bpf/prog_tests/wakeup_source_iter.c
+++ b/tools/testing/selftests/bpf/prog_tests/wakeup_source_iter.c
@@ -241,9 +241,37 @@ static void subtest_ws_iter_check_no_infinite_reads(
        close(iter_fd);
 }
 
+static void subtest_ws_iter_check_open_coded(struct wakeup_source_iter *skel,
+                                            int map_fd)
+{
+       LIBBPF_OPTS(bpf_test_run_opts, topts);
+       char key[WAKEUP_SOURCE_NAME_LEN] = {0};
+       int err, fd;
+       bool found = false;
+
+       fd = bpf_program__fd(skel->progs.iter_ws_for_each);
+
+       err = bpf_prog_test_run_opts(fd, &topts);
+       if (!ASSERT_OK(err, "test_run_opts err"))
+               return;
+       if (!ASSERT_OK(topts.retval, "test_run_opts retval"))
+               return;
+
+       strncpy(key, test_ws_name, WAKEUP_SOURCE_NAME_LEN - 1);
+
+       if (!ASSERT_OK(bpf_map_lookup_elem(map_fd, key, &found),
+                      "lookup test_ws_name"))
+               return;
+
+       ASSERT_TRUE(found, "found test ws via bpf_for_each");
+}
+
 void test_wakeup_source_iter(void)
 {
        struct wakeup_source_iter *skel = NULL;
+       int map_fd;
+       const bool found_val = false;
+       char key[WAKEUP_SOURCE_NAME_LEN] = {0};
 
        if (geteuid() != 0) {
                fprintf(stderr,
@@ -256,6 +284,17 @@ void test_wakeup_source_iter(void)
        if (!ASSERT_OK_PTR(skel, "wakeup_source_iter__open_and_load"))
                return;
 
+       map_fd = bpf_map__fd(skel->maps.test_ws_hash);
+       if (!ASSERT_OK_FD(map_fd, "map_fd"))
+               goto destroy_skel;
+
+       /* Copy test name to key buffer, ensuring it's zero-padded */
+       strncpy(key, test_ws_name, WAKEUP_SOURCE_NAME_LEN - 1);
+
+       if (!ASSERT_OK(bpf_map_update_elem(map_fd, key, &found_val, BPF_ANY),
+                      "insert test_ws_name"))
+               goto destroy_skel;
+
        if (!ASSERT_OK(setup_test_ws(), "setup_test_ws"))
                goto destroy;
 
@@ -274,8 +313,11 @@ void test_wakeup_source_iter(void)
                subtest_ws_iter_check_sleep_times(skel);
        if (test__start_subtest("no_infinite_reads"))
                subtest_ws_iter_check_no_infinite_reads(skel);
+       if (test__start_subtest("open_coded"))
+               subtest_ws_iter_check_open_coded(skel, map_fd);
 
 destroy:
        teardown_test_ws();
+destroy_skel:
        wakeup_source_iter__destroy(skel);
 }
diff --git a/tools/testing/selftests/bpf/progs/wakeup_source_iter.c 
b/tools/testing/selftests/bpf/progs/wakeup_source_iter.c
index 8c1470f06740..7812e773aa0c 100644
--- a/tools/testing/selftests/bpf/progs/wakeup_source_iter.c
+++ b/tools/testing/selftests/bpf/progs/wakeup_source_iter.c
@@ -9,6 +9,13 @@
 
 char _license[] SEC("license") = "GPL";
 
+struct {
+       __uint(type, BPF_MAP_TYPE_HASH);
+       __uint(key_size, WAKEUP_SOURCE_NAME_LEN);
+       __type(value, bool);
+       __uint(max_entries, 5);
+} test_ws_hash SEC(".maps");
+
 SEC("iter/wakeup_source")
 int wakeup_source_collector(struct bpf_iter__wakeup_source *ctx)
 {
@@ -68,3 +75,43 @@ int wakeup_source_collector(struct bpf_iter__wakeup_source 
*ctx)
                       wakeup_count);
        return 0;
 }
+
+SEC("syscall")
+int iter_ws_for_each(const void *ctx)
+{
+       struct wakeup_source *ws;
+
+       bpf_for_each(wakeup_source, ws) {
+               char name[WAKEUP_SOURCE_NAME_LEN];
+               const char *pname;
+               bool *found;
+               long len;
+               int i;
+
+               if (bpf_core_read(&pname, sizeof(pname), &ws->name))
+                       return 1;
+
+               if (!pname)
+                       continue;
+
+               len = bpf_probe_read_kernel_str(name, sizeof(name), pname);
+               if (len < 0)
+                       return 1;
+
+               /*
+                * Clear the remainder of the buffer to ensure a stable key for
+                * the map lookup.
+                */
+               bpf_for(i, len, WAKEUP_SOURCE_NAME_LEN)
+                       name[i] = 0;
+
+               found = bpf_map_lookup_elem(&test_ws_hash, name);
+               if (found) {
+                       bool t = true;
+
+                       bpf_map_update_elem(&test_ws_hash, name, &t, BPF_EXIST);
+               }
+       }
+
+       return 0;
+}
-- 
2.52.0.177.g9f829587af-goog


Reply via email to