mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
PM: wakeup: Add kfuncs to traverse over wakeup_sources
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. There is at least a 30x speedup for walking 150 wakeup sources and all their attributes. 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> Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Link: https://lore.kernel.org/r/20260511174559.659782-2-wusamuel@google.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
e651f3ce13
commit
5ff4495544
|
|
@ -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);
|
||||
void *bpf_wakeup_sources_get_head(void);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1168,11 +1168,78 @@ 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 void *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 = {
|
||||
.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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user