Linux Kernel Selftest development
 help / color / mirror / Atom feed
* [PATCH v1 0/4] bpf: Add wakeup_source iterators
@ 2025-12-04  2:49 Samuel Wu
  2025-12-04  2:49 ` [PATCH v1 1/4] bpf: Add wakeup_source iterator Samuel Wu
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Samuel Wu @ 2025-12-04  2:49 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Shuah Khan
  Cc: rafael.j.wysocki, Samuel Wu, kernel-team, linux-kernel, bpf,
	linux-kselftest

This patch series introduces BPF iterators for wakeup_source, enabling
BPF programs to efficiently traverse a device's wakeup sources.

Currently, inspecting wakeup sources typically involves reading interfaces
like /sys/class/wakeup/* or debugfs. The repeated syscalls to query the
sysfs nodes is inefficient, as there can be hundreds of wakeup_sources, and
each wakeup source have multiple stats, with one sysfs node per stat.
debugfs is unstable and insecure.

This series implements two types of iterators:
1. Standard BPF Iterator: Allows creating a BPF link to iterate over
   wakeup sources
2. Open-coded Iterator: Enables the use of wakeup_source iterators directly
   within BPF programs

Both iterators utilize pre-existing APIs wakeup_sources_walk_* to traverse
over the SRCU that backs the list of wakeup_sources.

Samuel Wu (4):
  bpf: Add wakeup_source iterator
  bpf: Open coded BPF for wakeup_sources
  selftests/bpf: Add tests for wakeup_sources
  selftests/bpf: Open coded BPF wakeup_sources test

 kernel/bpf/Makefile                           |   1 +
 kernel/bpf/helpers.c                          |   3 +
 kernel/bpf/wakeup_source_iter.c               | 137 ++++++++
 .../testing/selftests/bpf/bpf_experimental.h  |   5 +
 tools/testing/selftests/bpf/config            |   1 +
 .../bpf/prog_tests/wakeup_source_iter.c       | 323 ++++++++++++++++++
 .../selftests/bpf/progs/wakeup_source_iter.c  | 117 +++++++
 7 files changed, 587 insertions(+)
 create mode 100644 kernel/bpf/wakeup_source_iter.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/wakeup_source_iter.c
 create mode 100644 tools/testing/selftests/bpf/progs/wakeup_source_iter.c

-- 
2.52.0.177.g9f829587af-goog

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v1 1/4] bpf: Add wakeup_source iterator
  2025-12-04  2:49 [PATCH v1 0/4] bpf: Add wakeup_source iterators Samuel Wu
@ 2025-12-04  2:49 ` Samuel Wu
  2025-12-04 21:23   ` kernel test robot
  2025-12-05  3:17   ` kernel test robot
  2025-12-04  2:49 ` [PATCH v1 2/4] bpf: Open coded BPF for wakeup_sources Samuel Wu
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 7+ messages in thread
From: Samuel Wu @ 2025-12-04  2:49 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Shuah Khan
  Cc: rafael.j.wysocki, Samuel Wu, kernel-team, linux-kernel, bpf,
	linux-kselftest

Add a BPF iterator for traversing through wakeup_sources.

Setup iterators to traverse through a SRCUs of wakeup_sources. This is a
more elegant and efficient traversal than going through the options
today, such as at /sys/class/wakeup, or through debugfs.

Signed-off-by: Samuel Wu <wusamuel@google.com>
---
 kernel/bpf/Makefile             |   1 +
 kernel/bpf/wakeup_source_iter.c | 103 ++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+)
 create mode 100644 kernel/bpf/wakeup_source_iter.c

diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 232cbc97434d..6a479982469a 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_BPF_SYSCALL) += kmem_cache_iter.o
 ifeq ($(CONFIG_DMA_SHARED_BUFFER),y)
 obj-$(CONFIG_BPF_SYSCALL) += dmabuf_iter.o
 endif
+obj-$(CONFIG_BPF_SYSCALL) += wakeup_source_iter.o
 
 CFLAGS_REMOVE_percpu_freelist.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_bpf_lru_list.o = $(CC_FLAGS_FTRACE)
diff --git a/kernel/bpf/wakeup_source_iter.c b/kernel/bpf/wakeup_source_iter.c
new file mode 100644
index 000000000000..b8719f47428e
--- /dev/null
+++ b/kernel/bpf/wakeup_source_iter.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Google LLC */
+#include <linux/bpf.h>
+#include <linux/btf_ids.h>
+#include <linux/kernel.h>
+#include <linux/pm_wakeup.h>
+#include <linux/seq_file.h>
+
+struct bpf_iter__wakeup_source {
+	__bpf_md_ptr(struct bpf_iter_meta *, meta);
+	__bpf_md_ptr(struct wakeup_source *, wakeup_source);
+};
+
+static void *wakeup_source_iter_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	int *srcuidx = seq->private;
+	struct wakeup_source *ws;
+	loff_t i;
+
+	*srcuidx = wakeup_sources_read_lock();
+
+	ws = wakeup_sources_walk_start();
+	for (i = 0; ws && i < *pos; i++)
+		ws = wakeup_sources_walk_next(ws);
+
+	return ws;
+}
+
+static void *wakeup_source_iter_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct wakeup_source *ws = v;
+
+	++*pos;
+
+	return wakeup_sources_walk_next(ws);
+}
+
+static void wakeup_source_iter_seq_stop(struct seq_file *seq, void *v)
+{
+	int *srcuidx = seq->private;
+
+	if (*srcuidx >= 0)
+		wakeup_sources_read_unlock(*srcuidx);
+	*srcuidx = -1;
+}
+
+static int __wakeup_source_seq_show(struct seq_file *seq, void *v, bool in_stop)
+{
+	struct bpf_iter_meta meta = {
+		.seq = seq,
+	};
+	struct bpf_iter__wakeup_source ctx = {
+		.meta = &meta,
+		.wakeup_source = v,
+	};
+	struct bpf_prog *prog = bpf_iter_get_info(&meta, in_stop);
+
+	if (prog)
+		return bpf_iter_run_prog(prog, &ctx);
+
+	return 0;
+}
+
+static int wakeup_source_iter_seq_show(struct seq_file *seq, void *v)
+{
+	return __wakeup_source_seq_show(seq, v, false);
+}
+
+static const struct seq_operations wakeup_source_iter_seq_ops = {
+	.start	= wakeup_source_iter_seq_start,
+	.next	= wakeup_source_iter_seq_next,
+	.stop	= wakeup_source_iter_seq_stop,
+	.show	= wakeup_source_iter_seq_show,
+};
+
+static const struct bpf_iter_seq_info wakeup_source_iter_seq_info = {
+	.seq_ops		= &wakeup_source_iter_seq_ops,
+	.seq_priv_size		= sizeof(int),
+};
+
+static struct bpf_iter_reg bpf_wakeup_source_reg_info = {
+	.target			= "wakeup_source",
+	.ctx_arg_info_size	= 1,
+	.ctx_arg_info		= {
+		{
+			offsetof(struct bpf_iter__wakeup_source, wakeup_source),
+			PTR_TO_BTF_ID_OR_NULL
+		},
+	},
+	.seq_info		= &wakeup_source_iter_seq_info,
+};
+
+DEFINE_BPF_ITER_FUNC(wakeup_source, struct bpf_iter_meta *meta,
+		     struct wakeup_source *wakeup_source)
+BTF_ID_LIST_SINGLE(bpf_wakeup_source_btf_id, struct, wakeup_source)
+
+static int __init wakeup_source_iter_init(void)
+{
+	bpf_wakeup_source_reg_info.ctx_arg_info[0].btf_id = bpf_wakeup_source_btf_id[0];
+	return bpf_iter_reg_target(&bpf_wakeup_source_reg_info);
+}
+
+late_initcall(wakeup_source_iter_init);
-- 
2.52.0.177.g9f829587af-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v1 2/4] bpf: Open coded BPF for wakeup_sources
  2025-12-04  2:49 [PATCH v1 0/4] bpf: Add wakeup_source iterators Samuel Wu
  2025-12-04  2:49 ` [PATCH v1 1/4] bpf: Add wakeup_source iterator Samuel Wu
