* [PATCH v2 0/2] Support BPF traversal of wakeup sources
@ 2026-03-26 11:25 Samuel Wu
2026-03-26 11:25 ` [PATCH v2 1/2] PM: wakeup: Add kfuncs to traverse over wakeup_sources Samuel Wu
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Samuel Wu @ 2026-03-26 11:25 UTC (permalink / raw)
To: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, 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: memxor, Samuel Wu, kernel-team, linux-kernel, linux-pm,
driver-core, bpf, linux-kselftest
This patchset adds requisite kfuncs for BPF programs to safely traverse
wakeup_sources, and puts a config flag around the sysfs interface.
Currently, a traversal of wakeup sources require going through
/sys/class/wakeup/* or /d/wakeup_sources/*. The repeated syscalls to query
sysfs is inefficient, as there can be hundreds of wakeup_sources, with each
wakeup source also having multiple attributes. debugfs is unstable and
insecure.
Adding kfuncs to lock/unlock wakeup sources allows BPF program to safely
traverse the wakeup sources list. The head address of wakeup_sources can
safely be resolved through BPF helper functions or variable attributes.
On a quiescent Pixel 6 traversing 150 wakeup_sources, I am seeing ~34x
speedup (sampled 75 times in table below). For a device under load, the
speedup is greater.
+-------+----+----------+----------+
| | n | AVG (ms) | STD (ms) |
+-------+----+----------+----------+
| sysfs | 75 | 44.9 | 12.6 |
+-------+----+----------+----------+
| BPF | 75 | 1.3 | 0.7 |
+-------+----+----------+----------+
The initial attempts for BPF traversal of wakeup_sources was with BPF
iterators [1]. However, BPF already allows for traversing of a simple list
with bpf_for(), and this current patchset has the added benefit of being
~2-3x more performant than BPF iterators.
[1]: https://lore.kernel.org/all/20260225210820.177674-1-wusamuel@google.com/
Changes in v2:
- Dropped CONFIG_PM_WAKEUP_STATS_SYSFS patch for future patchset
- Added declarations for kfuncs to .h to fix sparse and checkpatch warnings
- Added kfunc to get address of wakeup_source's head
- Added example bpf prog selftest for traversal of wakeup sources per Kumar
- Added *_fail.c selftest per Kumar
- More concise commit message in patch 1/2
- v1 link: https://lore.kernel.org/all/20260320160055.4114055-1-wusamuel@google.com/
Samuel Wu (2):
PM: wakeup: Add kfuncs to traverse over wakeup_sources
selftests/bpf: Add tests for wakeup_sources kfuncs
drivers/base/power/power.h | 7 ++
drivers/base/power/wakeup.c | 72 +++++++++++-
tools/testing/selftests/bpf/config | 3 +-
.../selftests/bpf/prog_tests/wakeup_source.c | 101 +++++++++++++++++
.../selftests/bpf/progs/test_wakeup_source.c | 107 ++++++++++++++++++
.../selftests/bpf/progs/wakeup_source.h | 22 ++++
.../selftests/bpf/progs/wakeup_source_fail.c | 63 +++++++++++
7 files changed, 372 insertions(+), 3 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/wakeup_source.c
create mode 100644 tools/testing/selftests/bpf/progs/test_wakeup_source.c
create mode 100644 tools/testing/selftests/bpf/progs/wakeup_source.h
create mode 100644 tools/testing/selftests/bpf/progs/wakeup_source_fail.c
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/2] PM: wakeup: Add kfuncs to traverse over wakeup_sources
2026-03-26 11:25 [PATCH v2 0/2] Support BPF traversal of wakeup sources Samuel Wu
@ 2026-03-26 11:25 ` Samuel Wu
2026-03-26 11:59 ` Puranjay Mohan
2026-03-26 11:25 ` [PATCH v2 2/2] selftests/bpf: Add tests for wakeup_sources kfuncs Samuel Wu
2026-03-26 12:20 ` [PATCH v2 0/2] Support BPF traversal of wakeup sources Puranjay Mohan
2 siblings, 1 reply; 9+ messages in thread
From: Samuel Wu @ 2026-03-26 11:25 UTC (permalink / raw)
To: Rafael J. Wysocki, Len Brown, Pavel Machek, Greg Kroah-Hartman,
Danilo Krummrich, 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: memxor, Samuel Wu, kernel-team, linux-kernel, linux-pm,
driver-core, bpf, linux-kselftest
Iterating through wakeup sources via sysfs or debugfs can be inefficient
or restricted. Introduce BPF kfuncs to allow high-performance and safe
in-kernel traversal of the wakeup_sources list.
The new kfuncs include:
- bpf_wakeup_sources_get_head() to obtain the list head.
- bpf_wakeup_sources_read_lock/unlock() to manage the SRCU lock.
For verifier safety, the underlying SRCU index is wrapped in an opaque
'struct bpf_ws_lock' pointer. This enables the use of KF_ACQUIRE and
KF_RELEASE flags, allowing the BPF verifier to strictly enforce paired
lock/unlock cycles and prevent resource leaks.
Signed-off-by: Samuel Wu <wusamuel@google.com>
---
drivers/base/power/power.h | 7 ++++
drivers/base/power/wakeup.c | 72 +++++++++++++++++++++++++++++++++++--
2 files changed, 77 insertions(+), 2 deletions(-)
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 922ed457db19..ced563286ac5 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -168,3 +168,10 @@ static inline void device_pm_init(struct device *dev)
device_pm_sleep_init(dev);
pm_runtime_init(dev);
}
+
+#ifdef CONFIG_BPF_SYSCALL
+struct bpf_ws_lock { };
+struct bpf_ws_lock *bpf_wakeup_sources_read_lock(void);
+void bpf_wakeup_sources_read_unlock(struct bpf_ws_lock *lock);
+struct list_head *bpf_wakeup_sources_get_head(void);
+#endif
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index b8e48a023bf0..27a26a30b6ee 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -1168,11 +1168,79 @@ static const struct file_operations wakeup_sources_stats_fops = {
.release = seq_release_private,
};
-static int __init wakeup_sources_debugfs_init(void)
+#ifdef CONFIG_BPF_SYSCALL
+#include <linux/btf.h>
+
+__bpf_kfunc_start_defs();
+
+/**
+ * bpf_wakeup_sources_read_lock - Acquire the SRCU lock for wakeup sources
+ *
+ * The underlying SRCU lock returns an integer index. However, the BPF verifier
+ * requires a pointer (PTR_TO_BTF_ID) to strictly track the state of acquired
+ * resources using KF_ACQUIRE and KF_RELEASE semantics. We use an opaque
+ * structure pointer (struct bpf_ws_lock *) to satisfy the verifier while
+ * safely encoding the integer index within the pointer address itself.
+ *
+ * Return: An opaque pointer encoding the SRCU lock index + 1 (to avoid NULL).
+ */
+__bpf_kfunc struct bpf_ws_lock *bpf_wakeup_sources_read_lock(void)
+{
+ return (struct bpf_ws_lock *)(long)(wakeup_sources_read_lock() + 1);
+}
+
+/**
+ * bpf_wakeup_sources_read_unlock - Release the SRCU lock for wakeup sources
+ * @lock: The opaque pointer returned by bpf_wakeup_sources_read_lock()
+ *
+ * The BPF verifier guarantees that @lock is a valid, unreleased pointer from
+ * the acquire function. We decode the pointer back into the integer SRCU index
+ * by subtracting 1 and release the lock.
+ */
+__bpf_kfunc void bpf_wakeup_sources_read_unlock(struct bpf_ws_lock *lock)
+{
+ wakeup_sources_read_unlock((int)(long)lock - 1);
+}
+
+/**
+ * bpf_wakeup_sources_get_head - Get the head of the wakeup sources list
+ *
+ * Return: The head of the wakeup sources list.
+ */
+__bpf_kfunc struct list_head *bpf_wakeup_sources_get_head(void)
+{
+ return &wakeup_sources;
+}
+
+__bpf_kfunc_end_defs();
+
+BTF_KFUNCS_START(wakeup_source_kfunc_ids)
+BTF_ID_FLAGS(func, bpf_wakeup_sources_read_lock, KF_ACQUIRE)
+BTF_ID_FLAGS(func, bpf_wakeup_sources_read_unlock, KF_RELEASE)
+BTF_ID_FLAGS(func, bpf_wakeup_sources_get_head)
+BTF_KFUNCS_END(wakeup_source_kfunc_ids)
+
+static const struct btf_kfunc_id_set wakeup_source_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &wakeup_source_kfunc_ids,
+};
+
+static void __init wakeup_sources_bpf_init(void)
+{
+ if (register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &wakeup_source_kfunc_set))
+ pm_pr_dbg("Wakeup: failed to register BTF kfuncs\n");
+}
+#else
+static inline void wakeup_sources_bpf_init(void) {}
+#endif /* CONFIG_BPF_SYSCALL */
+
+static int __init wakeup_sources_init(void)
{
debugfs_create_file("wakeup_sources", 0444, NULL, NULL,
&wakeup_sources_stats_fops);
+ wakeup_sources_bpf_init();
+
return 0;
}
-postcore_initcall(wakeup_sources_debugfs_init);
+postcore_initcall(wakeup_sources_init);
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] selftests/bpf: Add tests for wakeup_sources kfuncs
2026-03-26 11:25 [PATCH v2 0/2] Support BPF traversal of wakeup sources Samuel Wu
2026-03-26 11:25 ` [PATCH v2 1/2] PM: wakeup: Add kfuncs to traverse over wakeup_sources Samuel Wu
@ 2026-03-26 11:25 ` Samuel Wu
2026-03-26 12:20 ` [PATCH v2 0/2] Support BPF traversal of wakeup sources Puranjay Mohan
2 siblings, 0 replies; 9+ messages in thread
From: Samuel Wu @ 2026-03-26 11:25 UTC (permalink / raw)
To: Rafael J. Wysocki, Pavel Machek, Len Brown, Greg Kroah-Hartman,
Danilo Krummrich, 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: memxor, Samuel Wu, kernel-team, linux-kernel, linux-pm,
driver-core, bpf, linux-kselftest
Introduce a set of BPF selftests to verify the safety and functionality
of wakeup_source kfuncs.
The suite includes:
1. A functional test (test_wakeup_source.c) that iterates over the
global wakeup_sources list. It uses CO-RE to read timing statistics
and validates them in user-space via the BPF ring buffer.
2. A negative test suite (wakeup_source_fail.c) ensuring the BPF
verifier correctly enforces reference tracking and type safety.
3. Enable CONFIG_PM_WAKELOCKS in the test config, allowing creation of
wakeup sources via /sys/power/wake_lock.
A shared header (wakeup_source.h) is introduced to ensure consistent
memory layout for the Ring Buffer data between BPF and user-space.
Signed-off-by: Samuel Wu <wusamuel@google.com>
---
tools/testing/selftests/bpf/config | 3 +-
.../selftests/bpf/prog_tests/wakeup_source.c | 101 +++++++++++++++++
.../selftests/bpf/progs/test_wakeup_source.c | 107 ++++++++++++++++++
.../selftests/bpf/progs/wakeup_source.h | 22 ++++
.../selftests/bpf/progs/wakeup_source_fail.c | 63 +++++++++++
5 files changed, 295 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/wakeup_source.c
create mode 100644 tools/testing/selftests/bpf/progs/test_wakeup_source.c
create mode 100644 tools/testing/selftests/bpf/progs/wakeup_source.h
create mode 100644 tools/testing/selftests/bpf/progs/wakeup_source_fail.c
diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
index 24855381290d..bac60b444551 100644
--- a/tools/testing/selftests/bpf/config
+++ b/tools/testing/selftests/bpf/config
@@ -130,4 +130,5 @@ CONFIG_INFINIBAND=y
CONFIG_SMC=y
CONFIG_SMC_HS_CTRL_BPF=y
CONFIG_DIBS=y
-CONFIG_DIBS_LO=y
\ No newline at end of file
+CONFIG_DIBS_LO=y
+CONFIG_PM_WAKELOCKS=y
diff --git a/tools/testing/selftests/bpf/prog_tests/wakeup_source.c b/tools/testing/selftests/bpf/prog_tests/wakeup_source.c
new file mode 100644
index 000000000000..ff2899cbf3a8
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/wakeup_source.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2026 Google LLC */
+
+#include <test_progs.h>
+#include <fcntl.h>
+#include "test_wakeup_source.skel.h"
+#include "wakeup_source_fail.skel.h"
+#include "progs/wakeup_source.h"
+
+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;
+}
+
+static void unlock_ws(const char *name)
+{
+ int fd;
+
+ fd = open("/sys/power/wake_unlock", O_WRONLY);
+ if (fd < 0)
+ return;
+
+ write(fd, name, strlen(name));
+ close(fd);
+}
+
+struct rb_ctx {
+ const char *name;
+ bool found;
+ long long active_time_ns;
+ long long total_time_ns;
+};
+
+static int process_sample(void *ctx, void *data, size_t len)
+{
+ struct rb_ctx *rb_ctx = ctx;
+ struct wakeup_event_t *e = data;
+
+ if (strcmp(e->name, rb_ctx->name) == 0) {
+ rb_ctx->found = true;
+ rb_ctx->active_time_ns = e->active_time_ns;
+ rb_ctx->total_time_ns = e->total_time_ns;
+ }
+ return 0;
+}
+
+void test_wakeup_source(void)
+{
+ if (test__start_subtest("iterate_and_verify_times")) {
+ struct test_wakeup_source *skel;
+ struct ring_buffer *rb = NULL;
+ struct rb_ctx rb_ctx = {
+ .name = "bpf_selftest_ws_times",
+ .found = false,
+ };
+ int err;
+
+ skel = test_wakeup_source__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
+ return;
+
+ rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), process_sample, &rb_ctx, NULL);
+ if (!ASSERT_OK_PTR(rb, "ring_buffer__new"))
+ goto destroy;
+
+ /* Create a temporary wakeup source */
+ if (!ASSERT_OK(lock_ws(rb_ctx.name), "lock_ws"))
+ goto unlock;
+
+ err = bpf_prog_test_run_opts(bpf_program__fd(
+ skel->progs.iterate_wakeupsources), NULL);
+ ASSERT_OK(err, "bpf_prog_test_run");
+
+ ring_buffer__consume(rb);
+
+ ASSERT_TRUE(rb_ctx.found, "found_test_ws_in_rb");
+ ASSERT_GT(rb_ctx.active_time_ns, 0, "active_time_gt_0");
+ ASSERT_GT(rb_ctx.total_time_ns, 0, "total_time_gt_0");
+
+unlock:
+ unlock_ws(rb_ctx.name);
+destroy:
+ if (rb)
+ ring_buffer__free(rb);
+ test_wakeup_source__destroy(skel);
+ }
+
+ RUN_TESTS(wakeup_source_fail);
+}
diff --git a/tools/testing/selftests/bpf/progs/test_wakeup_source.c b/tools/testing/selftests/bpf/progs/test_wakeup_source.c
new file mode 100644
index 000000000000..fa35156e31d2
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_wakeup_source.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2026 Google LLC */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+#include "bpf_experimental.h"
+#include "bpf_misc.h"
+#include "wakeup_source.h"
+
+#define MAX_LOOP_ITER 1000
+#define RB_SIZE (16384 * 4)
+
+struct wakeup_source___local {
+ const char *name;
+ unsigned long active_count;
+ unsigned long event_count;
+ unsigned long wakeup_count;
+ unsigned long expire_count;
+ ktime_t last_time;
+ ktime_t max_time;
+ ktime_t total_time;
+ ktime_t start_prevent_time;
+ ktime_t prevent_sleep_time;
+ struct list_head entry;
+ bool active:1;
+ bool autosleep_enabled:1;
+} __attribute__((preserve_access_index));
+
+struct {
+ __uint(type, BPF_MAP_TYPE_RINGBUF);
+ __uint(max_entries, RB_SIZE);
+} rb SEC(".maps");
+
+struct bpf_ws_lock;
+struct bpf_ws_lock *bpf_wakeup_sources_read_lock(void) __ksym;
+void bpf_wakeup_sources_read_unlock(struct bpf_ws_lock *lock) __ksym;
+struct list_head *bpf_wakeup_sources_get_head(void) __ksym;
+
+SEC("syscall")
+__success __retval(0)
+int iterate_wakeupsources(void *ctx)
+{
+ struct list_head *head = bpf_wakeup_sources_get_head();
+ struct list_head *pos = head;
+ struct bpf_ws_lock *lock;
+ int i;
+
+ lock = bpf_wakeup_sources_read_lock();
+ if (!lock)
+ return 0;
+
+ bpf_for(i, 0, MAX_LOOP_ITER) {
+ if (bpf_core_read(&pos, sizeof(pos), &pos->next) || !pos || pos == head)
+ break;
+
+ struct wakeup_event_t *e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
+
+ if (!e)
+ break;
+
+ struct wakeup_source___local *ws = container_of(
+ pos, struct wakeup_source___local, entry);
+ s64 active_time = 0;
+ bool active = BPF_CORE_READ_BITFIELD_PROBED(ws, active);
+ bool autosleep_enable = BPF_CORE_READ_BITFIELD_PROBED(ws, autosleep_enabled);
+ s64 last_time = BPF_CORE_READ(ws, last_time);
+ s64 max_time = BPF_CORE_READ(ws, max_time);
+ s64 prevent_sleep_time = BPF_CORE_READ(ws, prevent_sleep_time);
+ s64 total_time = BPF_CORE_READ(ws, total_time);
+
+ if (active) {
+ s64 curr_time = bpf_ktime_get_ns();
+ s64 prevent_time = BPF_CORE_READ(ws, start_prevent_time);
+
+ if (curr_time > last_time)
+ active_time = curr_time - last_time;
+
+ total_time += active_time;
+ if (active_time > max_time)
+ max_time = active_time;
+ if (autosleep_enable && curr_time > prevent_time)
+ prevent_sleep_time += curr_time - prevent_time;
+ }
+
+ e->active_count = BPF_CORE_READ(ws, active_count);
+ e->active_time_ns = active_time;
+ e->event_count = BPF_CORE_READ(ws, event_count);
+ e->expire_count = BPF_CORE_READ(ws, expire_count);
+ e->last_time_ns = last_time;
+ e->max_time_ns = max_time;
+ e->prevent_sleep_time_ns = prevent_sleep_time;
+ e->total_time_ns = total_time;
+ e->wakeup_count = BPF_CORE_READ(ws, wakeup_count);
+
+ if (bpf_probe_read_kernel_str(
+ e->name, WAKEUP_NAME_LEN, BPF_CORE_READ(ws, name)) < 0)
+ e->name[0] = '\0';
+
+ bpf_ringbuf_submit(e, 0);
+ }
+
+ bpf_wakeup_sources_read_unlock(lock);
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/wakeup_source.h b/tools/testing/selftests/bpf/progs/wakeup_source.h
new file mode 100644
index 000000000000..cd74de92c82f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/wakeup_source.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2026 Google LLC */
+
+#ifndef __WAKEUP_SOURCE_H__
+#define __WAKEUP_SOURCE_H__
+
+#define WAKEUP_NAME_LEN 128
+
+struct wakeup_event_t {
+ unsigned long active_count;
+ long long active_time_ns;
+ unsigned long event_count;
+ unsigned long expire_count;
+ long long last_time_ns;
+ long long max_time_ns;
+ long long prevent_sleep_time_ns;
+ long long total_time_ns;
+ unsigned long wakeup_count;
+ char name[WAKEUP_NAME_LEN];
+};
+
+#endif /* __WAKEUP_SOURCE_H__ */
diff --git a/tools/testing/selftests/bpf/progs/wakeup_source_fail.c b/tools/testing/selftests/bpf/progs/wakeup_source_fail.c
new file mode 100644
index 000000000000..a569c9d53d21
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/wakeup_source_fail.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2026 Google LLC */
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+struct bpf_ws_lock;
+
+struct bpf_ws_lock *bpf_wakeup_sources_read_lock(void) __ksym;
+void bpf_wakeup_sources_read_unlock(struct bpf_ws_lock *lock) __ksym;
+
+SEC("syscall")
+__failure __msg("BPF_EXIT instruction in main prog would lead to reference leak")
+int wakeup_source_lock_no_unlock(void *ctx)
+{
+ struct bpf_ws_lock *lock;
+
+ lock = bpf_wakeup_sources_read_lock();
+ if (!lock)
+ return 0;
+
+ return 0;
+}
+
+SEC("syscall")
+__failure __msg("access beyond struct")
+int wakeup_source_access_lock_fields(void *ctx)
+{
+ struct bpf_ws_lock *lock;
+ int val;
+
+ lock = bpf_wakeup_sources_read_lock();
+ if (!lock)
+ return 0;
+
+ val = *(int *)lock;
+
+ bpf_wakeup_sources_read_unlock(lock);
+ return val;
+}
+
+SEC("syscall")
+__failure __msg("type=scalar expected=fp")
+int wakeup_source_unlock_no_lock(void *ctx)
+{
+ struct bpf_ws_lock *lock = (void *)0x1;
+
+ bpf_wakeup_sources_read_unlock(lock);
+
+ return 0;
+}
+
+SEC("syscall")
+__failure __msg("Possibly NULL pointer passed to trusted arg0")
+int wakeup_source_unlock_null(void *ctx)
+{
+ bpf_wakeup_sources_read_unlock(NULL);
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/2] PM: wakeup: Add kfuncs to traverse over wakeup_sources
2026-03-26 11:25 ` [PATCH v2 1/2] PM: wakeup: Add kfuncs to traverse over wakeup_sources Samuel Wu
@ 2026-03-26 11:59 ` Puranjay Mohan
0 siblings, 0 replies; 9+ messages in thread
From: Puranjay Mohan @ 2026-03-26 11:59 UTC (permalink / raw)
To: Samuel Wu, Rafael J. Wysocki, Len Brown, Pavel Machek,
Greg Kroah-Hartman, Danilo Krummrich, 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: memxor, Samuel Wu, kernel-team, linux-kernel, linux-pm,
driver-core, bpf, linux-kselftest
Samuel Wu <wusamuel@google.com> writes:
> Iterating through wakeup sources via sysfs or debugfs can be inefficient
> or restricted. Introduce BPF kfuncs to allow high-performance and safe
> in-kernel traversal of the wakeup_sources list.
>
> The new kfuncs include:
> - bpf_wakeup_sources_get_head() to obtain the list head.
> - bpf_wakeup_sources_read_lock/unlock() to manage the SRCU lock.
>
> For verifier safety, the underlying SRCU index is wrapped in an opaque
> 'struct bpf_ws_lock' pointer. This enables the use of KF_ACQUIRE and
> KF_RELEASE flags, allowing the BPF verifier to strictly enforce paired
> lock/unlock cycles and prevent resource leaks.
>
> Signed-off-by: Samuel Wu <wusamuel@google.com>
> ---
> drivers/base/power/power.h | 7 ++++
> drivers/base/power/wakeup.c | 72 +++++++++++++++++++++++++++++++++++--
> 2 files changed, 77 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
> index 922ed457db19..ced563286ac5 100644
> --- a/drivers/base/power/power.h
> +++ b/drivers/base/power/power.h
> @@ -168,3 +168,10 @@ static inline void device_pm_init(struct device *dev)
> device_pm_sleep_init(dev);
> pm_runtime_init(dev);
> }
> +
> +#ifdef CONFIG_BPF_SYSCALL
> +struct bpf_ws_lock { };
> +struct bpf_ws_lock *bpf_wakeup_sources_read_lock(void);
> +void bpf_wakeup_sources_read_unlock(struct bpf_ws_lock *lock);
> +struct list_head *bpf_wakeup_sources_get_head(void);
> +#endif
> diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
> index b8e48a023bf0..27a26a30b6ee 100644
> --- a/drivers/base/power/wakeup.c
> +++ b/drivers/base/power/wakeup.c
> @@ -1168,11 +1168,79 @@ static const struct file_operations wakeup_sources_stats_fops = {
> .release = seq_release_private,
> };
>
> -static int __init wakeup_sources_debugfs_init(void)
> +#ifdef CONFIG_BPF_SYSCALL
> +#include <linux/btf.h>
> +
> +__bpf_kfunc_start_defs();
> +
> +/**
> + * bpf_wakeup_sources_read_lock - Acquire the SRCU lock for wakeup sources
> + *
> + * The underlying SRCU lock returns an integer index. However, the BPF verifier
> + * requires a pointer (PTR_TO_BTF_ID) to strictly track the state of acquired
> + * resources using KF_ACQUIRE and KF_RELEASE semantics. We use an opaque
> + * structure pointer (struct bpf_ws_lock *) to satisfy the verifier while
> + * safely encoding the integer index within the pointer address itself.
> + *
> + * Return: An opaque pointer encoding the SRCU lock index + 1 (to avoid NULL).
> + */
> +__bpf_kfunc struct bpf_ws_lock *bpf_wakeup_sources_read_lock(void)
> +{
> + return (struct bpf_ws_lock *)(long)(wakeup_sources_read_lock() + 1);
> +}
> +
> +/**
> + * bpf_wakeup_sources_read_unlock - Release the SRCU lock for wakeup sources
> + * @lock: The opaque pointer returned by bpf_wakeup_sources_read_lock()
> + *
> + * The BPF verifier guarantees that @lock is a valid, unreleased pointer from
> + * the acquire function. We decode the pointer back into the integer SRCU index
> + * by subtracting 1 and release the lock.
> + */
> +__bpf_kfunc void bpf_wakeup_sources_read_unlock(struct bpf_ws_lock *lock)
> +{
> + wakeup_sources_read_unlock((int)(long)lock - 1);
> +}
> +
> +/**
> + * bpf_wakeup_sources_get_head - Get the head of the wakeup sources list
> + *
> + * Return: The head of the wakeup sources list.
> + */
> +__bpf_kfunc struct list_head *bpf_wakeup_sources_get_head(void)
> +{
> + return &wakeup_sources;
> +}
What stops a bpf program from using this kfunc to get the wakeup_sources
pointer and iterating this list without taking the srcu lock?
An open-coded iterator would solve this by internalizing the lock:
// Iterator new() acquires SRCU lock
// Iterator next() returns next wakeup_source
// Iterator destroy() releases SRCU lock
> +
> +__bpf_kfunc_end_defs();
> +
> +BTF_KFUNCS_START(wakeup_source_kfunc_ids)
> +BTF_ID_FLAGS(func, bpf_wakeup_sources_read_lock, KF_ACQUIRE)
I think this needs KF_RET_NULL as well.
> +BTF_ID_FLAGS(func, bpf_wakeup_sources_read_unlock, KF_RELEASE)
> +BTF_ID_FLAGS(func, bpf_wakeup_sources_get_head)
> +BTF_KFUNCS_END(wakeup_source_kfunc_ids)
> +
> +static const struct btf_kfunc_id_set wakeup_source_kfunc_set = {
> + .owner = THIS_MODULE,
> + .set = &wakeup_source_kfunc_ids,
> +};
> +
> +static void __init wakeup_sources_bpf_init(void)
> +{
> + if (register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &wakeup_source_kfunc_set))
> + pm_pr_dbg("Wakeup: failed to register BTF kfuncs\n");
> +}
> +#else
> +static inline void wakeup_sources_bpf_init(void) {}
> +#endif /* CONFIG_BPF_SYSCALL */
> +
> +static int __init wakeup_sources_init(void)
> {
> debugfs_create_file("wakeup_sources", 0444, NULL, NULL,
> &wakeup_sources_stats_fops);
> + wakeup_sources_bpf_init();
> +
> return 0;
> }
>
> -postcore_initcall(wakeup_sources_debugfs_init);
> +postcore_initcall(wakeup_sources_init);
> --
> 2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/2] Support BPF traversal of wakeup sources
2026-03-26 11:25 [PATCH v2 0/2] Support BPF traversal of wakeup sources Samuel Wu
2026-03-26 11:25 ` [PATCH v2 1/2] PM: wakeup: Add kfuncs to traverse over wakeup_sources Samuel Wu
2026-03-26 11:25 ` [PATCH v2 2/2] selftests/bpf: Add tests for wakeup_sources kfuncs Samuel Wu
@ 2026-03-26 12:20 ` Puranjay Mohan
2026-03-26 14:53 ` Kumar Kartikeya Dwivedi
2 siblings, 1 reply; 9+ messages in thread
From: Puranjay Mohan @ 2026-03-26 12:20 UTC (permalink / raw)
To: Samuel Wu, Rafael J. Wysocki, Len Brown, Pavel Machek,
Greg Kroah-Hartman, Danilo Krummrich, 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: memxor, Samuel Wu, kernel-team, linux-kernel, linux-pm,
driver-core, bpf, linux-kselftest
Samuel Wu <wusamuel@google.com> writes:
> This patchset adds requisite kfuncs for BPF programs to safely traverse
> wakeup_sources, and puts a config flag around the sysfs interface.
>
> Currently, a traversal of wakeup sources require going through
> /sys/class/wakeup/* or /d/wakeup_sources/*. The repeated syscalls to query
> sysfs is inefficient, as there can be hundreds of wakeup_sources, with each
> wakeup source also having multiple attributes. debugfs is unstable and
> insecure.
>
> Adding kfuncs to lock/unlock wakeup sources allows BPF program to safely
> traverse the wakeup sources list. The head address of wakeup_sources can
> safely be resolved through BPF helper functions or variable attributes.
>
> On a quiescent Pixel 6 traversing 150 wakeup_sources, I am seeing ~34x
> speedup (sampled 75 times in table below). For a device under load, the
> speedup is greater.
> +-------+----+----------+----------+
> | | n | AVG (ms) | STD (ms) |
> +-------+----+----------+----------+
> | sysfs | 75 | 44.9 | 12.6 |
> +-------+----+----------+----------+
> | BPF | 75 | 1.3 | 0.7 |
> +-------+----+----------+----------+
>
> The initial attempts for BPF traversal of wakeup_sources was with BPF
> iterators [1]. However, BPF already allows for traversing of a simple list
> with bpf_for(), and this current patchset has the added benefit of being
> ~2-3x more performant than BPF iterators.
I left some inline comments on patch 1, but the high level concern is
that encoding the SRCU index into a fake pointer to get KF_ACQUIRE/
KF_RELEASE tracking is working against the verifier rather than with it.
Nothing actually prevents a BPF program from walking the list without
the lock, and the whole pointer encoding trick goes away if this is done
as an open-coded iterator instead.
Thanks,
Puranjay
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/2] Support BPF traversal of wakeup sources
2026-03-26 12:20 ` [PATCH v2 0/2] Support BPF traversal of wakeup sources Puranjay Mohan
@ 2026-03-26 14:53 ` Kumar Kartikeya Dwivedi
2026-03-26 15:01 ` Alexei Starovoitov
0 siblings, 1 reply; 9+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-03-26 14:53 UTC (permalink / raw)
To: Puranjay Mohan
Cc: Samuel Wu, Rafael J. Wysocki, Len Brown, Pavel Machek,
Greg Kroah-Hartman, Danilo Krummrich, 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,
kernel-team, linux-kernel, linux-pm, driver-core, bpf,
linux-kselftest
On Thu, 26 Mar 2026 at 13:20, Puranjay Mohan <puranjay@kernel.org> wrote:
>
> Samuel Wu <wusamuel@google.com> writes:
>
> > This patchset adds requisite kfuncs for BPF programs to safely traverse
> > wakeup_sources, and puts a config flag around the sysfs interface.
> >
> > Currently, a traversal of wakeup sources require going through
> > /sys/class/wakeup/* or /d/wakeup_sources/*. The repeated syscalls to query
> > sysfs is inefficient, as there can be hundreds of wakeup_sources, with each
> > wakeup source also having multiple attributes. debugfs is unstable and
> > insecure.
> >
> > Adding kfuncs to lock/unlock wakeup sources allows BPF program to safely
> > traverse the wakeup sources list. The head address of wakeup_sources can
> > safely be resolved through BPF helper functions or variable attributes.
> >
> > On a quiescent Pixel 6 traversing 150 wakeup_sources, I am seeing ~34x
> > speedup (sampled 75 times in table below). For a device under load, the
> > speedup is greater.
> > +-------+----+----------+----------+
> > | | n | AVG (ms) | STD (ms) |
> > +-------+----+----------+----------+
> > | sysfs | 75 | 44.9 | 12.6 |
> > +-------+----+----------+----------+
> > | BPF | 75 | 1.3 | 0.7 |
> > +-------+----+----------+----------+
> >
> > The initial attempts for BPF traversal of wakeup_sources was with BPF
> > iterators [1]. However, BPF already allows for traversing of a simple list
> > with bpf_for(), and this current patchset has the added benefit of being
> > ~2-3x more performant than BPF iterators.
>
> I left some inline comments on patch 1, but the high level concern is
> that encoding the SRCU index into a fake pointer to get KF_ACQUIRE/
> KF_RELEASE tracking is working against the verifier rather than with it.
> Nothing actually prevents a BPF program from walking the list without
> the lock, and the whole pointer encoding trick goes away if this is done
> as an open-coded iterator instead.
Which is fine, the critical section is only doing CO-RE accesses, and
the SRCU lock is just to be able to read things in a valid state while
walking the list. It is all best-effort.
Open coded iterators was already explored as an option in earlier
iterations of the series and discarded as no-go.
>
> Thanks,
> Puranjay
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/2] Support BPF traversal of wakeup sources
2026-03-26 14:53 ` Kumar Kartikeya Dwivedi
@ 2026-03-26 15:01 ` Alexei Starovoitov
2026-03-26 16:25 ` Samuel Wu
0 siblings, 1 reply; 9+ messages in thread
From: Alexei Starovoitov @ 2026-03-26 15:01 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi
Cc: Puranjay Mohan, Samuel Wu, Rafael J. Wysocki, Len Brown,
Pavel Machek, Greg Kroah-Hartman, Danilo Krummrich,
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, Android Kernel Team, LKML, Linux Power Management,
driver-core, bpf, open list:KERNEL SELFTEST FRAMEWORK
On Thu, Mar 26, 2026 at 7:54 AM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>
> On Thu, 26 Mar 2026 at 13:20, Puranjay Mohan <puranjay@kernel.org> wrote:
> >
> > Samuel Wu <wusamuel@google.com> writes:
> >
> > > This patchset adds requisite kfuncs for BPF programs to safely traverse
> > > wakeup_sources, and puts a config flag around the sysfs interface.
> > >
> > > Currently, a traversal of wakeup sources require going through
> > > /sys/class/wakeup/* or /d/wakeup_sources/*. The repeated syscalls to query
> > > sysfs is inefficient, as there can be hundreds of wakeup_sources, with each
> > > wakeup source also having multiple attributes. debugfs is unstable and
> > > insecure.
> > >
> > > Adding kfuncs to lock/unlock wakeup sources allows BPF program to safely
> > > traverse the wakeup sources list. The head address of wakeup_sources can
> > > safely be resolved through BPF helper functions or variable attributes.
> > >
> > > On a quiescent Pixel 6 traversing 150 wakeup_sources, I am seeing ~34x
> > > speedup (sampled 75 times in table below). For a device under load, the
> > > speedup is greater.
> > > +-------+----+----------+----------+
> > > | | n | AVG (ms) | STD (ms) |
> > > +-------+----+----------+----------+
> > > | sysfs | 75 | 44.9 | 12.6 |
> > > +-------+----+----------+----------+
> > > | BPF | 75 | 1.3 | 0.7 |
> > > +-------+----+----------+----------+
> > >
> > > The initial attempts for BPF traversal of wakeup_sources was with BPF
> > > iterators [1]. However, BPF already allows for traversing of a simple list
> > > with bpf_for(), and this current patchset has the added benefit of being
> > > ~2-3x more performant than BPF iterators.
> >
> > I left some inline comments on patch 1, but the high level concern is
> > that encoding the SRCU index into a fake pointer to get KF_ACQUIRE/
> > KF_RELEASE tracking is working against the verifier rather than with it.
> > Nothing actually prevents a BPF program from walking the list without
> > the lock, and the whole pointer encoding trick goes away if this is done
> > as an open-coded iterator instead.
>
> Which is fine, the critical section is only doing CO-RE accesses, and
> the SRCU lock is just to be able to read things in a valid state while
> walking the list. It is all best-effort.
> Open coded iterators was already explored as an option in earlier
> iterations of the series and discarded as no-go.
kinda best-effort...
the way it's written bpf_wakeup_sources_get_head() returns
trusted list_head. It's then core-read-ed anyway.
Ideally it should be trusted only within that srcu CS
and invalidated by the verifier similar to KF_RCU_PROTECTED,
but that's bigger task.
Instead let's make bpf_wakeup_sources_get_head() return 'void *',
so it's clearly untrusted.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/2] Support BPF traversal of wakeup sources
2026-03-26 15:01 ` Alexei Starovoitov
@ 2026-03-26 16:25 ` Samuel Wu
2026-03-26 16:30 ` Kumar Kartikeya Dwivedi
0 siblings, 1 reply; 9+ messages in thread
From: Samuel Wu @ 2026-03-26 16:25 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Kumar Kartikeya Dwivedi, Puranjay Mohan, Rafael J. Wysocki,
Len Brown, Pavel Machek, Greg Kroah-Hartman, Danilo Krummrich,
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, Android Kernel Team, LKML, Linux Power Management,
driver-core, bpf, open list:KERNEL SELFTEST FRAMEWORK
On Thu, Mar 26, 2026 at 8:02 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Thu, Mar 26, 2026 at 7:54 AM Kumar Kartikeya Dwivedi
> <memxor@gmail.com> wrote:
> >
> > On Thu, 26 Mar 2026 at 13:20, Puranjay Mohan <puranjay@kernel.org> wrote:
> > >
> > > Samuel Wu <wusamuel@google.com> writes:
> > >
> > > > This patchset adds requisite kfuncs for BPF programs to safely traverse
> > > > wakeup_sources, and puts a config flag around the sysfs interface.
> > > >
> > > > Currently, a traversal of wakeup sources require going through
> > > > /sys/class/wakeup/* or /d/wakeup_sources/*. The repeated syscalls to query
> > > > sysfs is inefficient, as there can be hundreds of wakeup_sources, with each
> > > > wakeup source also having multiple attributes. debugfs is unstable and
> > > > insecure.
> > > >
> > > > Adding kfuncs to lock/unlock wakeup sources allows BPF program to safely
> > > > traverse the wakeup sources list. The head address of wakeup_sources can
> > > > safely be resolved through BPF helper functions or variable attributes.
> > > >
> > > > On a quiescent Pixel 6 traversing 150 wakeup_sources, I am seeing ~34x
> > > > speedup (sampled 75 times in table below). For a device under load, the
> > > > speedup is greater.
> > > > +-------+----+----------+----------+
> > > > | | n | AVG (ms) | STD (ms) |
> > > > +-------+----+----------+----------+
> > > > | sysfs | 75 | 44.9 | 12.6 |
> > > > +-------+----+----------+----------+
> > > > | BPF | 75 | 1.3 | 0.7 |
> > > > +-------+----+----------+----------+
> > > >
> > > > The initial attempts for BPF traversal of wakeup_sources was with BPF
> > > > iterators [1]. However, BPF already allows for traversing of a simple list
> > > > with bpf_for(), and this current patchset has the added benefit of being
> > > > ~2-3x more performant than BPF iterators.
> > >
> > > I left some inline comments on patch 1, but the high level concern is
> > > that encoding the SRCU index into a fake pointer to get KF_ACQUIRE/
> > > KF_RELEASE tracking is working against the verifier rather than with it.
> > > Nothing actually prevents a BPF program from walking the list without
> > > the lock, and the whole pointer encoding trick goes away if this is done
> > > as an open-coded iterator instead.
> >
> > Which is fine, the critical section is only doing CO-RE accesses, and
> > the SRCU lock is just to be able to read things in a valid state while
> > walking the list. It is all best-effort.
> > Open coded iterators was already explored as an option in earlier
> > iterations of the series and discarded as no-go.
>
> kinda best-effort...
> the way it's written bpf_wakeup_sources_get_head() returns
> trusted list_head. It's then core-read-ed anyway.
> Ideally it should be trusted only within that srcu CS
> and invalidated by the verifier similar to KF_RCU_PROTECTED,
> but that's bigger task.
> Instead let's make bpf_wakeup_sources_get_head() return 'void *',
> so it's clearly untrusted.
Thanks all for the fruitful discussion; this is more rigorous. I'll
update v3 so that `bpf_wakeup_sources_get_head()`'s return type is
`void *` and I can add a corresponding selftest that directly
dereferences the head and expects a verifier failure.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/2] Support BPF traversal of wakeup sources
2026-03-26 16:25 ` Samuel Wu
@ 2026-03-26 16:30 ` Kumar Kartikeya Dwivedi
0 siblings, 0 replies; 9+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-03-26 16:30 UTC (permalink / raw)
To: Samuel Wu
Cc: Alexei Starovoitov, Puranjay Mohan, Rafael J. Wysocki, Len Brown,
Pavel Machek, Greg Kroah-Hartman, Danilo Krummrich,
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, Android Kernel Team, LKML, Linux Power Management,
driver-core, bpf, open list:KERNEL SELFTEST FRAMEWORK
On Thu, 26 Mar 2026 at 17:26, Samuel Wu <wusamuel@google.com> wrote:
>
> On Thu, Mar 26, 2026 at 8:02 AM Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Thu, Mar 26, 2026 at 7:54 AM Kumar Kartikeya Dwivedi
> > <memxor@gmail.com> wrote:
> > >
> > > On Thu, 26 Mar 2026 at 13:20, Puranjay Mohan <puranjay@kernel.org> wrote:
> > > >
> > > > Samuel Wu <wusamuel@google.com> writes:
> > > >
> > > > > This patchset adds requisite kfuncs for BPF programs to safely traverse
> > > > > wakeup_sources, and puts a config flag around the sysfs interface.
> > > > >
> > > > > Currently, a traversal of wakeup sources require going through
> > > > > /sys/class/wakeup/* or /d/wakeup_sources/*. The repeated syscalls to query
> > > > > sysfs is inefficient, as there can be hundreds of wakeup_sources, with each
> > > > > wakeup source also having multiple attributes. debugfs is unstable and
> > > > > insecure.
> > > > >
> > > > > Adding kfuncs to lock/unlock wakeup sources allows BPF program to safely
> > > > > traverse the wakeup sources list. The head address of wakeup_sources can
> > > > > safely be resolved through BPF helper functions or variable attributes.
> > > > >
> > > > > On a quiescent Pixel 6 traversing 150 wakeup_sources, I am seeing ~34x
> > > > > speedup (sampled 75 times in table below). For a device under load, the
> > > > > speedup is greater.
> > > > > +-------+----+----------+----------+
> > > > > | | n | AVG (ms) | STD (ms) |
> > > > > +-------+----+----------+----------+
> > > > > | sysfs | 75 | 44.9 | 12.6 |
> > > > > +-------+----+----------+----------+
> > > > > | BPF | 75 | 1.3 | 0.7 |
> > > > > +-------+----+----------+----------+
> > > > >
> > > > > The initial attempts for BPF traversal of wakeup_sources was with BPF
> > > > > iterators [1]. However, BPF already allows for traversing of a simple list
> > > > > with bpf_for(), and this current patchset has the added benefit of being
> > > > > ~2-3x more performant than BPF iterators.
> > > >
> > > > I left some inline comments on patch 1, but the high level concern is
> > > > that encoding the SRCU index into a fake pointer to get KF_ACQUIRE/
> > > > KF_RELEASE tracking is working against the verifier rather than with it.
> > > > Nothing actually prevents a BPF program from walking the list without
> > > > the lock, and the whole pointer encoding trick goes away if this is done
> > > > as an open-coded iterator instead.
> > >
> > > Which is fine, the critical section is only doing CO-RE accesses, and
> > > the SRCU lock is just to be able to read things in a valid state while
> > > walking the list. It is all best-effort.
> > > Open coded iterators was already explored as an option in earlier
> > > iterations of the series and discarded as no-go.
> >
> > kinda best-effort...
> > the way it's written bpf_wakeup_sources_get_head() returns
> > trusted list_head. It's then core-read-ed anyway.
> > Ideally it should be trusted only within that srcu CS
> > and invalidated by the verifier similar to KF_RCU_PROTECTED,
> > but that's bigger task.
> > Instead let's make bpf_wakeup_sources_get_head() return 'void *',
> > so it's clearly untrusted.
>
> Thanks all for the fruitful discussion; this is more rigorous. I'll
> update v3 so that `bpf_wakeup_sources_get_head()`'s return type is
> `void *` and I can add a corresponding selftest that directly
> dereferences the head and expects a verifier failure.
You could also use bpf_core_cast() instead of using macros to read
every field, should be equivalent. You may still need the macros for
bitfields but it should work otherwise.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-03-26 16:31 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-26 11:25 [PATCH v2 0/2] Support BPF traversal of wakeup sources Samuel Wu
2026-03-26 11:25 ` [PATCH v2 1/2] PM: wakeup: Add kfuncs to traverse over wakeup_sources Samuel Wu
2026-03-26 11:59 ` Puranjay Mohan
2026-03-26 11:25 ` [PATCH v2 2/2] selftests/bpf: Add tests for wakeup_sources kfuncs Samuel Wu
2026-03-26 12:20 ` [PATCH v2 0/2] Support BPF traversal of wakeup sources Puranjay Mohan
2026-03-26 14:53 ` Kumar Kartikeya Dwivedi
2026-03-26 15:01 ` Alexei Starovoitov
2026-03-26 16:25 ` Samuel Wu
2026-03-26 16:30 ` Kumar Kartikeya Dwivedi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox