From nobody Sat Feb 7 11:38:13 2026 Received: from mail-dl1-f73.google.com (mail-dl1-f73.google.com [74.125.82.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6BA6C1DE4DC for ; Sat, 24 Jan 2026 01:22:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769217723; cv=none; b=dlqFUDtQld+CB+UBx6xgFgzRI/dwuDyfttxrNvQDXfZivChVdMl/S9HigCgoo+jEyzByTKhP2F88/FtmIK1FhDe3slLHhahtmZud2NWS96b79g3LvyL2h3EqpVTp/LBvjd/WO9d03n+uFLE/BcXUWJIyHJfk3llrYUtfazODNZg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769217723; c=relaxed/simple; bh=wvQSevTks610RBfJ7oBqtsKqCB/HWm0eJW4rW75kywU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=CtjnFHkfX0ykzMuQOAaYsdaCO3Ze7vpvmsFvVb51G5EdcIPJw4f3fxOQ+HmmnlBjCDxvt/evqedT438VO06FbF393Wab00FjmhMopdFDjKtYIBb+fiZN9T3Gd1oMlUYvgvClvOP0JKRRV1XkK0lp4fwpO6TDsWwhJezkBBmQlD4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--wusamuel.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=YLYZQwrZ; arc=none smtp.client-ip=74.125.82.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--wusamuel.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="YLYZQwrZ" Received: by mail-dl1-f73.google.com with SMTP id a92af1059eb24-12338749ea9so3711966c88.0 for ; Fri, 23 Jan 2026 17:22:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1769217720; x=1769822520; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=a577FNgbL0JbRd6IsOu504RokGc/26jdmHoERsXu7xE=; b=YLYZQwrZQdClNm0+ozko3XXQMt5QHTLB7dWO7oLhxt0v1xuuJ3CcXIKg54k0W/Qomp 1IMBOsUl6CvRmULjpxw6yiTLZW0Zn9lGrvDwzayqa/+ZeCrum+Tr0WdhunptrrZwhayo gnfMxwWT1rbB40qlchCCJWgV+wN5AO8ttGME9i5xHxv3Tft5u0DpEBy7ji6Oo/eM8Yla k4RVwQwaz+kDUB2lp38uc9IOxpEjqzCSN1+Yq16vdPd07lqh91IG3ZnpEgHYjggqIPxs 7WIp1zY6+RlKqwUocNhrHV5AoyjRDTu2EZMvN2b+1MMqSxMOq/sk/NChMdnqT9wNoUGc 9NZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769217720; x=1769822520; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=a577FNgbL0JbRd6IsOu504RokGc/26jdmHoERsXu7xE=; b=LRYmoClQ0idoK7RNoUIGu7ZS0i4l1urlxXk03/vfVP+L54+qW+MJX9XUgZWkRGNW0p NDsfA2tfdrEyWmrOJ2aB08iQT1B8PkitkHsJTw9dQaqGawT1TKQrqMijTKGlCmHKjz/2 NKP9eO+9K3J8cexWAVnOD375DboTfF2d9YOYFg43FPAV1h66cR5zU0oFvIoIaXwRg50c e7jtbkLm8c4ucV+juAtJ6cbjjgzJGaP25O57pNmAfzG0vUfSjXu9y2u9QSz3nOqh7zQS evQHaFLpATJa3YC7bnzuBy+DRTjviDwkJpH5orrMeLXMascYLNj17TaddglnN6Hy62yu qWLg== X-Forwarded-Encrypted: i=1; AJvYcCXH6O+Kmuj33wV5RxNm3Sic8AlvXW/C7iVu4UrHFMddw+RHSkJ2qKRoBpmtVPoCmqPmr13/xEZiDeCT0UM=@vger.kernel.org X-Gm-Message-State: AOJu0YyGy4agikMN6tAIDhfpnrIztGUbZrpYZfsubCPP39tAfaD8cP8a 4aD5HuxWPkpxsFMAjSfSiqHLapImQTSlbLjcAwv8vO4HkjO54r89UUBaOnsyvbDvkSnkk7q26m6 YZfedhk0B/MGFTg== X-Received: from dlbcj34.prod.google.com ([2002:a05:7022:69a2:b0:11f:3043:2c7f]) (user=wusamuel job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7023:c081:b0:11d:fc4a:c4f7 with SMTP id a92af1059eb24-1247dba9450mr1771878c88.4.1769217720087; Fri, 23 Jan 2026 17:22:00 -0800 (PST) Date: Fri, 23 Jan 2026 17:21:29 -0800 In-Reply-To: <20260124012133.2451708-1-wusamuel@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260124012133.2451708-1-wusamuel@google.com> X-Mailer: git-send-email 2.52.0.457.g6b5491de43-goog Message-ID: <20260124012133.2451708-2-wusamuel@google.com> Subject: [PATCH bpf-next v3 1/3] PM: wakeup: Handle empty list in wakeup_sources_walk From: Samuel Wu 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: Samuel Wu , kernel-team@android.com, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, bpf@vger.kernel.org, linux-kselftest@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In the case of an empty wakeup_sources list, wakeup_sources_walk_start() will return an invalid but non-NULL address. This also affects wrappers of the aforementioned function, like for_each_wakeup_source(). This patch updates wakeup_sources_walk_start() to return NULL in case of an empty list. Signed-off-by: Samuel Wu --- drivers/base/power/wakeup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 1e1a0e7eeac5..e69033d16fba 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -275,9 +275,7 @@ EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock); */ struct wakeup_source *wakeup_sources_walk_start(void) { - struct list_head *ws_head =3D &wakeup_sources; - - return list_entry_rcu(ws_head->next, struct wakeup_source, entry); + return list_first_or_null_rcu(&wakeup_sources, struct wakeup_source, entr= y); } EXPORT_SYMBOL_GPL(wakeup_sources_walk_start); =20 --=20 2.52.0.457.g6b5491de43-goog From nobody Sat Feb 7 11:38:13 2026 Received: from mail-dy1-f202.google.com (mail-dy1-f202.google.com [74.125.82.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8B8D01FC0EF for ; Sat, 24 Jan 2026 01:22:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769217727; cv=none; b=bsfI5RdpBEMgFzGVnRd3zurSbaGi16CcjHelbsBw0FAgRFiawjoWfzRYDYMKdisn1Tcd98YBCislyv3bzDF2FUdFod3NsC94yiIvF7uBaagCILRSDV7tR/RnpoXP8lUV9WLDw5OJwYu89re856uMrR9W1NLYkkXY7IwN6E6QeuY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769217727; c=relaxed/simple; bh=O6ot7CPctdPFw6WHudhxbDM8ZE4E8EaTJG3EnZslIx8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=lt8WXsgvVW2XxIX/pw0iNAwb9KT061+D684XqcE/NRNPkJd1OcQARwjqHyTBD0DCKYK/bQQj0KVgCx9L9sIutaGRIue5ja8lv3IjGA4+IXoez5c0CsItbqwM9ygoxMB45/jf/cv4vKupmQbNH2RS4VCdIhXx5dcnr1xXvdBsMf0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--wusamuel.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=gO0cmGPH; arc=none smtp.client-ip=74.125.82.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--wusamuel.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="gO0cmGPH" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-2b6b9c1249fso5120030eec.1 for ; Fri, 23 Jan 2026 17:22:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1769217725; x=1769822525; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=dJJFhVKyiKKoV+I6tkl9SP4apjw+O1s0pu7zT4uXhoI=; b=gO0cmGPHoPjL0FEa7+aC8RAvx7qHuvbyE8WBKnm+mJ7K3XMBQvVCMgZVBrVFXhZYMK cvxbimsepumdv2GMGLbESoNTV/kpdr3aGb4NfkY7QcH/23ZUohmskfOhpDENAmOA1MAF ErUFK0v83LLa0/DIsVeBGOFH5jEz8kUxJp6/RjSLjyXoPmmyIGiUErT9lmWt0CmEPIxs toboya9rT4mnGw1NeHrKW482UjnaDJLPYBkv/dohPFh4nA1SfJtt+mD01NcmPNRTiFoI s2vrr0PDnK4m1XvBy6zg2H19RfTblwehcW0QrVcERQYUzEA2bsfyYhrdSDm88HkprFGA iGNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769217725; x=1769822525; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=dJJFhVKyiKKoV+I6tkl9SP4apjw+O1s0pu7zT4uXhoI=; b=FFnOk65ridoGyyxEdAF67Ud4dfZhfXPD+IvkPHZ/KBMil4xs00r5opjMKfCnPdcOPO ZZ2q3SOHw3XvlxCtwsX3QyZGoNksWti3vJyo77qMUnHqMs4oItioGd4pGiu7UzVEFSgj Ht3+nFS39Y3XXnrOi5jy2xiTGedUExPuBHfFsbk56TUkJEnehyi9P3Tl5bLsTUAP1x2p XWCtfGtKsaUZ7uKExIjY9OUo/fJ0spCSSqDj5WeRjm8tQGUu78hbl/9KpLXHnZZp1490 fZ9RsIEgiPL10cOcn34Ouo2v6wlOoN0jTFfLdXpkVUbHEgLEFOLpUgGAs1aK9mDwUzY2 WWAQ== X-Forwarded-Encrypted: i=1; AJvYcCXX/9S3Jtae4s6aiTdWtol5MUJqCI+QzpxcZD7f1jzmQT1/En1ddITDH97uSxCO/Z9jxZ8YLRUxk5vHWhE=@vger.kernel.org X-Gm-Message-State: AOJu0YxKtLqFNTPRdlgEWJ4alkWpJMfrnRTOi2Z/4Kxr/rOEnhrB5cAI mPIacBo5u8EiaQ0F1iAm59vLe5OcDjKgUIm9utkVzufYuJL8VPCJifQyEnFheKHtMDCNu+3LOaR vzucCuMU6C9cj0Q== X-Received: from dycal40.prod.google.com ([2002:a05:7301:1ca8:b0:2b6:e20b:d5e4]) (user=wusamuel job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:72c9:b0:2b7:2a17:af34 with SMTP id 5a478bee46e88-2b739b74177mr2687038eec.23.1769217724430; Fri, 23 Jan 2026 17:22:04 -0800 (PST) Date: Fri, 23 Jan 2026 17:21:30 -0800 In-Reply-To: <20260124012133.2451708-1-wusamuel@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260124012133.2451708-1-wusamuel@google.com> X-Mailer: git-send-email 2.52.0.457.g6b5491de43-goog Message-ID: <20260124012133.2451708-3-wusamuel@google.com> Subject: [PATCH bpf-next v3 2/3] bpf: Add wakeup_source iterator From: Samuel Wu 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: Samuel Wu , kernel-team@android.com, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, bpf@vger.kernel.org, linux-kselftest@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- kernel/bpf/Makefile | 3 + kernel/bpf/wakeup_source_iter.c | 103 ++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 kernel/bpf/wakeup_source_iter.c diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile index 79cf22860a99..1259373298e1 100644 --- a/kernel/bpf/Makefile +++ b/kernel/bpf/Makefile @@ -66,6 +66,9 @@ obj-$(CONFIG_BPF_SYSCALL) +=3D kmem_cache_iter.o ifeq ($(CONFIG_DMA_SHARED_BUFFER),y) obj-$(CONFIG_BPF_SYSCALL) +=3D dmabuf_iter.o endif +ifeq ($(CONFIG_PM_SLEEP),y) +obj-$(CONFIG_BPF_SYSCALL) +=3D wakeup_source_iter.o +endif =20 CFLAGS_REMOVE_percpu_freelist.o =3D $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_bpf_lru_list.o =3D $(CC_FLAGS_FTRACE) diff --git a/kernel/bpf/wakeup_source_iter.c b/kernel/bpf/wakeup_source_ite= r.c new file mode 100644 index 000000000000..ab83d212a1f9 --- /dev/null +++ b/kernel/bpf/wakeup_source_iter.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2026 Google LLC */ +#include +#include +#include +#include +#include + +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 *po= s) +{ + int *srcuidx =3D seq->private; + struct wakeup_source *ws; + loff_t i; + + *srcuidx =3D wakeup_sources_read_lock(); + + ws =3D wakeup_sources_walk_start(); + for (i =3D 0; ws && i < *pos; i++) + ws =3D wakeup_sources_walk_next(ws); + + return ws; +} + +static void *wakeup_source_iter_seq_next(struct seq_file *seq, void *v, lo= ff_t *pos) +{ + struct wakeup_source *ws =3D v; + + ++*pos; + + return wakeup_sources_walk_next(ws); +} + +static void wakeup_source_iter_seq_stop(struct seq_file *seq, void *v) +{ + int *srcuidx =3D seq->private; + + if (*srcuidx >=3D 0) + wakeup_sources_read_unlock(*srcuidx); + *srcuidx =3D -1; +} + +static int __wakeup_source_seq_show(struct seq_file *seq, void *v, bool in= _stop) +{ + struct bpf_iter_meta meta =3D { + .seq =3D seq, + }; + struct bpf_iter__wakeup_source ctx =3D { + .meta =3D &meta, + .wakeup_source =3D v, + }; + struct bpf_prog *prog =3D 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 =3D { + .start =3D wakeup_source_iter_seq_start, + .next =3D wakeup_source_iter_seq_next, + .stop =3D wakeup_source_iter_seq_stop, + .show =3D wakeup_source_iter_seq_show, +}; + +static const struct bpf_iter_seq_info wakeup_source_iter_seq_info =3D { + .seq_ops =3D &wakeup_source_iter_seq_ops, + .seq_priv_size =3D sizeof(int), +}; + +static struct bpf_iter_reg bpf_wakeup_source_reg_info =3D { + .target =3D "wakeup_source", + .ctx_arg_info_size =3D 1, + .ctx_arg_info =3D { + { + offsetof(struct bpf_iter__wakeup_source, wakeup_source), + PTR_TO_BTF_ID_OR_NULL + }, + }, + .seq_info =3D &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 =3D bpf_wakeup_source_b= tf_id[0]; + return bpf_iter_reg_target(&bpf_wakeup_source_reg_info); +} + +late_initcall(wakeup_source_iter_init); --=20 2.52.0.457.g6b5491de43-goog From nobody Sat Feb 7 11:38:13 2026 Received: from mail-dl1-f73.google.com (mail-dl1-f73.google.com [74.125.82.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 07EE11EF36C for ; Sat, 24 Jan 2026 01:22:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769217734; cv=none; b=ClPMDkT4qYZV9QGVCR/+7XRSzMI+fWX1cN0PIdQVmkvvF4jtmaXBWNYDIMt9xduJHED+UqBiYbjPPqdbH1jDyPabg1xDs1C6wcMxBejtX9hUm7QR/B+Y4oqCm1saiFtLAqiiLciV8qR7K2TcHzXip4lJ/tYCF3LJkVaAomDVSxM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769217734; c=relaxed/simple; bh=5nx1vabACddP8X8rCz/BHrB3L4m/zjtvvtqkMM/A9Q4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=NA26wakDvPcP7dOV1/aIBjZ8VcrueXBbUbIsD9NRUoRSSo7GVxrNPMp6xLK6rXLRvg/wbJLdWdbfR5Dx4b8vEpvUimUl/9or+Fust4VhtMIfLOoYwHMfp4kGJiFC/tNGp0HUoRz5kIoTqOBjPfsPjpv+GRyiaaJEd7mhhHllyLU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--wusamuel.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=gJtd0h4X; arc=none smtp.client-ip=74.125.82.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--wusamuel.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="gJtd0h4X" Received: by mail-dl1-f73.google.com with SMTP id a92af1059eb24-1233893db9fso11410756c88.0 for ; Fri, 23 Jan 2026 17:22:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1769217732; x=1769822532; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=HgDNIVQUbJ1g8aqYaibRfwYHVmGqmY8Tq8troMul2uo=; b=gJtd0h4XuOp73H/yOFrI+hO7U0RIPD1d1bi++rmurxYl387AZ1TJ2EFS3Ia5b/Ord3 W4ixyn1rK3/aulX28IrT/6joNuUgEx83ho8DTSQlIBMgL6d0g7sRlvpV87+opyusczZ/ 61tGxxJ1Myg6Jtp0XEL3PYMWCACgOQkVwgkECtBXBRmdmFyZvK1g0h3Fs7Hjnw8vpuZ5 db76T4AB6Gl4iiRDWFJhzfdfcHTqiVaSch9+mYdDXimRKGXBoK07R6ags+h4+RBTumgL PUWICvxeKE5xze44+ceRzJIeLNmlNHOcDHKUZrnSUV6VX8oGQCRxLbN4AgNJV1xX6swx +5BQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769217732; x=1769822532; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=HgDNIVQUbJ1g8aqYaibRfwYHVmGqmY8Tq8troMul2uo=; b=GfOTTPnuzXxg/IXb5YVBr0bYUAGO8kfeEwUS6Pz+41HZTs9YnCXrsxSi1u+3zyvJ3q L7difX3ABQC2Yf4OpTNTgexzhfsvj1fa4turMuAD6hDt1886Xb5JB/Txroy4F0OHnag+ oBmNoGbfUy9xKAXW5rtrcCi06VhUWN6tPMeBUUrIOlSXHUT3hEIly1gyXJEhfrJGXRUz qQP+MtLf4oHmAaYF9dMSzMfWmhoFWIBf54URBVTdwx6MMXdgw3GLmQC0CYBc1axC7JGQ 3mP21/Kps7gyWyC/2CmtvMB5lWTgI/8f8U03stq97KFGhc/5GBFx7yhpsISFspBfoe3f SsFw== X-Forwarded-Encrypted: i=1; AJvYcCV6SoKurCtaV7pKNWwjh7Xn8wLRv4gHPNhC4caQ8Y4bBbuElGB41E0f+/d1VzKpp5ow1jcPa1k+9g2iKc4=@vger.kernel.org X-Gm-Message-State: AOJu0YxqBBPtwnYpz8q29v84AEGhhDBL7unCLXpmYFgwxdzg5wpYACYY OyKcmBBH6//2oGIZ4mlPb9w6oGmDnfUXFFc6t0ctGUNh77mV+l7C5tfCwmBbSlcX/ihl/DWwB3k F85LRxoKaiJapvw== X-Received: from dlbrf17.prod.google.com ([2002:a05:7022:f211:b0:11b:f588:7cbc]) (user=wusamuel job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:4587:b0:11d:f464:5c97 with SMTP id a92af1059eb24-12481a46bf3mr1805783c88.39.1769217731989; Fri, 23 Jan 2026 17:22:11 -0800 (PST) Date: Fri, 23 Jan 2026 17:21:31 -0800 In-Reply-To: <20260124012133.2451708-1-wusamuel@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260124012133.2451708-1-wusamuel@google.com> X-Mailer: git-send-email 2.52.0.457.g6b5491de43-goog Message-ID: <20260124012133.2451708-4-wusamuel@google.com> Subject: [PATCH bpf-next v3 3/3] selftests/bpf: Add tests for wakeup_sources From: Samuel Wu 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: Samuel Wu , kernel-team@android.com, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, bpf@vger.kernel.org, linux-kselftest@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- tools/testing/selftests/bpf/config | 1 + .../bpf/prog_tests/wakeup_source_iter.c | 281 ++++++++++++++++++ .../selftests/bpf/progs/wakeup_source_iter.c | 60 ++++ 3 files changed, 342 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/wakeup_source_it= er.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/b= pf/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=3Dy CONFIG_IP6_NF_FILTER=3Dy CONFIG_NF_NAT=3Dy CONFIG_PACKET=3Dy +CONFIG_PM_WAKELOCKS=3Dy CONFIG_RC_CORE=3Dy CONFIG_SAMPLES=3Dy CONFIG_SAMPLE_LIVEPATCH=3Dm 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..c8a38717e284 --- /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) 2026 Google LLC */ + +#include +#include +#include "wakeup_source_iter.skel.h" + +#include +#include +#include +#include +#include +#include + + +/* 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[] =3D "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 =3D open("/sys/power/wake_lock", O_WRONLY); + if (!ASSERT_OK_FD(fd, "open /sys/power/wake_lock")) + return -1; + + bytes =3D 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 =3D 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 =3D true; + + return 0; +} + +/* + * Tears down and cleanups testing ws iterators. WIll run once after the s= uite + * of tests. + */ +static void teardown_test_ws(void) +{ + if (!test_ws_created) + return; + unlock_ws(test_ws_name); + test_ws_created =3D 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) =3D=3D -1) + return false; + + (*line)[strcspn(*line, "\n")] =3D 0; + + items =3D 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_f= d, + FILE **iter_file) +{ + *iter_fd =3D bpf_iter_create( + bpf_link__fd(skel->links.wakeup_source_collector)); + if (!ASSERT_OK_FD(*iter_fd, "iter_create")) + return -1; + + *iter_file =3D 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[] =3D "bpf_selftest_ws_active_count"; + const int lock_unlock_cycles =3D 5; + struct WakeupSourceInfo ws_info; + char *line =3D NULL; + bool found_ws =3D false; + FILE *iter_file =3D NULL; + int iter_fd =3D -1; + int i; + + for (i =3D 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) =3D=3D 0) { + found_ws =3D true; + ASSERT_EQ(ws_info.active_count, lock_unlock_cycles, + "active_count check"); + ASSERT_EQ(ws_info.event_count, lock_unlock_cycles, + "event_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 >=3D 0) + close(iter_fd); +} + +static void subtest_ws_iter_check_sleep_times(struct wakeup_source_iter *s= kel) +{ + bool found_test_ws =3D false; + struct WakeupSourceInfo ws_info; + char *line =3D 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) =3D=3D 0) { + found_test_ws =3D 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 >=3D TEST_SLEEP_MS"); + ASSERT_GE(ws_info.max_time_ms, TEST_SLEEP_MS, + "Expected max time >=3D TEST_SLEEP_MS"); + ASSERT_GE(ws_info.total_time_ms, TEST_SLEEP_MS, + "Expected total time >=3D 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 >=3D 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 =3D bpf_iter_create(bpf_link__fd(skel->links.wakeup_source_collec= tor)); + 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 =3D NULL; + + if (geteuid() !=3D 0) { + fprintf(stderr, + "Skipping wakeup_source_iter test, requires root\n"); + test__skip(); + return; + } + + skel =3D 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..eb19569e4424 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/wakeup_source_iter.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Google LLC */ +#include +#include +#include + +#define NSEC_PER_MS 1000000UL +#define WAKEUP_SOURCE_NAME_LEN 32 + +char _license[] SEC("license") =3D "GPL"; + +SEC("iter/wakeup_source") +int wakeup_source_collector(struct bpf_iter__wakeup_source *ctx) +{ + const struct wakeup_source *ws =3D ctx->wakeup_source; + struct seq_file *seq =3D ctx->meta->seq; + char name[WAKEUP_SOURCE_NAME_LEN] =3D {'\0'}; + const char *pname; + bool active, autosleep_enable; + s64 active_time, curr_time, max_time, prevent_sleep_time, total_time; + + if (!ws) + return 0; + + active =3D BPF_CORE_READ_BITFIELD_PROBED(ws, active); + autosleep_enable =3D 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) + return 0; + + active_time =3D 0; + curr_time =3D bpf_ktime_get_ns(); + max_time =3D ws->max_time; + prevent_sleep_time =3D ws->prevent_sleep_time; + total_time =3D ws->total_time; + + if (active) { + active_time =3D curr_time - ws->last_time; + total_time +=3D active_time; + if (active_time > max_time) + max_time =3D active_time; + if (autosleep_enable) + prevent_sleep_time +=3D + curr_time - ws->start_prevent_time; + } + + BPF_SEQ_PRINTF(seq, + "%s %lu %ld %lu %lu %ld %ld %ld %ld %lu\n", + name, + ws->active_count, + active_time / NSEC_PER_MS, + ws->event_count, + ws->expire_count, + ws->last_time / NSEC_PER_MS, + max_time / NSEC_PER_MS, + prevent_sleep_time / NSEC_PER_MS, + total_time / NSEC_PER_MS, + ws->wakeup_count); + return 0; +} --=20 2.52.0.457.g6b5491de43-goog