@ 2025-12-04  2:49 ` Samuel Wu
  2025-12-04  2:50 ` [PATCH v1 3/4] selftests/bpf: Add tests " Samuel Wu
  2025-12-04  2:50 ` [PATCH v1 4/4] selftests/bpf: Open coded BPF wakeup_sources test Samuel Wu
  3 siblings, 0 replies; 7+ messages in thread
From: Samuel Wu @ 2025-12-04  2:49 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Shuah Khan
  Cc: rafael.j.wysocki, Samuel Wu, kernel-team, linux-kernel, bpf,
	linux-kselftest

Add open coded BPF iterators for wakeup_sources, which opens up more
options for BPF programs that need to traverse through wakeup_sources.

Signed-off-by: Samuel Wu <wusamuel@google.com>
---
 kernel/bpf/helpers.c            |  3 +++
 kernel/bpf/wakeup_source_iter.c | 34 +++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index db72b96f9c8c..a5f867de6bd6 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -4518,6 +4518,9 @@ BTF_ID_FLAGS(func, bpf_iter_dmabuf_new, KF_ITER_NEW | KF_SLEEPABLE)
 BTF_ID_FLAGS(func, bpf_iter_dmabuf_next, KF_ITER_NEXT | KF_RET_NULL | KF_SLEEPABLE)
 BTF_ID_FLAGS(func, bpf_iter_dmabuf_destroy, KF_ITER_DESTROY | KF_SLEEPABLE)
 #endif
+BTF_ID_FLAGS(func, bpf_iter_wakeup_source_new, KF_ITER_NEW | KF_SLEEPABLE)
+BTF_ID_FLAGS(func, bpf_iter_wakeup_source_next, KF_ITER_NEXT | KF_RET_NULL | KF_SLEEPABLE)
+BTF_ID_FLAGS(func, bpf_iter_wakeup_source_destroy, KF_ITER_DESTROY | KF_SLEEPABLE)
 BTF_ID_FLAGS(func, __bpf_trap)
 BTF_ID_FLAGS(func, bpf_strcmp);
 BTF_ID_FLAGS(func, bpf_strcasecmp);
diff --git a/kernel/bpf/wakeup_source_iter.c b/kernel/bpf/wakeup_source_iter.c
index b8719f47428e..e2c0dcbfd02d 100644
--- a/kernel/bpf/wakeup_source_iter.c
+++ b/kernel/bpf/wakeup_source_iter.c
@@ -90,6 +90,40 @@ static struct bpf_iter_reg bpf_wakeup_source_reg_info = {
 	.seq_info		= &wakeup_source_iter_seq_info,
 };
 
+struct bpf_iter_wakeup_source {
+	struct wakeup_source *ws;
+	int srcuidx;
+};
+
+__bpf_kfunc_start_defs();
+
+__bpf_kfunc int bpf_iter_wakeup_source_new(struct bpf_iter_wakeup_source *it)
+{
+	it->srcuidx = wakeup_sources_read_lock();
+	it->ws = wakeup_sources_walk_start();
+
+	return 0;
+}
+
+__bpf_kfunc struct wakeup_source *bpf_iter_wakeup_source_next(struct bpf_iter_wakeup_source *it)
+{
+	struct wakeup_source *prev = it->ws;
+
+	if (!prev)
+		return NULL;
+
+	it->ws = wakeup_sources_walk_next(it->ws);
+
+	return prev;
+}
+
+__bpf_kfunc void bpf_iter_wakeup_source_destroy(struct bpf_iter_wakeup_source *it)
+{
+	wakeup_sources_read_unlock(it->srcuidx);
+}
+
+__bpf_kfunc_end_defs();
+
 DEFINE_BPF_ITER_FUNC(wakeup_source, struct bpf_iter_meta *meta,
 		     struct wakeup_source *wakeup_source)
 BTF_ID_LIST_SINGLE(bpf_wakeup_source_btf_id, struct, wakeup_source)
-- 
2.52.0.177.g9f829587af-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v1 3/4] selftests/bpf: Add tests for wakeup_sources
  2025-12-04  2:49 [PATCH v1 0/4] bpf: Add wakeup_source iterators Samuel Wu
  2025-12-04  2:49 ` [PATCH v1 1/4] bpf: Add wakeup_source iterator Samuel Wu
  2025-12-04  2:49 ` [PATCH v1 2/4] bpf: Open coded BPF for wakeup_sources Samuel Wu
@ 2025-12-04  2:50 ` Samuel Wu
  2025-12-04  2:50 ` [PATCH v1 4/4] selftests/bpf: Open coded BPF wakeup_sources test Samuel Wu
  3 siblings, 0 replies; 7+ messages in thread
From: Samuel Wu @ 2025-12-04  2:50 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Shuah Khan
  Cc: rafael.j.wysocki, Samuel Wu, kernel-team, linux-kernel, bpf,
	linux-kselftest

Sets up the framework to test wakeup_sources iterators using BPF, and
adds a few basic tests.

Adds several helper functions that for grabbing and releasing a
wakelock, abstracting out key functions to setup a framework for testing
wakeup_sources.

Additionally, adds 3 tests:
1. check_active_count: Checks that stats related to active_count are
   properly set after several lock/unlock cycles
2. check_sleep_times: Checks that time accounting related to sleep are
   properly calculated
3. check_no_infinite_reads: Checks that the iterator traversal returns
   NULL at the end

Signed-off-by: Samuel Wu <wusamuel@google.com>
---
 tools/testing/selftests/bpf/config            |   1 +
 .../bpf/prog_tests/wakeup_source_iter.c       | 281 ++++++++++++++++++
 .../selftests/bpf/progs/wakeup_source_iter.c  |  70 +++++
 3 files changed, 352 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/wakeup_source_iter.c
 create mode 100644 tools/testing/selftests/bpf/progs/wakeup_source_iter.c

diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
index 558839e3c185..c12c5e04b81f 100644
--- a/tools/testing/selftests/bpf/config
+++ b/tools/testing/selftests/bpf/config
@@ -111,6 +111,7 @@ CONFIG_IP6_NF_IPTABLES=y
 CONFIG_IP6_NF_FILTER=y
 CONFIG_NF_NAT=y
 CONFIG_PACKET=y
+CONFIG_PM_WAKELOCKS=y
 CONFIG_RC_CORE=y
 CONFIG_SAMPLES=y
 CONFIG_SAMPLE_LIVEPATCH=m
diff --git a/tools/testing/selftests/bpf/prog_tests/wakeup_source_iter.c b/tools/testing/selftests/bpf/prog_tests/wakeup_source_iter.c
new file mode 100644
index 000000000000..5cea4d4458f3
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/wakeup_source_iter.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Google LLC */
+
+#include <test_progs.h>
+#include <bpf/libbpf.h>
+#include "wakeup_source_iter.skel.h"
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+/* Sleep for 10ms to ensure active time is > 0 after converting ns to ms*/
+#define TEST_SLEEP_US 10000
+#define TEST_SLEEP_MS (TEST_SLEEP_US / 1000)
+#define WAKEUP_SOURCE_NAME_LEN 32
+
+static const char test_ws_name[] = "bpf_selftest_ws";
+static bool test_ws_created;
+
+/*
+ * Creates a new wakeup source by writing to /sys/power/wake_lock.
+ * This lock persists until explicitly unlocked.
+ */
+static int lock_ws(const char *name)
+{
+	int fd;
+	ssize_t bytes;
+
+	fd = open("/sys/power/wake_lock", O_WRONLY);
+	if (!ASSERT_OK_FD(fd, "open /sys/power/wake_lock"))
+		return -1;
+
+	bytes = write(fd, name, strlen(name));
+	close(fd);
+	if (!ASSERT_EQ(bytes, strlen(name), "write to wake_lock"))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Destroys the ws by writing the same name to /sys/power/wake_unlock.
+ */
+static void unlock_ws(const char *name)
+{
+	int fd;
+
+	fd = open("/sys/power/wake_unlock", O_WRONLY);
+	if (!ASSERT_OK_FD(fd, "open /sys/power/wake_unlock"))
+		goto cleanup;
+
+	write(fd, name, strlen(name));
+
+cleanup:
+	if (fd)
+		close(fd);
+}
+
+/*
+ * Setups for testing ws iterators. Will run once prior to suite of tests.
+ */
+static int setup_test_ws(void)
+{
+	if (lock_ws(test_ws_name))
+		return -1;
+	test_ws_created = true;
+
+	return 0;
+}
+
+/*
+ * Tears down and cleanups testing ws iterators. WIll run once after the suite
+ * of tests.
+ */
+static void teardown_test_ws(void)
+{
+	if (!test_ws_created)
+		return;
+	unlock_ws(test_ws_name);
+	test_ws_created = false;
+}
+
+struct WakeupSourceInfo {
+	char name[WAKEUP_SOURCE_NAME_LEN];
+	unsigned long active_count;
+	long active_time_ms;
+	unsigned long event_count;
+	unsigned long expire_count;
+	long last_change_ms;
+	long max_time_ms;
+	long prevent_sleep_time_ms;
+	long total_time_ms;
+	unsigned long wakeup_count;
+};
+
+/*
+ * Reads and parses one wakeup_source record from the iterator file.
+ * A record is a single space-delimited line.
+ * Returns true on success, false on EOF. Asserts internally on errors.
+ */
+static bool read_ws_info(FILE *iter_file, struct WakeupSourceInfo *ws_info,
+			 char **line)
+{
+	size_t linesize;
+	int items;
+
+	if (getline(line, &linesize, iter_file) == -1)
+		return false;
+
+	(*line)[strcspn(*line, "\n")] = 0;
+
+	items = sscanf(*line, "%s %lu %ld %lu %lu %ld %ld %ld %ld %lu",
+		       ws_info->name, &ws_info->active_count,
+		       &ws_info->active_time_ms, &ws_info->event_count,
+		       &ws_info->expire_count, &ws_info->last_change_ms,
+		       &ws_info->max_time_ms, &ws_info->prevent_sleep_time_ms,
+		       &ws_info->total_time_ms, &ws_info->wakeup_count);
+
+	if (!ASSERT_EQ(items, 10, "read wakeup source info"))
+		return false;
+
+	if (!ASSERT_LT(strlen(ws_info->name), WAKEUP_SOURCE_NAME_LEN,
+		       "name length"))
+		return false;
+
+	return true;
+}
+
+static int get_ws_iter_stream(struct wakeup_source_iter *skel, int *iter_fd,
+			      FILE **iter_file)
+{
+	*iter_fd = bpf_iter_create(
+			bpf_link__fd(skel->links.wakeup_source_collector));
+	if (!ASSERT_OK_FD(*iter_fd, "iter_create"))
+		return -1;
+
+	*iter_file = fdopen(*iter_fd, "r");
+	if (!ASSERT_OK_PTR(*iter_file, "fdopen"))
+		return -1;
+
+	return 0;
+}
+
+static void subtest_ws_iter_check_active_count(struct wakeup_source_iter *skel)
+{
+	static const char subtest_ws_name[] = "bpf_selftest_ws_active_count";
+	const int lock_unlock_cycles = 5;
+	struct WakeupSourceInfo ws_info;
+	char *line = NULL;
+	bool found_ws = false;
+	FILE *iter_file = NULL;
+	int iter_fd = -1;
+	int i;
+
+	for (i = 0; i < lock_unlock_cycles; i++) {
+		if (!ASSERT_OK(lock_ws(subtest_ws_name), "lock_ws"))
+			goto cleanup;
+		unlock_ws(subtest_ws_name);
+	}
+
+	if (!get_ws_iter_stream(skel, &iter_fd, &iter_file))
+		goto cleanup;
+
+	while (read_ws_info(iter_file, &ws_info, &line)) {
+		if (strcmp(ws_info.name, subtest_ws_name) == 0) {
+			found_ws = true;
+			ASSERT_EQ(ws_info.active_count, lock_unlock_cycles,
+				  "active_count check");
+			ASSERT_EQ(ws_info.wakeup_count, lock_unlock_cycles,
+				  "wakeup_count check");
+			break;
+		}
+	}
+
+	ASSERT_TRUE(found_ws, "found active_count test ws");
+
+	free(line);
+cleanup:
+	if (iter_file)
+		fclose(iter_file);
+	else if (iter_fd >= 0)
+		close(iter_fd);
+}
+
+static void subtest_ws_iter_check_sleep_times(struct wakeup_source_iter *skel)
+{
+	bool found_test_ws = false;
+	struct WakeupSourceInfo ws_info;
+	char *line = NULL;
+	FILE *iter_file;
+	int iter_fd;
+
+	if (!get_ws_iter_stream(skel, &iter_fd, &iter_file))
+		goto cleanup;
+
+	while (read_ws_info(iter_file, &ws_info, &line)) {
+		if (strcmp(ws_info.name, test_ws_name) == 0) {
+			found_test_ws = true;
+			ASSERT_GT(ws_info.last_change_ms, 0,
+				  "Expected non-zero last change");
+			ASSERT_GE(ws_info.active_time_ms, TEST_SLEEP_MS,
+				  "Expected active time >= TEST_SLEEP_MS");
+			ASSERT_GE(ws_info.max_time_ms, TEST_SLEEP_MS,
+				  "Expected max time >= TEST_SLEEP_MS");
+			ASSERT_GE(ws_info.total_time_ms, TEST_SLEEP_MS,
+				  "Expected total time >= TEST_SLEEP_MS");
+			break;
+		}
+	}
+
+	ASSERT_TRUE(found_test_ws, "found_test_ws");
+
+	free(line);
+cleanup:
+	if (iter_file)
+		fclose(iter_file);
+	else if (iter_fd >= 0)
+		close(iter_fd);
+}
+
+static void subtest_ws_iter_check_no_infinite_reads(
+		struct wakeup_source_iter *skel)
+{
+	int iter_fd;
+	char buf[256];
+
+	iter_fd = bpf_iter_create(bpf_link__fd(skel->links.wakeup_source_collector));
+	if (!ASSERT_OK_FD(iter_fd, "iter_create"))
+		return;
+
+	while (read(iter_fd, buf, sizeof(buf)) > 0)
+		;
+
+	/* Final read should return 0 */
+	ASSERT_EQ(read(iter_fd, buf, sizeof(buf)), 0, "read");
+
+	close(iter_fd);
+}
+
+void test_wakeup_source_iter(void)
+{
+	struct wakeup_source_iter *skel = NULL;
+
+	if (geteuid() != 0) {
+		fprintf(stderr,
+			"Skipping wakeup_source_iter test, requires root\n");
+		test__skip();
+		return;
+	}
+
+	skel = wakeup_source_iter__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "wakeup_source_iter__open_and_load"))
+		return;
+
+	if (!ASSERT_OK(setup_test_ws(), "setup_test_ws"))
+		goto destroy;
+
+	if (!ASSERT_OK(wakeup_source_iter__attach(skel), "skel_attach"))
+		goto destroy;
+
+	/*
+	 * Sleep on O(ms) to ensure that time stats' resolution isn't lost when
+	 * converting from ns to ms
+	 */
+	usleep(TEST_SLEEP_US);
+
+	if (test__start_subtest("active_count"))
+		subtest_ws_iter_check_active_count(skel);
+	if (test__start_subtest("sleep_times"))
+		subtest_ws_iter_check_sleep_times(skel);
+	if (test__start_subtest("no_infinite_reads"))
+		subtest_ws_iter_check_no_infinite_reads(skel);
+
+destroy:
+	teardown_test_ws();
+	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
new file mode 100644
index 000000000000..8c1470f06740
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/wakeup_source_iter.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Google LLC */
+#include <vmlinux.h>
+#include <bpf/bpf_core_read.h>
+#include <bpf/bpf_helpers.h>
+
+#define NSEC_PER_MS 1000000UL
+#define WAKEUP_SOURCE_NAME_LEN 32
+
+char _license[] SEC("license") = "GPL";
+
+SEC("iter/wakeup_source")
+int wakeup_source_collector(struct bpf_iter__wakeup_source *ctx)
+{
+	const struct wakeup_source *ws = ctx->wakeup_source;
+	struct seq_file *seq = ctx->meta->seq;
+	char name[WAKEUP_SOURCE_NAME_LEN] = {'\0'};
+	const char *pname;
+	bool active, autosleep_enable;
+	u64 active_count, event_count, expire_count, wakeup_count;
+	s64 active_time, curr_time, last_change_time, max_time,
+	    prevent_sleep_time, start_prevent_time, total_time;
+
+	if (!ws)
+		return 0;
+
+	active = BPF_CORE_READ_BITFIELD_PROBED(ws, active);
+	autosleep_enable = BPF_CORE_READ_BITFIELD_PROBED(ws, autosleep_enabled);
+	if (bpf_core_read(&pname, sizeof(pname), &ws->name) ||
+	    bpf_probe_read_kernel_str(name, sizeof(name), pname) < 0 ||
+	    bpf_core_read(&active_count, sizeof(active_count), &ws->active_count) ||
+	    bpf_core_read(&event_count, sizeof(event_count), &ws->event_count) ||
+	    bpf_core_read(&expire_count, sizeof(expire_count), &ws->expire_count) ||
+	    bpf_core_read(&last_change_time, sizeof(last_change_time), &ws->last_time) ||
+	    bpf_core_read(&max_time, sizeof(max_time), &ws->max_time) ||
+	    bpf_core_read(
+		&prevent_sleep_time, sizeof(prevent_sleep_time), &ws->prevent_sleep_time) ||
+	    bpf_core_read(
+		&start_prevent_time, sizeof(start_prevent_time), &ws->start_prevent_time) ||
+	    bpf_core_read(&total_time, sizeof(total_time), &ws->total_time) ||
+	    bpf_core_read(&wakeup_count, sizeof(wakeup_count), &ws->wakeup_count))
+		return 0;
+
+
+	curr_time = bpf_ktime_get_ns();
+	active_time = 0;
+	if (active) {
+		active_time = curr_time - last_change_time;
+		total_time += active_time;
+		if (active_time > max_time)
+			max_time = active_time;
+		if (autosleep_enable)
+			prevent_sleep_time += curr_time - start_prevent_time;
+
+	}
+
+	BPF_SEQ_PRINTF(seq,
+		       "%s %lu %ld %lu %lu %ld %ld %ld %ld %lu\n",
+		       name,
+		       active_count,
+		       active_time / NSEC_PER_MS,
+		       event_count,
+		       expire_count,
+		       last_change_time / NSEC_PER_MS,
+		       max_time / NSEC_PER_MS,
+		       prevent_sleep_time / NSEC_PER_MS,
+		       total_time / NSEC_PER_MS,
+		       wakeup_count);
+	return 0;
+}
-- 
2.52.0.177.g9f829587af-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v1 4/4] selftests/bpf: Open coded BPF wakeup_sources test
  2025-12-04  2:49 [PATCH v1 0/4] bpf: Add wakeup_source iterators Samuel Wu
                   ` (2 preceding siblings ...)
  2025-12-04  2:50 ` [PATCH v1 3/4] selftests/bpf: Add tests " Samuel Wu
@ 2025-12-04  2:50 ` Samuel Wu
  3 siblings, 0 replies; 7+ messages in thread
From: Samuel Wu @ 2025-12-04  2:50 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Shuah Khan
  Cc: rafael.j.wysocki, Samuel Wu, kernel-team, linux-kernel, bpf,
	linux-kselftest

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 <wusamuel@google.com>
---
 .../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


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v1 1/4] bpf: Add wakeup_source iterator
  2025-12-04  2:49 ` [PATCH v1 1/4] bpf: Add wakeup_source iterator Samuel Wu
@ 2025-12-04 21:23   ` kernel test robot
  2025-12-05  3:17   ` kernel test robot
  1 sibling, 0 replies; 7+ messages in thread
From: kernel test robot @ 2025-12-04 21:23 UTC (permalink / raw)
  To: Samuel Wu, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Shuah Khan
  Cc: oe-kbuild-all, rafael.j.wysocki, Samuel Wu, kernel-team,
	linux-kernel, bpf, linux-kselftest

Hi Samuel,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/master]
[also build test ERROR on bpf/master shuah-kselftest/next shuah-kselftest/fixes linus/master v6.18 next-20251204]
[cannot apply to bpf-next/net]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Samuel-Wu/bpf-Add-wakeup_source-iterator/20251204-111108
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20251204025003.3162056-2-wusamuel%40google.com
patch subject: [PATCH v1 1/4] bpf: Add wakeup_source iterator
config: um-randconfig-001-20251205 (https://download.01.org/0day-ci/archive/20251205/202512050548.YLgRm659-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251205/202512050548.YLgRm659-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512050548.YLgRm659-lkp@intel.com/

All errors (new ones prefixed by >>):

   kernel/bpf/wakeup_source_iter.c: In function 'wakeup_source_iter_seq_start':
   kernel/bpf/wakeup_source_iter.c:20:20: error: implicit declaration of function 'wakeup_sources_read_lock'; did you mean 'wakeup_source_register'? [-Wimplicit-function-declaration]
      20 |         *srcuidx = wakeup_sources_read_lock();
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~
         |                    wakeup_source_register
   kernel/bpf/wakeup_source_iter.c:22:14: error: implicit declaration of function 'wakeup_sources_walk_start'; did you mean 'wakeup_source_register'? [-Wimplicit-function-declaration]
      22 |         ws = wakeup_sources_walk_start();
         |              ^~~~~~~~~~~~~~~~~~~~~~~~~
         |              wakeup_source_register
>> kernel/bpf/wakeup_source_iter.c:22:12: error: assignment to 'struct wakeup_source *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      22 |         ws = wakeup_sources_walk_start();
         |            ^
   kernel/bpf/wakeup_source_iter.c:24:22: error: implicit declaration of function 'wakeup_sources_walk_next' [-Wimplicit-function-declaration]
      24 |                 ws = wakeup_sources_walk_next(ws);
         |                      ^~~~~~~~~~~~~~~~~~~~~~~~
   kernel/bpf/wakeup_source_iter.c:24:20: error: assignment to 'struct wakeup_source *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      24 |                 ws = wakeup_sources_walk_next(ws);
         |                    ^
   kernel/bpf/wakeup_source_iter.c: In function 'wakeup_source_iter_seq_next':
>> kernel/bpf/wakeup_source_iter.c:35:16: error: returning 'int' from a function with return type 'void *' makes pointer from integer without a cast [-Wint-conversion]
      35 |         return wakeup_sources_walk_next(ws);
         |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   kernel/bpf/wakeup_source_iter.c: In function 'wakeup_source_iter_seq_stop':
   kernel/bpf/wakeup_source_iter.c:43:17: error: implicit declaration of function 'wakeup_sources_read_unlock' [-Wimplicit-function-declaration]
      43 |                 wakeup_sources_read_unlock(*srcuidx);
         |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~


vim +22 kernel/bpf/wakeup_source_iter.c

    13	
    14	static void *wakeup_source_iter_seq_start(struct seq_file *seq, loff_t *pos)
    15	{
    16		int *srcuidx = seq->private;
    17		struct wakeup_source *ws;
    18		loff_t i;
    19	
    20		*srcuidx = wakeup_sources_read_lock();
    21	
  > 22		ws = wakeup_sources_walk_start();
    23		for (i = 0; ws && i < *pos; i++)
    24			ws = wakeup_sources_walk_next(ws);
    25	
    26		return ws;
    27	}
    28	
    29	static void *wakeup_source_iter_seq_next(struct seq_file *seq, void *v, loff_t *pos)
    30	{
    31		struct wakeup_source *ws = v;
    32	
    33		++*pos;
    34	
  > 35		return wakeup_sources_walk_next(ws);
    36	}
    37	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v1 1/4] bpf: Add wakeup_source iterator
  2025-12-04  2:49 ` [PATCH v1 1/4] bpf: Add wakeup_source iterator Samuel Wu
  2025-12-04 21:23   ` kernel test robot
@ 2025-12-05  3:17   ` kernel test robot
  1 sibling, 0 replies; 7+ messages in thread
