* [PATCH 1/2] mm/kmemleak: report leaks only after N consecutive unreferenced scans
From: Breno Leitao @ 2026-06-26 15:52 UTC (permalink / raw)
To: Catalin Marinas, Jonathan Corbet, Shuah Khan, Andrew Morton,
David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Shuah Khan
Cc: workflows, linux-doc, linux-kernel, linux-mm, linux-kselftest,
Breno Leitao, kernel-team
In-Reply-To: <20260626-kmemleak_twice-v1-0-ab28f7cc0971@debian.org>
kmemleak reports an object the first scan it is found unreferenced. Its
mark phase runs without stopping the rest of the kernel and without a
write barrier, so a live object whose only reference is briefly invisible
during a concurrent RCU update -- e.g. a VMA moved between maple tree
nodes, or a page-cache xa_node -- can be seen as unreferenced for that one
scan. Because an object is flagged as reported only once, such a transient
race turns into a permanent false positive.
Track how many consecutive scans each object has been seen unreferenced
and only report it once that reaches min_unref_scans, a new module
parameter. It defaults to 1, leaving the behaviour unchanged; setting it
higher (e.g. 2) still reports a genuine leak, one scan later, while an
object referenced again before the threshold restarts its run and is never
reported.
min_unref_scans can be set at boot with kmemleak.min_unref_scans=<n> or at
run-time via /sys/module/kmemleak/parameters/min_unref_scans.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Documentation/dev-tools/kmemleak.rst | 8 ++++++++
mm/kmemleak.c | 14 ++++++++++++--
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/Documentation/dev-tools/kmemleak.rst b/Documentation/dev-tools/kmemleak.rst
index 7d784e03f3f9d..a8a83bc69ceb8 100644
--- a/Documentation/dev-tools/kmemleak.rst
+++ b/Documentation/dev-tools/kmemleak.rst
@@ -198,6 +198,14 @@ systems, because of pointers temporarily stored in CPU registers or
stacks. Kmemleak defines MSECS_MIN_AGE (defaulting to 1000) representing
the minimum age of an object to be reported as a memory leak.
+The ``min_unref_scans`` module parameter (default 1) requires an object to
+be seen unreferenced in that many consecutive scans before it is reported.
+Keeping it at 1 preserves the historical behaviour; higher values filter
+the transient false positives described above, at the cost of delaying
+genuine reports by up to that many scans. It can be set at boot with
+``kmemleak.min_unref_scans=<n>`` or at run-time via
+``/sys/module/kmemleak/parameters/min_unref_scans``.
+
Limitations and Drawbacks
-------------------------
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 7c7ba17ce7af0..5b14ccb36f95b 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -151,6 +151,8 @@ struct kmemleak_object {
int min_count;
/* the total number of pointers found pointing to this object */
int count;
+ /* consecutive scans the object has been seen unreferenced */
+ unsigned int unref_scans;
/* checksum for detecting modified objects */
u32 checksum;
depot_stack_handle_t trace_handle;
@@ -232,6 +234,9 @@ static unsigned long max_percpu_addr;
static struct task_struct *scan_thread;
/* used to avoid reporting of recently allocated objects */
static unsigned long jiffies_min_age;
+/* consecutive scans an object must stay unreferenced before reporting */
+static unsigned int min_unref_scans = 1;
+module_param(min_unref_scans, uint, 0644);
static unsigned long jiffies_last_scan;
/* delay between automatic memory scannings */
static unsigned long jiffies_scan_wait;
@@ -687,6 +692,7 @@ static struct kmemleak_object *__alloc_object(gfp_t gfp)
atomic_set(&object->use_count, 1);
object->excess_ref = 0;
object->count = 0; /* white color initially */
+ object->unref_scans = 0;
object->checksum = 0;
object->del_state = 0;
@@ -1833,6 +1839,9 @@ static void kmemleak_scan(void)
__paint_it(object, KMEMLEAK_BLACK);
}
+ /* referenced last scan: restart the unreferenced run */
+ if (!color_white(object))
+ object->unref_scans = 0;
/* reset the reference count (whiten the object) */
object->count = 0;
if (color_gray(object) && get_object(object))
@@ -1968,8 +1977,9 @@ static void kmemleak_scan(void)
raw_spin_lock_irq(&object->lock);
trace_handle = 0;
dedup_print = false;
- if (unreferenced_object(object) &&
- !(object->flags & OBJECT_REPORTED)) {
+ if (!(object->flags & OBJECT_REPORTED) &&
+ unreferenced_object(object) &&
+ ++object->unref_scans >= min_unref_scans) {
object->flags |= OBJECT_REPORTED;
if (kmemleak_verbose) {
trace_handle = object->trace_handle;
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH 0/2] mm/kmemleak: add min_unref_scans to suppress transient false positives
From: Breno Leitao @ 2026-06-26 15:52 UTC (permalink / raw)
To: Catalin Marinas, Jonathan Corbet, Shuah Khan, Andrew Morton,
David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Shuah Khan
Cc: workflows, linux-doc, linux-kernel, linux-mm, linux-kselftest,
Breno Leitao, kernel-team
I have kmemleak on some test tiers to find memory leaks in my fleet, with
the reports dumped to dmesg (CONFIG_DEBUG_KMEMLEAK_VERBOSE set). It works
super well.
The problem I have is some false positives that show up from time to time
and go away on a subsequent scan. Something transiently unreferenced --
whose only reference is briefly invisible during a concurrent RCU update,
e.g. a VMA moving between maple-tree nodes, or a page-cache xa_node -- is
seen as unreferenced for a single scan and reported as a leak that does
not exist.
This series adds a min_unref_scans module parameter requiring an object
to stay unreferenced across that many consecutive scans before it is
reported. Basically it is a trade-off between report latency and
reliability (false-positiveness?).
It defaults to 1 (the unchanged report-on-first-scan behaviour) and, set
to 2 or more, filters these single-scan races while still reporting
genuine leaks one scan later. Would it be acceptable upstream?
Patch 1 implements it; patch 2 adds an mm selftest that drives the
parameter via samples/kmemleak, in case this is useful.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Breno Leitao (2):
mm/kmemleak: report leaks only after N consecutive unreferenced scans
selftests/mm: test kmemleak's N-consecutive-scan leak confirmation
Documentation/dev-tools/kmemleak.rst | 8 ++
mm/kmemleak.c | 14 ++-
tools/testing/selftests/mm/Makefile | 1 +
.../testing/selftests/mm/ksft_kmemleak_confirm.sh | 111 +++++++++++++++++++++
4 files changed, 132 insertions(+), 2 deletions(-)
---
base-commit: 30ffa8de54e5cc80d93fd211ca134d1764a7011f
change-id: 20260626-kmemleak_twice-ed01218aeccb
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply
* Re: [PATCH v2 7/8] dt-bindings: riscv: Add generic CBQRI controller binding
From: Conor Dooley @ 2026-06-26 15:44 UTC (permalink / raw)
To: Drew Fustini
Cc: Adrien Ricciardi, Alexandre Ghiti, Atish Kumar Patra, Atish Patra,
Babu Moger, Ben Horgan, Borislav Petkov, Chen Pei, Conor Dooley,
Conor Dooley, Dave Hansen, Dave Martin, Fenghua Yu, Gong Shuai,
Gong Shuai, guo.wenjia23, James Morse, Kornel Dulęba,
Krzysztof Kozlowski, liu.qingtao2, Liu Zhiwei, Palmer Dabbelt,
Paul Walmsley, Peter Newman, Radim Krčmář,
Reinette Chatre, Rob Herring, Samuel Holland,
Sebastian Andrzej Siewior, Tony Luck, Vasudevan Srinivasan,
Ved Shanbhogue, Weiwei Li, yunhui cui, linux-kernel, linux-riscv,
x86, devicetree, linux-rt-devel, linux-doc
In-Reply-To: <aj1_0AnIBk8_xoDd@gen8>
[-- Attachment #1: Type: text/plain, Size: 3519 bytes --]
On Thu, Jun 25, 2026 at 12:21:52PM -0700, Drew Fustini wrote:
> On Thu, Jun 25, 2026 at 05:19:28PM +0100, Conor Dooley wrote:
> > On Wed, Jun 24, 2026 at 06:38:35PM -0700, Drew Fustini wrote:
> > > Document the generic compatibles for capacity and bandwidth controllers
> > > that implement the RISC-V CBQRI specification. The binding also
> > > describes the common riscv,cbqri-rcid and riscv,cbqri-mcid properties,
> > > and the optional riscv,cbqri-cache phandle that links a capacity
> > > controller to the cache whose capacity it allocates.
> > >
> > > Assisted-by: Claude:claude-opus-4-8
> > > Co-developed-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > > Signed-off-by: Adrien Ricciardi <aricciardi@baylibre.com>
> > > Signed-off-by: Drew Fustini <fustini@kernel.org>
> > > ---
> > > .../devicetree/bindings/riscv/riscv,cbqri.yaml | 97 ++++++++++++++++++++++
> > > MAINTAINERS | 1 +
> > > 2 files changed, 98 insertions(+)
>
> Thanks for the review.
>
> [..]
> > > +properties:
> > > + compatible:
> > > + oneOf:
> > > + - items:
> > > + - description: Tenstorrent Ascalon Shared Cache
> > > + const: tenstorrent,ascalon-sc-cbqri
> > > + - const: riscv,cbqri-capacity-controller
> > > + - enum:
> > > + - riscv,cbqri-capacity-controller
> > > + - riscv,cbqri-bandwidth-controller
> >
> > Please modify this, as has been done for other riscv spec related
> > bindings, to let people get away without using device-specific
> > compatibles.
> >
> > In this case, you can just delete the first entry from this enum, since
> > it already has a user and only have to implement this feedback for the
> > second entry.
>
> Would this work?
>
> properties:
> compatible:
> oneOf:
> - items:
> - enum:
> - tenstorrent,ascalon-sc-cbqri # Tenstorrent Ascalon Shared Cache
> - const: riscv,cbqri-capacity-controller
> - items:
> - {}
> - const: riscv,cbqri-bandwidth-controller
Should do, yes. I question the need for a comment though, seems pretty
evident from the compatible what it is.
> > > +
> > > +required:
> > > + - compatible
> > > + - reg
> > > +
> > > +allOf:
> > > + - if:
> > > + properties:
> > > + compatible:
> > > + contains:
> > > + const: tenstorrent,ascalon-sc-cbqri
> > > + then:
> > > + required:
> > > + - riscv,cbqri-rcid
> > > + - riscv,cbqri-cache
> > > +
> > > +additionalProperties: false
> > > +
> > > +examples:
> > > + - |
> > > + l2_cache: l2-cache {
> > > + compatible = "cache";
> > > + cache-level = <2>;
> > > + cache-unified;
> > > + cache-size = <0xc00000>;
> > > + cache-sets = <512>;
> > > + cache-block-size = <64>;
> > > + };
> > > +
> > > + cache-controller@a21a00c0 {
> > > + compatible = "tenstorrent,ascalon-sc-cbqri",
> > > + "riscv,cbqri-capacity-controller";
> >
> > Is this or is this not a cache controller?
> > The compatible and fact that the property points to an actual cache
> > controller suggests that this is not.
>
> Good point. This nodes represents just the QoS interface (CBQRI) and
> should not use that node name. 'qos-controller' seems like it would be
> more appropriate but that has no precedent. What do you think?
Sure.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* [PATCH v10 0/6] mm/memory-failure: add panic option for unrecoverable pages
From: Breno Leitao @ 2026-06-26 15:33 UTC (permalink / raw)
To: Miaohe Lin, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Shuah Khan, Naoya Horiguchi, Jonathan Corbet, Shuah Khan,
Liam R. Howlett, lance.yang, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Liam R. Howlett
Cc: linux-mm, linux-kernel, linux-doc, linux-kselftest, Breno Leitao,
linux-trace-kernel, kernel-team
A multi-bit ECC error on a kernel-owned page that the memory failure
handler cannot recover is currently swallowed: PG_hwpoison is set, the
event is logged, and the kernel keeps running. The corrupted memory
remains accessible to the kernel and either drives silent data
corruption or surfaces seconds-to-minutes later as an apparently
unrelated crash. In a large fleet that delayed, unattributable crash
turns into significant engineering effort to root-cause; in a kdump
configuration, by the time the crash happens the original error
context (faulting PFN, MCE/GHES record, page state) is long gone.
This series adds an opt-in sysctl,
vm.panic_on_unrecoverable_memory_failure, that converts an
unrecoverable kernel-page hwpoison event into an immediate panic with
a clean dmesg/vmcore that still contains the original failure
context. The default is disabled so existing workloads see no
change.
There is a selftest that test different cases, and I tested it using
the following variants:
┌─────────┬──────────┬───────────────────────────────────────────────────────────┐
│ Variant │ PFN │ Result │
├─────────┼──────────┼───────────────────────────────────────────────────────────┤
│ rodata │ 0x2600 │ Panic with "Memory failure: 0x2600: unrecoverable page" │
├─────────┼──────────┼───────────────────────────────────────────────────────────┤
│ slab │ 0x100032 │ Panic with "Memory failure: 0x100032: unrecoverable page" │
├─────────┼──────────┼───────────────────────────────────────────────────────────┤
│ pgtable │ 0x100000 │ Panic with "Memory failure: 0x100000: unrecoverable page" │
└─────────┴──────────┴───────────────────────────────────────────────────────────┘
Each one shows the same call trace, exactly the path the series builds:
hard_offline_page_store
→ memory_failure
→ action_result
→ panic("Memory failure: %#lx: unrecoverable page")
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Changes in v10:
- EDITME: describe what is new in this series revision.
- EDITME: use bulletpoints and terse descriptions.
- Link to v9: https://lore.kernel.org/r/20260609-ecc_panic-v9-0-432a74002e74@debian.org
Changes in v9:
- HWPoisonKernelOwned(): wrap the head-page checks in a
compound_head() recheck loop so a concurrent split or compound free
cannot leave us trusting a stale view (Miaohe, Lance, David).
- selftest: drop the gawk-only strtonum() in hwpoison-panic.sh; do the
hex parsing with a small index()-based helper so the test no longer
spuriously skips itself on mawk-based distros (Sashiko).
- selftest: move hwpoison-panic.sh from TEST_FILES to
TEST_PROGS_EXTENDED so the script is installed executable rather
than as a non-executable data file (Sashiko).
- Link to v8: https://patch.msgid.link/20260527-ecc_panic-v8-0-9ea0cfa16bb0@debian.org
Changes in v8:
- Commit message rewording (David)
- Add HWPoisonKernelOwned() helper (Lance)
- Removed patch "mm/memory-failure: short-circuit PG_reserved before get_hwpoison_page()"
- Broaden the selftest (Lance)
- Link to v7: https://patch.msgid.link/20260513-ecc_panic-v7-0-be2e578e61da@debian.org
Changes in v7:
- Move the PG_reserved / unhandlable-kernel-page classification into
get_any_page() and surface it via -ENOTRECOVERABLE, per David
Hildenbrand's and Lance Yang's review of v6. This drops the
is_reserved snapshot in memory_failure() and the mf_get_page_status
enum / out-parameter introduced in v6.
- Restructure the post-call branch in memory_failure() as a switch
over the get_hwpoison_page() return code (David).
- Drop the "reserved" qualifier from the MF_MSG_KERNEL label and the
matching tracepoint string; the enum now covers both PG_reserved
pages and other unhandlable kernel pages.
- Squash the former patches 1/4 ("MF_MSG_KERNEL for reserved pages")
and 2/4 ("classify get_any_page() failures by reason") into a
single classification patch; the series is now 3 patches.
- Simplify panic_on_unrecoverable_mf() to a single return statement
(David).
- Link to v6: https://patch.msgid.link/20260511-ecc_panic-v6-0-183012ba7d4b@debian.org
Changes in v6:
- Dropped the selftest given the value was not clear
- Get the status of the failure from get_any_page()
- Small nits from different people/AIs.
- Link to v5: https://patch.msgid.link/20260424-ecc_panic-v5-0-a35f4b50425c@debian.org
Changes in v5:
- Add vm.panic_on_unrecoverable_memory_failure sysctl to panic on
unrecoverable kernel page hwpoison events (reserved pages, refcount-0
non-buddy pages, unknown state), with a recheck to avoid racing with
concurrent buddy allocations. (Miaohe)
- Distinguish reserved pages as MF_MSG_KERNEL in memory_failure(),
document the new sysctl in Documentation/admin-guide/sysctl/vm.rst,
and add a selftest verifying SIGBUS recovery on userspace pages still
works when the sysctl is enabled. (Miaohe)
- Added a selftest
- Link to v4:
https://patch.msgid.link/20260415-ecc_panic-v4-0-2d0277f8f601@debian.org
Changes in v4:
- Drop CONFIG_BOOTPARAM_MEMORY_FAILURE_PANIC kernel configuration option.
- Split the reserved page classification (MF_MSG_KERNEL) into its own
patch, separate from the panic mechanism.
- Document why the buddy allocator TOCTOU race (between
get_hwpoison_page() and is_free_buddy_page()) cannot cause false
positives: PG_hwpoison is set beforehand and check_new_page() in the
page allocator rejects hwpoisoned pages.
- Document the narrow LRU isolation race window for MF_MSG_UNKNOWN and
its mitigation via identify_page_state()'s two-pass design.
- Explicitly document why MF_MSG_GET_HWPOISON is excluded from the
panic conditions (shared path with transient races and non-reserved
kernel memory).
- Link to v3: https://patch.msgid.link/20260413-ecc_panic-v3-0-1dcbb2f12bc4@debian.org
Changes in v3:
- Rename is_unrecoverable_memory_failure() to panic_on_unrecoverable_mf()
as suggested by maintainer.
- Add CONFIG_BOOTPARAM_MEMORY_FAILURE_PANIC kernel configuration option,
similar to CONFIG_BOOTPARAM_HARDLOCKUP_PANIC.
- Add documentation for the sysctl and CONFIG option.
- Add code comments documenting the panic condition design rationale and
how the retry mechanism mitigates false positives from buddy allocator
races.
- Link to v2: https://patch.msgid.link/20260331-ecc_panic-v2-0-9e40d0f64f7a@debian.org
Changes in v2:
- Panic on MF_MSG_KERNEL, MF_MSG_KERNEL_HIGH_ORDER and MF_MSG_UNKNOWN
instead of MF_MSG_GET_HWPOISON.
- Report MF_MSG_KERNEL for reserved pages when get_hwpoison_page() fails
instead of MF_MSG_GET_HWPOISON.
- Link to v1: https://patch.msgid.link/20260323-ecc_panic-v1-0-72a1921726c5@debian.org
To: Miaohe Lin <linmiaohe@huawei.com>
To: Naoya Horiguchi <nao.horiguchi@gmail.com>
To: Andrew Morton <akpm@linux-foundation.org>
To: Steven Rostedt <rostedt@goodmis.org>
To: Masami Hiramatsu <mhiramat@kernel.org>
To: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
To: Jonathan Corbet <corbet@lwn.net>
To: Shuah Khan <skhan@linuxfoundation.org>
To: David Hildenbrand <david@kernel.org>
To: Lorenzo Stoakes <ljs@kernel.org>
To: "Liam R. Howlett" <liam@infradead.org>
To: Vlastimil Babka <vbabka@kernel.org>
To: Mike Rapoport <rppt@kernel.org>
To: Suren Baghdasaryan <surenb@google.com>
To: Michal Hocko <mhocko@suse.com>
To: Shuah Khan <shuah@kernel.org>
Cc: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-trace-kernel@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kselftest@vger.kernel.org
---
Breno Leitao (6):
mm/memory-failure: drop dead error_states[] entry for reserved pages
mm/memory-failure: surface unhandlable kernel pages as -ENOTRECOVERABLE
mm/memory-failure: report MF_MSG_KERNEL for unrecoverable kernel pages
mm/memory-failure: add panic option for unrecoverable pages
Documentation: document panic_on_unrecoverable_memory_failure sysctl
selftests/mm: add hwpoison-panic destructive test
Documentation/admin-guide/sysctl/vm.rst | 80 +++++++++
mm/memory-failure.c | 104 +++++++++--
tools/testing/selftests/mm/Makefile | 4 +
tools/testing/selftests/mm/hwpoison-panic.sh | 249 +++++++++++++++++++++++++++
4 files changed, 419 insertions(+), 18 deletions(-)
---
base-commit: 30ffa8de54e5cc80d93fd211ca134d1764a7011f
change-id: 20260323-ecc_panic-4e473b83087c
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply
* [PATCH v10 6/6] selftests/mm: add hwpoison-panic destructive test
From: Breno Leitao @ 2026-06-26 15:33 UTC (permalink / raw)
To: Miaohe Lin, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Shuah Khan, Naoya Horiguchi, Jonathan Corbet, Shuah Khan,
Liam R. Howlett, lance.yang, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Liam R. Howlett
Cc: linux-mm, linux-kernel, linux-doc, linux-kselftest, Breno Leitao,
linux-trace-kernel, kernel-team
In-Reply-To: <20260626-ecc_panic-v10-0-6dacb8ad024d@debian.org>
Add a destructive selftest that verifies
vm.panic_on_unrecoverable_memory_failure actually panics when a
hwpoison error hits a kernel-owned page.
Three "kinds" of kernel-owned page can be targeted, selectable via
the script's first positional argument (default: rodata):
rodata - a PG_reserved page in the kernel rodata range, sourced
from the "Kernel rodata" sub-resource of "System RAM" in
/proc/iomem. That entry is reported on every major
architecture and guarantees the chosen PFN is backed by
struct page (an online System RAM range, not a firmware
hole), is PG_reserved, and is read-only -- so even if
the panic fails to fire for some reason, the resulting
PG_hwpoison marker on rodata does not corrupt writable
kernel state.
slab - a slab page found by walking /proc/kpageflags for the
first PFN with KPF_SLAB set (and KPF_HWPOISON / KPF_NOPAGE
/ KPF_COMPOUND_TAIL clear). Exercises the get_any_page()
path on a non PG_reserved kernel-owned page and so
catches regressions where get_any_page() collapses
kernel-owned pages into a transient -EIO instead of
-ENOTRECOVERABLE.
pgtable - same as slab, but the PFN is selected via KPF_PGTABLE.
PageLargeKmalloc, the fourth page type matched by
is_kernel_owned_page(), is intentionally not covered: it is a
PAGE_TYPE_OPS flag with no /proc/kpageflags bit, so selecting such
a PFN from userspace is not feasible. The slab and pgtable
variants already exercise the same get_any_page() positive-check
branch.
The script enables the sysctl and writes the selected physical
address to /sys/devices/system/memory/hard_offline_page. A
successful run crashes the kernel with
Memory failure: <pfn>: unrecoverable page
A return from the inject means no panic fired. Before reporting, the
script restores the sysctl and best-effort unpoisons the target PFN
through the hwpoison debugfs interface (hard_offline_page() injects
with MF_SW_SIMULATED, so the page stays unpoisonable), then re-reads
/proc/kpageflags: a PFN that is still the kernel-owned type it selected
is a genuine failure, while one that raced to a different type before
the inject is skipped as inconclusive. Test outcome is therefore
observed externally (serial console, kdump) rather than from the
script's own exit code.
The script is intentionally NOT wired into run_vmtests.sh: every
successful run panics the kernel, which is incompatible with the
sequential "run each category in the same VM" model that
run_vmtests.sh assumes. It is also not registered as a TEST_PROGS /
ksft_* wrapper so a default kselftest run does not opt itself into
a panic. The script is meant to be executed manually inside a
disposable VM (e.g. virtme-ng), one variant per VM boot, and
requires RUN_DESTRUCTIVE=1 in the environment as a safety net.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
tools/testing/selftests/mm/Makefile | 4 +
tools/testing/selftests/mm/hwpoison-panic.sh | 249 +++++++++++++++++++++++++++
2 files changed, 253 insertions(+)
diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
index e6df968f0971c..ed321ae709dac 100644
--- a/tools/testing/selftests/mm/Makefile
+++ b/tools/testing/selftests/mm/Makefile
@@ -174,6 +174,10 @@ TEST_PROGS += ksft_userfaultfd.sh
TEST_PROGS += ksft_vma_merge.sh
TEST_PROGS += ksft_vmalloc.sh
+# Destructive: every successful run panics the kernel. Installed and
+# kept executable, but not run from a default kselftest invocation.
+TEST_PROGS_EXTENDED += hwpoison-panic.sh
+
TEST_FILES := test_vmalloc.sh
TEST_FILES += test_hmm.sh
TEST_FILES += va_high_addr_switch.sh
diff --git a/tools/testing/selftests/mm/hwpoison-panic.sh b/tools/testing/selftests/mm/hwpoison-panic.sh
new file mode 100755
index 0000000000000..aafc06e895d01
--- /dev/null
+++ b/tools/testing/selftests/mm/hwpoison-panic.sh
@@ -0,0 +1,249 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Verify vm.panic_on_unrecoverable_memory_failure by injecting a hwpoison
+# error on a kernel-owned page and confirming the kernel panics.
+#
+# Three "kinds" of kernel-owned page can be targeted, selectable via the
+# first positional argument (default: rodata):
+#
+# rodata - a PG_reserved page in the kernel rodata range
+# (sourced from /proc/iomem "Kernel rodata"). Exercises
+# memory_failure() -> get_any_page() on a PageReserved page.
+#
+# slab - a slab page found via /proc/kpageflags (KPF_SLAB).
+# Exercises memory_failure() -> get_any_page() on a non
+# PG_reserved kernel-owned page. This path is what catches
+# regressions where get_any_page() collapses kernel-owned
+# pages into a transient -EIO instead of -ENOTRECOVERABLE.
+#
+# pgtable - a page-table page found via /proc/kpageflags (KPF_PGTABLE).
+# Same path as slab, different page type.
+#
+# This test is DESTRUCTIVE: a successful run crashes the kernel. It is
+# meant to be executed inside a disposable VM (e.g. virtme-ng) with a
+# serial console captured by the harness. It is skipped unless the
+# caller opts in via RUN_DESTRUCTIVE=1.
+#
+# Test passes externally: the kernel must panic with
+# "Memory failure: <pfn>: unrecoverable page"
+# A return from the inject means no panic fired: that is a failure,
+# unless the target PFN raced to a different page type before injection,
+# in which case the run is inconclusive and is skipped.
+#
+# Author: Breno Leitao <leitao@debian.org>
+
+set -u
+
+ksft_skip=4
+sysctl_path=/proc/sys/vm/panic_on_unrecoverable_memory_failure
+inject_path=/sys/devices/system/memory/hard_offline_page
+kpageflags_path=/proc/kpageflags
+unpoison_path=/sys/kernel/debug/hwpoison/unpoison-pfn
+
+# /proc/kpageflags bit positions (see include/uapi/linux/kernel-page-flags.h)
+KPF_SLAB=7
+KPF_COMPOUND_TAIL=16
+KPF_HWPOISON=19
+KPF_NOPAGE=20
+KPF_PGTABLE=26
+KPF_RESERVED=32
+
+pagesize=$(getconf PAGE_SIZE)
+
+kind=${1:-rodata}
+
+ksft_print() { echo "# $*"; }
+ksft_exit_skip() { ksft_print "$*"; exit "$ksft_skip"; }
+ksft_exit_fail() { echo "not ok 1 $*"; exit 1; }
+
+if [ "$(id -u)" -ne 0 ]; then
+ ksft_exit_skip "must run as root"
+fi
+
+if [ ! -w "$sysctl_path" ]; then
+ ksft_exit_skip "$sysctl_path not present (kernel without the sysctl?)"
+fi
+
+if [ ! -w "$inject_path" ]; then
+ ksft_exit_skip "$inject_path not present (no MEMORY_HOTPLUG?)"
+fi
+
+if [ "${RUN_DESTRUCTIVE:-0}" != "1" ]; then
+ ksft_exit_skip "destructive test; re-run with RUN_DESTRUCTIVE=1 inside a disposable VM"
+fi
+
+# Pick a PFN inside the kernel image rodata region of /proc/iomem.
+# This is preferred over a top-level "Reserved" entry because top-level
+# Reserved ranges are often firmware holes that have no backing struct
+# page; pfn_to_online_page() returns NULL on those and memory_failure()
+# bails out with -ENXIO before reaching the panic path.
+#
+# "Kernel rodata" is reported as a sub-resource of "System RAM" on every
+# major architecture, which guarantees:
+# - the PFN is backed by struct page (within an online memory range);
+# - PG_reserved is set on the page (kernel image area);
+# - the memory is read-only, so setting PG_hwpoison on it does not
+# corrupt writable kernel state if the panic somehow does not fire.
+#
+# /proc/iomem entries look like (indented for sub-resources):
+# " 02500000-02ffffff : Kernel rodata"
+pick_rodata_phys_addr() {
+ awk -v pagesize="$(getconf PAGE_SIZE)" '
+ # Convert a hex string to a number without relying on the gawk-only
+ # strtonum(). mawk lacks it and would otherwise spuriously skip
+ # this test on distros that ship mawk as /usr/bin/awk.
+ function hex2num(s, n, i, c, v) {
+ n = 0
+ for (i = 1; i <= length(s); i++) {
+ c = tolower(substr(s, i, 1))
+ v = index("0123456789abcdef", c) - 1
+ if (v < 0)
+ return -1
+ n = n * 16 + v
+ }
+ return n
+ }
+ /: Kernel rodata[[:space:]]*$/ {
+ sub(/^[[:space:]]+/, "")
+ n = split($0, a, /[- ]/)
+ start = hex2num(a[1])
+ end = hex2num(a[2])
+ if (end <= start)
+ next
+ # Page-align upward and emit the first byte of that page.
+ pfn = int((start + pagesize - 1) / pagesize)
+ printf "0x%x\n", pfn * pagesize
+ exit 0
+ }
+ ' /proc/iomem
+}
+
+# Walk /proc/kpageflags and return the phys addr of the first PFN that
+# has bit $1 set, with KPF_HWPOISON, KPF_NOPAGE and KPF_COMPOUND_TAIL
+# all clear (so we attack a real, non-tail, not-already-poisoned page).
+#
+# We skip the first 16 MiB of PFNs to step past low-memory special
+# ranges (BIOS/EFI/ACPI/etc.) that often are PG_reserved and would not
+# exhibit the slab/pgtable type we are looking for.
+pick_kpageflags_phys_addr() {
+ local want_bit=$1
+ local pagesize skip_pfn
+
+ [ -r "$kpageflags_path" ] || return
+
+ pagesize=$(getconf PAGE_SIZE)
+ skip_pfn=$(((16 * 1024 * 1024) / pagesize))
+
+ od -An -tx8 -v -w8 -j "$((skip_pfn * 8))" "$kpageflags_path" 2>/dev/null | \
+ awk -v want_bit="$want_bit" \
+ -v hwp_bit="$KPF_HWPOISON" \
+ -v nopage_bit="$KPF_NOPAGE" \
+ -v tail_bit="$KPF_COMPOUND_TAIL" \
+ -v base_pfn="$skip_pfn" \
+ -v pagesize="$pagesize" '
+ # Test whether bit "b" is set in the 16-hex-digit value "hex".
+ # Done with substring + per-digit lookup so we never rely on awk
+ # bitwise operators (mawk lacks them), 64-bit FP precision or the
+ # gawk-only strtonum().
+ function bit_set(hex, b, di, bi, c, v) {
+ di = int(b / 4)
+ bi = b - di * 4
+ c = substr(hex, length(hex) - di, 1)
+ v = index("0123456789abcdef", tolower(c)) - 1
+ if (bi == 0) return (v % 2) == 1
+ if (bi == 1) return int(v / 2) % 2 == 1
+ if (bi == 2) return int(v / 4) % 2 == 1
+ return int(v / 8) % 2 == 1
+ }
+ {
+ gsub(/^[[:space:]]+/, "")
+ h = $1
+ if (bit_set(h, want_bit) &&
+ !bit_set(h, hwp_bit) &&
+ !bit_set(h, nopage_bit) &&
+ !bit_set(h, tail_bit)) {
+ pfn = base_pfn + NR - 1
+ printf "0x%x\n", pfn * pagesize
+ exit 0
+ }
+ }
+ '
+}
+
+# Return 0 if /proc/kpageflags bit $2 is set for PFN $1, 1 if it is
+# clear, or 2 if the word cannot be read. Used to re-confirm the target
+# page type after a non-panicking inject.
+kpageflags_bit_set() {
+ local word
+
+ word=$(od -An -tx8 -v -j "$(($1 * 8))" -N 8 "$kpageflags_path" 2>/dev/null | tr -d '[:space:]')
+ [ -n "$word" ] || return 2
+ (( (16#$word >> $2) & 1 ))
+}
+
+# Best-effort: drop the PG_hwpoison marker set by the inject so a failed
+# run does not leave a poisoned page behind. hard_offline_page() injects
+# with MF_SW_SIMULATED, so the page stays unpoisonable through the
+# hwpoison debugfs interface (needs CONFIG_HWPOISON_INJECT + debugfs).
+try_unpoison() {
+ [ -w "$unpoison_path" ] || return 0
+ echo "$1" > "$unpoison_path" 2>/dev/null || true
+}
+
+case "$kind" in
+rodata)
+ phys_addr=$(pick_rodata_phys_addr)
+ recheck_bit=$KPF_RESERVED
+ missing_msg='no "Kernel rodata" entry in /proc/iomem'
+ ;;
+slab)
+ phys_addr=$(pick_kpageflags_phys_addr "$KPF_SLAB")
+ recheck_bit=$KPF_SLAB
+ missing_msg="no usable slab PFN found in $kpageflags_path"
+ ;;
+pgtable)
+ phys_addr=$(pick_kpageflags_phys_addr "$KPF_PGTABLE")
+ recheck_bit=$KPF_PGTABLE
+ missing_msg="no usable page-table PFN found in $kpageflags_path"
+ ;;
+*)
+ ksft_exit_fail "unknown kind '$kind' (expected: rodata|slab|pgtable)"
+ ;;
+esac
+
+if [ -z "$phys_addr" ]; then
+ ksft_exit_skip "$missing_msg"
+fi
+
+ksft_print "enabling $sysctl_path"
+prior=$(cat "$sysctl_path")
+echo 1 > "$sysctl_path" || ksft_exit_fail "failed to enable sysctl"
+
+pfn=$((phys_addr / pagesize))
+ksft_print "injecting hwpoison at phys 0x$(printf '%x' "$phys_addr") (pfn 0x$(printf '%x' "$pfn"), kind=$kind)"
+ksft_print "expecting kernel panic: 'Memory failure: <pfn>: unrecoverable page'"
+
+# A successful run never returns from the inject -- it panics the kernel.
+# Reaching the code below therefore means no panic fired. Note whether
+# the write itself succeeded, then put the machine back: restore the
+# sysctl and best-effort unpoison the page we just marked.
+if echo "$phys_addr" > "$inject_path"; then
+ verdict="inject returned without panic; sysctl ineffective"
+else
+ verdict="inject failed before reaching the panic path"
+fi
+
+echo "$prior" > "$sysctl_path"
+try_unpoison "$pfn"
+
+# The page type can change between selection and injection (e.g. a slab
+# or page-table page is freed and reused). Only treat a missing panic as
+# a failure if the target PFN is still the kernel-owned type we aimed at;
+# if it raced to another type the run is inconclusive, so skip instead.
+kpageflags_bit_set "$pfn" "$recheck_bit"
+case $? in
+0) ksft_exit_fail "$verdict (page still $kind)" ;;
+1) ksft_exit_skip "target PFN no longer $kind; raced before inject, inconclusive" ;;
+*) ksft_exit_fail "$verdict (could not reconfirm page type via $kpageflags_path)" ;;
+esac
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH v10 5/6] Documentation: document panic_on_unrecoverable_memory_failure sysctl
From: Breno Leitao @ 2026-06-26 15:33 UTC (permalink / raw)
To: Miaohe Lin, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Shuah Khan, Naoya Horiguchi, Jonathan Corbet, Shuah Khan,
Liam R. Howlett, lance.yang, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Liam R. Howlett
Cc: linux-mm, linux-kernel, linux-doc, linux-kselftest, Breno Leitao,
linux-trace-kernel, kernel-team
In-Reply-To: <20260626-ecc_panic-v10-0-6dacb8ad024d@debian.org>
Add documentation for the new vm.panic_on_unrecoverable_memory_failure
sysctl, describing which failures trigger a panic (kernel-owned pages
the handler cannot recover) and which are intentionally left out
(transient allocator races and unclassified pages).
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Documentation/admin-guide/sysctl/vm.rst | 80 +++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/Documentation/admin-guide/sysctl/vm.rst b/Documentation/admin-guide/sysctl/vm.rst
index b9b0c218bfb44..22cc54cac3b21 100644
--- a/Documentation/admin-guide/sysctl/vm.rst
+++ b/Documentation/admin-guide/sysctl/vm.rst
@@ -67,6 +67,7 @@ Currently, these files are in /proc/sys/vm:
- page-cluster
- page_lock_unfairness
- panic_on_oom
+- panic_on_unrecoverable_memory_failure
- percpu_pagelist_high_fraction
- stat_interval
- stat_refresh
@@ -925,6 +926,85 @@ panic_on_oom=2+kdump gives you very strong tool to investigate
why oom happens. You can get snapshot.
+panic_on_unrecoverable_memory_failure
+======================================
+
+When a hardware memory error (e.g. multi-bit ECC) hits a kernel page
+that cannot be recovered by the memory failure handler, the default
+behaviour is to ignore the error and continue operation. This is
+dangerous because the corrupted data remains accessible to the kernel,
+risking silent data corruption or a delayed crash when the poisoned
+memory is next accessed.
+
+When enabled, this sysctl triggers a panic on memory failure events
+hitting kernel-owned pages that the handler cannot recover:
+``PageReserved`` (firmware reservations, kernel image, vDSO, zero
+page, and similar memblock-reserved regions), ``PageSlab``,
+``PageTable``, and ``PageLargeKmalloc``. These are owned by the
+kernel and the memory failure handler cannot reliably evict their
+contents.
+
+Other unrecoverable kernel-owned populations (vmalloc allocations,
+kernel stack pages, ...) are not currently covered because the
+handler has no page-type signal that distinguishes them from a
+userspace folio temporarily off the LRU during migration or
+compaction. Such pages still go through the standard
+MF_MSG_GET_HWPOISON path: ``PG_hwpoison`` is set on them and a
+delayed crash on the next access remains possible. Coverage may
+grow as the handler gains stronger kernel-ownership signals.
+
+Recoverable failure paths are also intentionally left out: in-flight
+buddy allocations and other transient races with the page allocator
+can reach the same diagnostic, and panicking on them would risk
+killing the box for a page destined for userspace where the standard
+SIGBUS recovery path applies. Pages whose state could not be
+classified at all are not covered either, since an unknown state is
+not a sound basis for a panic decision.
+
+For many environments it is preferable to panic immediately with a clean
+crash dump that captures the original error context, rather than to
+continue and face a random crash later whose cause is difficult to
+diagnose.
+
+Use cases
+---------
+
+This option is most useful in environments where unattributed crashes
+are expensive to debug or where data integrity must take precedence
+over availability:
+
+* Large fleets, where multi-bit ECC errors on kernel pages are observed
+ regularly and post-mortem analysis of an unrelated downstream crash
+ (often seconds to minutes after the original error) consumes
+ significant engineering effort.
+
+* Systems configured with kdump, where panicking at the moment of the
+ hardware error produces a vmcore that still contains the faulting
+ address, the affected page state, and the originating MCE/GHES
+ record — context that is typically lost by the time a delayed crash
+ occurs.
+
+* High-availability clusters that rely on fast, deterministic node
+ failure for failover, and prefer an immediate panic over silent data
+ corruption propagating to replicas or persistent storage.
+
+* Kernel and platform developers reproducing hwpoison issues with
+ tools such as ``mce-inject`` or error-injection debugfs interfaces,
+ where panicking on the unrecoverable path makes regressions
+ immediately visible instead of surfacing as later, unrelated
+ failures.
+
+= =====================================================================
+0 Try to continue operation (default).
+1 Panic immediately. If the ``panic`` sysctl is also non-zero then the
+ machine will be rebooted.
+= =====================================================================
+
+Example::
+
+ echo 1 > /proc/sys/vm/panic_on_unrecoverable_memory_failure
+
+
percpu_pagelist_high_fraction
=============================
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH v10 4/6] mm/memory-failure: add panic option for unrecoverable pages
From: Breno Leitao @ 2026-06-26 15:33 UTC (permalink / raw)
To: Miaohe Lin, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Shuah Khan, Naoya Horiguchi, Jonathan Corbet, Shuah Khan,
Liam R. Howlett, lance.yang, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Liam R. Howlett
Cc: linux-mm, linux-kernel, linux-doc, linux-kselftest, Breno Leitao,
linux-trace-kernel, kernel-team
In-Reply-To: <20260626-ecc_panic-v10-0-6dacb8ad024d@debian.org>
Add a sysctl panic_on_unrecoverable_memory_failure (disabled by
default) that triggers a kernel panic when memory_failure()
encounters pages that cannot be recovered. This provides a clean
crash with useful debug information rather than allowing silent
data corruption or a delayed crash at an unrelated code path.
Panic eligibility is intentionally narrow: only MF_MSG_KERNEL with
result == MF_IGNORED panics. After the previous patch, MF_MSG_KERNEL
covers PG_reserved pages and the kernel-owned pages promoted from
get_hwpoison_page() via -ENOTRECOVERABLE (slab, page tables,
large-kmalloc).
All other action types are excluded:
- MF_MSG_GET_HWPOISON and MF_MSG_KERNEL_HIGH_ORDER can be reached by
transient refcount races with the page allocator (an in-flight buddy
allocation has refcount 0 and is no longer on the buddy free list,
briefly), and panicking on them would risk killing the box for what
is actually a recoverable userspace page.
- MF_MSG_UNKNOWN means identify_page_state() could not classify the
page; that is precisely the wrong basis for a panic decision.
Acked-by: Miaohe Lin <linmiaohe@huawei.com>
Signed-off-by: Breno Leitao <leitao@debian.org>
---
mm/memory-failure.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 8e2aa2fafc14e..611160c98c6f6 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -74,6 +74,8 @@ static int sysctl_memory_failure_recovery __read_mostly = 1;
static int sysctl_enable_soft_offline __read_mostly = 1;
+static int sysctl_panic_on_unrecoverable_mf __read_mostly;
+
atomic_long_t num_poisoned_pages __read_mostly = ATOMIC_LONG_INIT(0);
static bool hw_memory_failure __read_mostly = false;
@@ -155,6 +157,15 @@ static const struct ctl_table memory_failure_table[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
+ },
+ {
+ .procname = "panic_on_unrecoverable_memory_failure",
+ .data = &sysctl_panic_on_unrecoverable_mf,
+ .maxlen = sizeof(sysctl_panic_on_unrecoverable_mf),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
}
};
@@ -1255,6 +1266,15 @@ static void update_per_node_mf_stats(unsigned long pfn,
++mf_stats->total;
}
+static bool panic_on_unrecoverable_mf(enum mf_action_page_type type,
+ enum mf_result result)
+{
+ if (!sysctl_panic_on_unrecoverable_mf)
+ return false;
+
+ return type == MF_MSG_KERNEL && result == MF_IGNORED;
+}
+
/*
* "Dirty/Clean" indication is not 100% accurate due to the possibility of
* setting PG_dirty outside page lock. See also comment above set_page_dirty().
@@ -1272,6 +1292,9 @@ static int action_result(unsigned long pfn, enum mf_action_page_type type,
pr_err("%#lx: recovery action for %s: %s\n",
pfn, action_page_types[type], action_name[result]);
+ if (panic_on_unrecoverable_mf(type, result))
+ panic("Memory failure: %#lx: unrecoverable page", pfn);
+
return (result == MF_RECOVERED || result == MF_DELAYED) ? 0 : -EBUSY;
}
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH v10 3/6] mm/memory-failure: report MF_MSG_KERNEL for unrecoverable kernel pages
From: Breno Leitao @ 2026-06-26 15:33 UTC (permalink / raw)
To: Miaohe Lin, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Shuah Khan, Naoya Horiguchi, Jonathan Corbet, Shuah Khan,
Liam R. Howlett, lance.yang, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Liam R. Howlett
Cc: linux-mm, linux-kernel, linux-doc, linux-kselftest, Breno Leitao,
linux-trace-kernel, kernel-team
In-Reply-To: <20260626-ecc_panic-v10-0-6dacb8ad024d@debian.org>
The previous patch teaches get_any_page() to return -ENOTRECOVERABLE
for stable unhandlable kernel pages (PG_reserved, slab, page tables,
large-kmalloc). memory_failure() still folds every negative return
into MF_MSG_GET_HWPOISON, so callers that want to react to the
unrecoverable cases (a panic option, smarter logging) cannot tell
them apart from transient page-allocator races.
Turn the post-call branch into a switch over the get_hwpoison_page()
return code: map -ENOTRECOVERABLE to MF_MSG_KERNEL and any other
negative return to MF_MSG_GET_HWPOISON. case 0 keeps the existing
free-buddy / kernel-high-order handling and case 1 falls through to
the rest of memory_failure() unchanged.
The MF_MSG_KERNEL label and tracepoint string are kept as
"reserved kernel page" to avoid breaking userspace tools that match
on those literals; the enum value still adequately tags the failure
even though it now also covers slab, page tables and large-kmalloc
pages.
Suggested-by: David Hildenbrand <david@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Miaohe Lin <linmiaohe@huawei.com>
Signed-off-by: Breno Leitao <leitao@debian.org>
---
mm/memory-failure.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index d08fbd0d8c39f..8e2aa2fafc14e 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -2434,7 +2434,8 @@ int memory_failure(unsigned long pfn, int flags)
* that may make page_ref_freeze()/page_ref_unfreeze() mismatch.
*/
res = get_hwpoison_page(p, flags);
- if (!res) {
+ switch (res) {
+ case 0:
if (is_free_buddy_page(p)) {
if (take_page_off_buddy(p)) {
page_ref_inc(p);
@@ -2453,7 +2454,19 @@ int memory_failure(unsigned long pfn, int flags)
res = action_result(pfn, MF_MSG_KERNEL_HIGH_ORDER, MF_IGNORED);
}
goto unlock_mutex;
- } else if (res < 0) {
+ case 1:
+ /* Got a refcount on a handlable page. */
+ break;
+ case -ENOTRECOVERABLE:
+ /*
+ * Stable unhandlable kernel-owned page (PG_reserved,
+ * slab, page tables, large-kmalloc).
+ * No recovery possible.
+ */
+ res = action_result(pfn, MF_MSG_KERNEL, MF_IGNORED);
+ goto unlock_mutex;
+ default:
+ /* Transient lifecycle race with the page allocator. */
res = action_result(pfn, MF_MSG_GET_HWPOISON, MF_IGNORED);
goto unlock_mutex;
}
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH v10 2/6] mm/memory-failure: surface unhandlable kernel pages as -ENOTRECOVERABLE
From: Breno Leitao @ 2026-06-26 15:33 UTC (permalink / raw)
To: Miaohe Lin, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Shuah Khan, Naoya Horiguchi, Jonathan Corbet, Shuah Khan,
Liam R. Howlett, lance.yang, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Liam R. Howlett
Cc: linux-mm, linux-kernel, linux-doc, linux-kselftest, Breno Leitao,
linux-trace-kernel, kernel-team
In-Reply-To: <20260626-ecc_panic-v10-0-6dacb8ad024d@debian.org>
get_any_page() collapses every HWPoisonHandlable() rejection into a
single -EIO via the __get_hwpoison_page() -> -EBUSY -> shake_page()
-> retry path. That is correct for the transient case (a userspace
folio briefly off LRU during migration or compaction, which a later
shake can drag back), but wrong for stable kernel-owned pages: slab,
page-table, large-kmalloc and PG_reserved pages will never become
HWPoisonHandlable(), so the retry loop is wasted work and the final
-EIO loses the "this is structurally unrecoverable" information.
memory_failure() then maps -EIO into MF_MSG_GET_HWPOISON, which the
panic-on-unrecoverable sysctl deliberately does not act on.
Introduce is_kernel_owned_page(), a small predicate that positively
identifies pages the hwpoison handler cannot recover from:
is_kernel_owned_page(p) :=
PageReserved(p) ||
PageSlab(head) || PageTable(head) || PageLargeKmalloc(head)
where head = compound_head(p).
PG_reserved is a per-page flag (PF_NO_COMPOUND) and is tested on the
page directly. The slab, page-table and large-kmalloc page-type bits
are only stored on the head page, so those tests resolve the compound
head first, then re-read compound_head(page) afterwards: a concurrent
split or compound free that moves head invalidates the just-read flags
and the loop retries. The lookup still takes no refcount, mirroring
the rest of get_any_page(); the recheck closes the common split race,
and a residual free->alloc->free in the same window can only mis-tag
a genuinely poisoned page, never reclassify a handlable one.
No MF_SOFT_OFFLINE / page_has_movable_ops() opt-out is needed: a
movable_ops page is always PageOffline or PageZsmalloc, whose
page_type is mutually exclusive with slab, page-table and
large-kmalloc, and it never carries PG_reserved, so it can never
match any of the checks above.
The list is intentionally not exhaustive. vmalloc and kernel-stack
pages, for example, do not carry a page_type bit and would need a
different oracle; they keep going through the existing retry path
unchanged. This is the smallest set we can identify with certainty
by page type.
Wire the helper into the top of get_any_page() to short-circuit
those pages before the retry loop runs. On a hit, drop the caller's
MF_COUNT_INCREASED reference (if any) and return -ENOTRECOVERABLE
straight away. Pages outside the helper's positive list still take
the existing retry path and return -EIO, leaving operator-visible
behaviour for those cases unchanged.
Extend the unhandlable-page pr_err() to fire for either errno and
update the get_hwpoison_page() kerneldoc to document the new return.
memory_failure() still folds every negative return into
MF_MSG_GET_HWPOISON via its existing "else if (res < 0)" branch, so
this patch on its own only changes the errno that soft_offline_page()
can propagate to its callers. A follow-up wires -ENOTRECOVERABLE
through memory_failure() and reports MF_MSG_KERNEL for the
unrecoverable cases, which is what the
panic_on_unrecoverable_memory_failure sysctl observes.
Suggested-by: David Hildenbrand <david@kernel.org>
Suggested-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: Breno Leitao <leitao@debian.org>
---
mm/memory-failure.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 48 insertions(+), 2 deletions(-)
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index f4d3e6e20e13f..d08fbd0d8c39f 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1325,6 +1325,36 @@ static inline bool HWPoisonHandlable(struct page *page, unsigned long flags)
return PageLRU(page) || is_free_buddy_page(page);
}
+/*
+ * Positive identification of pages the hwpoison handler cannot recover:
+ * pages owned by kernel internals with no userspace mapping to unmap, no
+ * file mapping to invalidate, and no migration target.
+ */
+static inline bool is_kernel_owned_page(struct page *page)
+{
+ struct page *head;
+ bool kernel_owned;
+
+ /* PG_reserved is a per-page flag, never set on a compound page. */
+ if (PageReserved(page))
+ return true;
+
+ /*
+ * Page-type bits live only on the head page, so resolve any tail
+ * first. The check takes no refcount; recheck the head afterwards
+ * so a concurrent split or compound free cannot leave us trusting
+ * a stale view. A free->alloc->free in the same window is still
+ * possible but closing it would require taking a reference here.
+ */
+retry:
+ head = compound_head(page);
+ kernel_owned = PageSlab(head) || PageTable(head) ||
+ PageLargeKmalloc(head);
+ if (head != compound_head(page))
+ goto retry;
+ return kernel_owned;
+}
+
static int __get_hwpoison_page(struct page *page, unsigned long flags)
{
struct folio *folio = page_folio(page);
@@ -1371,6 +1401,19 @@ static int get_any_page(struct page *p, unsigned long flags)
if (flags & MF_COUNT_INCREASED)
count_increased = true;
+ /*
+ * Page types we know are kernel-owned and cannot be recovered.
+ * Short-circuit before the shake_page() / retry loop, which
+ * cannot turn any of these into something HWPoisonHandlable().
+ * Drop the caller's reference if MF_COUNT_INCREASED took one.
+ */
+ if (is_kernel_owned_page(p)) {
+ if (count_increased)
+ put_page(p);
+ ret = -ENOTRECOVERABLE;
+ goto out;
+ }
+
try_again:
if (!count_increased) {
ret = __get_hwpoison_page(p, flags);
@@ -1418,7 +1461,7 @@ static int get_any_page(struct page *p, unsigned long flags)
ret = -EIO;
}
out:
- if (ret == -EIO)
+ if (ret == -EIO || ret == -ENOTRECOVERABLE)
pr_err("%#lx: unhandlable page.\n", page_to_pfn(p));
return ret;
@@ -1475,7 +1518,10 @@ static int __get_unpoison_page(struct page *page)
* -EIO for pages on which we can not handle memory errors,
* -EBUSY when get_hwpoison_page() has raced with page lifecycle
* operations like allocation and free,
- * -EHWPOISON when the page is hwpoisoned and taken off from buddy.
+ * -EHWPOISON when the page is hwpoisoned and taken off from buddy,
+ * -ENOTRECOVERABLE for kernel-owned pages identified by
+ * is_kernel_owned_page() (PG_reserved, slab,
+ * page-table, large-kmalloc) that the handler cannot recover.
*/
static int get_hwpoison_page(struct page *p, unsigned long flags)
{
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH v10 1/6] mm/memory-failure: drop dead error_states[] entry for reserved pages
From: Breno Leitao @ 2026-06-26 15:33 UTC (permalink / raw)
To: Miaohe Lin, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Shuah Khan, Naoya Horiguchi, Jonathan Corbet, Shuah Khan,
Liam R. Howlett, lance.yang, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Liam R. Howlett
Cc: linux-mm, linux-kernel, linux-doc, linux-kselftest, Breno Leitao,
linux-trace-kernel, kernel-team
In-Reply-To: <20260626-ecc_panic-v10-0-6dacb8ad024d@debian.org>
The first entry of error_states[],
{ reserved, reserved, MF_MSG_KERNEL, me_kernel },
is unreachable. identify_page_state() has two callers, and neither
one can dispatch a PG_reserved page to me_kernel():
* memory_failure() reaches identify_page_state() only after
get_hwpoison_page() returned 1. get_any_page() reaches that
return only via __get_hwpoison_page(), which only takes a
refcount when the page is HWPoisonHandlable().
HWPoisonHandlable() is an allowlist for LRU, free-buddy, and
(for soft-offline) movable_ops pages -- PG_reserved pages do
not satisfy any of these, so they fail with -EBUSY/-EIO long
before identify_page_state() runs.
* try_memory_failure_hugetlb() reaches identify_page_state() only
via the MF_HUGETLB_IN_USED branch, where the page is necessarily
a hugetlb folio. hugetlb folios don't carry PG_reserved at that
point: hugetlb_folio_init_vmemmap() calls __folio_clear_reserved()
during init, so the reserved entry would not match even if it
were still present.
me_kernel() never executes and the entry exists only to be matched
against by code that cannot see it.
Drop the entry, the me_kernel() helper, and the now-unused
"reserved" macro. Leave the MF_MSG_KERNEL enum value in place: it
remains part of the tracepoint and pr_err() string tables, and
follow-on work to classify unrecoverable kernel pages can reuse it
without churning the user-visible enum.
No functional change.
Suggested-by: David Hildenbrand <david@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Acked-by: Miaohe Lin <linmiaohe@huawei.com>
Signed-off-by: Breno Leitao <leitao@debian.org>
---
mm/memory-failure.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 51508a55c4055..f4d3e6e20e13f 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -980,17 +980,6 @@ static bool has_extra_refcount(struct page_state *ps, struct page *p,
return false;
}
-/*
- * Error hit kernel page.
- * Do nothing, try to be lucky and not touch this instead. For a few cases we
- * could be more sophisticated.
- */
-static int me_kernel(struct page_state *ps, struct page *p)
-{
- unlock_page(p);
- return MF_IGNORED;
-}
-
/*
* Page in unknown state. Do nothing.
* This is a catch-all in case we fail to make sense of the page state.
@@ -1199,10 +1188,8 @@ static int me_huge_page(struct page_state *ps, struct page *p)
#define mlock (1UL << PG_mlocked)
#define lru (1UL << PG_lru)
#define head (1UL << PG_head)
-#define reserved (1UL << PG_reserved)
static struct page_state error_states[] = {
- { reserved, reserved, MF_MSG_KERNEL, me_kernel },
/*
* free pages are specially detected outside this table:
* PG_buddy pages only make a small fraction of all free pages.
@@ -1234,7 +1221,6 @@ static struct page_state error_states[] = {
#undef mlock
#undef lru
#undef head
-#undef reserved
static void update_per_node_mf_stats(unsigned long pfn,
enum mf_result result)
--
2.53.0-Meta
^ permalink raw reply related
* Re: [PATCH v12 00/16] Direct Map Removal Support for guest_memfd
From: Brendan Jackman @ 2026-06-26 15:28 UTC (permalink / raw)
To: Takahiro Itazuri, seanjc, ljs
Cc: Liam.Howlett, ackerleytng, agordeev, ajones, akpm, alex, andrii,
aou, ast, baolu.lu, catalin.marinas, chenhuacai, corbet, coxu,
daniel, dave.hansen, david, dev.jain, itazur, jackmanb, jannh,
jhubbard, jmattson, joey.gouly, john.fastabend, jolsa, jthoughton,
kas, kernel, kpsingh, kvm, kvmarm, lenb, linux-arm-kernel,
linux-doc, linux-fsdevel, linux-kernel, linux-kselftest, linux-mm,
linux-pm, linux-riscv, linux-s390, loongarch, lorenzo.stoakes,
luto, maobibo, martin.lau, maz, mhocko, mingo, mlevitsk,
nikita.kalyazin, oupton, palmer, patrick.roy, pavel, pbonzini,
peterx, peterz, pfalcato, pjw, prsampat, rafael, riel, rppt,
ryan.roberts, sdf, shijie, skhan, song, surenb, suzuki.poulose,
svens, tabba, tglx, thuth, urezki, vannapurve, vbabka, will,
willy, wu.fei9, x86, yang, yangyicong, yonghong.song, yosry,
yu-cheng.yu, yuzenghui, zhengqi.arch
In-Reply-To: <20260506080753.14517-1-itazur@amazon.com>
On Wed May 6, 2026 at 8:07 AM UTC, Takahiro Itazuri wrote:
> Hi Lorenzo and Sean,
>
> Apologies for the delayed reply — Nikita is leaving Amazon, and I'm
> taking over this series going forward. Thanks for your patience.
>
> On Tue, Apr 21, 2026 at 01:40:00PM +0000, Lorenzo Stoakes wrote:
>> Hm, given this touches a fair bit of mm, I wonder if we shouldn't try to do this
>> through the mm tree?
>
> On Tue, Apr 21, 2026 at 04:36:00PM +0000, Sean Christopherson wrote:
>> Yeah, when the time comes, the mm pieces definitely need to go through the mm
>> tree. Ideally, I think this would be merged in two separate parts, with all mm
>> changes going through the mm tree, and then the KVM changes through the KVM tree
>> using a stable topic branch/tag from Andrew.
>
> Thanks for the guidance. The split makes sense to me; I'm planning to
> follow this approach with patches 1-6 (mm) going through the mm tree
> and patches 7-16 (KVM) through the KVM tree on top of a stable
> branch/tag from mm. I'll confirm the exact boundary and coordination
> details as I prepare the repost.
>
> On Tue, Apr 21, 2026 at 01:40:00PM +0000, Lorenzo Stoakes wrote:
>> In any case, we definitely need a rebase on something not-next :) if not mm then
>> Linus's tree at least maybe?
>>
>> I'm seeing a lot of conflicts against mm-unstable, it can't b4 shazam even patch
>> 1 and in Linus's tree it's failing at an mm patch (mm: introduce
>> AS_NO_DIRECT_MAP).
>
Just as an FYI, I am gonna look at trying to move this forward a bit
while Takahiro ramps up on taking over (I spoke to him about this off
list).
My ulterior motive is that this would give me an excuse to add
ALLOC_UNMAPPED (formerly __GFP_UNMAPPED) and the mermap [0] which
unblocks various security nonsense including ASI [1]. (But also, this
feature is a good idea).
[0] https://lore.kernel.org/all/20260320-page_alloc-unmapped-v2-0-28bf1bd54f41@google.com/
[1] https://linuxasi.dev
^ permalink raw reply
* Re: [PATCH v12 01/16] set_memory: set_direct_map_* to take address
From: Mike Rapoport @ 2026-06-26 15:28 UTC (permalink / raw)
To: Brendan Jackman
Cc: Lorenzo Stoakes, Kalyazin, Nikita, kvm@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org,
bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
kernel@xen0n.name, linux-riscv@lists.infradead.org,
pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
oupton@kernel.org, suzuki.poulose@arm.com, yuzenghui@huawei.com,
will@kernel.org, seanjc@google.com, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
hpa@zytor.com, luto@kernel.org, willy@infradead.org,
akpm@linux-foundation.org, david@kernel.org,
lorenzo.stoakes@oracle.com, vbabka@kernel.org, surenb@google.com,
mhocko@suse.com, ast@kernel.org, daniel@iogearbox.net,
andrii@kernel.org, martin.lau@linux.dev, eddyz87@gmail.com,
song@kernel.org, yonghong.song@linux.dev,
john.fastabend@gmail.com, kpsingh@kernel.org, haoluo@google.com,
jolsa@kernel.org, jhubbard@nvidia.com, jannh@google.com,
pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
kas@kernel.org, coxu@redhat.com, ackerleytng@google.com,
yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
prsampat@amd.com, wu.fei9@sanechips.com.cn, mlevitsk@redhat.com,
jthoughton@google.com, agordeev@linux.ibm.com, alex@ghiti.fr,
aou@eecs.berkeley.edu, borntraeger@linux.ibm.com,
chenhuacai@kernel.org, baolu.lu@linux.intel.com, dev.jain@arm.com,
gor@linux.ibm.com, hca@linux.ibm.com, palmer@dabbelt.com,
pjw@kernel.org, shijie@os.amperecomputing.com,
svens@linux.ibm.com, thuth@redhat.com, Liam.Howlett@oracle.com,
urezki@gmail.com, zhengqi.arch@bytedance.com, pavel@kernel.org,
yangyicong@hisilicon.com, vannapurve@google.com,
jackmanb@google.com, patrick.roy@linux.dev, Thomson, Jack,
Itazuri, Takahiro, Manwaring, Derek
In-Reply-To: <DJJ2NKKPRANG.188CUADJO2CKK@linux.dev>
On Fri, Jun 26, 2026 at 03:04:48PM +0000, Brendan Jackman wrote:
> On Fri Jun 26, 2026 at 2:38 PM UTC, Brendan Jackman wrote:
> > On Tue Apr 21, 2026 at 2:43 PM UTC, Lorenzo Stoakes wrote:
> >> On Fri, Apr 10, 2026 at 03:17:58PM +0000, Kalyazin, Nikita wrote:
> >>> From: Nikita Kalyazin <nikita.kalyazin@linux.dev>
> >>>
> >>> Let's convert set_direct_map_*() to take an address instead of a page to
> >>> prepare for adding helpers that operate on folios; it will be more
> >>> efficient to convert from a folio directly to an address without going
> >>> through a page first.
> >
> > Why is this more efficient? Isn't it a purely compile-time conversion?
> >
> > Indeed in the current implementation folio_address() is
> > page_address(&folio->page) so it still goes through a page anyway, no?
> >
> > I might be missing context here about how this will look in the
> > memdesc future.
>
> Sorry I failed to do the history search here, this was suggested by
> Willy during the review here:
>
> https://lore.kernel.org/kvm/aWkN4yzwPtotaTeq@casper.infradead.org/
>
> Matthew Wilcox <willy@infradead.org> wrote:
> > The implementation isn't the greatest. None of the implementations
> > of set_direct_map_valid_noflush() actually do anything with the struct
> > page; they all call page_address() or page_to_virt() (fundamentally the
> > same thing).
>
> But IMO the struct page isn't there to carry runtime information, it's a
> type hint that this API operates on physical pages. Yes this is already
> implied by the name but it also gives us a certain amount of safety
> since it avoids unaligned or non-physmap addresses at compile time.
I think it's more historical thingy, the initial user was
vmalloc::set_area_direct_map() that passed each page from vm->pages[] to
set_direct_map functions.
And yes, having a page there let's the implementation to go directly from
the page to it's address in the direct map, even for highmem ...
> > So converting folio->page->address is a bit inefficient.
>
> ... but yeah now I see this comes from Willy I definitely suspect I'm
> missing memdesc insight here.
>
> > It feels like we should change set_direct_map_valid_noflush() to take a
> > const void * and pass either page_address() or folio_address(), depending
> > whether the caller has a page or a folio. What do you think?
... while with void * it's not necessarily one-to-one because void * can be
a vmalloc address.
--
Sincerely yours,
Mike.
^ permalink raw reply
* Re: [PATCH v8 23/46] KVM: TDX: Make source page optional for KVM_TDX_INIT_MEM_REGION
From: Ackerley Tng @ 2026-06-26 15:28 UTC (permalink / raw)
To: Yan Zhao
Cc: Sean Christopherson, aik, andrew.jones, binbin.wu, brauner,
chao.p.peng, david, jmattson, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, forkloop, pratyush,
suzuki.poulose, aneesh.kumar, liam, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Jonathan Corbet, Shuah Khan, Shuah Khan,
Vishal Annapurve, Andrew Morton, Chris Li, Kairui Song,
Kemeng Shi, Nhat Pham, Barry Song, Axel Rasmussen, Yuanchu Xie,
Wei Xu, Youngjun Park, Qi Zheng, Shakeel Butt, Kiryl Shutsemau,
Baoquan He, Jason Gunthorpe, Vlastimil Babka, kvm, linux-kernel,
linux-trace-kernel, linux-doc, linux-kselftest, linux-mm,
linux-coco
In-Reply-To: <aj3TGLGWT1kMFIVH@yzhao56-desk.sh.intel.com>
Yan Zhao <yan.y.zhao@intel.com> writes:
> On Thu, Jun 25, 2026 at 05:07:23PM -0700, Ackerley Tng wrote:
>> Yan Zhao <yan.y.zhao@intel.com> writes:
>>
>> > On Wed, Jun 24, 2026 at 04:00:32PM -0700, Ackerley Tng wrote:
>> >> Sean Christopherson <seanjc@google.com> writes:
>> >>
>> >> > On Tue, Jun 23, 2026, Yan Zhao wrote:
>> >> >> On Tue, Jun 23, 2026 at 01:16:14PM +0800, Yan Zhao wrote:
>> >> >> > On Mon, Jun 22, 2026 at 06:22:45PM -0700, Sean Christopherson wrote:
>> >> >> > > On Mon, Jun 22, 2026, Yan Zhao wrote:
>> >> >> > > > On Thu, Jun 18, 2026 at 05:32:00PM -0700, Ackerley Tng via B4 Relay wrote:
>> >> >> > > > > diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
>> >> >> > > > > index ffe9d0db58c59..56d10333c61a7 100644
>> >> >> > > > > --- a/arch/x86/kvm/vmx/tdx.c
>> >> >> > > > > +++ b/arch/x86/kvm/vmx/tdx.c
>> >> >> > > > > @@ -3198,8 +3198,12 @@ static int tdx_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
>> >> >> > > > > if (KVM_BUG_ON(kvm_tdx->page_add_src, kvm))
>> >> >> > > > > return -EIO;
>> >> >> > > > >
>> >> >> > > > > - if (!src_page)
>> >> >> > > > > - return -EOPNOTSUPP;
>> >> >> > > > > + if (!src_page) {
>> >> >> > > > > + if (!gmem_in_place_conversion)
>> >> >> > > > When userspace turns on gmem_in_place_conversion while creating guest_memfd
>> >> >> > > > without the MMAP flag, the absence of src_page should still be treated as an
>> >> >> > > > error.
>> >> >> > >
>> >> >> > > Why MMAP?
>> >> >> > Hmm, I was showing a scenario that in-place conversion couldn't occur.
>> >> >> > I didn't mean that with the MMAP flag, mmap() and user write must occur.
>> >> >> >
>> >> >> > > Shouldn't this be a general "if (!src_page && !up-to-date)"? Just
>> >> >> > > because userspace _can_ mmap() the memory doesn't mean userspace _has_ mmap()'d
>> >> >> > > and written memory. And when write() lands, MMAP wouldn't be necessary to
>> >> >> > > initialize the memory.
>> >> >> > Do you mean using up-to-date flag as below?
>> >> >
>> >> > Yes? I didn't actually look at the implementation details.
>> >> >
>> >> >> > if (!src_page) {
>> >> >> > src_page = pfn_to_page(pfn);
>> >> >> > if (!folio_test_uptodate(page_folio(src_page)))
>> >> >> > return -EOPNOTSUPP;
>> >> >> > }
>> >>
>> >> Yan is right that with the earlier patch "Zero page while getting pfn",
>> >> folio_test_uptodate() here will always return true.
>> >>
>> >> Actually, this is an alternative fix for the issue Sashiko pointed out
>> >> on v7 where userspace can do a populate() (either TDX or SNP) without
>> >> first allocating the page, with src_address == NULL, and leak
>> >> uninitialized memory into the guest.
>> >>
>> >> Advantage of using the uptodate check in populate: if the host never
>> >> allocates the page, populate doesn't incur zeroing before writing the
>> >> page anyway in populate().
>> >>
>> >> Disadvantage: Both TDX and SNP will have to implement this uptodate
>> >> check. guest_memfd can't check centrally because for SNP, for a
>> >> PAGE_TYPE_ZERO, !src_page should be allowed with a !uptodate page since
>> >> firmware will zero and there's no leakage of uninitialized host memory?
>> > Another disadvantage: the uptodate flag is per-folio. What if the folio
>> > is only partially initialized by the userspace especially after huge page is
>> > supported?
>> >
>>
>> Good point on huge pages!
>>
>> The uptodate flag on the folio in guest_memfd means "this folio has been
>> written to". As of now (before patch at [1]), this happens when
>>
>> + folio is zeroed on first use by userspace
>> + folio is zeroed on first use of the guest
>> + folio is populated
>>
>> When huge pages are supported, the folio can't partially be initialized?
>>
>> On allocation, if any part is shared, we split the page. The parts are
>> separate folios that have their own uptodate flags.
>>
>> On splitting, if the huge page is uptodate, the split pages will also be
>> uptodate. If the huge page is not uptodate, the split pages won't be
>> uptodate, but that's ok since they will be marked uptodate on first use.
>>
>> On merging, the non-uptodate parts have to be zeroed and then marked
> If that's true, it would be good.
>
>> uptodate. Any parts that are in use would have been marked uptodate
>> already, so there's no overwriting data that is in use. I'll need to
>> think more about when it's safe to zero.
>>
>> I'm still on the fence between the two options
>>
>> 1. Using uptodate check in populate to reject src_pages that have never
>> been written to or
>> 2. Always zero before populate
> 2 does not work?
> The flow is
> 1. mmap gmem_fd, make GFN shared, and write initial content.
> 2. convert GFN to private
> 3. invoke ioctl to trigger populate.
>
This flow is correct, is what users of in-place conversion should do.
"Always" is the wrong word, I should have said "zero if not uptodate
before populate", as in, with patch at [1].
By doing the zeroing in __kvm_gmem_get_pfn instead, by the time populate
gets the pfn, the page would be zeroed, either because userspace faulted
it in, and the zeroing happened in kvm_gmem_fault_user_mapping(), or if
userspace never faulted it in, the zeroing would happen because
populate() allocated the page.
>> but whether the uptodate flag is per-folio or not doesn't affect these
>> two options in terms of fixing the leak of uninitialized host memory,
>> right?
> yes, provided "On merging, the non-uptodate parts have to be zeroed and then
> marked uptodate".
>
Thank you so much for bringing this up, I hadn't considered this
before. I'll do that when I get to guest_memfd hugepage restructuring.
>> >
>> >> >> Another concern with this fix is that:
>> >> >> commit "KVM: guest_memfd: Zero page while getting pfn" [1] always marks the
>> >> >> folio uptodate before reaching post_populate().
>> >> >>
>> >> >> [1] https://lore.kernel.org/all/20260618-gmem-inplace-conversion-v8-21-9d2959357853@google.com/
>> >> >>
>> >> >> > One concern is that TDX now does not much care about the up-to-date flag since
>> >> >> > TDX doesn't rely on the flag to clear pages on conversions.
>> >> >> > I'm not sure if the flag can be reliably checked in this case. e.g.,
>> >> >> > now the whole folio is marked up-to-date even if only part of it is faulted by
>> >> >> > user access.
>> >> >> > Ensuring that the up-to-date flag works correctly with huge page support seems
>> >> >> > to have more effort than introducing a dedicated flag for TDX.
>> >> >> >
>> >> >> > > > Additionally, to properly enable in-place copying for the TDX initial memory
>> >> >> > > > region, userspace must not only specify source_addr to NULL, but also follow
>> >> >> > > > a specific sequence (where steps 1/2/3/7 are required only for in-place copy):
>> >> >> > > > 1. create guest_memfd with MMAP flag
>> >> >> > > > 2. mmap the guest_memfd.
>> >> >> > > > 3. convert the initial memory range to shared.
>> >> >> > > > 4. copy initial content to the source page.
>> >> >> > > > 5. convert the initial memory range to private
>> >> >> > > > 6. invoke ioctl KVM_TDX_INIT_MEM_REGION.
>> >> >> > > > 7. do not unmap the source backend.
>> >> >> > > >
>> >> >> > > > So, would it be reasonable to introduce a dedicated flag that allows userspace
>> >> >> > > > to explicitly opt into the in-place copy functionality? e.g.,
>> >> >> > >
>> >> >> > > Why? It's userspace's responsibility to get the above right. If userspace fails
>> >> >> > > to provide a src_page when it doesn't want in-place copy, that's a userspace bug.
>> >>
>> >> Yan, is your concern that userspace forgot to update the code and
>> >> forgets to provide a src_page, and if we keep the "Zero page while
>> > Yes. Previously, it would be rejected after GUP fails.
>> >
>>
>> I see, didn't realize previously it would be rejected because GUP
>> fails. GUP failed because it wasn't faulted into the host?
> GUP fails if 0 is not a valid user address.
> But GUP would not fail if 0 is a valid address. e.g., in below scenario:
>
> #include <sys/mman.h>
> #include <stdio.h>
> int main(void)
> {
> void *p=mmap((void*)0,4096,PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
> if (p==MAP_FAILED) {
> perror("mmap");
> return 1;
> }
> *(char*)0='Y';
> printf("addr0=%p val=%c\n",p,*(char*)0);
> return 0;
> }
>
>
>> That's kind of orthogonal, I don't think GUP fail leading to rejecting
>> populate was meant to help userspace catch these issues. GUP would also
>> fail if the user did mmap(), write to it, unmap using
>> madvise(MADV_DONTNEED), then forget and pass 0 as src_address.
> The original uAPI did not explicitly define 0 as an invalid uaddr. Whether 0 was
> rejected depended on whether the user mmap()'d address 0. If 0 was a valid
> mapping, populate() could proceed.
>
> commit 2a62345b3052 ("KVM: guest_memfd: GUP source pages prior to populating
> guest memory") changed the behavior though. It would return -EOPNOTSUPP for a 0
> uaddr.
>
I see, I only looked at this after commit 2a62345b3052.
> But if a user configures 0 uaddr as valid, writes to it, and then passes 0 as
> source_addr(not from gmem), I'm not sure if it's good for the kernel to silently
> treat 0 uaddr as an identifier for in-place copy from the private PFN in gmem.
>
I'd say the original uAPI perhaps just didn't document 0 as an
unsupported uaddr. Given that commit 2a62345b3052 already merged, uAPI
was perhaps accidentally changed and no customer complained, I think we
can move forward with 0 as an invalid src_address? I wouldn't think
anyone relies on 0 intentionally being a valid address.
I could document that, if it helps?
>
>> >> getting pfn" patch, ends up with the guest silently having a zero page?
>> >> I think that would be found quite early in userspace VMM testing...
>> > I actually encountered this during testing this patch.
>> > I update most code path to follow this sequence. However, still some corner ones
>> > for TDVF HOB, which are less obvious and harder to update.
>> > The TD just booted up and hang silently.
>> >
>>
>> I think this is just the life of a close-to-hardware software engineer
>> :P no errors, got stuck somewhere, root cause is some unitialized
>> thing.
>>
>> >> >> > I mean if userspace specifies a NULL source_addr by mistake, it's better for
>> >> >> > kernel to detect this mistake, similar to how it validates whether source_addr
>> >> >> > is PAGE_ALIGNED.
>> >> >
>> >> > The alignment case is different. If userspace provides an unaligned value, KVM
>> >> > *can't* do what userspace is asking because hardware and thus KVM only supports
>> >> > converting on page boundaries.
>> >> >
>> >> > For a NULL source, KVM can still do what userspace is asking. Rejecting userspace's
>> >> > request would then be making assumptions about what userspace wants.
>> >> >
>> >>
>> >> Also, +1 on this, what if userspace, knowing that pages are zeroed on
>> >> allocation, actually wants to rely on that to get a zero page in the guest?
>> > What if 0 uaddr is a valid address? :)
>> >
>> >> >> > Since userspace already needs to perform additional steps to enable in-place
>> >> >> > copy, specifying a dedicated flag to indicate that the NULL source_addr is
>> >> >> > intentional seems like a reasonable burden.
>> >> >
>> >> > I don't see how it adds any value. I wouldn't be at all surprised if most VMMs
>> >> > just wen up with code that does:
>> >> >
>> >> > if (in-place) {
>> >> > src = NULL;
>> >> > flags |= KVM_TDX_IN_PLACE_COPY_INITIAL_MEMORY_REGION;
>> >> > }
>> >>
^ permalink raw reply
* Re: [PATCH v12 01/16] set_memory: set_direct_map_* to take address
From: Brendan Jackman @ 2026-06-26 15:08 UTC (permalink / raw)
To: David Hildenbrand (Arm), Brendan Jackman, Lorenzo Stoakes,
Kalyazin, Nikita
Cc: kvm@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org,
bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
kernel@xen0n.name, linux-riscv@lists.infradead.org,
pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
oupton@kernel.org, suzuki.poulose@arm.com, yuzenghui@huawei.com,
will@kernel.org, seanjc@google.com, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
hpa@zytor.com, luto@kernel.org, willy@infradead.org,
akpm@linux-foundation.org, lorenzo.stoakes@oracle.com,
vbabka@kernel.org, rppt@kernel.org, surenb@google.com,
mhocko@suse.com, ast@kernel.org, daniel@iogearbox.net,
andrii@kernel.org, martin.lau@linux.dev, eddyz87@gmail.com,
song@kernel.org, yonghong.song@linux.dev,
john.fastabend@gmail.com, kpsingh@kernel.org, haoluo@google.com,
jolsa@kernel.org, jhubbard@nvidia.com, jannh@google.com,
pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
kas@kernel.org, coxu@redhat.com, ackerleytng@google.com,
yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
prsampat@amd.com, wu.fei9@sanechips.com.cn, mlevitsk@redhat.com,
jthoughton@google.com, agordeev@linux.ibm.com, alex@ghiti.fr,
aou@eecs.berkeley.edu, borntraeger@linux.ibm.com,
chenhuacai@kernel.org, baolu.lu@linux.intel.com, dev.jain@arm.com,
gor@linux.ibm.com, hca@linux.ibm.com, palmer@dabbelt.com,
pjw@kernel.org, shijie@os.amperecomputing.com,
svens@linux.ibm.com, thuth@redhat.com, Liam.Howlett@oracle.com,
urezki@gmail.com, zhengqi.arch@bytedance.com, pavel@kernel.org,
yangyicong@hisilicon.com, vannapurve@google.com,
jackmanb@google.com, patrick.roy@linux.dev, Thomson, Jack,
Itazuri, Takahiro, Manwaring, Derek
In-Reply-To: <f7a40359-a210-4711-acba-677e9c1d565c@kernel.org>
On Fri Jun 26, 2026 at 2:58 PM UTC, David Hildenbrand (Arm) wrote:
> On 6/26/26 16:38, Brendan Jackman wrote:
>> On Tue Apr 21, 2026 at 2:43 PM UTC, Lorenzo Stoakes wrote:
>>> On Fri, Apr 10, 2026 at 03:17:58PM +0000, Kalyazin, Nikita wrote:
>>>> From: Nikita Kalyazin <nikita.kalyazin@linux.dev>
>>>>
>>>> Let's convert set_direct_map_*() to take an address instead of a page to
>>>> prepare for adding helpers that operate on folios; it will be more
>>>> efficient to convert from a folio directly to an address without going
>>>> through a page first.
>>
>> Why is this more efficient? Isn't it a purely compile-time conversion?
>>
>> Indeed in the current implementation folio_address() is
>> page_address(&folio->page) so it still goes through a page anyway, no?
>>
>> I might be missing context here about how this will look in the
>> memdesc future.
>
> Good question. page_address() is really only complicated for highmem. For
> non-highmem stuff it's simply derived from the page pfn.
>
> I suspect going page -> pfn will remain as efficient as it currently is (with
> vmemmap). For odd cases (SPARSEMEM without VMEMMAP) going through folio->pfn [1]
> might be slighty faster.
>
> [1] https://kernelnewbies.org/MatthewWilcox/Memdescs/Path
Ah sorry I raced with you and replied to myself:
https://lore.kernel.org/all/DJJ2NKKPRANG.188CUADJO2CKK@linux.dev/
The above makes me realise that if we really do want to avoid needing a
struct page here, the "right" thing would be to make this API accept a
PFN.
The problem would be that our favourite programming language we use
doesn't know the difference between `unsigned long addr` and `unsigned
long pfn`... but I thiiiiink its unlikely those bugs will be latent,
I've made that mistake a few times and my computer usually let me know
about it.
Still, I'm not really convinced we need to change anything here yet
(modulo fuzziness about memdesc etc).
^ permalink raw reply
* Re: [PATCH v12 01/16] set_memory: set_direct_map_* to take address
From: Brendan Jackman @ 2026-06-26 15:04 UTC (permalink / raw)
To: Brendan Jackman, Lorenzo Stoakes, Kalyazin, Nikita
Cc: kvm@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org,
bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
kernel@xen0n.name, linux-riscv@lists.infradead.org,
pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
oupton@kernel.org, suzuki.poulose@arm.com, yuzenghui@huawei.com,
will@kernel.org, seanjc@google.com, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
hpa@zytor.com, luto@kernel.org, willy@infradead.org,
akpm@linux-foundation.org, david@kernel.org,
lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
surenb@google.com, mhocko@suse.com, ast@kernel.org,
daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
john.fastabend@gmail.com, kpsingh@kernel.org, haoluo@google.com,
jolsa@kernel.org, jhubbard@nvidia.com, jannh@google.com,
pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
kas@kernel.org, coxu@redhat.com, ackerleytng@google.com,
yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
prsampat@amd.com, wu.fei9@sanechips.com.cn, mlevitsk@redhat.com,
jthoughton@google.com, agordeev@linux.ibm.com, alex@ghiti.fr,
aou@eecs.berkeley.edu, borntraeger@linux.ibm.com,
chenhuacai@kernel.org, baolu.lu@linux.intel.com, dev.jain@arm.com,
gor@linux.ibm.com, hca@linux.ibm.com, palmer@dabbelt.com,
pjw@kernel.org, shijie@os.amperecomputing.com,
svens@linux.ibm.com, thuth@redhat.com, Liam.Howlett@oracle.com,
urezki@gmail.com, zhengqi.arch@bytedance.com, pavel@kernel.org,
yangyicong@hisilicon.com, vannapurve@google.com,
jackmanb@google.com, patrick.roy@linux.dev, Thomson, Jack,
Itazuri, Takahiro, Manwaring, Derek
In-Reply-To: <DJJ23EXF55VK.1EGQZS511HFB6@linux.dev>
On Fri Jun 26, 2026 at 2:38 PM UTC, Brendan Jackman wrote:
> On Tue Apr 21, 2026 at 2:43 PM UTC, Lorenzo Stoakes wrote:
>> On Fri, Apr 10, 2026 at 03:17:58PM +0000, Kalyazin, Nikita wrote:
>>> From: Nikita Kalyazin <nikita.kalyazin@linux.dev>
>>>
>>> Let's convert set_direct_map_*() to take an address instead of a page to
>>> prepare for adding helpers that operate on folios; it will be more
>>> efficient to convert from a folio directly to an address without going
>>> through a page first.
>
> Why is this more efficient? Isn't it a purely compile-time conversion?
>
> Indeed in the current implementation folio_address() is
> page_address(&folio->page) so it still goes through a page anyway, no?
>
> I might be missing context here about how this will look in the
> memdesc future.
Sorry I failed to do the history search here, this was suggested by
Willy during the review here:
https://lore.kernel.org/kvm/aWkN4yzwPtotaTeq@casper.infradead.org/
Matthew Wilcox <willy@infradead.org> wrote:
> The implementation isn't the greatest. None of the implementations
> of set_direct_map_valid_noflush() actually do anything with the struct
> page; they all call page_address() or page_to_virt() (fundamentally the
> same thing).
But IMO the struct page isn't there to carry runtime information, it's a
type hint that this API operates on physical pages. Yes this is already
implied by the name but it also gives us a certain amount of safety
since it avoids unaligned or non-physmap addresses at compile time.
> So converting folio->page->address is a bit inefficient.
... but yeah now I see this comes from Willy I definitely suspect I'm
missing memdesc insight here.
> It feels like we should change set_direct_map_valid_noflush() to take a
> const void * and pass either page_address() or folio_address(), depending
> whether the caller has a page or a folio. What do you think?
^ permalink raw reply
* Re: [PATCH v12 01/16] set_memory: set_direct_map_* to take address
From: David Hildenbrand (Arm) @ 2026-06-26 14:58 UTC (permalink / raw)
To: Brendan Jackman, Lorenzo Stoakes, Kalyazin, Nikita
Cc: kvm@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org,
bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
kernel@xen0n.name, linux-riscv@lists.infradead.org,
pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
oupton@kernel.org, suzuki.poulose@arm.com, yuzenghui@huawei.com,
will@kernel.org, seanjc@google.com, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
hpa@zytor.com, luto@kernel.org, willy@infradead.org,
akpm@linux-foundation.org, lorenzo.stoakes@oracle.com,
vbabka@kernel.org, rppt@kernel.org, surenb@google.com,
mhocko@suse.com, ast@kernel.org, daniel@iogearbox.net,
andrii@kernel.org, martin.lau@linux.dev, eddyz87@gmail.com,
song@kernel.org, yonghong.song@linux.dev,
john.fastabend@gmail.com, kpsingh@kernel.org, haoluo@google.com,
jolsa@kernel.org, jhubbard@nvidia.com, jannh@google.com,
pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
kas@kernel.org, coxu@redhat.com, ackerleytng@google.com,
yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
prsampat@amd.com, wu.fei9@sanechips.com.cn, mlevitsk@redhat.com,
jthoughton@google.com, agordeev@linux.ibm.com, alex@ghiti.fr,
aou@eecs.berkeley.edu, borntraeger@linux.ibm.com,
chenhuacai@kernel.org, baolu.lu@linux.intel.com, dev.jain@arm.com,
gor@linux.ibm.com, hca@linux.ibm.com, palmer@dabbelt.com,
pjw@kernel.org, shijie@os.amperecomputing.com,
svens@linux.ibm.com, thuth@redhat.com, Liam.Howlett@oracle.com,
urezki@gmail.com, zhengqi.arch@bytedance.com, pavel@kernel.org,
yangyicong@hisilicon.com, vannapurve@google.com,
jackmanb@google.com, patrick.roy@linux.dev, Thomson, Jack,
Itazuri, Takahiro, Manwaring, Derek
In-Reply-To: <DJJ23EXF55VK.1EGQZS511HFB6@linux.dev>
On 6/26/26 16:38, Brendan Jackman wrote:
> On Tue Apr 21, 2026 at 2:43 PM UTC, Lorenzo Stoakes wrote:
>> On Fri, Apr 10, 2026 at 03:17:58PM +0000, Kalyazin, Nikita wrote:
>>> From: Nikita Kalyazin <nikita.kalyazin@linux.dev>
>>>
>>> Let's convert set_direct_map_*() to take an address instead of a page to
>>> prepare for adding helpers that operate on folios; it will be more
>>> efficient to convert from a folio directly to an address without going
>>> through a page first.
>
> Why is this more efficient? Isn't it a purely compile-time conversion?
>
> Indeed in the current implementation folio_address() is
> page_address(&folio->page) so it still goes through a page anyway, no?
>
> I might be missing context here about how this will look in the
> memdesc future.
Good question. page_address() is really only complicated for highmem. For
non-highmem stuff it's simply derived from the page pfn.
I suspect going page -> pfn will remain as efficient as it currently is (with
vmemmap). For odd cases (SPARSEMEM without VMEMMAP) going through folio->pfn [1]
might be slighty faster.
[1] https://kernelnewbies.org/MatthewWilcox/Memdescs/Path
--
Cheers,
David
^ permalink raw reply
* Re: [RFC v2 PATCH] reserve_mem: add support for static memory
From: Shyam Saini @ 2026-06-26 14:54 UTC (permalink / raw)
To: Mike Rapoport
Cc: linux-mm, linux-doc, linux-kernel, akpm, tgopinath, bboscaccy,
kees, tony.luck, gpiccoli, bp, rdunlap, peterz, feng.tang,
dapeng1.mi, elver, enelsonmoore, kuba, lirongqing, ebiggers,
Catalin Marinas, Will Deacon, Ard Biesheuvel, David Hildenbrand,
linux-arm-kernel
In-Reply-To: <ajzovhWHcFQZ9d3l@kernel.org>
On 25 Jun 2026 11:37, Mike Rapoport wrote:
> Hi Shyam,
>
> On Wed, Jun 24, 2026 at 06:22:33PM -0700, Shyam Saini wrote:
> > On 21 Jun 2026 13:36, Mike Rapoport wrote:
> > > On Thu, Jun 18, 2026 at 11:23:31PM -0700, Shyam Saini wrote:
> > > > reserve_mem relies on dynamic memory allocation, this limits the
> > > > usecase where memory is required to be preserved across the boots.
> > > > Eg: ramoops memory reservation on ACPI platforms
> > > >
> > > > So add support to pass a pre-determined static address and reserve
> > > > memory at a specified location. This enables use case like ramoops
> > > > on ACPI platforms to reliably access ramoops region with previous
> > > > boot logs.
> > > >
> > > > Also skip the parsing of <align> when static address is passed.
> > > >
> > > > Example syntax for static address
> > > > reserve_mem=4M@0x1E0000000:oops
> > >
> > > reserve_mem is best effort by design because such hacks as well as memmap=
> > > cannot guarantee this memory is actually free.
> > >
> > > If you want to preserve ramoops reliably, use KHO with reserve_mem.
> > > The first kernel will allocate memory, this memory will be preserved by KHO
> > > and could be picked up by the second kernel.
> >
> > ok, On ARM64 DTS systems, we can reserve ramoops memory in the device tree during
> > the warm reboot.
>
> The cc list actually implied x86 ;-)
> Added arm64 folks now.
Thanks for adding ARM folks, I had just included whatever get_maintainer script
suggested, sorry.
> > For an equivalent ARM64 ACPI platform, what is the recommended way to reserve
> > and preserve that memory across the boots?
>
> I don't think it exists, but a command line option (be it memmap= or
> reserve_mem=) does not seem the right way to me.
>
> Most of the arguments that were made against adding memmap= to arm64 [1]
> apply here.
>
> If kexec is an option, KHO provides a reliable way to preserve memory
> across boots.
>
> If kexec is not an option, we should look for a generic way to specify
> something like DT's reserved_mem for ACPI/EFI systems.
>
> [1] https://lkml.kernel.org/lkml/20201118063314.22940-1-song.bao.hua@hisilicon.com/T/
>
Well, kexec is one of the option for my use case, it also requires
memory reservation during warm reboot, I think memory can be reserved in
the firmware but this will create a dependency on firmware for Linux
reservation.
It would be great to have a in kernel memory reservation mechanism for
ARM64 ACPI platforms. I believe some other use cases like PMEM
reservation would also benefit from this.
Thanks,
Shyam
^ permalink raw reply
* Re: [PATCH v7 0/9] bootconfig: embed kernel.* cmdline at build time
From: Breno Leitao @ 2026-06-26 14:53 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Andrew Morton, Nathan Chancellor, paulmck, Nicolas Schier,
Nick Desaulniers, Bill Wendling, Justin Stitt, Jonathan Corbet,
Shuah Khan, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, linux-kernel,
linux-trace-kernel, linux-kbuild, bpf, llvm, linux-doc,
kernel-team, Nicolas Schier
In-Reply-To: <20260626233327.b5c9c8de494acdde4ddf5c02@kernel.org>
On Fri, Jun 26, 2026 at 11:33:27PM +0900, Masami Hiramatsu wrote:
> > The userspace pieces (xbc_snprint_cmdline() in lib/, tools/bootconfig -C)
> > already landed; this series wires the rendered cmdline into the kernel.
> >
> > Motivation: today the embedded bootconfig is parsed at runtime, after
> > parse_early_param() has already run, so early_param() handlers can't
> > see embedded values. Folding the kernel.* subtree into the cmdline at
> > build time gives a CONFIG_CMDLINE-equivalent for embedded-bootconfig
> > users without forcing them to maintain two cmdline sources.
> >
> > Behaviorally, the "kernel" subtree is rendered to a flat string at
> > build time and stashed in .init.rodata. setup_arch() prepends it to
> > boot_command_line before parse_early_param() runs. Overflow is a soft
> > error: the helper logs and leaves boot_command_line untouched rather
> > than panicking, so an oversized embedded bconf cannot brick a boot.
> >
>
> Thanks for update!! This looks good to me.
> Let me pick it and test it.
This is great. Thanks for it and for the support so far.
--breno
^ permalink raw reply
* Re: [PATCH] docs: pagemap: fix flags location, member name and sample code
From: David Hildenbrand (Arm) @ 2026-06-26 14:47 UTC (permalink / raw)
To: Zenghui Yu, linux-mm, linux-doc, linux-kernel
Cc: akpm, ljs, liam, vbabka, rppt, surenb, mhocko, corbet, skhan
In-Reply-To: <20260625174447.24292-1-zenghui.yu@linux.dev>
On 6/25/26 19:44, Zenghui Yu wrote:
> The userland visible page flags (KPF_*) were initially moved to
> include/linux/kernel-page-flags.h in commit 1a9b5b7fe0c5 ("mm: export
> stable page flags"), and later moved to
> include/uapi/linux/kernel-page-flags.h in commit 607ca46e97a1 ("UAPI:
> (Scripted) Disintegrate include/linux"). Upadte the doc to reflect the
s/Upadte/Update/
> current location of these flags.
Ack
>
> The member @walk_end of struct pm_scan_arg {} was wrongly written as
> "end_walk".
Ack
>
> The first sample code of the PAGEMAP_SCAN ioctl wrongly used the
> PM_SCAN_CHECK_WPASYNC flag twice, instead of the PM_SCAN_WP_MATCHING flag.
That makes sense.
> The second one missed PAGE_IS_FILE in the required mask.
Hm. The description says: "Find pages which have been written, are file backed,
not swapped and either present or huge".
But doesn't that mean that
it should actually be
.category_mask = PAGE_IS_WRITTEN | PAGE_IS_FILE,
Because
.category_inverted = PAGE_IS_SWAPPED,
--
Cheers,
David
^ permalink raw reply
* Re: [PATCH v12 09/16] KVM: arm64: define kvm_arch_gmem_supports_no_direct_map()
From: Brendan Jackman @ 2026-06-26 14:45 UTC (permalink / raw)
To: Marc Zyngier, Kalyazin, Nikita
Cc: kvm@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
kernel@xen0n.name, linux-riscv@lists.infradead.org,
linux-s390@vger.kernel.org, loongarch@lists.linux.dev,
linux-pm@vger.kernel.org, pbonzini@redhat.com, corbet@lwn.net,
oupton@kernel.org, joey.gouly@arm.com, suzuki.poulose@arm.com,
yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
seanjc@google.com, tglx@kernel.org, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
hpa@zytor.com, luto@kernel.org, peterz@infradead.org,
willy@infradead.org, akpm@linux-foundation.org, david@kernel.org,
lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
surenb@google.com, mhocko@suse.com, ast@kernel.org,
daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
haoluo@google.com, jolsa@kernel.org, jgg@ziepe.ca,
jhubbard@nvidia.com, peterx@redhat.com, jannh@google.com,
pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
kas@kernel.org, coxu@redhat.com, ackerleytng@google.com,
yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
tabba@google.com, prsampat@amd.com, wu.fei9@sanechips.com.cn,
mlevitsk@redhat.com, jmattson@google.com, jthoughton@google.com,
agordeev@linux.ibm.com, alex@ghiti.fr, borntraeger@linux.ibm.com,
chenhuacai@kernel.org, baolu.lu@linux.intel.com, dev.jain@arm.com,
palmer@dabbelt.com, pjw@kernel.org, shijie@os.amperecomputing.com,
thuth@redhat.com, yang@os.amperecomputing.com,
Liam.Howlett@oracle.com, zhengqi.arch@bytedance.com,
lenb@kernel.org, pavel@kernel.org, yangyicong@hisilicon.com,
vannapurve@google.com, jackmanb@google.com, patrick.roy@linux.dev,
Itazuri, Takahiro
In-Reply-To: <86fr4o1ceu.wl-maz@kernel.org>
On Tue Apr 21, 2026 at 4:55 PM UTC, Marc Zyngier wrote:
> On Fri, 10 Apr 2026 16:19:24 +0100,
> "Kalyazin, Nikita" <kalyazin@amazon.co.uk> wrote:
>>
>> From: Patrick Roy <patrick.roy@linux.dev>
>>
>> Support for GUEST_MEMFD_FLAG_NO_DIRECT_MAP on arm64 depends on 1) direct
>> map manipulations at 4k granularity being possible, and 2) FEAT_S2FWB.
>>
>> 1) is met whenever the direct map is set up at 4k granularity (e.g. not
>> with huge/gigantic pages) at boottime, as due to ARM's
>> break-before-make semantics, breaking huge mappings into 4k mappings in
>> the direct map is not possible (BBM would require temporary invalidation
>> of the entire huge mapping, even if only a 4k subrange should be zapped,
>> which will probably crash the kernel). However, the current default for
>> rodata_full is true, which forces a 4k direct map.
>
> Where is this 4kB requirement enforced? Or is it that you means
> "PAGE_SIZE"?
Yeah I believe this means PAGE_SIZE and that it's effectively enforced
by checking can_set_direct_map() in
kvm_arch_gmem_supports_no_direct_map().
^ permalink raw reply
* Re: [PATCH RESEND] riscv: enable HAVE_CMPXCHG_{DOUBLE,LOCAL}
From: Miquel Sabaté Solà @ 2026-06-26 14:39 UTC (permalink / raw)
To: Paul Walmsley
Cc: linux-riscv, corbet, skhan, palmer, alex, linux-doc, linux-kernel
In-Reply-To: <87a4t6w0gi.fsf@>
[-- Attachment #1: Type: text/plain, Size: 7897 bytes --]
Hello,
Miquel Sabaté Solà @ 2026-06-07 22:38 +02:
> Hi,
>
> Paul Walmsley @ 2026-06-06 18:50 -06:
>
>> Hi,
>>
>> On Fri, 5 Jun 2026, Miquel Sabaté Solà wrote:
>>
>>> Support for atomic Compare-And-Swap instructions has been in the RISC-V
>>> port of the Linux kernel for a long time. That being said, we apparently
>>> never bothered to set HAVE_CMPXCHG_DOUBLE and HAVE_CMPXCHG_LOCAL in the
>>> Kconfig, despite having all the framework to support them.
>>>
>>> Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
>>> ---
>>> This is a resend of [1], rebased on top of the latest commit from the
>>> for-next branch.
>>>
>>> I have built this patch with multiple configurations and ran it with KVM
>>> (the VisionFive2 board that I have lacks the needed extensions). All seems
>>> to work, but I do wonder if we did not enable these for a reason or this
>>> just slipped through. So far in the code I believe everything is in place,
>>> and I haven't seen any commit in the git log stating otherwise.
>>>
>>> [1] https://lore.kernel.org/all/20260220074449.8526-1-mssola@mssola.com/
>>
>> Thanks for the patch. Your comments above are why I've been hesitant to
>> merge it. I'm not aware of any publicly available hardware that supports
>> Zacas/Zabha. No one has stepped forward to provide any Tested-by:s on
>> hardware that hasn't been released yet. You mention that you tested on
>> your VisionFive2 board, but it would not have exercised those code paths.
>
> No, I mention that I ran it _only_ on KVM, as my VisionFive2 board lacks
> these extensions and hence I couldn't possible have tested this there :)
>
>>
>> Of course, we already have Zacas/Zabha support, merged back in 2024, in
>> cmpxchg.h. I assume (?) that it was tested in QEMU, but I don't see any
>> comments about that in the patch series. No one sent any Tested-by:s
>> then, either.
>>
>> It would be good if you (and ideally others) could put this patch through
>> some testing on QEMU with Zacas and Zabha enabled, before we merge it.
>> The affected code paths for HAVE_CMPXCHG_LOCAL seem to primarily involve
>> per-CPU counters and MM zone counters, so those would be the areas to
>> focus. HAVE_CMPXCHG_DOUBLE seems to do nothing useful other than
>> preventing the AMD IOMMU driver from being selected if it's not present,
>> so that part of the patch seems fairly useless. In fact I'd suggest
>> dropping that from the patch and just sending a separate patch to remove
>> HAVE_CMPXCHG_DOUBLE from the kernel completely.
>
> To be fair, on QEMU I only "tested" it by booting it, running a few
> things for some time and ensuring that nothing got totally broken in the
> process while taking a look at the kernel logs.
>
> In any case, let me double check with QEMU with these extensions enabled
> and I'll try to be more thorough about it. I'll do just that whenever I
> have some spare time during the following week :)
So much for "the following week" :) Sorry for being a bit late.
I have finally taken a deeper look at this, and I have the following
comments that I hope you can further clarify so we can land a more
precise patch.
First of all, HAVE_CMPXCHG_LOCAL is fundamentally used in two places: in
mm/vmstat.c and in lib/percpu_counter.c. In the latter it is used in the
percpu_counter_add_batch() function, which is used tree-wide. Hence,
selecting this config option has a wide effect.
As far as I can tell, both HAVE_CMPXCHG_LOCAL and HAVE_CMPXCHG_DOUBLE
could have been added in this patch series [1] by Alexandre Ghiti, but
I've been unable to tell how it was actually tested (no mentions on that
on no Tested-by either). On my side, the board I have doesn't have
neither Zacas nor the Zabha extensions so, as I mentioned on my previous
email, I have to test everything via KVM.
Having that into account, if I build the kernel with or without the
patch applied, functions like percpu_counter_add_batch() have a
different implementation, as expected (good ol' objdump -d vmlinux
--disassemble=percpu_counter_add_batch confirmed as much); and from a
general outlook, the given assembly code is what I'd expect. In order to
test it, I have to say that I've relied on checking that selftests and
similar continue to pass before/after the patch. In particular, I've run
the selftests from btrfs, and they seem just fine (and toggling a
breakpoint inside of percpu_counter_add_batch() confirms that it's being
constantly called, so we are definitely calling the "new" code).
>
> As for HAVE_CMPXCHG_DOUBLE, removing it makes sense. Let me just take
> another look and I will send a separate patch whenever I'm ready for it.
Here I'm a bit conflicted, because you mentioned that it's only used for the AMD
IOMMU driver, but support on different architectures like 5284e1b4bc8a ("arm64:
xchg: Implement cmpxchg_double") or f0e4b1b6e295 ("LoongArch: Add 128-bit atomic
cmpxchg support") hint into other places where this is needed. In fact, for
loongarch, it's apparently needed to fix multiple tests on sched_ext. Thus, I
believe that sending a patch to drop it from the kernel would be misguided.
As for RISC-V, first of all I believe that my patch should've also included that
HAVE_CMPXCHG_DOUBLE can only be selected on CONFIG_64BIT. In fact, commit
f7bd2be7663c ("riscv: Implement arch_cmpxchg128() using Zacas"), which brings
support for this (again, from the same series [1]), also requires this
configuration option. That being said, this commit doesn't say how it was
tested, and there are not Tested-by either. On my end, so far I got no luck
trying the sched_ext route mentioned in the loongarch support, which is a bit of
a hussle in KVM with cross-compilation and the library requirements.
But as a final note, I have used hackbench on this. I have statically compiled
hackbench from source [2] at commit e6fb0b2c8ad1 ("rt-tests: Add AGENTS.md guide
for AI coding assistants") (i.e. current master). This binary has been deployed
in three iterations where the kernel was built as:
1. Before the patch.
2. With the patch (both HAVE_CMPXCHG_LOCAL and HAVE_CMPXCHG_DOUBLE selected).
3. With only HAVE_CMPXCHG_LOCAL selected.
Again, given that I can only test this on QEMU, this whole thing is tested on
virtualized environments, so take it with a grain of salt :)
In any case, I got the following results:
| | Mainline | Both selected | Only _LOCAL selected |
|--------+----------+---------------+----------------------|
| Mean | 50.9966 | 54.2076 | 51.6488 |
| StdDev | 0.1508 | 0.1097 | 0.7051 |
As you can see, the results on Mainline and "only _LOCAL selected" are more or
less the same, but not so much whenever _DOUBLE is also selected. I figure that
that these instructions are not as fast as expected on my virtualized
environment.
With all of this, I'm torned on whether we should include HAVE_CMPXCHG_DOUBLE,
as code-wise is pretty much the same as HAVE_CMPXCHG_LOCAL, but I can also see
how it can be removed as I cannot properly test it. As a middle ground, maybe we
can leave a TODO in __arch_cmpxchg128() asking to introduce HAVE_CMPXCHG_DOUBLE
whenever someone can actually test it and guarantee that there are no
performance penalties as I saw on my virtualized environment.
And that's enough of my rumblings :) I'd appreciate any comments on this.
Thanks,
Miquel
[1] https://lore.kernel.org/all/20241103145153.105097-1-alexghiti@rivosinc.com/
[2] https://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git
>
>>
>>
>> - Paul
>
> Thanks for your input!
> Miquel
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 897 bytes --]
^ permalink raw reply
* Re: [PATCH v12 01/16] set_memory: set_direct_map_* to take address
From: Brendan Jackman @ 2026-06-26 14:38 UTC (permalink / raw)
To: Lorenzo Stoakes, Kalyazin, Nikita
Cc: kvm@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org,
bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
kernel@xen0n.name, linux-riscv@lists.infradead.org,
pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
oupton@kernel.org, suzuki.poulose@arm.com, yuzenghui@huawei.com,
will@kernel.org, seanjc@google.com, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
hpa@zytor.com, luto@kernel.org, willy@infradead.org,
akpm@linux-foundation.org, david@kernel.org,
lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
surenb@google.com, mhocko@suse.com, ast@kernel.org,
daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
john.fastabend@gmail.com, kpsingh@kernel.org, haoluo@google.com,
jolsa@kernel.org, jhubbard@nvidia.com, jannh@google.com,
pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
kas@kernel.org, coxu@redhat.com, ackerleytng@google.com,
yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
prsampat@amd.com, wu.fei9@sanechips.com.cn, mlevitsk@redhat.com,
jthoughton@google.com, agordeev@linux.ibm.com, alex@ghiti.fr,
aou@eecs.berkeley.edu, borntraeger@linux.ibm.com,
chenhuacai@kernel.org, baolu.lu@linux.intel.com, dev.jain@arm.com,
gor@linux.ibm.com, hca@linux.ibm.com, palmer@dabbelt.com,
pjw@kernel.org, shijie@os.amperecomputing.com,
svens@linux.ibm.com, thuth@redhat.com, Liam.Howlett@oracle.com,
urezki@gmail.com, zhengqi.arch@bytedance.com, pavel@kernel.org,
yangyicong@hisilicon.com, vannapurve@google.com,
jackmanb@google.com, patrick.roy@linux.dev, Thomson, Jack,
Itazuri, Takahiro, Manwaring, Derek
In-Reply-To: <aeeDvpDnGnY5n69n@lucifer>
On Tue Apr 21, 2026 at 2:43 PM UTC, Lorenzo Stoakes wrote:
> On Fri, Apr 10, 2026 at 03:17:58PM +0000, Kalyazin, Nikita wrote:
>> From: Nikita Kalyazin <nikita.kalyazin@linux.dev>
>>
>> Let's convert set_direct_map_*() to take an address instead of a page to
>> prepare for adding helpers that operate on folios; it will be more
>> efficient to convert from a folio directly to an address without going
>> through a page first.
Why is this more efficient? Isn't it a purely compile-time conversion?
Indeed in the current implementation folio_address() is
page_address(&folio->page) so it still goes through a page anyway, no?
I might be missing context here about how this will look in the
memdesc future.
^ permalink raw reply
* Re: [PATCH v7 0/9] bootconfig: embed kernel.* cmdline at build time
From: Masami Hiramatsu @ 2026-06-26 14:33 UTC (permalink / raw)
To: Breno Leitao
Cc: Andrew Morton, Nathan Chancellor, paulmck, Nicolas Schier,
Nick Desaulniers, Bill Wendling, Justin Stitt, Jonathan Corbet,
Shuah Khan, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, H. Peter Anvin, linux-kernel,
linux-trace-kernel, linux-kbuild, bpf, llvm, linux-doc,
kernel-team, Nicolas Schier
In-Reply-To: <20260626-bootconfig_using_tools-v7-0-24ab72139c29@debian.org>
On Fri, 26 Jun 2026 05:50:09 -0700
Breno Leitao <leitao@debian.org> wrote:
> The userspace pieces (xbc_snprint_cmdline() in lib/, tools/bootconfig -C)
> already landed; this series wires the rendered cmdline into the kernel.
>
> Motivation: today the embedded bootconfig is parsed at runtime, after
> parse_early_param() has already run, so early_param() handlers can't
> see embedded values. Folding the kernel.* subtree into the cmdline at
> build time gives a CONFIG_CMDLINE-equivalent for embedded-bootconfig
> users without forcing them to maintain two cmdline sources.
>
> Behaviorally, the "kernel" subtree is rendered to a flat string at
> build time and stashed in .init.rodata. setup_arch() prepends it to
> boot_command_line before parse_early_param() runs. Overflow is a soft
> error: the helper logs and leaves boot_command_line untouched rather
> than panicking, so an oversized embedded bconf cannot brick a boot.
>
Thanks for update!! This looks good to me.
Let me pick it and test it.
Thanks,
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
> Changes in v7:
> - The runtime opt-in now shares one helper instead of open-coding its
> own. (Masami)
> - bootconfig_cmdline_requested() moved into generic lib code (Masami)
> - Link to v6: https://lore.kernel.org/r/20260623-bootconfig_using_tools-v6-0-640c2f587a3c@debian.org
>
> Changes in v6:
> - renamed CONFIG_BOOT_CONFIG_EMBED_CMDLINE to
> CONFIG_CMDLINE_FROM_BOOTCONFIG
> - prepend embedded bootconfig cmdline before parse_early_param
> - Link to v5: https://lore.kernel.org/r/20260617-bootconfig_using_tools-v5-0-fd589a9cc5e3@debian.org
>
> Changes in v5:
> - Patch 3 (Kconfig): drop the redundant "depends on BOOT_CONFIG_EMBED"
> from CMDLINE_FROM_BOOTCONFIG; Julian Braha.
> - Patch 6 (Documentation): spell out how the embedded cmdline interacts
> with the bootloader cmdline, an initrd bootconfig, and the embedded
> bootconfig
> - Link to v4: https://lore.kernel.org/r/20260609-bootconfig_using_tools-v4-0-73c463f03a97@debian.org
>
> Changes in v4:
> - Patch 3 (build pipeline): clear CROSS_COMPILE= in the kernel-side
> tools/bootconfig sub-make. Without it, an LLVM=1 cross build
> inherits CROSS_COMPILE and tools/scripts/Makefile.include injects
> --target=/--sysroot= into the host clang, producing a target
> binary that fails to exec.
> - Patch 3 (build pipeline): place embedded-cmdline.S in its own
> .init.rodata.embed_cmdline subsection ("a") so ld.lld does not
> see a section-type mismatch against lib/bootconfig-data.S's
> writable .init.rodata ("aw"). The linker's *(.init.rodata
> .init.rodata.*) glob still folds it into the init image.
> - Patch 6 (x86/setup): also accept the bootconfig=<anything> form
> via cmdline_find_option(), matching the runtime parse_args() loop.
> Without it, bootconfig=0/=off would skip the early prepend but
> still trigger the late runtime apply -- a split-brain state.
> - New patch 7: document CONFIG_CMDLINE_FROM_BOOTCONFIG in
> Documentation/admin-guide/bootconfig.rst (semantics, opt-in,
> precedence, overflow behavior, example).
> - Link to v3: https://lore.kernel.org/r/20260608-bootconfig_using_tools-v3-0-4ddd079a0696@debian.org
>
> Changes in v3:
> - Patch 3: Move HOSTCC override to the kernel-side rule; tool keeps
> $(CC) for standalone/cross builds.
> - Patch 6: Drop the false fail-safe wording; document the
> BOOT_CONFIG_FORCE=y default interaction.
> - Link to v2:
> https://lore.kernel.org/r/20260605-bootconfig_using_tools-v2-0-d309f544b5f7@debian.org
>
> Changes in v2 (addressing review of v1):
> - Split out a standalone fix for the NULL-pointer arithmetic in
> xbc_snprint_cmdline() so the build-time render cannot trip host
> UBSan/FORTIFY_SOURCE.
> - Rework the leaf-root handling: instead of returning early, skip @root
> inside the loop so a root carrying both a value and subkeys
> (kernel = x together with kernel.foo = bar) still renders its
> descendant keys.
> - Build tools/bootconfig with $(HOSTCC) so cross-compiled (ARCH=...)
> builds render the cmdline on the build host instead of failing with
> "Exec format error".
> - Mark the embedded cmdline section read-only (drop the "w" flag from
> .init.rodata).
> - Add a make-clean hook so tools/bootconfig artifacts are removed by
> make clean.
> - Gate the x86 prepend on "bootconfig" being present on the command
> line (or CONFIG_BOOT_CONFIG_FORCE), matching the init.* opt-in
> semantics documented in bootconfig.rst and preserving fail-safe
> recovery: dropping "bootconfig" from the bootloader cmdline now also
> disables the embedded kernel.* keys.
> - Link to v1: https://patch.msgid.link/20260527-bootconfig_using_tools-v1-0-b6906a86e7d5@debian.org
>
> ---
> Breno Leitao (9):
> bootconfig: fix NULL-pointer arithmetic in xbc_snprint_cmdline()
> bootconfig: render descendant keys when xbc_snprint_cmdline() root has a value
> bootconfig: render embedded bootconfig as a kernel cmdline at build time
> bootconfig: clean build-time tools/bootconfig from make clean
> bootconfig: add xbc_prepend_embedded_cmdline() helper
> Documentation: bootconfig: document build-time cmdline rendering
> x86/setup: prepend embedded bootconfig cmdline before parse_early_param
> bootconfig: skip runtime kernel.* render once prepended early
> init/main.c: use bootconfig_cmdline_requested() for the runtime opt-in
>
> Documentation/admin-guide/bootconfig.rst | 81 ++++++++++++++++
> MAINTAINERS | 1 +
> Makefile | 27 +++++-
> arch/x86/Kconfig | 1 +
> arch/x86/kernel/setup.c | 14 ++-
> include/linux/bootconfig.h | 14 +++
> init/Kconfig | 36 +++++++
> init/main.c | 52 +++++-----
> lib/Makefile | 16 +++
> lib/bootconfig.c | 162 +++++++++++++++++++++++++++++--
> lib/embedded-cmdline.S | 16 +++
> tools/bootconfig/Makefile | 4 +-
> 12 files changed, 388 insertions(+), 36 deletions(-)
> ---
> base-commit: a87737435cfa134f9cdcc696ba3080759d04cf72
> change-id: 20260508-bootconfig_using_tools-cfa7aa9d6a5a
>
> Best regards,
> --
> Breno Leitao <leitao@debian.org>
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply
* Re: [PATCH v12 13/16] KVM: selftests: Add guest_memfd based vm_mem_backing_src_types
From: Brendan Jackman @ 2026-06-26 14:22 UTC (permalink / raw)
To: Kalyazin, Nikita, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
bpf@vger.kernel.org, linux-kselftest@vger.kernel.org
Cc: pbonzini@redhat.com, corbet@lwn.net, maz@kernel.org,
oupton@kernel.org, joey.gouly@arm.com, suzuki.poulose@arm.com,
yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
seanjc@google.com, tglx@kernel.org, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
hpa@zytor.com, luto@kernel.org, peterz@infradead.org,
willy@infradead.org, akpm@linux-foundation.org, david@kernel.org,
lorenzo.stoakes@oracle.com, vbabka@kernel.org, rppt@kernel.org,
surenb@google.com, mhocko@suse.com, ast@kernel.org,
daniel@iogearbox.net, andrii@kernel.org, martin.lau@linux.dev,
eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev,
john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
haoluo@google.com, jolsa@kernel.org, jgg@ziepe.ca,
jhubbard@nvidia.com, peterx@redhat.com, jannh@google.com,
pfalcato@suse.de, skhan@linuxfoundation.org, riel@surriel.com,
ryan.roberts@arm.com, jgross@suse.com, yu-cheng.yu@intel.com,
kas@kernel.org, coxu@redhat.com, ackerleytng@google.com,
yosry@kernel.org, ajones@ventanamicro.com, maobibo@loongson.cn,
tabba@google.com, prsampat@amd.com, wu.fei9@sanechips.com.cn,
mlevitsk@redhat.com, jmattson@google.com, jthoughton@google.com,
agordeev@linux.ibm.com, alex@ghiti.fr, aou@eecs.berkeley.edu,
borntraeger@linux.ibm.com, chenhuacai@kernel.org,
baolu.lu@linux.intel.com, dev.jain@arm.com, gor@linux.ibm.com,
hca@linux.ibm.com, palmer@dabbelt.com, pjw@kernel.org,
shijie@os.amperecomputing.com, svens@linux.ibm.com,
thuth@redhat.com, yang@os.amperecomputing.com,
Liam.Howlett@oracle.com, urezki@gmail.com,
zhengqi.arch@bytedance.com, gerald.schaefer@linux.ibm.com,
jiayuan.chen@shopee.com, lenb@kernel.org, pavel@kernel.org,
rafael@kernel.org, yangyicong@hisilicon.com,
vannapurve@google.com, jackmanb@google.com, patrick.roy@linux.dev,
Itazuri, Takahiro
In-Reply-To: <20260410151746.61150-14-kalyazin@amazon.com>
On Fri Apr 10, 2026 at 3:20 PM UTC, Nikita Kalyazin wrote:
> From: Patrick Roy <patrick.roy@linux.dev>
>
> Allow selftests to configure their memslots such that userspace_addr is
> set to a MAP_SHARED mapping of the guest_memfd that's associated with
> the memslot. This setup is the configuration for non-CoCo VMs, where all
> guest memory is backed by a guest_memfd whose folios are all marked
> shared, but KVM is still able to access guest memory to provide
> functionality such as MMIO emulation on x86.
>
> Add backing types for normal guest_memfd, as well as direct map removed
> guest_memfd.
>
> Signed-off-by: Patrick Roy <patrick.roy@linux.dev>
> Signed-off-by: Nikita Kalyazin <nikita.kalyazin@linux.dev>
> ---
> .../testing/selftests/kvm/include/kvm_util.h | 18 ++++++
> .../testing/selftests/kvm/include/test_util.h | 7 +++
> tools/testing/selftests/kvm/lib/kvm_util.c | 61 ++++++++++---------
> tools/testing/selftests/kvm/lib/test_util.c | 8 +++
> 4 files changed, 65 insertions(+), 29 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
> index 8b39cb919f4f..056a003a63c0 100644
> --- a/tools/testing/selftests/kvm/include/kvm_util.h
> +++ b/tools/testing/selftests/kvm/include/kvm_util.h
> @@ -664,6 +664,24 @@ static inline bool is_smt_on(void)
>
> void vm_create_irqchip(struct kvm_vm *vm);
>
> +static inline uint32_t backing_src_guest_memfd_flags(enum vm_mem_backing_src_type t)
> +{
> + uint32_t flags = 0;
> +
> + switch (t) {
> + case VM_MEM_SRC_GUEST_MEMFD_NO_DIRECT_MAP:
> + flags |= GUEST_MEMFD_FLAG_NO_DIRECT_MAP;
> + fallthrough;
> + case VM_MEM_SRC_GUEST_MEMFD:
> + flags |= GUEST_MEMFD_FLAG_MMAP | GUEST_MEMFD_FLAG_INIT_SHARED;
> + break;
> + default:
> + break;
> + }
> +
> + return flags;
> +}
> +
> static inline int __vm_create_guest_memfd(struct kvm_vm *vm, uint64_t size,
> uint64_t flags)
> {
> diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
> index 8140e59b59e5..ea6de20ce8ef 100644
> --- a/tools/testing/selftests/kvm/include/test_util.h
> +++ b/tools/testing/selftests/kvm/include/test_util.h
> @@ -152,6 +152,8 @@ enum vm_mem_backing_src_type {
> VM_MEM_SRC_ANONYMOUS_HUGETLB_16GB,
> VM_MEM_SRC_SHMEM,
> VM_MEM_SRC_SHARED_HUGETLB,
> + VM_MEM_SRC_GUEST_MEMFD,
> + VM_MEM_SRC_GUEST_MEMFD_NO_DIRECT_MAP,
> NUM_SRC_TYPES,
> };
>
> @@ -184,6 +186,11 @@ static inline bool backing_src_is_shared(enum vm_mem_backing_src_type t)
> return vm_mem_backing_src_alias(t)->flag & MAP_SHARED;
> }
>
> +static inline bool backing_src_is_guest_memfd(enum vm_mem_backing_src_type t)
> +{
> + return t == VM_MEM_SRC_GUEST_MEMFD || t == VM_MEM_SRC_GUEST_MEMFD_NO_DIRECT_MAP;
> +}
> +
> static inline bool backing_src_can_be_huge(enum vm_mem_backing_src_type t)
> {
> return t != VM_MEM_SRC_ANONYMOUS && t != VM_MEM_SRC_SHMEM;
> diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> index 5b0865683047..fa4a2fc236fe 100644
> --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> @@ -1046,6 +1046,33 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
> alignment = 1;
> #endif
>
> + if (guest_memfd < 0) {
> + if ((flags & KVM_MEM_GUEST_MEMFD) || backing_src_is_guest_memfd(src_type)) {
> + uint32_t guest_memfd_flags = backing_src_guest_memfd_flags(src_type);
> +
> + TEST_ASSERT(!guest_memfd_offset,
> + "Offset must be zero when creating new guest_memfd");
> + guest_memfd = vm_create_guest_memfd(vm, mem_size, guest_memfd_flags);
> + }
> + } else {
> + /*
> + * Install a unique fd for each memslot so that the fd
> + * can be closed when the region is deleted without
> + * needing to track if the fd is owned by the framework
> + * or by the caller.
> + */
> + guest_memfd = kvm_dup(guest_memfd);
> + }
> +
> + if (guest_memfd >= 0) {
> + flags |= KVM_MEM_GUEST_MEMFD;
> +
> + region->region.guest_memfd = guest_memfd;
> + region->region.guest_memfd_offset = guest_memfd_offset;
> + } else {
> + region->region.guest_memfd = -1;
> + }
> +
> /*
> * When using THP mmap is not guaranteed to returned a hugepage aligned
> * address so we have to pad the mmap. Padding is not needed for HugeTLB
> @@ -1061,10 +1088,13 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
> if (alignment > 1)
> region->mmap_size += alignment;
>
> - region->fd = -1;
> - if (backing_src_is_shared(src_type))
> + if (backing_src_is_guest_memfd(src_type))
> + region->fd = guest_memfd;
This seems to cause a double-close in __vm_mem_region_delete() - it was
fine when this patch was written but now we have kvm_free_fd() which
crashes the test when this happens.
AFAICS it's easy to fix we just need to enlighten
__vm_mem_region_delete() that they might be the same FD.
^ permalink raw reply
* [PATCH v11 11/11] tracing/probes: Add a new testcase for BTF typecasts
From: Masami Hiramatsu (Google) @ 2026-06-26 14:16 UTC (permalink / raw)
To: Steven Rostedt, Mathieu Desnoyers
Cc: Jonathan Corbet, Shuah Khan, Masami Hiramatsu, linux-kernel,
linux-trace-kernel, linux-doc, linux-kselftest
In-Reply-To: <178248325671.841606.17344906774310339507.stgit@devnote2>
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
With the introduction of container_of-style BTF typecasting and
per-CPU variable access support in trace probes, we need a way to
verify their functionality and prevent regressions.
Add a new ftrace kselftest and update the trace event sample module
to test and validate these features.
Specifically, update the trace-events-sample module to set up a
periodic timer whose callback accesses a per-CPU counter. Introduce
a new sample trace event, foo_timer_fn, to trace this callback
and log the current counter value.
Then, add a new test case, btf_probe_event.tc, which defines a
dynamic probe on the timer callback. The probe uses BTF typecasting
to recover the parent structure from the timer argument and
this_cpu_read() to fetch the per-CPU counter. The test verifies
the integrity of the implementation by ensuring the values
recorded by the dynamic probe match those from the static tracepoint.
Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
Changes in v11:
- nit: fix the error code in comment.
Changes in v10:
- Add a check for $current and this_cpu_* for eprobe
Changes in v9:
- Add a testcase for checking new syntax.
Changes in v8:
- Add more test cases.
Changes in v6:
- Update testcase according to changes.
Changes in v5:
- Add more syntax test cases.
Changes in v4:
- Fix uprobe $current test.
Changes in v3:
- Add syntax test case.
- Update testcase to use this_cpu_read()
Changes in v2:
- Use timer_shutdown_sync() instead of timer_delete_sync() for teardown.
---
samples/trace_events/trace-events-sample.c | 40 +++++++
samples/trace_events/trace-events-sample.h | 34 ++++++
.../ftrace/test.d/dynevent/btf_probe_event.tc | 51 ++++++++++
.../test.d/dynevent/btf_typecast_accepted.tc | 107 ++++++++++++++++++++
.../test.d/dynevent/eprobes_syntax_errors.tc | 9 ++
.../ftrace/test.d/dynevent/fprobe_syntax_errors.tc | 12 ++
.../ftrace/test.d/kprobe/kprobe_syntax_errors.tc | 12 ++
.../ftrace/test.d/kprobe/uprobe_syntax_errors.tc | 5 +
8 files changed, 265 insertions(+), 5 deletions(-)
create mode 100644 tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc
create mode 100644 tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_accepted.tc
diff --git a/samples/trace_events/trace-events-sample.c b/samples/trace_events/trace-events-sample.c
index 0b7a6efdb247..ca5d98c360cb 100644
--- a/samples/trace_events/trace-events-sample.c
+++ b/samples/trace_events/trace-events-sample.c
@@ -94,6 +94,20 @@ static int simple_thread_fn(void *arg)
static DEFINE_MUTEX(thread_mutex);
static int simple_thread_cnt;
+static struct foo_timer_data *foo_timer_data;
+
+static void sample_timer_cb(struct timer_list *t)
+{
+ struct foo_timer_data *data = container_of(t, struct foo_timer_data, timer);
+
+ get_cpu();
+ trace_foo_timer_fn(data);
+ (*this_cpu_ptr(data->counter))++;
+ put_cpu();
+
+ mod_timer(t, jiffies + HZ);
+}
+
int foo_bar_reg(void)
{
mutex_lock(&thread_mutex);
@@ -132,9 +146,27 @@ void foo_bar_unreg(void)
static int __init trace_event_init(void)
{
+ foo_timer_data = kzalloc_obj(*foo_timer_data, GFP_KERNEL);
+ if (!foo_timer_data)
+ return -ENOMEM;
+
+ foo_timer_data->name = "sample_timer_counter";
+ foo_timer_data->counter = alloc_percpu(int);
+ if (!foo_timer_data->counter) {
+ kfree(foo_timer_data);
+ return -ENOMEM;
+ }
+
+ timer_setup(&foo_timer_data->timer, sample_timer_cb, 0);
+ mod_timer(&foo_timer_data->timer, jiffies + HZ);
+
simple_tsk = kthread_run(simple_thread, NULL, "event-sample");
- if (IS_ERR(simple_tsk))
- return -1;
+ if (IS_ERR(simple_tsk)) {
+ timer_shutdown_sync(&foo_timer_data->timer);
+ free_percpu(foo_timer_data->counter);
+ kfree(foo_timer_data);
+ return PTR_ERR(simple_tsk);
+ }
return 0;
}
@@ -147,6 +179,10 @@ static void __exit trace_event_exit(void)
kthread_stop(simple_tsk_fn);
simple_tsk_fn = NULL;
mutex_unlock(&thread_mutex);
+
+ timer_shutdown_sync(&foo_timer_data->timer);
+ free_percpu(foo_timer_data->counter);
+ kfree(foo_timer_data);
}
module_init(trace_event_init);
diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h
index 1a05fc153353..816848a456a2 100644
--- a/samples/trace_events/trace-events-sample.h
+++ b/samples/trace_events/trace-events-sample.h
@@ -247,12 +247,14 @@
*/
/*
- * It is OK to have helper functions in the file, but they need to be protected
- * from being defined more than once. Remember, this file gets included more
- * than once.
+ * It is OK to have helper functions and data structures in the file, but they
+ * need to be protected from being defined more than once. Remember, this file
+ * gets included more than once.
*/
#ifndef __TRACE_EVENT_SAMPLE_HELPER_FUNCTIONS
#define __TRACE_EVENT_SAMPLE_HELPER_FUNCTIONS
+#include <linux/timer.h>
+
static inline int __length_of(const int *list)
{
int i;
@@ -270,6 +272,13 @@ enum {
TRACE_SAMPLE_BAR = 4,
TRACE_SAMPLE_ZOO = 8,
};
+
+struct foo_timer_data {
+ const char *name;
+ struct timer_list timer;
+ int __percpu *counter;
+};
+
#endif
/*
@@ -595,6 +604,25 @@ TRACE_EVENT(foo_rel_loc,
__get_rel_bitmask(bitmask),
__get_rel_cpumask(cpumask))
);
+
+TRACE_EVENT(foo_timer_fn,
+
+ TP_PROTO(struct foo_timer_data *data),
+
+ TP_ARGS(data),
+
+ TP_STRUCT__entry(
+ __string( name, data->name )
+ __field( int, count )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name);
+ __entry->count = *this_cpu_ptr(data->counter);
+ ),
+
+ TP_printk("name=%s count=%d", __get_str(name), __entry->count)
+);
#endif
/***** NOTICE! The #if protection ends here. *****/
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc b/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc
new file mode 100644
index 000000000000..96791e120b7d
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc
@@ -0,0 +1,51 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: BTF event with typecast and percpu access
+# requires: dynamic_events "this_cpu_read(<fetcharg>)":README "[(structname[,field])]<argname>[->field[->field|.field...]]":README
+
+# Check if the sample module is loaded
+if ! lsmod | grep -q trace_events_sample; then
+ modprobe trace-events-sample || exit_unsupported
+fi
+
+echo 0 > events/enable
+echo > dynamic_events
+
+# The sample_timer_cb(struct timer_list *t) is called.
+# We want to check (STRUCT,FIELD)VAR typecast and this_cpu_read() access.
+# (foo_timer_data,timer)t converts t to struct foo_timer_data * using container_of.
+# data->counter is a per-cpu pointer to int.
+# this_cpu_read(data->counter) should give the value of the counter.
+
+echo 'f:mysample/myevent sample_timer_cb name=(foo_timer_data,timer)t->name:string count=this_cpu_read((foo_timer_data,timer)t->counter)' >> dynamic_events
+
+echo 1 > events/mysample/myevent/enable
+echo 1 > events/sample-trace/foo_timer_fn/enable
+
+sleep 2
+
+echo 0 > events/mysample/myevent/enable
+echo 0 > events/sample-trace/foo_timer_fn/enable
+
+# Compare the values.
+MATCH=0
+while read line; do
+ if echo $line | grep -q "foo_timer_fn:"; then
+ NAME=`echo $line | sed 's/.*name=\([^ ]*\) .*/\1/'`
+ COUNT=`echo $line | sed 's/.*count=\([^ ]*\).*/\1/'`
+ if grep -q "myevent:.*name=\"${NAME}\" count=$COUNT" trace; then
+ MATCH=$((MATCH+1))
+ fi
+ fi
+done < trace
+
+if [ $MATCH -eq 0 ]; then
+ echo "No matching events found"
+ exit_fail
+fi
+
+# Clean up
+echo 0 > events/mysample/myevent/enable
+echo 0 > events/sample-trace/foo_timer_fn/enable
+echo > dynamic_events
+clear_trace
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_accepted.tc b/tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_accepted.tc
new file mode 100644
index 000000000000..acf0b5a917d3
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_accepted.tc
@@ -0,0 +1,107 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: BTF typecast and percpu access syntax validation
+# requires: dynamic_events "this_cpu_read(<fetcharg>)":README "[(structname[,field])]<argname>[->field[->field|.field...]]":README
+
+KPROBES=
+FPROBES=
+
+if grep -qF "p[:[<group>/][<event>]] <place> [<args>]" README ; then
+ KPROBES=yes
+fi
+if grep -qF "f[:[<group>/][<event>]] <func-name>[%return] [<args>]" README ; then
+ FPROBES=yes
+fi
+
+if [ -z "$KPROBES" -a -z "$FPROBES" ] ; then
+ exit_unsupported
+fi
+
+echo 0 > events/enable
+echo > dynamic_events
+
+# Load trace-events-sample module if available to have per-CPU counter structure defined
+if ! lsmod | grep -q trace_events_sample; then
+ modprobe trace-events-sample || true
+fi
+
+if [ "$FPROBES" ] ; then
+ # 1. Test basic typecast on fprobe
+ echo 'f:fpevent1 vfs_read name=(file)file->f_path.dentry->d_name.name:string' >> dynamic_events
+ # 2. Test parenthesized typecast target on fprobe
+ echo 'f:fpevent2 vfs_read name=(file)(file)->f_path.dentry->d_name.name:string' >> dynamic_events
+ # 3. Test nested typecasts on fprobe
+ echo 'f:fpevent3 vfs_read name=(dentry)((file)file->f_path.dentry)->d_name.name:string' >> dynamic_events
+ # 4. Test container_of-style typecast with field option on fprobe
+ echo 'f:fpevent4 vfs_read name=(file,f_path)file->f_mode' >> dynamic_events
+ # 5. Test typecast on return value on fprobe
+ echo 'f:fpevent5 vfs_read%return name=(file)$retval->f_path.dentry->d_name.name:string' >> dynamic_events
+ # 6. Test $current variable support on fprobe
+ echo 'f:fpevent6 vfs_read pid=$current->pid' >> dynamic_events
+ echo 'f:fpevent7 vfs_read pid=(task_struct)$current->pid' >> dynamic_events
+ echo 'f:fpevent8 vfs_read pid=(task_struct,group_leader)$current->pid' >> dynamic_events
+
+ # Test this_cpu_read and this_cpu_ptr on fprobe
+ if lsmod | grep -q trace_events_sample; then
+ echo 'f:fpevent9 sample_timer_cb name=(foo_timer_data,timer)t->name:string count=this_cpu_read((foo_timer_data,timer)t->counter)' >> dynamic_events
+ echo 'f:fpevent10 sample_timer_cb ptr=this_cpu_ptr((foo_timer_data,timer)t->counter)' >> dynamic_events
+ fi
+fi
+
+if [ "$KPROBES" ] ; then
+ # 7. Test basic typecast on kprobe
+ echo 'p:kpevent1 vfs_read name=(file)file->f_path.dentry->d_name.name:string' >> dynamic_events
+ # 8. Test parenthesized typecast target on kprobe
+ echo 'p:kpevent2 vfs_read name=(file)(file)->f_path.dentry->d_name.name:string' >> dynamic_events
+ # 9. Test nested typecasts on kprobe
+ echo 'p:kpevent3 vfs_read name=(dentry)((file)file->f_path.dentry)->d_name.name:string' >> dynamic_events
+ # 10. Test container_of-style typecast with field option on kprobe
+ echo 'p:kpevent4 vfs_read name=(file,f_path)file->f_mode' >> dynamic_events
+ # 11. Test typecast on return value on kretprobe
+ echo 'r:kpevent5 vfs_read name=(file)$retval->f_path.dentry->d_name.name:string' >> dynamic_events
+ # 12. Test $current variable support on kprobe
+ echo 'p:kpevent6 vfs_read pid=$current->pid' >> dynamic_events
+ echo 'p:kpevent7 vfs_read pid=(task_struct)$current->pid' >> dynamic_events
+ echo 'p:kpevent8 vfs_read pid=(task_struct,group_leader)$current->pid' >> dynamic_events
+
+ # Test this_cpu_read and this_cpu_ptr on kprobe
+ if lsmod | grep -q trace_events_sample; then
+ echo 'p:kpevent9 sample_timer_cb name=(foo_timer_data,timer)t->name:string count=this_cpu_read((foo_timer_data,timer)t->counter)' >> dynamic_events
+ echo 'p:kpevent10 sample_timer_cb ptr=this_cpu_ptr((foo_timer_data,timer)t->counter)' >> dynamic_events
+ fi
+fi
+
+# Verify the events exist in dynamic_events
+if [ "$FPROBES" ] ; then
+ grep -q "fpevent1 " dynamic_events
+ grep -q "fpevent2 " dynamic_events
+ grep -q "fpevent3 " dynamic_events
+ grep -q "fpevent4 " dynamic_events
+ grep -q "fpevent5 " dynamic_events
+ grep -q "fpevent6 " dynamic_events
+ grep -q "fpevent7 " dynamic_events
+ grep -q "fpevent8 " dynamic_events
+ if lsmod | grep -q trace_events_sample; then
+ grep -q "fpevent9 " dynamic_events
+ grep -q "fpevent10 " dynamic_events
+ fi
+fi
+
+if [ "$KPROBES" ] ; then
+ grep -q "kpevent1 " dynamic_events
+ grep -q "kpevent2 " dynamic_events
+ grep -q "kpevent3 " dynamic_events
+ grep -q "kpevent4 " dynamic_events
+ grep -q "kpevent5 " dynamic_events
+ grep -q "kpevent6 " dynamic_events
+ grep -q "kpevent7 " dynamic_events
+ grep -q "kpevent8 " dynamic_events
+ if lsmod | grep -q trace_events_sample; then
+ grep -q "kpevent9 " dynamic_events
+ grep -q "kpevent10 " dynamic_events
+ fi
+fi
+
+# Clean up
+echo > dynamic_events
+clear_trace
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc
index 0e65e787e426..1d6d1cf94f16 100644
--- a/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc
@@ -21,8 +21,17 @@ check_error 'e:foo/^bar.1 syscalls/sys_enter_openat' # BAD_EVENT_NAME
check_error 'e:foo/bar syscalls/sys_enter_openat arg=^$foo' # BAD_ATTACH_ARG
+check_error 'e:foo/bar syscalls/sys_enter_openat arg=^COMM' # NO_EVENT_FIELD
+if grep -q '\\$current' README; then
+ check_error 'e:foo/bar syscalls/sys_enter_openat arg=^current' # NO_EVENT_FIELD
+fi
+
if grep -q '<attached-group>\.<attached-event>.*\[if <filter>\]' README; then
check_error 'e:foo/bar syscalls/sys_enter_openat if ^' # NO_EP_FILTER
fi
+if grep -q 'this_cpu_read(<fetcharg>)' README; then
+ check_error 'e:foo/bar syscalls/sys_enter_openat arg=^this_cpu_read(file)' # NOSUP_PERCPU
+fi
+
exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_errors.tc
index fee479295e2f..e9d7e6919c7f 100644
--- a/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_errors.tc
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_syntax_errors.tc
@@ -112,6 +112,18 @@ check_error 'f vfs_read%return $retval->^foo' # NO_PTR_STRCT
check_error 'f vfs_read file->^foo' # NO_BTF_FIELD
check_error 'f vfs_read file^-.foo' # BAD_HYPHEN
check_error 'f vfs_read ^file:string' # BAD_TYPE4STR
+if grep -qF "[(structname" README ; then
+check_error 'f vfs_read arg1=(task_struct)file^' # TYPECAST_REQ_FIELD
+check_error 'f vfs_read arg1=(a)((b)((c)(^(d)file->d)->c)->b)->a' # TOO_MANY_NESTED
+check_error 'f vfs_read arg1=(task_struct,^in_execve)file->comm' # TYPECAST_NOT_ALIGNED
+check_error 'f vfs_read arg1=(task_struct,^foo_bar)file->pid' # NO_BTF_FIELD
+check_error 'f vfs_read arg1=(^task_struct1234)file->pid' # NO_PTR_STRCT
+check_error 'f vfs_read arg1=(task_struct,se^->group_node)file->comm' # TYPECAST_BAD_ARROW
+check_error 'f vfs_read arg1=(task_struct,^->pid)file->comm' # NO_BTF_FIELD
+check_error 'f vfs_read arg1=(task_struct,^.pid)file->comm' # NO_BTF_FIELD
+check_error 'f vfs_read arg1=(task_struct,^.)file->comm' # NO_BTF_FIELD
+check_error 'f vfs_read arg1=(task_struct)^@symbol+10->comm' # TYPECAST_SYM_OFFSET
+fi
fi
else
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
index 8f1c58f0c239..21ce8414459f 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
@@ -115,6 +115,18 @@ check_error 'p vfs_read+20 ^$arg*' # NOFENTRY_ARGS
check_error 'p vfs_read ^hoge' # NO_BTFARG
check_error 'p kfree ^$arg10' # NO_BTFARG (exceed the number of parameters)
check_error 'r kfree ^$retval' # NO_RETVAL
+if grep -qF "[(structname" README ; then
+check_error 'p vfs_read arg1=(task_struct)file^' # TYPECAST_REQ_FIELD
+check_error 'p vfs_read arg1=(a)((b)((c)(^(d)file->d)->c)->b)->a' # TOO_MANY_NESTED
+check_error 'p vfs_read arg1=(task_struct,^in_execve)file->comm' # TYPECAST_NOT_ALIGNED
+check_error 'p vfs_read arg1=(task_struct,^foo_bar)file->pid' # NO_BTF_FIELD
+check_error 'p vfs_read arg1=(^task_struct1234)file->pid' # NO_PTR_STRCT
+check_error 'p vfs_read arg1=(task_struct,se^->group_node)file->comm' # TYPECAST_BAD_ARROW
+check_error 'p vfs_read arg1=(task_struct,^->pid)file->comm' # NO_BTF_FIELD
+check_error 'p vfs_read arg1=(task_struct,^.pid)file->comm' # NO_BTF_FIELD
+check_error 'p vfs_read arg1=(task_struct,^.)file->comm' # NO_BTF_FIELD
+check_error 'p vfs_read arg1=(task_struct)^@symbol+10->comm' # TYPECAST_SYM_OFFSET
+fi
else
check_error 'p vfs_read ^$arg*' # NOSUP_BTFARG
fi
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc
index c817158b99db..e12dc967ec76 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/uprobe_syntax_errors.tc
@@ -28,4 +28,9 @@ if grep -q ".*symstr.*" README; then
check_error 'p /bin/sh:10 $stack0:^symstr' # BAD_TYPE
fi
+# $current is not supported by uprobe
+if grep -q "\$current.*" README; then
+check_error 'p /bin/sh:10 ^$current:u8' # BAD_VAR
+fi
+
exit 0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox