* Re: [PATCH 02/61] btrfs: Prefer IS_ERR_OR_NULL over manual NULL check
From: David Sterba @ 2026-03-13 19:22 UTC (permalink / raw)
To: Philipp Hahn
Cc: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
linux-sctp, linux-security-module, linux-sh, linux-sound,
linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
netdev, ntfs3, samba-technical, sched-ext, target-devel,
tipc-discussion, v9fs, Chris Mason, David Sterba
In-Reply-To: <20260310-b4-is_err_or_null-v1-2-bd63b656022d@avm.de>
On Tue, Mar 10, 2026 at 12:48:28PM +0100, Philipp Hahn wrote:
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.
>
> IS_ERR_OR_NULL() already uses likely(!ptr) internally. checkpatch does
> not like nesting it:
> > WARNING: nested (un)?likely() calls, IS_ERR_OR_NULL already uses
> > unlikely() internally
> Remove the explicit use of likely().
>
> Change generated with coccinelle.
>
> To: Chris Mason <clm@fb.com>
> To: David Sterba <dsterba@suse.com>
> Cc: linux-btrfs@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
Added to for-next, we seem to be using IS_ERR_OR_NULL() already in a
few other places so this is makes sense for consistency. Thanks.
^ permalink raw reply
* Re: [PATCH v2] tracing: Generate undef symbols allowlist for simple_ring_buffer
From: Nathan Chancellor @ 2026-03-13 16:37 UTC (permalink / raw)
To: Vincent Donnefort
Cc: maz, rostedt, arnd, linux-trace-kernel, kvmarm, kernel-team
In-Reply-To: <20260313105829.1214123-1-vdonnefort@google.com>
On Fri, Mar 13, 2026 at 10:58:29AM +0000, Vincent Donnefort wrote:
> Compiler and tooling-generated symbols are difficult to maintain
> across all supported architectures. Make the allowlist more robust by
> replacing the harcoded list with a mechanism that automatically detects
> these symbols.
>
> This mechanism generates a C function designed to trigger common
> compiler-inserted symbols.
>
> Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
>
> ---
>
> Changes in v2:
>
> - Use filechk (Nathan)
> - Removed deprecated extra-y (Nathan)
> - Added simple_ring_buffer in allowlist (Nathan)
> - Added memcpy() to generate more symbols (Nathan)
> - Added __sancov
>
> diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
> index beb15936829d..96627a909ecc 100644
> --- a/kernel/trace/Makefile
> +++ b/kernel/trace/Makefile
> @@ -136,17 +136,42 @@ obj-$(CONFIG_TRACE_REMOTE_TEST) += remote_test.o
> # simple_ring_buffer is used by the pKVM hypervisor which does not have access
> # to all kernel symbols. Fail the build if forbidden symbols are found.
> #
> -UNDEFINED_ALLOWLIST := memset alt_cb_patch_nops __x86 __ubsan __asan __kasan __gcov __aeabi_unwind
> -UNDEFINED_ALLOWLIST += __stack_chk_fail stackleak_track_stack __ref_stack __sanitizer llvm_gcda llvm_gcov
> -UNDEFINED_ALLOWLIST += .TOC\. __clear_pages_unrolled __memmove copy_page warn_slowpath_fmt
> -UNDEFINED_ALLOWLIST += ftrace_likely_update __hwasan_load __hwasan_store __hwasan_tag_memory
> -UNDEFINED_ALLOWLIST += warn_bogus_irq_restore __stack_chk_guard
> -UNDEFINED_ALLOWLIST := $(addprefix -e , $(UNDEFINED_ALLOWLIST))
> +# undefsyms_base generates a set of compiler and tooling-generated symbols that can
> +# safely be ignored for simple_ring_buffer.
> +#
> +filechk_undefsyms_base = \
> + echo '$(pound)include <linux/atomic.h>'; \
> + echo '$(pound)include <linux/string.h>'; \
> + echo '$(pound)include <asm/page.h>'; \
> + echo 'static char page[PAGE_SIZE] __aligned(PAGE_SIZE);'; \
> + echo 'void undefsyms_base(void *p, int n);'; \
> + echo 'void undefsyms_base(void *p, int n) {'; \
> + echo ' char buffer[256] = { 0 };'; \
> + echo ' u32 u = 0;'; \
> + echo ' memset((char * volatile)page, 8, PAGE_SIZE);'; \
> + echo ' memset((char * volatile)buffer, 8, sizeof(buffer));'; \
> + echo ' memcpy((void * volatile)p, buffer, sizeof(buffer));'; \
> + echo ' cmpxchg((u32 * volatile)&u, 0, 8);'; \
> + echo ' WARN_ON(n == 0xdeadbeef);'; \
> + echo '}'
> +
> +$(obj)/undefsyms_base.c: FORCE
> + $(call filechk,undefsyms_base)
> +
> +clean-files += undefsyms_base.c
> +
> +$(obj)/undefsyms_base.o: $(obj)/undefsyms_base.c
> +
> +targets += undefsyms_base.o
> +
> +UNDEFINED_ALLOWLIST = __asan __gcov __kasan __kcsan __hwasan __sancov __sanitizer __tsan __ubsan __x86_indirect_thunk \
> + simple_ring_buffer \
> + $(shell $(NM) -u $(obj)/undefsyms_base.o 2>/dev/null | awk '{print $$2}')
>
> quiet_cmd_check_undefined = NM $<
> - cmd_check_undefined = test -z "`$(NM) -u $< | grep -v $(UNDEFINED_ALLOWLIST)`"
> + cmd_check_undefined = test -z "`$(NM) -u $< | grep -v $(addprefix -e , $(UNDEFINED_ALLOWLIST))`"
>
> -$(obj)/%.o.checked: $(obj)/%.o FORCE
> +$(obj)/%.o.checked: $(obj)/%.o $(obj)/undefsyms_base.o FORCE
> $(call if_changed,check_undefined)
>
> always-$(CONFIG_SIMPLE_RING_BUFFER) += simple_ring_buffer.o.checked
>
> base-commit: 33f2e266515717c4b2df585dadefa0525557726c
> --
> 2.53.0.851.ga537e3e6e9-goog
>
Thanks! This is almost perfect for my tests, one final thing that I
noticed as a result of my full overnight builds. For ARCH=riscv (and
some other architectures from a quick grep), there is some logic in
their include/asm/string.h files to avoid FORTIFY_SOURCE when KASAN is
enabled for the entire build but not enabled for the particular file. As
undefsyms_base.o is not linked into vmlinux or modules, it does not
automatically have KASAN enabled.
$ cat allmod.config
CONFIG_GCOV_KERNEL=n
CONFIG_LTO_CLANG_THIN=y
CONFIG_WERROR=n
$ make -skj"$(nproc)" ARCH=riscv KCONFIG_ALLCONFIG=1 LLVM=1 mrproper allmodconfig kernel/trace/
Unexpected symbols in kernel/trace/simple_ring_buffer.o:
U __fortify_panic
U __write_overflow_field
...
This cures that for me.
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 260382f62dbf..55af887a90e2 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -164,6 +164,11 @@ $(obj)/undefsyms_base.o: $(obj)/undefsyms_base.c
targets += undefsyms_base.o
+# ensure KASAN is enabled to avoid logic that may disable FORTIFY_SOURCE when
+# KASAN is not enabled. undefsyms_base.o does not automatically get KASAN flags
+# because it is not linked into vmlinux.
+KASAN_SANITIZE_undefsyms_base.o := y
+
UNDEFINED_ALLOWLIST = __asan __gcov __kasan __kcsan __hwasan __sancov __sanitizer __tsan __ubsan __x86_indirect_thunk \
simple_ring_buffer \
$(shell $(NM) -u $(obj)/undefsyms_base.o 2>/dev/null | awk '{print $$2}')
--
With that addressed:
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Cheers,
Nathan
^ permalink raw reply related
* Re: [PATCH RFC v3 00/43] guest_memfd: In-place conversion support
From: Sean Christopherson @ 2026-03-13 15:45 UTC (permalink / raw)
To: Ackerley Tng
Cc: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, 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, Jason Gunthorpe, Vlastimil Babka, kvm,
linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
On Fri, Mar 13, 2026, Ackerley Tng wrote:
> Hi,
>
> (Here's the motivation for this series, which I realized was missing from
> the earlier revisions of this series)
...
> I'm intending RFC (v3) as a basis for discussion of flags/content
> modes (name TBD) to allow userspace to request guarantees on how the memory
> contents will look like after setting memory attributes. The last 6 patches
> implement content mode support. These patches will be reordered, and some
> of them could be absorbed into earlier patches, in later revisions.
>
> Here are the discussion points I can think of (please add on):
>
> 1. (Might hopefully resolve soon?) Should ZERO be supported on shared to
> private conversions? Discussion is at [6].
No. There is no use case. The entire point of CoCo is that the VMM is untrusted.
Having the guest rely on the VMM to zero memory makes no sense whatsoever. There
may be a contract between the trusted whatever and the guest, but that's between
those two entities, the VMM is not involved, period.
PRESERVE is different because the intent is to allow the guest to operate on
*untrusted* data. Operating on untrusted zeros is nonsensical.
ZERO for private=>shared is different between the VMM trusts the host kernel.
> 2. Do we need a CAP for userspace to query the flags/modes supported?
Yes.
> It seems like there won't be anything dynamic about the flags/modes
> supported.
>
> The userspace code can check what platform it is running on, and then
> decide ZERO or PRESERVE based on the platform:
>
> If the VM is running on TDX,
No. No, no, no, no. I have said this over, and over, and over. The contract
is between userspace and KVM, not between userspace and the underlying CoCo
implementation. Anything that requires making assumptions based on the VM type
is a non-starter for me.
> it would want to specify ZERO all the
> time. If the VM were running on pKVM it would want to specify PRESERVE
> if it wants to enable in-place sharing, and ZERO if it wants to zero the
> memory.
>
> If someday TDX supports PRESERVE, then there's room for discovery of
> which algorithm to choose when running the guest. Perhaps that's when
> the CAP should be introduced?
>
> 3. What do people think of the structure of how various content modes are
> checked for support or applied? I used overridable weak functions for
> architectures that haven't defined support, and defined overrides for
> x86 to show how I think it would work. For CoCo platforms, I only
> implemented TDX for illustration purposes and might need help with the
> other platforms. Should I have used kvm_x86_ops? I tried and found
> myself defining lots of boilerplate.
>
> 4. enum for ZERO and PRESERVE?
>
> Pros:
>
> * No way to define both ZERO and PRESERVE (make impossible states
> unrepresentable)
> * e.g. enum kvm_device_type in __u32 type in struct
> kvm_create_device
> * But maybe someday some modes can be used together?
Huh? Oh, you don't mean "enum", you mean "values vs. flags". Because in C you
can obviously have an enum of flags.
I don't have a strong preference, though I think I'd vote for flags.
Practically speaking, I doubt we'll ever have more than DEFAULT, ZERO, and PRESERVE,
i.e. more than '0', '1, and '2'. Perhaps I lack imagination, but I can't think
of any operation that we would want to become ABI. ZERO is special purely because
various CoCo implementations already zero memory on conversion. Everything else
fits into PRESERVE, because if the kernel perform the operation, then userspace
can do the same, and likely more performantly and obviously without needing a
contract with KVM.
The only other option I can think of is if a CoCo implementation wanted to use an
specific value other than '0' to fill a page on conversion. Given that starting
from '0' is by far the most common state in computing, I just don't see that
happening. E.g. that's be like adding k1salloc() in addition to kmalloc() and
kzalloc().
So, we're likely only going to have DEFAULT, ZERO, and PRESERVE, at which point
whether we use flags or values is a wash in terms of how many bits we need: 2.
If we use flags, then we can have a single CAP to enumerate all FLAGS that are
supported KVM_SET_MEMORY_ATTRIBUTES2. If we use values, we'd need a separate CAP
for flags and a separate cap for conversion operations.
Using values would allow providing a dedicated field in kvm_memory_attributes2,
which _might_ make some code more readable. But for me, that doesn't outweigh the
disadvantage of needing another CAP.
^ permalink raw reply
* Re: [PATCH v3 1/4] tracing/preemptirq: Optimize preempt_disable/enable() tracepoint overhead
From: Wander Lairson Costa @ 2026-03-13 15:36 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Ingo Molnar, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
Masami Hiramatsu, Mathieu Desnoyers, Andrew Morton,
open list:SCHEDULER, open list:TRACING, acme, williams, gmonaco
In-Reply-To: <20260313090404.GK606826@noisy.programming.kicks-ass.net>
On Fri, Mar 13, 2026 at 10:04:04AM +0100, Peter Zijlstra wrote:
> On Thu, Mar 12, 2026 at 02:19:15PM -0300, Wander Lairson Costa wrote:
>
> > > That's significant bloat, for really very little gain. Realistically
> > > nobody is going to need these.
> > >
> >
> > Of course, I can't speak for others, but more than once I debugged issues
> > that those tracepoints had made my life far easier. Those cases convinced
> > me that such a feature would be worth it. But if you don't see
> > value and will reject the patches no matter what, nothing can be done,
> > and I will have to accept defeat.
>
> If distros are going to enable this, I suppose I'm not going to stop
> this. But I do very much worry about the general bloat of things, there
> are a *LOT* of preempt_{dis,en}able() sites.
>
We plan to enable these tracepoints in the RHEL kernel-rt to track
extended non-preemptible states that cause high latencies. These
issues occasionally surface in customer OpenShift deployments, where
deploying a custom debug kernel is highly impractical. Having these
tracepoints available in the distribution kernel would be handful for
debugging these production systems. That said, I expect enabling this
feature to be the exception rather than the rule — most distribution
kernels would leave it disabled.
^ permalink raw reply
* Re: [PATCH 00/15] tracepoint: Avoid double static_branch evaluation at guarded call sites
From: Vineeth Remanan Pillai @ 2026-03-13 14:02 UTC (permalink / raw)
To: Steven Rostedt
Cc: Andrii Nakryiko, Mathieu Desnoyers, Peter Zijlstra,
Dmitry Ilvokhin, Masami Hiramatsu, Ingo Molnar, Jens Axboe,
io-uring, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Alexei Starovoitov, Daniel Borkmann,
Marcelo Ricardo Leitner, Xin Long, Jon Maloy, Aaron Conole,
Eelco Chaudron, Ilya Maximets, netdev, bpf, linux-sctp,
tipc-discussion, dev, Oded Gabbay, Koby Elbaz, dri-devel,
Rafael J. Wysocki, Viresh Kumar, Gautham R. Shenoy, Huang Rui,
Mario Limonciello, Len Brown, Srinivas Pandruvada, linux-pm,
MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Christian König,
Sumit Semwal, linaro-mm-sig, Eddie James, Andrew Jeffery,
Joel Stanley, linux-fsi, David Airlie, Simona Vetter,
Alex Deucher, Danilo Krummrich, Matthew Brost, Philipp Stanner,
Harry Wentland, Leo Li, amd-gfx, Jiri Kosina, Benjamin Tissoires,
linux-input, Wolfram Sang, linux-i2c, Mark Brown,
Michael Hennerich, Nuno Sá, linux-spi, James E.J. Bottomley,
Martin K. Petersen, linux-scsi, Chris Mason, David Sterba,
linux-btrfs, linux-trace-kernel, linux-kernel
In-Reply-To: <20260312130255.6476e560@gandalf.local.home>
On Thu, Mar 12, 2026 at 1:03 PM Steven Rostedt <rostedt@goodmis.org> wrote:
>
> On Thu, 12 Mar 2026 09:54:29 -0700
> Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
>
> > > > emit_trace_foo()
> > > > __trace_foo()
> >
> > this seems like the best approach, IMO. double-underscored variants
> > are usually used for some specialized/internal version of a function
> > when we know that some conditions are correct (e.g., lock is already
> > taken, or something like that). Which fits here: trace_xxx() will
> > check if tracepoint is enabled, while __trace_xxx() will not check and
> > just invoke the tracepoint? It's short, it's distinct, and it says "I
> > know what I am doing".
>
> Honestly, I consider double underscore as internal only and not something
> anyone but the subsystem maintainers use.
>
> This, is a normal function where it's just saying: If you have it already
> enabled, then you can use this. Thus, I don't think it qualifies as a "you
> know what you are doing".
>
> Perhaps: call_trace_foo() ?
>
call_trace_foo has one collision with the tracepoint
sched_update_nr_running and a function
call_trace_sched_update_nr_running. I had considered this and later
moved to trace_invoke_foo() because of the collision. But I can rename
call_trace_sched_update_nr_running to something else if call_trace_foo
is the general consensus.
Thanks,
Vineeth
^ permalink raw reply
* Re: [PATCH v7 05/15] Documentation/rv: Add documentation about hybrid automata
From: Juri Lelli @ 2026-03-13 13:23 UTC (permalink / raw)
To: gmonaco
Cc: linux-kernel, Steven Rostedt, Nam Cao, Juri Lelli,
Jonathan Corbet, linux-trace-kernel, linux-doc, Tomas Glozar,
Clark Williams, John Kacur
In-Reply-To: <4620e92b1c7f4d87f192a017f3026dfc17bcaef6.camel@redhat.com>
On 13/03/26 14:05, gmonaco@redhat.com wrote:
> Hello,
>
> On Thu, 2026-03-12 at 11:39 +0100, Juri Lelli wrote:
> > Very minor nit, feel free to ignore, but ...
> >
> > The formal 7-tuple definition includes 'i' (invariant function), but
> > unlike other elements, 'i' isn't stored in the automaton struct -
> > it's implemented as generated code in ha_verify_constraint(), IIUC.
> > Worth a brief note clarifying this design choice so readers don't
> > expect to find an invariants[] member in the struct? Here or below in
> > the example C code section.
>
> Thanks for the review! I haven't really thought of that.
> At this stage we are not mentioning any struct element (it's purely
> theoretical), so there shouldn't be any expectation from the reader.
>
> Later I mention "The function verify_constraint checks guards,
> performs resets and starts timers to validate invariants according to
> specification".
> In fact, also guards are not represented as part of 'function', I may
> mention after that sentence something like: "those cannot easily be
> represented in the automaton struct".
>
> Not sure if saying more wouldn't make it even more confusing than it
> already is.
Yeah, probably. As mentioned, feel free to ignore, it was just a
thought. :)
^ permalink raw reply
* Re: [PATCH v7 05/15] Documentation/rv: Add documentation about hybrid automata
From: gmonaco @ 2026-03-13 13:05 UTC (permalink / raw)
To: Juri Lelli
Cc: linux-kernel, Steven Rostedt, Nam Cao, Juri Lelli,
Jonathan Corbet, linux-trace-kernel, linux-doc, Tomas Glozar,
Clark Williams, John Kacur
In-Reply-To: <abKX1XO4vqY74uA7@jlelli-thinkpadt14gen4.remote.csb>
Hello,
On Thu, 2026-03-12 at 11:39 +0100, Juri Lelli wrote:
> Very minor nit, feel free to ignore, but ...
>
> The formal 7-tuple definition includes 'i' (invariant function), but
> unlike other elements, 'i' isn't stored in the automaton struct -
> it's implemented as generated code in ha_verify_constraint(), IIUC.
> Worth a brief note clarifying this design choice so readers don't
> expect to find an invariants[] member in the struct? Here or below in
> the example C code section.
Thanks for the review! I haven't really thought of that.
At this stage we are not mentioning any struct element (it's purely
theoretical), so there shouldn't be any expectation from the reader.
Later I mention "The function verify_constraint checks guards,
performs resets and starts timers to validate invariants according to
specification".
In fact, also guards are not represented as part of 'function', I may
mention after that sentence something like: "those cannot easily be
represented in the automaton struct".
Not sure if saying more wouldn't make it even more confusing than it
already is.
Thanks,
Gabriele
^ permalink raw reply
* Re: [PATCH 15/15] btrfs: Use trace_invoke_##name() at guarded tracepoint call sites
From: David Sterba @ 2026-03-13 11:57 UTC (permalink / raw)
To: Vineeth Pillai (Google)
Cc: Steven Rostedt, Peter Zijlstra, Chris Mason, David Sterba,
linux-btrfs, linux-kernel, linux-trace-kernel
In-Reply-To: <20260312150523.2054552-16-vineeth@bitbyteword.org>
On Thu, Mar 12, 2026 at 11:05:10AM -0400, Vineeth Pillai (Google) wrote:
> Replace trace_foo() with the new trace_invoke_foo() at sites already
> guarded by trace_foo_enabled(), avoiding a redundant
> static_branch_unlikely() re-evaluation inside the tracepoint.
> trace_invoke_foo() calls the tracepoint callbacks directly without
> utilizing the static branch again.
>
> Suggested-by: Steven Rostedt <rostedt@goodmis.org>
> Suggested-by: Peter Zijlstra <peterz@infradead.org>
> Signed-off-by: Vineeth Pillai (Google) <vineeth@bitbyteword.org>
> Assisted-by: Claude:claude-sonnet-4-6
Acked-by: David Sterba <dsterba@suse.com>
^ permalink raw reply
* [PATCH v2] tracing: Generate undef symbols allowlist for simple_ring_buffer
From: Vincent Donnefort @ 2026-03-13 10:58 UTC (permalink / raw)
To: maz
Cc: rostedt, arnd, nathan, linux-trace-kernel, kvmarm, kernel-team,
Vincent Donnefort
Compiler and tooling-generated symbols are difficult to maintain
across all supported architectures. Make the allowlist more robust by
replacing the harcoded list with a mechanism that automatically detects
these symbols.
This mechanism generates a C function designed to trigger common
compiler-inserted symbols.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
Changes in v2:
- Use filechk (Nathan)
- Removed deprecated extra-y (Nathan)
- Added simple_ring_buffer in allowlist (Nathan)
- Added memcpy() to generate more symbols (Nathan)
- Added __sancov
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index beb15936829d..96627a909ecc 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -136,17 +136,42 @@ obj-$(CONFIG_TRACE_REMOTE_TEST) += remote_test.o
# simple_ring_buffer is used by the pKVM hypervisor which does not have access
# to all kernel symbols. Fail the build if forbidden symbols are found.
#
-UNDEFINED_ALLOWLIST := memset alt_cb_patch_nops __x86 __ubsan __asan __kasan __gcov __aeabi_unwind
-UNDEFINED_ALLOWLIST += __stack_chk_fail stackleak_track_stack __ref_stack __sanitizer llvm_gcda llvm_gcov
-UNDEFINED_ALLOWLIST += .TOC\. __clear_pages_unrolled __memmove copy_page warn_slowpath_fmt
-UNDEFINED_ALLOWLIST += ftrace_likely_update __hwasan_load __hwasan_store __hwasan_tag_memory
-UNDEFINED_ALLOWLIST += warn_bogus_irq_restore __stack_chk_guard
-UNDEFINED_ALLOWLIST := $(addprefix -e , $(UNDEFINED_ALLOWLIST))
+# undefsyms_base generates a set of compiler and tooling-generated symbols that can
+# safely be ignored for simple_ring_buffer.
+#
+filechk_undefsyms_base = \
+ echo '$(pound)include <linux/atomic.h>'; \
+ echo '$(pound)include <linux/string.h>'; \
+ echo '$(pound)include <asm/page.h>'; \
+ echo 'static char page[PAGE_SIZE] __aligned(PAGE_SIZE);'; \
+ echo 'void undefsyms_base(void *p, int n);'; \
+ echo 'void undefsyms_base(void *p, int n) {'; \
+ echo ' char buffer[256] = { 0 };'; \
+ echo ' u32 u = 0;'; \
+ echo ' memset((char * volatile)page, 8, PAGE_SIZE);'; \
+ echo ' memset((char * volatile)buffer, 8, sizeof(buffer));'; \
+ echo ' memcpy((void * volatile)p, buffer, sizeof(buffer));'; \
+ echo ' cmpxchg((u32 * volatile)&u, 0, 8);'; \
+ echo ' WARN_ON(n == 0xdeadbeef);'; \
+ echo '}'
+
+$(obj)/undefsyms_base.c: FORCE
+ $(call filechk,undefsyms_base)
+
+clean-files += undefsyms_base.c
+
+$(obj)/undefsyms_base.o: $(obj)/undefsyms_base.c
+
+targets += undefsyms_base.o
+
+UNDEFINED_ALLOWLIST = __asan __gcov __kasan __kcsan __hwasan __sancov __sanitizer __tsan __ubsan __x86_indirect_thunk \
+ simple_ring_buffer \
+ $(shell $(NM) -u $(obj)/undefsyms_base.o 2>/dev/null | awk '{print $$2}')
quiet_cmd_check_undefined = NM $<
- cmd_check_undefined = test -z "`$(NM) -u $< | grep -v $(UNDEFINED_ALLOWLIST)`"
+ cmd_check_undefined = test -z "`$(NM) -u $< | grep -v $(addprefix -e , $(UNDEFINED_ALLOWLIST))`"
-$(obj)/%.o.checked: $(obj)/%.o FORCE
+$(obj)/%.o.checked: $(obj)/%.o $(obj)/undefsyms_base.o FORCE
$(call if_changed,check_undefined)
always-$(CONFIG_SIMPLE_RING_BUFFER) += simple_ring_buffer.o.checked
base-commit: 33f2e266515717c4b2df585dadefa0525557726c
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* Re: [PATCH] tracing: Generate undef symbols allowlist for simple_ring_buffer
From: Vincent Donnefort @ 2026-03-13 10:23 UTC (permalink / raw)
To: Nathan Chancellor
Cc: maz, rostedt, arnd, linux-trace-kernel, kvmarm, kernel-team
In-Reply-To: <20260312235153.GA1147071@ax162>
On Thu, Mar 12, 2026 at 04:51:53PM -0700, Nathan Chancellor wrote:
> Hi Vincent,
>
> On Thu, Mar 12, 2026 at 06:20:10PM +0000, Vincent Donnefort wrote:
> > Compiler and tooling-generated symbols are difficult to maintain
> > across all supported architectures. Make the allowlist more robust by
> > replacing the harcoded list with a mechanism that automatically detects
> > these symbols.
> >
> > This mechanism generates a C function designed to trigger common
> > compiler-inserted symbols.
>
> This certainly seems more robust.
>
> > Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
> >
> > diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
> > index beb15936829d..3b427b76434a 100644
> > --- a/kernel/trace/Makefile
> > +++ b/kernel/trace/Makefile
> > @@ -136,17 +136,37 @@ obj-$(CONFIG_TRACE_REMOTE_TEST) += remote_test.o
> > # simple_ring_buffer is used by the pKVM hypervisor which does not have access
> > # to all kernel symbols. Fail the build if forbidden symbols are found.
> > #
> > -UNDEFINED_ALLOWLIST := memset alt_cb_patch_nops __x86 __ubsan __asan __kasan __gcov __aeabi_unwind
> > -UNDEFINED_ALLOWLIST += __stack_chk_fail stackleak_track_stack __ref_stack __sanitizer llvm_gcda llvm_gcov
> > -UNDEFINED_ALLOWLIST += .TOC\. __clear_pages_unrolled __memmove copy_page warn_slowpath_fmt
> > -UNDEFINED_ALLOWLIST += ftrace_likely_update __hwasan_load __hwasan_store __hwasan_tag_memory
> > -UNDEFINED_ALLOWLIST += warn_bogus_irq_restore __stack_chk_guard
> > -UNDEFINED_ALLOWLIST := $(addprefix -e , $(UNDEFINED_ALLOWLIST))
> > +# undefsyms_base generates a set of compiler and tooling-generated symbols that can
> > +# safely be ignored for simple_ring_buffer.
> > +#
> > +$(obj)/undefsyms_base.c: FORCE
> > + $(Q)echo '#include <asm/page.h>' > $@
> > + $(Q)echo '#include <asm/local.h>' >> $@
> > + $(Q)echo 'static char page[PAGE_SIZE] __aligned(PAGE_SIZE);' >> $@
> > + $(Q)echo 'void undefsyms_base(int n);' >> $@
> > + $(Q)echo 'void undefsyms_base(int n) {' >> $@
> > + $(Q)echo ' char buffer[256] = { 0 };' >> $@
> > + $(Q)echo ' u32 u = 0;' >> $@
> > + $(Q)echo ' memset((char * volatile)page, 8, PAGE_SIZE);' >> $@
> > + $(Q)echo ' memset((char * volatile)buffer, 8, sizeof(buffer));' >> $@
> > + $(Q)echo ' cmpxchg((u32 * volatile)&u, 0, 8);' >> $@
> > + $(Q)echo ' WARN_ON(n == 0xdeadbeef);' >> $@
> > + $(Q)echo '}' >> $@
>
> This should use filechk, otherwise undefsyms_base.c will be regenerated
> every build, resulting in undefsyms_base.o being rebuilt every time.
>
> $ make -skj"$(nproc)" ARCH=x86_64 mrproper allmodconfig kernel/trace/
>
> $ make -skj"$(nproc)" ARCH=x86_64 V=2 kernel/trace/
> ...
> CC kernel/trace/undefsyms_base.o - due to: kernel/trace/undefsyms_base.c
> NM kernel/trace/simple_ring_buffer.o - due to target missing
>
> filechk_undefsyms_base = { \
> echo '$(pound)include <asm/page.h>'; \
> echo '$(pound)include <asm/local.h>'; \
> echo 'static char page[PAGE_SIZE] __aligned(PAGE_SIZE);'; \
> echo 'void undefsyms_base(int n);'; \
> echo 'void undefsyms_base(int n) {'; \
> echo ' char buffer[256] = { 0 };'; \
> echo ' u32 u = 0;'; \
> echo ' memset((char * volatile)page, 8, PAGE_SIZE);'; \
> echo ' memset((char * volatile)buffer, 8, sizeof(buffer));'; \
> echo ' cmpxchg((u32 * volatile)&u, 0, 8);'; \
> echo ' WARN_ON(n == 0xdeadbeef);'; \
> echo '}'; \
> }
>
> $(obj)/undefsyms_base.c: FORCE
> $(call filechk,undefsyms_base)
>
> $ make -skj"$(nproc)" ARCH=x86_64 mrproper allmodconfig kernel/trace/
>
> $ make -skj"$(nproc)" ARCH=x86_64 V=2 kernel/trace/
> GEN Makefile - due to target is PHONY
> DESCEND objtool
> CALL scripts/checksyscalls.sh - due to target is PHONY
> INSTALL libsubcmd_headers
> NM kernel/trace/simple_ring_buffer.o - due to target missing
>
> > +clean-files += undefsyms_base.c
> > +targets += undefsyms_base.c
>
> I don't think this targets addition is necessary.
>
> > +$(obj)/undefsyms_base.o: $(obj)/undefsyms_base.c
> > +
> > +extra-y += undefsyms_base.o
>
> I think this should be
>
> targets += undefsyms_base.o
>
> as extra-y is deprecated per Documentation/kbuild/makefiles.rst.
>
> > +UNDEFINED_ALLOWLIST = __asan __gcov __kasan __kcsan __hwasan __sanitizer __tsan __ubsan __x86_indirect_thunk \
> > + $(shell $(NM) -u $(obj)/undefsyms_base.o 2>/dev/null | awk '{print $$2}')
>
> With an allmodconfig + ThinLTO build, I still see:
>
> $ cat allmod.config
> CONFIG_GCOV_KERNEL=n
> CONFIG_KASAN=n
> CONFIG_LTO_CLANG_THIN=y
>
> $ make -skj"$(nproc)" ARCH=x86_64 KCONFIG_ALLCONFIG=1 LLVM=1 mrproper allmodconfig kernel/trace/
> Unexpected symbols in kernel/trace/simple_ring_buffer.o:
> U __fortify_panic
> U __write_overflow_field
> U simple_ring_buffer_commit
> U simple_ring_buffer_enable_tracing
> U simple_ring_buffer_init
> U simple_ring_buffer_reserve
> U simple_ring_buffer_reset
> U simple_ring_buffer_swap_reader_page
> U simple_ring_buffer_unload
>
> Something like:
>
> diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
> index 48c415a0c7e4..0f9a6ce9abd9 100644
> --- a/kernel/trace/Makefile
> +++ b/kernel/trace/Makefile
> @@ -142,13 +142,15 @@ obj-$(CONFIG_TRACE_REMOTE_TEST) += remote_test.o
> filechk_undefsyms_base = { \
> echo '$(pound)include <asm/page.h>'; \
> echo '$(pound)include <asm/local.h>'; \
> + echo '$(pound)include <linux/string.h>'; \
> echo 'static char page[PAGE_SIZE] __aligned(PAGE_SIZE);'; \
> - echo 'void undefsyms_base(int n);'; \
> - echo 'void undefsyms_base(int n) {'; \
> + echo 'void undefsyms_base(int n, void *ptr);'; \
> + echo 'void undefsyms_base(int n, void *ptr) {'; \
> echo ' char buffer[256] = { 0 };'; \
> echo ' u32 u = 0;'; \
> echo ' memset((char * volatile)page, 8, PAGE_SIZE);'; \
> echo ' memset((char * volatile)buffer, 8, sizeof(buffer));'; \
> + echo ' memcpy((void* volatile)ptr, buffer, sizeof(buffer));'; \
> echo ' cmpxchg((u32 * volatile)&u, 0, 8);'; \
> echo ' WARN_ON(n == 0xdeadbeef);'; \
> echo '}'; \
> --
>
> cures the first two. The simple_ring_buffer symbols are very odd...
>
> $ llvm-nm kernel/trace/simple_ring_buffer.o | grep simple_ring_buffer
> ---------------- d __UNIQUE_ID_addressable_simple_ring_buffer_commit_845
> ---------------- d __UNIQUE_ID_addressable_simple_ring_buffer_enable_tracing_849
> ---------------- d __UNIQUE_ID_addressable_simple_ring_buffer_init_847
> ---------------- d __UNIQUE_ID_addressable_simple_ring_buffer_reserve_841
> ---------------- d __UNIQUE_ID_addressable_simple_ring_buffer_reset_846
> ---------------- d __UNIQUE_ID_addressable_simple_ring_buffer_swap_reader_page_837
> ---------------- d __UNIQUE_ID_addressable_simple_ring_buffer_unload_848
> ---------------- t __export_symbol_simple_ring_buffer_commit
> ---------------- t __export_symbol_simple_ring_buffer_enable_tracing
> ---------------- t __export_symbol_simple_ring_buffer_init
> ---------------- t __export_symbol_simple_ring_buffer_reserve
> ---------------- t __export_symbol_simple_ring_buffer_reset
> ---------------- t __export_symbol_simple_ring_buffer_swap_reader_page
> ---------------- t __export_symbol_simple_ring_buffer_unload
> ---------------- T simple_ring_buffer_commit
> U simple_ring_buffer_commit
> ---------------- T simple_ring_buffer_enable_tracing
> U simple_ring_buffer_enable_tracing
> U simple_ring_buffer_init
> ---------------- T simple_ring_buffer_init
> ---------------- T simple_ring_buffer_init_mm
> ---------------- T simple_ring_buffer_reserve
> U simple_ring_buffer_reserve
> ---------------- T simple_ring_buffer_reset
> U simple_ring_buffer_reset
> U simple_ring_buffer_swap_reader_page
> ---------------- T simple_ring_buffer_swap_reader_page
> U simple_ring_buffer_unload
> ---------------- T simple_ring_buffer_unload
> ---------------- T simple_ring_buffer_unload_mm
>
> This is LLVM IR bitcode at this stage, which could be messing things up.
>
> $ file kernel/trace/simple_ring_buffer.o
> kernel/trace/simple_ring_buffer.o: LLVM IR bitcode
>
> Maybe not worth thinking about too much and just adding it to the
> allowlist manually?
That looks good, thanks for having a look. I'll spin a v2 with your comments.
>
> diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
> index 0f9a6ce9abd9..cb1ec50a8386 100644
> --- a/kernel/trace/Makefile
> +++ b/kernel/trace/Makefile
> @@ -166,6 +166,7 @@ $(obj)/undefsyms_base.o: $(obj)/undefsyms_base.c
> targets += undefsyms_base.o
>
> UNDEFINED_ALLOWLIST = __asan __gcov __kasan __kcsan __hwasan __sanitizer __tsan __ubsan __x86_indirect_thunk \
> + simple_ring_buffer \
> $(shell $(NM) -u $(obj)/undefsyms_base.o 2>/dev/null | awk '{print $$2}')
>
> quiet_cmd_check_undefined = NM $<
> --
>
> Cheers,
> Nathan
^ permalink raw reply
* Re: [PATCH v3 1/4] tracing/preemptirq: Optimize preempt_disable/enable() tracepoint overhead
From: Peter Zijlstra @ 2026-03-13 9:04 UTC (permalink / raw)
To: Wander Lairson Costa
Cc: Ingo Molnar, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
Masami Hiramatsu, Mathieu Desnoyers, Andrew Morton,
open list:SCHEDULER, open list:TRACING, acme, williams, gmonaco
In-Reply-To: <abLzS0T_wEt_SkL6@fedora>
On Thu, Mar 12, 2026 at 02:19:15PM -0300, Wander Lairson Costa wrote:
> > That's significant bloat, for really very little gain. Realistically
> > nobody is going to need these.
> >
>
> Of course, I can't speak for others, but more than once I debugged issues
> that those tracepoints had made my life far easier. Those cases convinced
> me that such a feature would be worth it. But if you don't see
> value and will reject the patches no matter what, nothing can be done,
> and I will have to accept defeat.
If distros are going to enable this, I suppose I'm not going to stop
this. But I do very much worry about the general bloat of things, there
are a *LOT* of preempt_{dis,en}able() sites.
^ permalink raw reply
* Re: [RFC PATCH v2 09/37] KVM: guest_memfd: Add support for KVM_SET_MEMORY_ATTRIBUTES2
From: Fuad Tabba @ 2026-03-13 8:32 UTC (permalink / raw)
To: Sean Christopherson
Cc: Ackerley Tng, kvm, linux-doc, linux-kernel, linux-kselftest,
linux-trace-kernel, x86, aik, andrew.jones, binbin.wu, bp,
brauner, chao.p.peng, chao.p.peng, chenhuacai, corbet,
dave.hansen, david, hpa, ira.weiny, jgg, jmattson, jroedel,
jthoughton, maobibo, mathieu.desnoyers, maz, mhiramat,
michael.roth, mingo, mlevitsk, oupton, pankaj.gupta, pbonzini,
prsampat, qperret, ricarkol, rick.p.edgecombe, rientjes, rostedt,
shivankg, shuah, steven.price, tglx, vannapurve, vbabka, willy,
wyihan, yan.y.zhao
In-Reply-To: <abNcEkNseDEBIhop@google.com>
Hi,
On Fri, 13 Mar 2026 at 00:36, Sean Christopherson <seanjc@google.com> wrote:
>
> On Thu, Mar 12, 2026, Ackerley Tng wrote:
> > Sean Christopherson <seanjc@google.com> writes:
> >
> > > On Thu, Mar 12, 2026, Fuad Tabba wrote:
> > >> Hi Ackerley,
> > >>
> > >> Before getting into the UAPI semantics, thank you for all the heavy
> > >> lifting you've done here. Figuring out how to make it all work across
> > >> the different platforms is not easy :)
> > >>
> > >> <snip>
> > >>
> > >> > The policy definitions below provide more details:
> > >
> > > Please drop "CONTENT_POLICY" from the KVM documentation. From KVM's perspective,
> > > these are not "policy", they are purely properties of the underlying memory.
> > > Userspace will likely use the attributes to implement policy of some kind, but
> > > KVM straight up doesn't care.
> >
> > Policy might have been the wrong word. I think this is a property of the
> > conversion process/request, not a property of the memory like how
> > shared/private is a property of the memory?
> >
> > I'll have to find another word to describe this enum of
>
> Or just don't? I'm 100% serious, because unless we carve out a field _just_ for
> these two flags, they're eventually going to get mixed with other stuff. At that
> point, having a precisely named enum container just gets in the way.
I agree. It makes sense to drop the enum wrapper and the "policy"
terminology entirely. Let's go with direct flags passed to the ioctl
representing the requested memory properties upon conversion.
> > I see you dropped any documentation to do with testing.
>
> Yes.
>
> > I meant to document it (at least something about the unspecified case) so it
> > can be relied on in selftests, with the understanding (already specified
> > elsewhere in Documentation/virt/kvm/api.rst) that nothing about
> > KVM_X86_SW_PROTECTED_VM is to be relied on in production, and can be changed
> > anytime. What do you think?
>
> KVM_X86_SW_PROTECTED_VM should self-report like all other VM types, and shouldn't
> support anything that isn't documented as possible. I.e. we shouldn't allow
> ZERO on shared=>private "for testing".
>
> What I do think we should do is scribble memory on conversions without ZERO or
> PRIVATE, probably guarded by a Kconfig or maybe a module param, to do a best
> effort enforcement of the ABI, i.e. to try and prevent userspace from depending
> on uarch/vendor specific behavior.
I strongly agree with scribbling/poisoning the memory on default
conversions. If userspace specifies neither flag, actively destroying
the data in software is the only way to strictly enforce that the ABI
makes no guarantees, preventing the VMM from implicitly relying on
underlying hardware behavior (like TDX automatically zeroing).
Cheers,
/fuad
^ permalink raw reply
* Re: [RFC PATCH v2 09/37] KVM: guest_memfd: Add support for KVM_SET_MEMORY_ATTRIBUTES2
From: Fuad Tabba @ 2026-03-13 8:31 UTC (permalink / raw)
To: Ackerley Tng
Cc: Sean Christopherson, kvm, linux-doc, linux-kernel,
linux-kselftest, linux-trace-kernel, x86, aik, andrew.jones,
binbin.wu, bp, brauner, chao.p.peng, chao.p.peng, chenhuacai,
corbet, dave.hansen, david, hpa, ira.weiny, jgg, jmattson,
jroedel, jthoughton, maobibo, mathieu.desnoyers, maz, mhiramat,
michael.roth, mingo, mlevitsk, oupton, pankaj.gupta, pbonzini,
prsampat, qperret, ricarkol, rick.p.edgecombe, rientjes, rostedt,
shivankg, shuah, steven.price, tglx, vannapurve, vbabka, willy,
wyihan, yan.y.zhao
In-Reply-To: <CAEvNRgFUc+9xCoN9Yo5NThHrvbccWAhPwp9nNM2fvx7QqrcJsg@mail.gmail.com>
Hi Ackerley,
<snip>
> > By default, KVM makes no guarantees about the in-memory values after memory is
> > convert to/from shared/private. Optionally, userspace may instruct KVM to
> > ensure the contents of memory are zeroed or preserved, e.g. to enable in-place
> > sharing of data, or as an optimization to avoid having to re-zero memory when
> > the trusted entity guarantees the memory will be zeroed after conversion.
> >
>
> How about:
>
> or as an optimization to avoid having to re-zero memory when userspace
> could have relied on the trusted entity to guarantee the memory will be
> zeroed as part of the entire conversion process.
>
> > The behaviors supported by a given KVM instance can be queried via <cap>. If
>
> I started with some implementation and was questioning the value of a
> CAP. It seems like there won't be anything dynamic about this?
We can drop the CAP for now. Probing via the ioctl and handling
-EOPNOTSUPP is entirely sufficient for the VMM to discover whether
ZERO or PRESERVE are supported for a given architecture and conversion
direction.
> The userspace code can check what platform it is running on, and then
> decide ZERO or PRESERVE based on the platform:
>
> If the VM is running on TDX, it would want to specify ZERO all the
> time. If the VM were running on pKVM it would want to specify PRESERVE
> if it wants to enable in-place sharing, and ZERO if it wants to zero the
> memory.
>
> If someday TDX supports PRESERVE, then there's room for discovery of
> which algorithm to choose when running the guest. Perhaps that's when
> the CAP should be introduced?
>
> > the requested behavior is an unsupported, KVM will return -EOPNOTSUPP and
> > reject the conversion request. Note! The "ZERO" request is only support for
> > private to shared conversion!
I think that this makes sensefor the UAPI. Returning -EOPNOTSUPP for
shared-to-private ZERO conversions.
For pKVM's specific use cases where the VMM requires a zeroed page to
be injected into the guest's private space via attribute conversion,
the VMM can simply `memset()` the shared memory to zero in userspace,
and then invoke the ioctl with the
`KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE` flag. This completely offloads
the UAPI from making guarantees on behalf of the trusted entity, while
still satisfying pKVM's functional requirements.
Cheers,
/fuad
^ permalink raw reply
* Re: [PATCH] bootconfig: Add bootconfig tests about braces
From: Josh Law @ 2026-03-13 7:10 UTC (permalink / raw)
To: Masami Hiramatsu (Google)
Cc: Steven Rostedt, Andrew Morton, Josh Law, linux-kernel,
linux-trace-kernel
In-Reply-To: <177337553551.416919.11217619471547711262.stgit@devnote2>
13 Mar 2026 04:19:06 Masami Hiramatsu (Google) <mhiramat@kernel.org>:
> From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
>
> Add more bootconfig tests for checking the error message of
> non closing brace and max number of nested braces.
>
> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> ---
> .../bootconfig/samples/bad-non-closed-brace.bconf | 4 ++++
> tools/bootconfig/samples/bad-over-max-brace.bconf | 19 +++++++++++++++++++
> .../bootconfig/samples/exp-good-nested-brace.bconf | 1 +
> tools/bootconfig/samples/good-nested-brace.bconf | 18 ++++++++++++++++++
> tools/bootconfig/test-bootconfig.sh | 9 +++++++++
> 5 files changed, 51 insertions(+)
> create mode 100644 tools/bootconfig/samples/bad-non-closed-brace.bconf
> create mode 100644 tools/bootconfig/samples/bad-over-max-brace.bconf
> create mode 100644 tools/bootconfig/samples/exp-good-nested-brace.bconf
> create mode 100644 tools/bootconfig/samples/good-nested-brace.bconf
>
> diff --git a/tools/bootconfig/samples/bad-non-closed-brace.bconf b/tools/bootconfig/samples/bad-non-closed-brace.bconf
> new file mode 100644
> index 000000000000..6ed9f3363dde
> --- /dev/null
> +++ b/tools/bootconfig/samples/bad-non-closed-brace.bconf
> @@ -0,0 +1,4 @@
> +foo {
> + bar {
> + buz
> + }
> diff --git a/tools/bootconfig/samples/bad-over-max-brace.bconf b/tools/bootconfig/samples/bad-over-max-brace.bconf
> new file mode 100644
> index 000000000000..74b5dc9e21dc
> --- /dev/null
> +++ b/tools/bootconfig/samples/bad-over-max-brace.bconf
> @@ -0,0 +1,19 @@
> +key1 {
> +key2 {
> +key3 {
> +key4 {
> +key5 {
> +key6 {
> +key7 {
> +key8 {
> +key9 {
> +key10 {
> +key11 {
> +key12 {
> +key13 {
> +key14 {
> +key15 {
> +key16 {
> +key17 {
> +}}}}}}}}}}}}}}}}}
> +
> diff --git a/tools/bootconfig/samples/exp-good-nested-brace.bconf b/tools/bootconfig/samples/exp-good-nested-brace.bconf
> new file mode 100644
> index 000000000000..19e0f51b4553
> --- /dev/null
> +++ b/tools/bootconfig/samples/exp-good-nested-brace.bconf
> @@ -0,0 +1 @@
> +key1.key2.key3.key4.key5.key6.key7.key8.key9.key10.key11.key12.key13.key14.key15.key16;
> diff --git a/tools/bootconfig/samples/good-nested-brace.bconf b/tools/bootconfig/samples/good-nested-brace.bconf
> new file mode 100644
> index 000000000000..980d094f296e
> --- /dev/null
> +++ b/tools/bootconfig/samples/good-nested-brace.bconf
> @@ -0,0 +1,18 @@
> +key1 {
> +key2 {
> +key3 {
> +key4 {
> +key5 {
> +key6 {
> +key7 {
> +key8 {
> +key9 {
> +key10 {
> +key11 {
> +key12 {
> +key13 {
> +key14 {
> +key15 {
> +key16 {
> +}}}}}}}}}}}}}}}}
> +
> diff --git a/tools/bootconfig/test-bootconfig.sh b/tools/bootconfig/test-bootconfig.sh
> index be9bd18b1d56..fc69f815ce4a 100755
> --- a/tools/bootconfig/test-bootconfig.sh
> +++ b/tools/bootconfig/test-bootconfig.sh
> @@ -171,6 +171,15 @@ $BOOTCONF $INITRD > $OUTFILE
> xfail grep -q 'val[[:space:]]' $OUTFILE
> xpass grep -q 'val2[[:space:]]' $OUTFILE
>
> +echo "Showing correct line:column of no closing brace"
> +cat > $TEMPCONF << EOF
> +foo {
> +bar {
> +}
> +EOF
> +$BOOTCONF -a $TEMPCONF $INITRD 2> $OUTFILE
> +xpass grep -q "1:1" $OUTFILE
> +
> echo "=== expected failure cases ==="
> for i in samples/bad-* ; do
> xfail $BOOTCONF -a $i $INITRD
Acked-By: Josh Law <objecting@objecting.org>
^ permalink raw reply
* [PATCH RFC v3 43/43] KVM: selftests: Update tests to use flag-enabled library functions
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
Update tests to use the set_memory_attributes-related library functions
that now allow specification of flags.
This was manually tested by updating content_mode in main() and
recompiling/running.
TODOs:
+ If we introduce self-reporting of supported content modes, test based on
reported content modes. If supported content modes are relatively static,
accept a command line argument for this test to test different content
modes.
+ Fold this patch into the earlier patches after getting through RFC.
---
.../selftests/kvm/guest_memfd_conversions_test.c | 20 +++++++++++++++-----
.../selftests/kvm/x86/private_mem_conversions_test.c | 10 +++++++---
2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/tools/testing/selftests/kvm/guest_memfd_conversions_test.c b/tools/testing/selftests/kvm/guest_memfd_conversions_test.c
index 8727474325451..42f3ea950c192 100644
--- a/tools/testing/selftests/kvm/guest_memfd_conversions_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_conversions_test.c
@@ -27,6 +27,7 @@ typedef FIXTURE_DATA(gmem_conversions) test_data_t;
FIXTURE_SETUP(gmem_conversions) { }
static uint64_t page_size;
+static u64 content_mode;
static void guest_do_rmw(void);
#define GUEST_MEMFD_SHARING_TEST_GVA 0x90000000ULL
@@ -192,7 +193,9 @@ static void test_private(test_data_t *t, loff_t pgoff, char starting_val,
static void test_convert_to_private(test_data_t *t, loff_t pgoff,
char starting_val, char write_val)
{
- gmem_set_private(t->gmem_fd, pgoff * page_size, page_size);
+ gmem_set_memory_attributes(t->gmem_fd, pgoff * page_size, page_size,
+ KVM_MEMORY_ATTRIBUTE_PRIVATE,
+ content_mode);
test_private(t, pgoff, starting_val, write_val);
}
@@ -208,7 +211,8 @@ static void test_convert_to_shared(test_data_t *t, loff_t pgoff,
char starting_val, char host_write_val,
char write_val)
{
- gmem_set_shared(t->gmem_fd, pgoff * page_size, page_size);
+ gmem_set_memory_attributes(t->gmem_fd, pgoff * page_size, page_size,
+ 0, content_mode);
test_shared(t, pgoff, starting_val, host_write_val, write_val);
}
@@ -298,7 +302,9 @@ GMEM_CONVERSION_MULTIPAGE_TEST_INIT_SHARED(unallocated_folios, 8)
if (test_page != second_page_to_fault)
host_do_rmw(t->mem, second_page_to_fault, 0, 'A');
- gmem_set_private(t->gmem_fd, 0, nr_pages * page_size);
+ gmem_set_memory_attributes(t->gmem_fd, 0, nr_pages * page_size,
+ KVM_MEMORY_ATTRIBUTE_PRIVATE,
+ content_mode);
for (i = 0; i < nr_pages; ++i) {
char expected = (i == test_page || i == second_page_to_fault) ? 'A' : 0;
@@ -429,7 +435,8 @@ static void test_convert_to_private_fails(test_data_t *t, loff_t pgoff,
do {
ret = __gmem_set_private(t->gmem_fd, offset,
- nr_pages * page_size, &error_offset);
+ nr_pages * page_size, &error_offset,
+ content_mode);
} while (ret == -1 && errno == EINTR);
TEST_ASSERT(ret == -1 && errno == EAGAIN,
"Wanted EAGAIN on page %lu, got %d (ret = %d)", pgoff,
@@ -465,7 +472,9 @@ GMEM_CONVERSION_MULTIPAGE_TEST_INIT_SHARED(elevated_refcount, 4)
unpin_pages();
- gmem_set_private(t->gmem_fd, 0, nr_pages * page_size);
+ gmem_set_memory_attributes(t->gmem_fd, 0, nr_pages * page_size,
+ KVM_MEMORY_ATTRIBUTE_PRIVATE,
+ content_mode);
for (i = 0; i < nr_pages; i++) {
char expected = i == test_page ? 'B' : 'C';
@@ -481,6 +490,7 @@ int main(int argc, char *argv[])
KVM_MEMORY_ATTRIBUTE_PRIVATE);
page_size = getpagesize();
+ content_mode = KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE;
return test_harness_run(argc, argv);
}
diff --git a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
index f85717662a73b..7d72c36d102c9 100644
--- a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
+++ b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
@@ -306,9 +306,13 @@ static void handle_exit_hypercall(struct kvm_vcpu *vcpu)
if (do_fallocate)
vm_guest_mem_fallocate(vm, gpa, size, map_shared);
- if (set_attributes)
- vm_mem_set_memory_attributes(vm, gpa, size,
- map_shared ? 0 : KVM_MEMORY_ATTRIBUTE_PRIVATE);
+ if (set_attributes) {
+ u64 attrs = map_shared ? 0 : KVM_MEMORY_ATTRIBUTE_PRIVATE;
+
+ vm_mem_set_memory_attributes(vm, gpa, size, attrs,
+ KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE);
+ }
+
run->hypercall.ret = 0;
}
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 42/43] KVM: selftests: Allow flags to be specified in set_memory_attributes functions
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
Update the set_memory_attributes-related selftest library functions to
support specification of flags.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
tools/testing/selftests/kvm/include/kvm_util.h | 36 ++++++++++++++++----------
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index e4de0050d1ab3..a89a4f85aefdb 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -459,13 +459,14 @@ static inline void vm_set_memory_attributes(struct kvm_vm *vm, uint64_t gpa,
static inline int __gmem_set_memory_attributes(int fd, loff_t offset,
uint64_t size,
uint64_t attributes,
- loff_t *error_offset)
+ loff_t *error_offset,
+ u64 flags)
{
struct kvm_memory_attributes2 attr = {
.attributes = attributes,
.offset = offset,
.size = size,
- .flags = 0,
+ .flags = flags,
};
int r;
@@ -478,27 +479,30 @@ static inline int __gmem_set_memory_attributes(int fd, loff_t offset,
}
static inline int __gmem_set_private(int fd, loff_t offset, uint64_t size,
- loff_t *error_offset)
+ loff_t *error_offset, u64 flags)
{
return __gmem_set_memory_attributes(fd, offset, size,
KVM_MEMORY_ATTRIBUTE_PRIVATE,
- error_offset);
+ error_offset, flags);
}
static inline int __gmem_set_shared(int fd, loff_t offset, uint64_t size,
- loff_t *error_offset)
+ loff_t *error_offset, u64 flags)
{
- return __gmem_set_memory_attributes(fd, offset, size, 0, error_offset);
+ return __gmem_set_memory_attributes(fd, offset, size, 0,
+ error_offset, flags);
}
static inline void gmem_set_memory_attributes(int fd, loff_t offset,
- uint64_t size, uint64_t attributes)
+ uint64_t size,
+ uint64_t attributes,
+ u64 flags)
{
struct kvm_memory_attributes2 attr = {
.attributes = attributes,
.offset = offset,
.size = size,
- .flags = 0,
+ .flags = flags,
};
TEST_ASSERT_SUPPORTED_ATTRIBUTES(attributes);
@@ -511,16 +515,19 @@ static inline void gmem_set_memory_attributes(int fd, loff_t offset,
static inline void gmem_set_private(int fd, loff_t offset, uint64_t size)
{
- gmem_set_memory_attributes(fd, offset, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
+ gmem_set_memory_attributes(fd, offset, size, KVM_MEMORY_ATTRIBUTE_PRIVATE,
+ KVM_SET_MEMORY_ATTRIBUTES2_ZERO);
}
static inline void gmem_set_shared(int fd, loff_t offset, uint64_t size)
{
- gmem_set_memory_attributes(fd, offset, size, 0);
+ gmem_set_memory_attributes(fd, offset, size, 0,
+ KVM_SET_MEMORY_ATTRIBUTES2_ZERO);
}
static inline void vm_mem_set_memory_attributes(struct kvm_vm *vm, uint64_t gpa,
- uint64_t size, uint64_t attrs)
+ uint64_t size, uint64_t attrs,
+ u64 flags)
{
if (kvm_has_gmem_attributes) {
uint64_t end = gpa + size;
@@ -532,9 +539,10 @@ static inline void vm_mem_set_memory_attributes(struct kvm_vm *vm, uint64_t gpa,
fd = kvm_gpa_to_guest_memfd(vm, addr, &fd_offset, &len);
len = min(end - addr, len);
- gmem_set_memory_attributes(fd, fd_offset, len, attrs);
+ gmem_set_memory_attributes(fd, fd_offset, len, attrs, flags);
}
} else {
+ TEST_ASSERT(!flags, "Flags are not supported.");
vm_set_memory_attributes(vm, gpa, size, attrs);
}
}
@@ -542,13 +550,13 @@ static inline void vm_mem_set_memory_attributes(struct kvm_vm *vm, uint64_t gpa,
static inline void vm_mem_set_private(struct kvm_vm *vm, uint64_t gpa,
uint64_t size)
{
- vm_mem_set_memory_attributes(vm, gpa, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
+ vm_mem_set_memory_attributes(vm, gpa, size, KVM_MEMORY_ATTRIBUTE_PRIVATE, 0);
}
static inline void vm_mem_set_shared(struct kvm_vm *vm, uint64_t gpa,
uint64_t size)
{
- vm_mem_set_memory_attributes(vm, gpa, size, 0);
+ vm_mem_set_memory_attributes(vm, gpa, size, 0, 0);
}
void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t gpa, uint64_t size,
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 41/43] KVM: x86: Support content mode ZERO for TDX
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
Support content mode ZERO for TDX by doing nothing, since TDX firmware will
zero for the host on private to shared conversions.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
arch/x86/kvm/x86.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 49c19897a9c30..1354fa89edb09 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -14088,8 +14088,9 @@ u64 kvm_arch_gmem_supported_content_modes(struct kvm *kvm)
case KVM_X86_SEV_VM:
case KVM_X86_SEV_ES_VM:
case KVM_X86_SNP_VM:
- case KVM_X86_TDX_VM:
return 0;
+ case KVM_X86_TDX_VM:
+ return KVM_SET_MEMORY_ATTRIBUTES2_ZERO;
case KVM_X86_DEFAULT_VM:
default:
WARN_ONCE(1, "Unexpected conversion request for vm_type.");
@@ -14103,6 +14104,9 @@ int kvm_arch_gmem_apply_content_mode_zero(struct kvm *kvm,
switch (kvm->arch.vm_type) {
case KVM_X86_SW_PROTECTED_VM:
return kvm_gmem_apply_content_mode_zero(folio);
+ case KVM_X86_TDX_VM:
+ /* Rely on TDX firmware to do zeroing. */
+ return 0;
default:
WARN_ONCE(1, "Unexpected request to zero for vm_type.");
return -EOPNOTSUPP;
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 40/43] KVM: x86: Add support for applying content modes
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
For x86, override the default implementations of content mode functions to
handle reporting of supported content modes, and application of requested
modes based on x86 VM types.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
arch/x86/kvm/x86.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 9c29407712580..49c19897a9c30 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -14078,6 +14078,75 @@ void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end)
kvm_x86_call(gmem_invalidate)(start, end);
}
#endif
+
+u64 kvm_arch_gmem_supported_content_modes(struct kvm *kvm)
+{
+ switch (kvm->arch.vm_type) {
+ case KVM_X86_SW_PROTECTED_VM:
+ return KVM_SET_MEMORY_ATTRIBUTES2_ZERO |
+ KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE;
+ case KVM_X86_SEV_VM:
+ case KVM_X86_SEV_ES_VM:
+ case KVM_X86_SNP_VM:
+ case KVM_X86_TDX_VM:
+ return 0;
+ case KVM_X86_DEFAULT_VM:
+ default:
+ WARN_ONCE(1, "Unexpected conversion request for vm_type.");
+ return 0;
+ }
+}
+
+int kvm_arch_gmem_apply_content_mode_zero(struct kvm *kvm,
+ struct folio *folio)
+{
+ switch (kvm->arch.vm_type) {
+ case KVM_X86_SW_PROTECTED_VM:
+ return kvm_gmem_apply_content_mode_zero(folio);
+ default:
+ WARN_ONCE(1, "Unexpected request to zero for vm_type.");
+ return -EOPNOTSUPP;
+ }
+}
+
+int kvm_arch_gmem_apply_content_mode_preserve(struct kvm *kvm,
+ struct folio *folio)
+{
+ switch (kvm->arch.vm_type) {
+ case KVM_X86_SW_PROTECTED_VM:
+ return 0;
+ default:
+ WARN_ONCE(1, "Unexpected request to preserve for vm_type.");
+ return -EOPNOTSUPP;
+ }
+}
+
+int kvm_arch_gmem_apply_content_mode_unspecified(struct kvm *kvm,
+ struct folio *folio)
+{
+ switch (kvm->arch.vm_type) {
+ case KVM_X86_SW_PROTECTED_VM: {
+ char *addr;
+ int i;
+
+ /*
+ * KVM_X86_SW_PROTECTED_VM is a test vehicle, this
+ * case is just for testing and does not need to be
+ * performant.
+ */
+ for (i = 0; i < folio_nr_pages(folio); ++i) {
+ addr = kmap_local_page(folio_page(folio, i));
+ get_random_bytes(addr, PAGE_SIZE);
+ kunmap_local(addr);
+ }
+
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
#endif
int kvm_spec_ctrl_test_value(u64 value)
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 39/43] KVM: guest_memfd: Apply content modes while setting memory attributes
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
Provide defined memory content modes so that KVM can make guarantees about
memory content after setting memory attributes, according to userspace
requests.
Suggested-by: Sean Christoperson <seanjc@google.com>
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
Documentation/virt/kvm/api.rst | 40 +++++++++++++++++++++++++++++
include/uapi/linux/kvm.h | 4 +++
virt/kvm/guest_memfd.c | 58 ++++++++++++++++++++++++++++++++++++++++--
3 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 15148c80cfdb6..3ec92f8606099 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -6571,6 +6571,8 @@ Errors:
EAGAIN Some page within requested range had unexpected refcounts. The
offset of the page will be returned in `error_offset`.
ENOMEM Ran out of memory trying to track private/shared state
+ EOPNOTSUPP There is no way for KVM to guarantee in-memory contents as
+ requested.
========== ===============================================================
KVM_SET_MEMORY_ATTRIBUTES2 is an extension to
@@ -6619,6 +6621,44 @@ on the shared pages, such as refcounts taken by get_user_pages(), and
try the ioctl again. A possible source of these long term refcounts is
if the guest_memfd memory was pinned in IOMMU page tables.
+By default, KVM makes no guarantees about the in-memory values after
+memory is convert to/from shared/private. Optionally, userspace may
+instruct KVM to ensure the contents of memory are zeroed or preserved,
+e.g. to enable in-place sharing of data, or as an optimization to
+avoid having to re-zero memory when userspace could have relied on the
+trusted entity to guarantee the memory will be zeroed as part of the
+entire conversion process.
+
+The content modes available are as follows:
+
+``KVM_SET_MEMORY_ATTRIBUTES2_ZERO``
+
+ On conversion, KVM guarantees all entities that have "allowed"
+ access to the memory will read zeros. E.g. on private to shared
+ conversion, both trusted and untrusted code will read zeros.
+
+ Zeroing is currently only guaranteed for private-to-shared
+ conversions, as KVM in general is untrusted and thus cannot
+ guarantee the guest (or any trusted entity) will read zeros after
+ conversion. Note, some CoCo implementations do zero memory contents
+ such that the guest reads zeros after conversion, and the guest may
+ choose to rely on that behavior. However, that's a contract between
+ the trusted CoCo entity and the guest, not between KVM and the
+ guest.
+
+``KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE``
+
+ On conversion, KVM guarantees memory contents will be preserved with
+ respect to the last written unencrypted value. As a concrete
+ example, if the host writes ``0xbeef`` to shared memory and converts
+ the memory to private, the guest will also read ``0xbeef``, even if
+ the in-memory data is encrypted as part of the conversion. And vice
+ versa, if the guest writes ``0xbeef`` to private memory and then
+ converts the memory to shared, the host (and guest) will read
+ ``0xbeef`` (if the memory is accessible).
+
+TODO: Document CAP after CAP discussion.
+
See also: :ref: `KVM_SET_MEMORY_ATTRIBUTES`.
.. _kvm_run:
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 29baaa60de35a..0fc9ad4ea0d93 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1642,6 +1642,10 @@ struct kvm_memory_attributes {
/* Available with KVM_CAP_MEMORY_ATTRIBUTES2 */
#define KVM_SET_MEMORY_ATTRIBUTES2 _IOWR(KVMIO, 0xd2, struct kvm_memory_attributes2)
+#define KVM_SET_MEMORY_ATTRIBUTES2_MODE_UNSPECIFIED 0
+#define KVM_SET_MEMORY_ATTRIBUTES2_ZERO (1ULL << 0)
+#define KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE (1ULL << 1)
+
struct kvm_memory_attributes2 {
union {
__u64 address;
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index f23acbca28e54..6bfcb2ed12c61 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -674,8 +674,50 @@ int __weak kvm_arch_gmem_apply_content_mode_preserve(struct kvm *kvm,
return -EOPNOTSUPP;
}
+static int kvm_gmem_apply_content_mode_folio(struct kvm *kvm,
+ struct folio *folio,
+ uint64_t content_mode)
+{
+ switch (content_mode) {
+ case KVM_SET_MEMORY_ATTRIBUTES2_MODE_UNSPECIFIED:
+ return kvm_arch_gmem_apply_content_mode_unspecified(kvm, folio);
+ case KVM_SET_MEMORY_ATTRIBUTES2_ZERO:
+ return kvm_arch_gmem_apply_content_mode_zero(kvm, folio);
+ case KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE:
+ return kvm_arch_gmem_apply_content_mode_preserve(kvm, folio);
+ default:
+ WARN_ONCE(1, "Unexpected policy requested.");
+ return -EOPNOTSUPP;
+ }
+}
+
+static void kvm_gmem_apply_content_mode(struct inode *inode, pgoff_t start,
+ pgoff_t end, struct kvm *kvm,
+ uint64_t content_mode)
+{
+ struct address_space *mapping = inode->i_mapping;
+ struct folio_batch fbatch;
+ int i;
+
+ folio_batch_init(&fbatch);
+ while (filemap_get_folios(mapping, &start, end - 1, &fbatch)) {
+
+ for (i = 0; i < folio_batch_count(&fbatch); ++i) {
+ struct folio *folio = fbatch.folios[i];
+ int ret;
+
+ ret = kvm_gmem_apply_content_mode_folio(kvm, folio,
+ content_mode);
+ WARN_ON_ONCE(ret);
+ }
+
+ folio_batch_release(&fbatch);
+ }
+}
+
static int __kvm_gmem_set_attributes(struct inode *inode, pgoff_t start,
size_t nr_pages, uint64_t attrs,
+ struct kvm *kvm, uint64_t content_mode,
pgoff_t *err_index)
{
struct address_space *mapping = inode->i_mapping;
@@ -689,6 +731,12 @@ static int __kvm_gmem_set_attributes(struct inode *inode, pgoff_t start,
filemap_invalidate_lock(mapping);
+ if (content_mode &&
+ !(kvm_gmem_supported_content_modes(kvm) & content_mode)) {
+ r = -EOPNOTSUPP;
+ goto out;
+ }
+
mas_init(&mas, mt, start);
if (kvm_gmem_range_has_attributes(mt, start, nr_pages, attrs)) {
@@ -715,6 +763,8 @@ static int __kvm_gmem_set_attributes(struct inode *inode, pgoff_t start,
kvm_gmem_invalidate_begin(inode, start, end);
+ kvm_gmem_apply_content_mode(inode, start, end, kvm, content_mode);
+
mas_store_prealloc(&mas, xa_mk_value(attrs));
kvm_gmem_invalidate_end(inode, start, end);
@@ -736,7 +786,11 @@ static long kvm_gmem_set_attributes(struct file *file, void __user *argp)
if (copy_from_user(&attrs, argp, sizeof(attrs)))
return -EFAULT;
- if (attrs.flags)
+ if (attrs.flags & ~(KVM_SET_MEMORY_ATTRIBUTES2_ZERO |
+ KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE))
+ return -EINVAL;
+ if ((attrs.flags & KVM_SET_MEMORY_ATTRIBUTES2_ZERO) &&
+ (attrs.flags & KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE))
return -EINVAL;
if (attrs.error_offset)
return -EINVAL;
@@ -758,7 +812,7 @@ static long kvm_gmem_set_attributes(struct file *file, void __user *argp)
nr_pages = attrs.size >> PAGE_SHIFT;
index = attrs.offset >> PAGE_SHIFT;
r = __kvm_gmem_set_attributes(inode, index, nr_pages, attrs.attributes,
- &err_index);
+ f->kvm, attrs.flags, &err_index);
if (r) {
attrs.error_offset = err_index << PAGE_SHIFT;
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 38/43] KVM: guest_memfd: Introduce default handlers for content modes
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
Currently, when setting memory attributes, KVM provides no guarantees about
the memory contents.
Introduce default handlers for applying memory content modes, which
different architectures should override.
These handlers will be used later to apply memory content modes during set
memory attributes requests.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
include/linux/kvm_host.h | 9 +++++++++
virt/kvm/guest_memfd.c | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 1ea14c66fc82e..bcb81e871fd37 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -740,6 +740,15 @@ static inline u64 kvm_gmem_get_supported_flags(struct kvm *kvm)
return flags;
}
+
+u64 kvm_arch_gmem_supported_content_modes(struct kvm *kvm);
+int kvm_gmem_apply_content_mode_zero(struct folio *folio);
+int kvm_arch_gmem_apply_content_mode_zero(struct kvm *kvm,
+ struct folio *folio);
+int kvm_arch_gmem_apply_content_mode_preserve(struct kvm *kvm,
+ struct folio *folio);
+int kvm_arch_gmem_apply_content_mode_unspecified(struct kvm *kvm,
+ struct folio *folio);
#endif
#ifndef kvm_arch_has_readonly_mem
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index c4f6bdad6289e..f23acbca28e54 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -638,6 +638,42 @@ static int kvm_gmem_mas_preallocate(struct ma_state *mas, u64 attributes,
return mas_preallocate(mas, xa_mk_value(attributes), GFP_KERNEL);
}
+u64 __weak kvm_arch_gmem_supported_content_modes(struct kvm *kvm)
+{
+ /* Architectures must override with supported modes. */
+ return 0;
+}
+
+static u64 kvm_gmem_supported_content_modes(struct kvm *kvm)
+{
+ return kvm_arch_gmem_supported_content_modes(kvm);
+}
+
+int kvm_gmem_apply_content_mode_zero(struct folio *folio)
+{
+ folio_zero_segment(folio, 0, folio_size(folio));
+
+ return 0;
+}
+
+int __weak kvm_arch_gmem_apply_content_mode_unspecified(struct kvm *kvm,
+ struct folio *folio)
+{
+ return 0;
+}
+
+int __weak kvm_arch_gmem_apply_content_mode_zero(struct kvm *kvm,
+ struct folio *folio)
+{
+ return kvm_gmem_apply_content_mode_zero(folio);
+}
+
+int __weak kvm_arch_gmem_apply_content_mode_preserve(struct kvm *kvm,
+ struct folio *folio)
+{
+ return -EOPNOTSUPP;
+}
+
static int __kvm_gmem_set_attributes(struct inode *inode, pgoff_t start,
size_t nr_pages, uint64_t attrs,
pgoff_t *err_index)
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 37/43] KVM: selftests: Update private memory exits test work with per-gmem attributes
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
From: Sean Christopherson <seanjc@google.com>
Skip setting memory to private in the private memory exits test when using
per-gmem memory attributes, as memory is initialized to private by default
for guest_memfd, and using vm_mem_set_private() on a guest_memfd instance
requires creating guest_memfd with GUEST_MEMFD_FLAG_MMAP (which is totally
doable, but would need to be conditional and is ultimately unnecessary).
Expect an emulated MMIO instead of a memory fault exit when attributes are
per-gmem, as deleting the memslot effectively drops the private status,
i.e. the GPA becomes shared and thus supports emulated MMIO.
Skip the "memslot not private" test entirely, as private vs. shared state
for x86 software-protected VMs comes from the memory attributes themselves,
and so when doing in-place conversions there can never be a disconnect
between the expected and actual states.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
.../selftests/kvm/x86/private_mem_kvm_exits_test.c | 36 ++++++++++++++++++----
1 file changed, 30 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c b/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c
index 13e72fcec8dd2..10be67441d457 100644
--- a/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c
+++ b/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c
@@ -62,8 +62,9 @@ static void test_private_access_memslot_deleted(void)
virt_map(vm, EXITS_TEST_GVA, EXITS_TEST_GPA, EXITS_TEST_NPAGES);
- /* Request to access page privately */
- vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE);
+ /* Request to access page privately. */
+ if (!kvm_has_gmem_attributes)
+ vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE);
pthread_create(&vm_thread, NULL,
(void *(*)(void *))run_vcpu_get_exit_reason,
@@ -74,10 +75,26 @@ static void test_private_access_memslot_deleted(void)
pthread_join(vm_thread, &thread_return);
exit_reason = (uint32_t)(uint64_t)thread_return;
- TEST_ASSERT_EQ(exit_reason, KVM_EXIT_MEMORY_FAULT);
- TEST_ASSERT_EQ(vcpu->run->memory_fault.flags, KVM_MEMORY_EXIT_FLAG_PRIVATE);
- TEST_ASSERT_EQ(vcpu->run->memory_fault.gpa, EXITS_TEST_GPA);
- TEST_ASSERT_EQ(vcpu->run->memory_fault.size, EXITS_TEST_SIZE);
+ /*
+ * If attributes are tracked per-gmem, deleting the memslot that points
+ * at the gmem instance effectively makes the memory shared, and so the
+ * read should trigger emulated MMIO.
+ *
+ * If attributes are tracked per-VM, deleting the memslot shouldn't
+ * affect the private attribute, and so KVM should generate a memory
+ * fault exit (emulated MMIO on private GPAs is disallowed).
+ */
+ if (kvm_has_gmem_attributes) {
+ TEST_ASSERT_EQ(exit_reason, KVM_EXIT_MMIO);
+ TEST_ASSERT_EQ(vcpu->run->mmio.phys_addr, EXITS_TEST_GPA);
+ TEST_ASSERT_EQ(vcpu->run->mmio.len, sizeof(uint64_t));
+ TEST_ASSERT_EQ(vcpu->run->mmio.is_write, false);
+ } else {
+ TEST_ASSERT_EQ(exit_reason, KVM_EXIT_MEMORY_FAULT);
+ TEST_ASSERT_EQ(vcpu->run->memory_fault.flags, KVM_MEMORY_EXIT_FLAG_PRIVATE);
+ TEST_ASSERT_EQ(vcpu->run->memory_fault.gpa, EXITS_TEST_GPA);
+ TEST_ASSERT_EQ(vcpu->run->memory_fault.size, EXITS_TEST_SIZE);
+ }
kvm_vm_free(vm);
}
@@ -88,6 +105,13 @@ static void test_private_access_memslot_not_private(void)
struct kvm_vcpu *vcpu;
uint32_t exit_reason;
+ /*
+ * Accessing non-private memory as private with a software-protected VM
+ * isn't possible when doing in-place conversions.
+ */
+ if (kvm_has_gmem_attributes)
+ return;
+
vm = vm_create_shape_with_one_vcpu(protected_vm_shape, &vcpu,
guest_repeatedly_read);
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 36/43] KVM: selftests: Update pre-fault test to work with per-guest_memfd attributes
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
From: Sean Christopherson <seanjc@google.com>
Skip setting memory to private in the pre-fault memory test when using
per-gmem memory attributes, as memory is initialized to private by default
for guest_memfd, and using vm_mem_set_private() on a guest_memfd instance
requires creating guest_memfd with GUEST_MEMFD_FLAG_MMAP (which is totally
doable, but would need to be conditional and is ultimately unnecessary).
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/pre_fault_memory_test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c
index 93e603d91311c..831b612449ecf 100644
--- a/tools/testing/selftests/kvm/pre_fault_memory_test.c
+++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c
@@ -187,7 +187,7 @@ static void __test_pre_fault_memory(unsigned long vm_type, bool private)
TEST_NPAGES, private ? KVM_MEM_GUEST_MEMFD : 0);
virt_map(vm, gva, gpa, TEST_NPAGES);
- if (private)
+ if (!kvm_has_gmem_attributes && private)
vm_mem_set_private(vm, gpa, TEST_SIZE);
pre_fault_memory(vcpu, gpa, 0, SZ_2M, 0, private);
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 35/43] KVM: selftests: Add script to exercise private_mem_conversions_test
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
Add a wrapper script to simplify running the private_mem_conversions_test
with a variety of configurations. Manually invoking the test for all
supported memory backing source types is tedious.
The script automatically detects the availability of 2MB and 1GB hugepages
and builds a list of source types to test. It then iterates through the
list, running the test for each type with both a single memslot and
multiple memslots.
This makes it easier to get comprehensive test coverage across different
memory configurations.
Use python to be able to issue an ioctl to /dev/kvm.
Update .gitignore to allowlist python scripts.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
tools/testing/selftests/kvm/.gitignore | 1 +
.../kvm/x86/private_mem_conversions_test.py | 152 +++++++++++++++++++++
2 files changed, 153 insertions(+)
diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
index 1d41a046a7bfd..d7e9c1d97e376 100644
--- a/tools/testing/selftests/kvm/.gitignore
+++ b/tools/testing/selftests/kvm/.gitignore
@@ -4,6 +4,7 @@
!*.c
!*.h
!*.S
+!*.py
!*.sh
!.gitignore
!config
diff --git a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.py b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.py
new file mode 100755
index 0000000000000..17f46c21e85e5
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.py
@@ -0,0 +1,152 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Wrapper script which runs different test setups of
+# private_mem_conversions_test.
+#
+# Copyright (C) 2025, Google LLC.
+
+import os
+import fcntl
+import sys
+import subprocess
+
+
+NUM_VCPUS_TO_TEST = 4
+NUM_MEMSLOTS_TO_TEST = NUM_VCPUS_TO_TEST
+
+# Required pages are based on the test setup in the C code.
+# These static requirements are set to the maximum required for
+# NUM_VCPUS_TO_TEST, over all the hugetlb-related tests
+REQUIRED_NUM_2M_HUGEPAGES = 1024 * NUM_VCPUS_TO_TEST
+REQUIRED_NUM_1G_HUGEPAGES = 2 * NUM_VCPUS_TO_TEST
+
+
+def get_hugepage_count(page_size_kb: int) -> int:
+ """Reads the current number of hugepages available for a given size."""
+ try:
+ path = f"/sys/kernel/mm/hugepages/hugepages-{page_size_kb}kB/nr_hugepages"
+ with open(path, 'r') as f:
+ return int(f.read().strip())
+ except (FileNotFoundError, ValueError):
+ return 0
+
+
+def get_default_hugepage_size_in_kb():
+ """Reads the default hugepage size from /proc/meminfo."""
+ try:
+ with open("/proc/meminfo", 'r') as f:
+ for line in f:
+ if line.startswith("Hugepagesize:"):
+ parts = line.split()
+ if len(parts) >= 2 and parts[1].isdigit():
+ return int(parts[1])
+ except FileNotFoundError:
+ return None
+
+
+def run_tests(executable_path: str, src_type: str, num_memslots: int, num_vcpus: int) -> None:
+ """Runs the test executable with different arguments."""
+ command = [executable_path, "-s", src_type, "-m", str(num_memslots), "-n", str(num_vcpus)]
+ print(" ".join(command))
+ _ = subprocess.run(command, check=True)
+
+
+def kvm_check_cap(capability: int) -> int:
+ KVM_CHECK_EXTENSION = 0xAE03
+ KVM_DEVICE = '/dev/kvm'
+
+ if not os.path.exists(KVM_DEVICE):
+ print(f"Error: KVM device not found at {KVM_DEVICE}. Is the 'kvm' module loaded?")
+ return -1
+
+ try:
+ fd = os.open(KVM_DEVICE, os.O_RDONLY)
+
+ result = fcntl.ioctl(fd, KVM_CHECK_EXTENSION, capability)
+
+ os.close(fd)
+ return result
+ except OSError as e:
+ print(f"Error issuing KVM ioctl on {KVM_DEVICE}: {e}", file=sys.stderr)
+ if fd > 0:
+ os.close(fd)
+ return -1
+
+
+def kvm_has_gmem_attributes() -> bool:
+ KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES = 246
+
+ return kvm_check_cap(KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES) > 0
+
+
+def get_backing_source_types() -> list[str]:
+ hugepage_2mb_count = get_hugepage_count(2048)
+ hugepage_2mb_enabled = hugepage_2mb_count >= REQUIRED_NUM_2M_HUGEPAGES
+ hugepage_1gb_count = get_hugepage_count(1048576)
+ hugepage_1gb_enabled = hugepage_1gb_count >= REQUIRED_NUM_1G_HUGEPAGES
+
+ default_hugepage_size_kb = get_default_hugepage_size_in_kb()
+ hugepage_default_enabled = False
+ if default_hugepage_size_kb == 2048:
+ hugepage_default_enabled = hugepage_2mb_enabled
+ elif default_hugepage_size_kb == 1048576:
+ hugepage_default_enabled = hugepage_1gb_enabled
+
+ backing_src_types: list[str] = ["anonymous", "anonymous_thp"]
+
+ if hugepage_default_enabled:
+ backing_src_types.append("anonymous_hugetlb")
+ else:
+ print("skipping anonymous_hugetlb backing source type")
+
+ if hugepage_2mb_enabled:
+ backing_src_types.append("anonymous_hugetlb_2mb")
+ else:
+ print("skipping anonymous_hugetlb_2mb backing source type")
+
+ if hugepage_1gb_enabled:
+ backing_src_types.append("anonymous_hugetlb_1gb")
+ else:
+ print("skipping anonymous_hugetlb_1gb backing source type")
+
+ backing_src_types.append("shmem")
+
+ if hugepage_default_enabled:
+ backing_src_types.append("shared_hugetlb")
+ else:
+ print("skipping shared_hugetlb backing source type")
+
+ return backing_src_types
+
+
+def main():
+ script_dir = os.path.dirname(os.path.abspath(__file__))
+ test_executable = os.path.join(script_dir, "private_mem_conversions_test")
+
+ if not os.path.exists(test_executable):
+ print(f"Error: Test executable not found at '{test_executable}'", file=sys.stderr)
+ sys.exit(1)
+
+ return_code = 0
+
+ backing_src_types = ["shmem"] if kvm_has_gmem_attributes() else get_backing_source_types()
+ try:
+ for i, src_type in enumerate(backing_src_types):
+ if i > 0:
+ print()
+ run_tests(test_executable, src_type, num_memslots=1, num_vcpus=1)
+ run_tests(test_executable, src_type, num_memslots=1, num_vcpus=NUM_VCPUS_TO_TEST)
+ run_tests(test_executable, src_type, num_memslots=NUM_MEMSLOTS_TO_TEST, num_vcpus=NUM_VCPUS_TO_TEST)
+ except subprocess.CalledProcessError as e:
+ print(f"Test failed for source type '{src_type}'. Command: {' '.join(e.cmd)}", file=sys.stderr)
+ return_code = e.returncode
+ except Exception as e:
+ print(f"An unexpected error occurred: {e}", file=sys.stderr)
+ return_code = 1
+
+ sys.exit(return_code)
+
+
+if __name__ == "__main__":
+ main()
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 34/43] KVM: selftests: Update private_mem_conversions_test to mmap() guest_memfd
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
Update the private memory conversions selftest to also test conversions
that are done "in-place" via per-guest_memfd memory attributes. In-place
conversions require the host to be able to mmap() the guest_memfd so that
the host and guest can share the same backing physical memory.
This includes several updates, that are conditioned on the system
supporting per-guest_memfd attributes (kvm_has_gmem_attributes):
1. Set up guest_memfd requesting MMAP and INIT_SHARED.
2. With in-place conversions, the host's mapping points directly to the
guest's memory. When the guest converts a region to private, host access
to that region is blocked. Update the test to expect a SIGBUS when
attempting to access the host virtual address (HVA) of private memory.
3. Use vm_mem_set_memory_attributes(), which chooses how to set memory
attributes based on whether kvm_has_gmem_attributes.
Restrict the test to using VM_MEM_SRC_SHMEM because guest_memfd's required
mmap() flags and page sizes happens to align with those of
VM_MEM_SRC_SHMEM. As long as VM_MEM_SRC_SHMEM is used for src_type,
vm_mem_add() works as intended.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
Co-developed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
.../kvm/x86/private_mem_conversions_test.c | 39 ++++++++++++++++++----
1 file changed, 32 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
index 47f1eb9212591..f85717662a73b 100644
--- a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
+++ b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
@@ -307,8 +307,8 @@ static void handle_exit_hypercall(struct kvm_vcpu *vcpu)
vm_guest_mem_fallocate(vm, gpa, size, map_shared);
if (set_attributes)
- vm_set_memory_attributes(vm, gpa, size,
- map_shared ? 0 : KVM_MEMORY_ATTRIBUTE_PRIVATE);
+ vm_mem_set_memory_attributes(vm, gpa, size,
+ map_shared ? 0 : KVM_MEMORY_ATTRIBUTE_PRIVATE);
run->hypercall.ret = 0;
}
@@ -352,8 +352,20 @@ static void *__test_mem_conversions(void *__vcpu)
size_t nr_bytes = min_t(size_t, vm->page_size, size - i);
uint8_t *hva = addr_gpa2hva(vm, gpa + i);
- /* In all cases, the host should observe the shared data. */
- memcmp_h(hva, gpa + i, uc.args[3], nr_bytes);
+ /*
+ * When using per-guest_memfd memory attributes,
+ * i.e. in-place conversion, host accesses will
+ * point at guest memory and should SIGBUS when
+ * guest memory is private. When using per-VM
+ * attributes, i.e. separate backing for shared
+ * vs. private, the host should always observe
+ * the shared data.
+ */
+ if (kvm_has_gmem_attributes &&
+ uc.args[0] == SYNC_PRIVATE)
+ TEST_EXPECT_SIGBUS(READ_ONCE(*hva));
+ else
+ memcmp_h(hva, gpa + i, uc.args[3], nr_bytes);
/* For shared, write the new pattern to guest memory. */
if (uc.args[0] == SYNC_SHARED)
@@ -382,6 +394,7 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, uint32_t
const size_t slot_size = memfd_size / nr_memslots;
struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
pthread_t threads[KVM_MAX_VCPUS];
+ uint64_t gmem_flags;
struct kvm_vm *vm;
int memfd, i;
@@ -397,12 +410,17 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, uint32_t
vm_enable_cap(vm, KVM_CAP_EXIT_HYPERCALL, (1 << KVM_HC_MAP_GPA_RANGE));
- memfd = vm_create_guest_memfd(vm, memfd_size, 0);
+ if (kvm_has_gmem_attributes)
+ gmem_flags = GUEST_MEMFD_FLAG_MMAP | GUEST_MEMFD_FLAG_INIT_SHARED;
+ else
+ gmem_flags = 0;
+
+ memfd = vm_create_guest_memfd(vm, memfd_size, gmem_flags);
for (i = 0; i < nr_memslots; i++)
vm_mem_add(vm, src_type, BASE_DATA_GPA + slot_size * i,
BASE_DATA_SLOT + i, slot_size / vm->page_size,
- KVM_MEM_GUEST_MEMFD, memfd, slot_size * i, 0);
+ KVM_MEM_GUEST_MEMFD, memfd, slot_size * i, gmem_flags);
for (i = 0; i < nr_vcpus; i++) {
uint64_t gpa = BASE_DATA_GPA + i * per_cpu_size;
@@ -452,17 +470,24 @@ static void usage(const char *cmd)
int main(int argc, char *argv[])
{
- enum vm_mem_backing_src_type src_type = DEFAULT_VM_MEM_SRC;
+ enum vm_mem_backing_src_type src_type;
uint32_t nr_memslots = 1;
uint32_t nr_vcpus = 1;
int opt;
TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM));
+ src_type = kvm_has_gmem_attributes ? VM_MEM_SRC_SHMEM :
+ DEFAULT_VM_MEM_SRC;
+
while ((opt = getopt(argc, argv, "hm:s:n:")) != -1) {
switch (opt) {
case 's':
src_type = parse_backing_src_type(optarg);
+ TEST_ASSERT(!kvm_has_gmem_attributes ||
+ src_type == VM_MEM_SRC_SHMEM,
+ "Testing in-place conversions, only %s mem_type supported\n",
+ vm_mem_backing_src_alias(VM_MEM_SRC_SHMEM)->name);
break;
case 'n':
nr_vcpus = atoi_positive("nr_vcpus", optarg);
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* [PATCH RFC v3 33/43] KVM: selftests: Make TEST_EXPECT_SIGBUS thread-safe
From: Ackerley Tng @ 2026-03-13 6:13 UTC (permalink / raw)
To: aik, andrew.jones, binbin.wu, brauner, chao.p.peng, david,
ira.weiny, jmattson, jroedel, jthoughton, michael.roth, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, suzuki.poulose, aneesh.kumar, Paolo Bonzini,
Sean Christopherson, 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, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
Ackerley Tng
In-Reply-To: <20260313-gmem-inplace-conversion-v3-0-5fc12a70ec89@google.com>
The TEST_EXPECT_SIGBUS macro is not thread-safe as it uses a global
sigjmp_buf and installs a global SIGBUS signal handler. If multiple threads
execute the macro concurrently, they will race on installing the signal
handler and stomp on other threads' jump buffers, leading to incorrect test
behavior.
Make TEST_EXPECT_SIGBUS thread-safe with the following changes:
Share the KVM tests' global signal handler. sigaction() applies to all
threads; without sharing a global signal handler, one thread may have
removed the signal handler that another thread added, hence leading to
unexpected signals.
The alternative of layering signal handlers was considered, but calling
sigaction() within TEST_EXPECT_SIGBUS() necessarily creates a race. To
avoid adding new setup and teardown routines to do sigaction() and keep
usage of TEST_EXPECT_SIGBUS() simple, share the KVM tests' global signal
handler.
Opportunistically rename report_unexpected_signal to
catchall_signal_handler.
To continue to only expect SIGBUS within specific regions of code, use a
thread-specific variable, expecting_sigbus, to replace installing and
removing signal handlers.
Make the execution environment for the thread, sigjmp_buf, a
thread-specific variable.
As part of TEST_EXPECT_SIGBUS(), assert the prerequisite for this setup,
that the current signal handler is the catchall_signal_handler.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
tools/testing/selftests/kvm/include/test_util.h | 30 +++++++++++++------------
tools/testing/selftests/kvm/lib/kvm_util.c | 18 ++++++++++-----
tools/testing/selftests/kvm/lib/test_util.c | 7 ------
3 files changed, 29 insertions(+), 26 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
index 2871a42928471..63e57d189f5fd 100644
--- a/tools/testing/selftests/kvm/include/test_util.h
+++ b/tools/testing/selftests/kvm/include/test_util.h
@@ -80,21 +80,23 @@ do { \
__builtin_unreachable(); \
} while (0)
-extern sigjmp_buf expect_sigbus_jmpbuf;
-void expect_sigbus_handler(int signum);
+extern __thread sigjmp_buf expect_sigbus_jmpbuf;
+extern __thread bool expecting_sigbus;
+extern void catchall_signal_handler(int signum);
-#define TEST_EXPECT_SIGBUS(action) \
-do { \
- struct sigaction sa_old, sa_new = { \
- .sa_handler = expect_sigbus_handler, \
- }; \
- \
- sigaction(SIGBUS, &sa_new, &sa_old); \
- if (sigsetjmp(expect_sigbus_jmpbuf, 1) == 0) { \
- action; \
- TEST_FAIL("'%s' should have triggered SIGBUS", #action); \
- } \
- sigaction(SIGBUS, &sa_old, NULL); \
+#define TEST_EXPECT_SIGBUS(action) \
+do { \
+ struct sigaction sa = {}; \
+ \
+ TEST_ASSERT_EQ(sigaction(SIGBUS, NULL, &sa), 0); \
+ TEST_ASSERT_EQ(sa.sa_handler, &catchall_signal_handler); \
+ \
+ expecting_sigbus = true; \
+ if (sigsetjmp(expect_sigbus_jmpbuf, 1) == 0) { \
+ action; \
+ TEST_FAIL("'%s' should have triggered SIGBUS", #action);\
+ } \
+ expecting_sigbus = false; \
} while (0)
size_t parse_size(const char *size);
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 6f7d3adb25d0a..f4aa762f050aa 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -2347,13 +2347,20 @@ __weak void kvm_selftest_arch_init(void)
{
}
-static void report_unexpected_signal(int signum)
+__thread sigjmp_buf expect_sigbus_jmpbuf;
+__thread bool expecting_sigbus;
+
+void catchall_signal_handler(int signum)
{
+ switch (signum) {
+ case SIGBUS: {
+ if (expecting_sigbus)
+ siglongjmp(expect_sigbus_jmpbuf, 1);
+
+ TEST_FAIL("Unexpected SIGBUS (%d)\n", signum);
+ }
#define KVM_CASE_SIGNUM(sig) \
case sig: TEST_FAIL("Unexpected " #sig " (%d)\n", signum)
-
- switch (signum) {
- KVM_CASE_SIGNUM(SIGBUS);
KVM_CASE_SIGNUM(SIGSEGV);
KVM_CASE_SIGNUM(SIGILL);
KVM_CASE_SIGNUM(SIGFPE);
@@ -2365,12 +2372,13 @@ static void report_unexpected_signal(int signum)
void __attribute((constructor)) kvm_selftest_init(void)
{
struct sigaction sig_sa = {
- .sa_handler = report_unexpected_signal,
+ .sa_handler = catchall_signal_handler,
};
/* Tell stdout not to buffer its content. */
setbuf(stdout, NULL);
+ expecting_sigbus = false;
sigaction(SIGBUS, &sig_sa, NULL);
sigaction(SIGSEGV, &sig_sa, NULL);
sigaction(SIGILL, &sig_sa, NULL);
diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c
index 8a1848586a857..03eb99af9b8de 100644
--- a/tools/testing/selftests/kvm/lib/test_util.c
+++ b/tools/testing/selftests/kvm/lib/test_util.c
@@ -18,13 +18,6 @@
#include "test_util.h"
-sigjmp_buf expect_sigbus_jmpbuf;
-
-void __attribute__((used)) expect_sigbus_handler(int signum)
-{
- siglongjmp(expect_sigbus_jmpbuf, 1);
-}
-
/*
* Random number generator that is usable from guest code. This is the
* Park-Miller LCG using standard constants.
--
2.53.0.851.ga537e3e6e9-goog
^ 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