From: kernel test robot @ 2025-12-05  3:17 UTC (permalink / raw)
  To: Samuel Wu, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Shuah Khan
  Cc: oe-kbuild-all, rafael.j.wysocki, Samuel Wu, kernel-team,
	linux-kernel, bpf, linux-kselftest

Hi Samuel,

kernel test robot noticed the following build errors:

[auto build test ERROR on bpf-next/master]
[also build test ERROR on bpf/master shuah-kselftest/next shuah-kselftest/fixes linus/master v6.18 next-20251204]
[cannot apply to bpf-next/net]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Samuel-Wu/bpf-Add-wakeup_source-iterator/20251204-111108
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20251204025003.3162056-2-wusamuel%40google.com
patch subject: [PATCH v1 1/4] bpf: Add wakeup_source iterator
config: um-randconfig-r052-20251205 (https://download.01.org/0day-ci/archive/20251205/202512051019.IljjrKRb-lkp@intel.com/config)
compiler: gcc-13 (Debian 13.3.0-16) 13.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251205/202512051019.IljjrKRb-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512051019.IljjrKRb-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   kernel/bpf/wakeup_source_iter.c: In function 'wakeup_source_iter_seq_start':
>> kernel/bpf/wakeup_source_iter.c:20:20: error: implicit declaration of function 'wakeup_sources_read_lock'; did you mean 'wakeup_source_register'? [-Werror=implicit-function-declaration]
      20 |         *srcuidx = wakeup_sources_read_lock();
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~
         |                    wakeup_source_register
>> kernel/bpf/wakeup_source_iter.c:22:14: error: implicit declaration of function 'wakeup_sources_walk_start'; did you mean 'wakeup_source_register'? [-Werror=implicit-function-declaration]
      22 |         ws = wakeup_sources_walk_start();
         |              ^~~~~~~~~~~~~~~~~~~~~~~~~
         |              wakeup_source_register
>> kernel/bpf/wakeup_source_iter.c:22:12: warning: assignment to 'struct wakeup_source *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      22 |         ws = wakeup_sources_walk_start();
         |            ^
>> kernel/bpf/wakeup_source_iter.c:24:22: error: implicit declaration of function 'wakeup_sources_walk_next' [-Werror=implicit-function-declaration]
      24 |                 ws = wakeup_sources_walk_next(ws);
         |                      ^~~~~~~~~~~~~~~~~~~~~~~~
   kernel/bpf/wakeup_source_iter.c:24:20: warning: assignment to 'struct wakeup_source *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      24 |                 ws = wakeup_sources_walk_next(ws);
         |                    ^
   kernel/bpf/wakeup_source_iter.c: In function 'wakeup_source_iter_seq_next':
>> kernel/bpf/wakeup_source_iter.c:35:16: warning: returning 'int' from a function with return type 'void *' makes pointer from integer without a cast [-Wint-conversion]
      35 |         return wakeup_sources_walk_next(ws);
         |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   kernel/bpf/wakeup_source_iter.c: In function 'wakeup_source_iter_seq_stop':
>> kernel/bpf/wakeup_source_iter.c:43:17: error: implicit declaration of function 'wakeup_sources_read_unlock' [-Werror=implicit-function-declaration]
      43 |                 wakeup_sources_read_unlock(*srcuidx);
         |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +20 kernel/bpf/wakeup_source_iter.c

    13	
    14	static void *wakeup_source_iter_seq_start(struct seq_file *seq, loff_t *pos)
    15	{
    16		int *srcuidx = seq->private;
    17		struct wakeup_source *ws;
    18		loff_t i;
    19	
  > 20		*srcuidx = wakeup_sources_read_lock();
    21	
  > 22		ws = wakeup_sources_walk_start();
    23		for (i = 0; ws && i < *pos; i++)
  > 24			ws = wakeup_sources_walk_next(ws);
    25	
    26		return ws;
    27	}
    28	
    29	static void *wakeup_source_iter_seq_next(struct seq_file *seq, void *v, loff_t *pos)
    30	{
    31		struct wakeup_source *ws = v;
    32	
    33		++*pos;
    34	
  > 35		return wakeup_sources_walk_next(ws);
    36	}
    37	
    38	static void wakeup_source_iter_seq_stop(struct seq_file *seq, void *v)
    39	{
    40		int *srcuidx = seq->private;
    41	
    42		if (*srcuidx >= 0)
  > 43			wakeup_sources_read_unlock(*srcuidx);
    44		*srcuidx = -1;
    45	}
    46	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-12-05  3:17 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-04  2:49 [PATCH v1 0/4] bpf: Add wakeup_source iterators Samuel Wu
2025-12-04  2:49 ` [PATCH v1 1/4] bpf: Add wakeup_source iterator Samuel Wu
2025-12-04 21:23   ` kernel test robot
2025-12-05  3:17   ` kernel test robot
2025-12-04  2:49 ` [PATCH v1 2/4] bpf: Open coded BPF for wakeup_sources Samuel Wu
2025-12-04  2:50 ` [PATCH v1 3/4] selftests/bpf: Add tests " Samuel Wu
2025-12-04  2:50 ` [PATCH v1 4/4] selftests/bpf: Open coded BPF wakeup_sources test Samuel Wu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox