* [PATCH RFC v4 34/44] KVM: selftests: Support checking that data not equal expected
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@google.com>
Expand run_guest_do_rmw() to support checking that data at given pgoff is
not equal to expected_val. This will be used in a later patch that tests
that memory contents are scrambled.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
.../selftests/kvm/guest_memfd_conversions_test.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/kvm/guest_memfd_conversions_test.c b/tools/testing/selftests/kvm/guest_memfd_conversions_test.c
index c0abc69f15332..277b122ec294c 100644
--- a/tools/testing/selftests/kvm/guest_memfd_conversions_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_conversions_test.c
@@ -137,6 +137,7 @@ static void __gmem_conversions_multipage_##test(test_data_t *t, int nr_pages, \
struct guest_check_data {
void *mem;
char expected_val;
+ bool assert_not_equal;
char write_val;
};
static struct guest_check_data guest_data;
@@ -146,7 +147,13 @@ static void guest_do_rmw(void)
for (;;) {
char *mem = READ_ONCE(guest_data.mem);
- GUEST_ASSERT_EQ(READ_ONCE(*mem), READ_ONCE(guest_data.expected_val));
+ if (READ_ONCE(guest_data.assert_not_equal)) {
+ GUEST_ASSERT_NE(READ_ONCE(*mem),
+ READ_ONCE(guest_data.expected_val));
+ } else {
+ GUEST_ASSERT_EQ(READ_ONCE(*mem),
+ READ_ONCE(guest_data.expected_val));
+ }
WRITE_ONCE(*mem, READ_ONCE(guest_data.write_val));
GUEST_SYNC(0);
@@ -154,13 +161,15 @@ static void guest_do_rmw(void)
}
static void run_guest_do_rmw(struct kvm_vcpu *vcpu, loff_t pgoff,
- char expected_val, char write_val)
+ char expected_val, char write_val,
+ bool assert_not_equal)
{
struct ucall uc;
int r;
guest_data.mem = (void *)GUEST_MEMFD_SHARING_TEST_GVA + pgoff * page_size;
guest_data.expected_val = expected_val;
+ guest_data.assert_not_equal = assert_not_equal;
guest_data.write_val = write_val;
sync_global_to_guest(vcpu->vm, guest_data);
@@ -191,7 +200,7 @@ static void test_private(test_data_t *t, loff_t pgoff, char starting_val,
char write_val)
{
TEST_EXPECT_SIGBUS(WRITE_ONCE(t->mem[pgoff * page_size], write_val));
- run_guest_do_rmw(t->vcpu, pgoff, starting_val, write_val);
+ run_guest_do_rmw(t->vcpu, pgoff, starting_val, write_val, false);
TEST_EXPECT_SIGBUS(READ_ONCE(t->mem[pgoff * page_size]));
}
@@ -207,7 +216,7 @@ static void test_shared(test_data_t *t, loff_t pgoff, char starting_val,
char host_write_val, char write_val)
{
host_do_rmw(t->mem, pgoff, starting_val, host_write_val);
- run_guest_do_rmw(t->vcpu, pgoff, host_write_val, write_val);
+ run_guest_do_rmw(t->vcpu, pgoff, host_write_val, write_val, false);
TEST_ASSERT_EQ(READ_ONCE(t->mem[pgoff * page_size]), write_val);
}
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 35/44] KVM: selftests: Test that not specifying a conversion flag scrambles memory contents
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@google.com>
When using KVM_SET_MEMORY_ATTRIBUTES2, not specifying flags for the ioctl
implies no guarantees on memory contents.
For KVM_X86_SW_PROTECTED_VM, this mode is implemented by scrambling
contents of converted memory ranges. Add a test to check that the
unspecified conversion mode was handled in KVM by checking the expected
behavior, that existing memory contents are scrambled.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
.../selftests/kvm/guest_memfd_conversions_test.c | 28 ++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/tools/testing/selftests/kvm/guest_memfd_conversions_test.c b/tools/testing/selftests/kvm/guest_memfd_conversions_test.c
index 277b122ec294c..4b2f00afda01c 100644
--- a/tools/testing/selftests/kvm/guest_memfd_conversions_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_conversions_test.c
@@ -512,6 +512,34 @@ GMEM_CONVERSION_TEST_INIT_SHARED(convert_to_private_does_not_support_zero)
TEST_ASSERT_EQ(error_offset, start_offset);
}
+GMEM_CONVERSION_TEST_INIT_SHARED(convert_mode_unspecified_scrambles)
+{
+ loff_t error_offset = -1ul;
+ int ret;
+
+ test_shared(t, 0, 0, 'A', 'B');
+ ret = __gmem_set_private(t->gmem_fd, 0, nr_pages * page_size,
+ &error_offset, 0);
+ TEST_ASSERT_EQ(ret, 0);
+ TEST_ASSERT_EQ(error_offset, -1ul);
+
+ /*
+ * Since the content mode 0 scrambles data in memory, there is
+ * a small chance that this test will falsely fail when the
+ * scrambled value matches the initial value.
+ */
+ run_guest_do_rmw(t->vcpu, 0, 'B', 'C', true);
+
+ ret = __gmem_set_shared(t->gmem_fd, 0, nr_pages * page_size,
+ &error_offset, 0);
+ TEST_ASSERT_EQ(ret, 0);
+ TEST_ASSERT_EQ(error_offset, -1ul);
+
+ /* Same small chance of falsely failing test applies here. */
+ TEST_ASSERT(READ_ONCE(t->mem[0]) != 'C',
+ "Conversion without specifying mode should scramble memory.");
+}
+
int main(int argc, char *argv[])
{
TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM));
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 36/44] KVM: selftests: Reset shared memory after hole-punching
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@google.com>
private_mem_conversions_test used to reset the shared memory that was used
for the test to an initial pattern at the end of each test iteration. Then,
it would punch out the pages, which would zero memory.
Without in-place conversion, the resetting would write shared memory, and
hole-punching will zero private memory, hence resetting the test to the
state at the beginning of the for loop.
With in-place conversion, resetting writes memory as shared, and
hole-punching zeroes the same physical memory, hence undoing the reset
done before the hole punch.
Move the resetting after the hole-punching, and reset the entire
PER_CPU_DATA_SIZE instead of just the tested range.
With in-place conversion, this zeroes and then resets the same physical
memory. Without in-place conversion, the private memory is zeroed, and the
shared memory is reset to init_p.
This is sufficient since at each test stage, the memory is assumed to start
as shared, and private memory is always assumed to start zeroed. Conversion
zeroes memory, so the future test stages will work as expected.
Fixes: 43f623f350ce1 ("KVM: selftests: Add x86-only selftest for private memory conversions")
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
tools/testing/selftests/kvm/x86/private_mem_conversions_test.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 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 41f6b38f04071..47f1eb9212591 100644
--- a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
+++ b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
@@ -202,15 +202,18 @@ static void guest_test_explicit_conversion(uint64_t base_gpa, bool do_fallocate)
guest_sync_shared(gpa, size, p3, p4);
memcmp_g(gpa, p4, size);
- /* Reset the shared memory back to the initial pattern. */
- memset((void *)gpa, init_p, size);
-
/*
* Free (via PUNCH_HOLE) *all* private memory so that the next
* iteration starts from a clean slate, e.g. with respect to
* whether or not there are pages/folios in guest_mem.
*/
guest_map_shared(base_gpa, PER_CPU_DATA_SIZE, true);
+
+ /*
+ * Hole-punching above zeroed private memory. Reset shared
+ * memory in preparation for the next GUEST_STAGE.
+ */
+ memset((void *)base_gpa, init_p, PER_CPU_DATA_SIZE);
}
}
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 37/44] KVM: selftests: Provide function to look up guest_memfd details from gpa
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@google.com>
Introduce a new helper, kvm_gpa_to_guest_memfd(), to find the
guest_memfd-related details of a memory region that contains a given guest
physical address (GPA).
The function returns the file descriptor for the memfd, the offset into
the file that corresponds to the GPA, and the number of bytes remaining
in the region from that GPA.
kvm_gpa_to_guest_memfd() was factored out from vm_guest_mem_fallocate();
refactor vm_guest_mem_fallocate() to use the new helper.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
Co-developed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
tools/testing/selftests/kvm/include/kvm_util.h | 3 +++
tools/testing/selftests/kvm/lib/kvm_util.c | 34 ++++++++++++++++----------
2 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index a539a98f79e08..3434f3df028b0 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -427,6 +427,9 @@ static inline void vm_enable_cap(struct kvm_vm *vm, uint32_t cap, uint64_t arg0)
vm_ioctl(vm, KVM_ENABLE_CAP, &enable_cap);
}
+int kvm_gpa_to_guest_memfd(struct kvm_vm *vm, vm_paddr_t gpa, off_t *fd_offset,
+ uint64_t *nr_bytes);
+
/*
* KVM_SET_MEMORY_ATTRIBUTES overwrites _all_ attributes. These flows need
* significant enhancements to support multiple attributes.
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 404efb5318f09..6deb6b333a066 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1291,27 +1291,19 @@ void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t base, uint64_t size,
bool punch_hole)
{
const int mode = FALLOC_FL_KEEP_SIZE | (punch_hole ? FALLOC_FL_PUNCH_HOLE : 0);
- struct userspace_mem_region *region;
uint64_t end = base + size;
uint64_t gpa, len;
off_t fd_offset;
- int ret;
+ int fd, ret;
for (gpa = base; gpa < end; gpa += len) {
- uint64_t offset;
-
- region = userspace_mem_region_find(vm, gpa, gpa);
- TEST_ASSERT(region && region->region.flags & KVM_MEM_GUEST_MEMFD,
- "Private memory region not found for GPA 0x%lx", gpa);
+ fd = kvm_gpa_to_guest_memfd(vm, gpa, &fd_offset, &len);
+ len = min(end - gpa, len);
- offset = gpa - region->region.guest_phys_addr;
- fd_offset = region->region.guest_memfd_offset + offset;
- len = min_t(uint64_t, end - gpa, region->region.memory_size - offset);
-
- ret = fallocate(region->region.guest_memfd, mode, fd_offset, len);
+ ret = fallocate(fd, mode, fd_offset, len);
TEST_ASSERT(!ret, "fallocate() failed to %s at %lx (len = %lu), fd = %d, mode = %x, offset = %lx",
punch_hole ? "punch hole" : "allocate", gpa, len,
- region->region.guest_memfd, mode, fd_offset);
+ fd, mode, fd_offset);
}
}
@@ -1717,6 +1709,22 @@ void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa)
return (void *) ((uintptr_t) region->host_alias + offset);
}
+int kvm_gpa_to_guest_memfd(struct kvm_vm *vm, vm_paddr_t gpa, off_t *fd_offset,
+ uint64_t *nr_bytes)
+{
+ struct userspace_mem_region *region;
+ vm_paddr_t gpa_offset;
+
+ region = userspace_mem_region_find(vm, gpa, gpa);
+ TEST_ASSERT(region && region->region.flags & KVM_MEM_GUEST_MEMFD,
+ "guest_memfd memory region not found for GPA 0x%lx", gpa);
+
+ gpa_offset = gpa - region->region.guest_phys_addr;
+ *fd_offset = region->region.guest_memfd_offset + gpa_offset;
+ *nr_bytes = region->region.memory_size - gpa_offset;
+ return region->region.guest_memfd;
+}
+
/* Create an interrupt controller chip for the specified VM. */
void vm_create_irqchip(struct kvm_vm *vm)
{
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 38/44] KVM: selftests: Provide common function to set memory attributes
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@google.com>
From: Sean Christopherson <seanjc@google.com>
Introduce vm_mem_set_memory_attributes(), which handles setting of memory
attributes for a range of guest physical addresses, regardless of whether
the attributes should be set via guest_memfd or via the memory attributes
at the VM level.
Refactor existing vm_mem_set_{shared,private} functions to use the new
function.
Update existing caller of vm_mem_set_private().
Signed-off-by: Sean Christopherson <seanjc@google.com>
Co-developed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
tools/testing/selftests/kvm/guest_memfd_test.c | 2 +-
tools/testing/selftests/kvm/include/kvm_util.h | 47 ++++++++++++++++------
tools/testing/selftests/kvm/lib/x86/sev.c | 2 +-
.../testing/selftests/kvm/pre_fault_memory_test.c | 2 +-
.../selftests/kvm/x86/private_mem_kvm_exits_test.c | 4 +-
5 files changed, 40 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
index 10b57fd4fa9ba..ff8c0c56399dd 100644
--- a/tools/testing/selftests/kvm/guest_memfd_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_test.c
@@ -506,7 +506,7 @@ static void test_guest_private_mem(void)
fd, 0, 0);
virt_map(vm, gpa, gpa, npages);
- vm_mem_set_private(vm, gpa, page_size);
+ vm_mem_set_private(vm, gpa, page_size, 0);
vcpu_args_set(vcpu, 1, gpa);
vcpu_run(vcpu);
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 3434f3df028b0..d975cc3047a2d 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -456,18 +456,6 @@ static inline void vm_set_memory_attributes(struct kvm_vm *vm, uint64_t gpa,
vm_ioctl(vm, KVM_SET_MEMORY_ATTRIBUTES2, &attr);
}
-static inline void vm_mem_set_private(struct kvm_vm *vm, uint64_t gpa,
- uint64_t size)
-{
- vm_set_memory_attributes(vm, gpa, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
-}
-
-static inline void vm_mem_set_shared(struct kvm_vm *vm, uint64_t gpa,
- uint64_t size)
-{
- vm_set_memory_attributes(vm, gpa, size, 0);
-}
-
static inline int __gmem_set_memory_attributes(int fd, loff_t offset,
uint64_t size,
uint64_t attributes,
@@ -536,6 +524,41 @@ static inline void gmem_set_shared(int fd, loff_t offset, uint64_t size, u64 fla
gmem_set_memory_attributes(fd, offset, size, 0, flags);
}
+static inline void vm_mem_set_memory_attributes(struct kvm_vm *vm, uint64_t gpa,
+ uint64_t size, uint64_t attrs,
+ u64 flags)
+{
+ if (kvm_has_gmem_attributes) {
+ uint64_t end = gpa + size;
+ uint64_t addr, len;
+ off_t fd_offset;
+ int fd;
+
+ for (addr = gpa; addr < end; addr += len) {
+ 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, flags);
+ }
+ } else {
+ TEST_ASSERT(!flags, "Flags are not supported.");
+ vm_set_memory_attributes(vm, gpa, size, attrs);
+ }
+}
+
+static inline void vm_mem_set_private(struct kvm_vm *vm, uint64_t gpa,
+ uint64_t size, u64 flags)
+{
+ vm_mem_set_memory_attributes(vm, gpa, size,
+ KVM_MEMORY_ATTRIBUTE_PRIVATE, flags);
+}
+
+static inline void vm_mem_set_shared(struct kvm_vm *vm, uint64_t gpa,
+ uint64_t size, u64 flags)
+{
+ vm_mem_set_memory_attributes(vm, gpa, size, 0, flags);
+}
+
void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t gpa, uint64_t size,
bool punch_hole);
diff --git a/tools/testing/selftests/kvm/lib/x86/sev.c b/tools/testing/selftests/kvm/lib/x86/sev.c
index c3a9838f4806a..d3a7241e5fc13 100644
--- a/tools/testing/selftests/kvm/lib/x86/sev.c
+++ b/tools/testing/selftests/kvm/lib/x86/sev.c
@@ -33,7 +33,7 @@ static void encrypt_region(struct kvm_vm *vm, struct userspace_mem_region *regio
const uint64_t offset = (i - lowest_page_in_region) * vm->page_size;
if (private)
- vm_mem_set_private(vm, gpa_base + offset, size);
+ vm_mem_set_private(vm, gpa_base + offset, size, 0);
if (is_sev_snp_vm(vm))
snp_launch_update_data(vm, gpa_base + offset,
diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c
index 93e603d91311c..3b2c4179d42ee 100644
--- a/tools/testing/selftests/kvm/pre_fault_memory_test.c
+++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c
@@ -188,7 +188,7 @@ static void __test_pre_fault_memory(unsigned long vm_type, bool private)
virt_map(vm, gva, gpa, TEST_NPAGES);
if (private)
- vm_mem_set_private(vm, gpa, TEST_SIZE);
+ vm_mem_set_private(vm, gpa, TEST_SIZE, 0);
pre_fault_memory(vcpu, gpa, 0, SZ_2M, 0, private);
pre_fault_memory(vcpu, gpa, SZ_2M, PAGE_SIZE * 2, PAGE_SIZE, private);
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..cbcb5d6d04436 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
@@ -63,7 +63,7 @@ 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);
+ vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE, 0);
pthread_create(&vm_thread, NULL,
(void *(*)(void *))run_vcpu_get_exit_reason,
@@ -99,7 +99,7 @@ static void test_private_access_memslot_not_private(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);
+ vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE, 0);
exit_reason = run_vcpu_get_exit_reason(vcpu);
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 39/44] KVM: selftests: Check fd/flags provided to mmap() when setting up memslot
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@google.com>
From: Sean Christopherson <seanjc@google.com>
Check that a valid fd provided to mmap() must be accompanied by MAP_SHARED.
With an invalid fd (usually used for anonymous mappings), there are no
constraints on mmap() flags.
Add this check to make sure that when a guest_memfd is used as region->fd,
the flag provided to mmap() will include MAP_SHARED.
Signed-off-by: Sean Christopherson <seanjc@google.com>
[Rephrase assertion message.]
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
tools/testing/selftests/kvm/lib/kvm_util.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 6deb6b333a066..6f7d3adb25d0a 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1095,6 +1095,9 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
src_type == VM_MEM_SRC_SHARED_HUGETLB);
}
+ TEST_ASSERT(region->fd == -1 || backing_src_is_shared(src_type),
+ "A valid fd provided to mmap() must be accompanied by MAP_SHARED.");
+
region->mmap_start = __kvm_mmap(region->mmap_size, PROT_READ | PROT_WRITE,
vm_mem_backing_src_alias(src_type)->flag,
region->fd, mmap_offset);
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 40/44] KVM: selftests: Make TEST_EXPECT_SIGBUS thread-safe
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@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 | 32 +++++++++++++------------
tools/testing/selftests/kvm/lib/kvm_util.c | 18 ++++++++++----
tools/testing/selftests/kvm/lib/test_util.c | 7 ------
3 files changed, 30 insertions(+), 27 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
index 2871a42928471..82f6b371fe767 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);
-
-#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); \
+extern __thread sigjmp_buf expect_sigbus_jmpbuf;
+extern __thread volatile sig_atomic_t expecting_sigbus;
+extern void catchall_signal_handler(int signum);
+
+#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..eaa5a1afa1d9b 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 volatile sig_atomic_t 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.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 41/44] KVM: selftests: Update private_mem_conversions_test to mmap() guest_memfd
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@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 | 46 ++++++++++++++++++----
1 file changed, 38 insertions(+), 8 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..29c3c5b2f538e 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,14 @@ 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_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;
+ u64 flags = kvm_has_gmem_attributes ?
+ KVM_SET_MEMORY_ATTRIBUTES2_PRESERVE : 0;
+
+ vm_mem_set_memory_attributes(vm, gpa, size, attrs, flags);
+ }
+
run->hypercall.ret = 0;
}
@@ -352,8 +357,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 +399,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 +415,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 +475,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.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 42/44] KVM: selftests: Add script to exercise private_mem_conversions_test
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@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.
Add and use a helper program in C to be able to read
KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES as defined in header files and then
issue the ioctl to read the KVM CAP.
Signed-off-by: Ackerley Tng <ackerleytng@google.com>
---
tools/testing/selftests/kvm/Makefile.kvm | 4 +
.../selftests/kvm/kvm_has_gmem_attributes.c | 17 +++
.../kvm/x86/private_mem_conversions_test.sh | 128 +++++++++++++++++++++
3 files changed, 149 insertions(+)
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 0e2a9adfca57e..c326aecfeebb0 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -54,6 +54,7 @@ LIBKVM_loongarch += lib/loongarch/exception.S
# Non-compiled test targets
TEST_PROGS_x86 += x86/nx_huge_pages_test.sh
+TEST_PROGS_x86 += x86/private_mem_conversions_test.sh
# Compiled test targets valid on all architectures with libkvm support
TEST_GEN_PROGS_COMMON = demand_paging_test
@@ -65,6 +66,8 @@ TEST_GEN_PROGS_COMMON += kvm_create_max_vcpus
TEST_GEN_PROGS_COMMON += kvm_page_table_test
TEST_GEN_PROGS_COMMON += set_memory_region_test
+TEST_GEN_PROGS_EXTENDED_COMMON += kvm_has_gmem_attributes
+
# Compiled test targets
TEST_GEN_PROGS_x86 = $(TEST_GEN_PROGS_COMMON)
TEST_GEN_PROGS_x86 += x86/cpuid_test
@@ -242,6 +245,7 @@ SPLIT_TESTS += get-reg-list
TEST_PROGS += $(TEST_PROGS_$(ARCH))
TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(ARCH))
+TEST_GEN_PROGS_EXTENDED += $(TEST_GEN_PROGS_EXTENDED_COMMON)
TEST_GEN_PROGS_EXTENDED += $(TEST_GEN_PROGS_EXTENDED_$(ARCH))
LIBKVM += $(LIBKVM_$(ARCH))
diff --git a/tools/testing/selftests/kvm/kvm_has_gmem_attributes.c b/tools/testing/selftests/kvm/kvm_has_gmem_attributes.c
new file mode 100644
index 0000000000000..4f361349412fb
--- /dev/null
+++ b/tools/testing/selftests/kvm/kvm_has_gmem_attributes.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Utility to check if KVM supports guest_memfd attributes.
+ *
+ * Copyright (C) 2025, Google LLC.
+ */
+
+#include <stdio.h>
+
+#include "kvm_util.h"
+
+int main(void)
+{
+ printf("%u\n", kvm_check_cap(KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES) > 0);
+
+ return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.sh b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.sh
new file mode 100755
index 0000000000000..7179a4fcdd498
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.sh
@@ -0,0 +1,128 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Wrapper script which runs different test setups of
+# private_mem_conversions_test.
+#
+# Copyright (C) 2025, Google LLC.
+
+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.
+REQUIRED_NUM_2M_HUGEPAGES=$((1024 * NUM_VCPUS_TO_TEST))
+REQUIRED_NUM_1G_HUGEPAGES=$((2 * NUM_VCPUS_TO_TEST))
+
+get_hugepage_count() {
+ local page_size_kb=$1
+ local path="/sys/kernel/mm/hugepages/hugepages-${page_size_kb}kB/nr_hugepages"
+ if [ -f "$path" ]; then
+ cat "$path"
+ else
+ echo 0
+ fi
+}
+
+get_default_hugepage_size_in_kb() {
+ local size=$(grep "Hugepagesize:" /proc/meminfo | awk '{print $2}')
+ echo "$size"
+}
+
+run_tests() {
+ local executable_path=$1
+ local src_type=$2
+ local num_memslots=$3
+ local num_vcpus=$4
+
+ echo "$executable_path -s $src_type -m $num_memslots -n $num_vcpus"
+ "$executable_path" -s "$src_type" -m "$num_memslots" -n "$num_vcpus"
+}
+
+script_dir=$(dirname "$(realpath "$0")")
+test_executable="${script_dir}/private_mem_conversions_test"
+kvm_has_gmem_attributes_tool="${script_dir}/../kvm_has_gmem_attributes"
+
+if [ ! -f "$test_executable" ]; then
+ echo "Error: Test executable not found at '$test_executable'" >&2
+ exit 1
+fi
+
+if [ ! -f "$kvm_has_gmem_attributes_tool" ]; then
+ echo "Error: kvm_has_gmem_attributes utility not found at '$kvm_has_gmem_attributes_tool'" >&2
+ exit 1
+fi
+
+kvm_has_gmem_attributes=$("$kvm_has_gmem_attributes_tool" | tail -n1)
+
+if [ "$kvm_has_gmem_attributes" -eq 1 ]; then
+ backing_src_types=("shmem")
+else
+ 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=0
+ if [ "$default_hugepage_size_kb" -eq 2048 ]; then
+ hugepage_default_enabled=$hugepage_2mb_enabled
+ elif [ "$default_hugepage_size_kb" -eq 1048576 ]; then
+ hugepage_default_enabled=$hugepage_1gb_enabled
+ fi
+
+ backing_src_types=("anonymous" "anonymous_thp")
+
+ if [ "$hugepage_default_enabled" -eq 1 ]; then
+ backing_src_types+=("anonymous_hugetlb")
+ else
+ echo "skipping anonymous_hugetlb backing source type"
+ fi
+
+ if [ "$hugepage_2mb_enabled" -eq 1 ]; then
+ backing_src_types+=("anonymous_hugetlb_2mb")
+ else
+ echo "skipping anonymous_hugetlb_2mb backing source type"
+ fi
+
+ if [ "$hugepage_1gb_enabled" -eq 1 ]; then
+ backing_src_types+=("anonymous_hugetlb_1gb")
+ else
+ echo "skipping anonymous_hugetlb_1gb backing source type"
+ fi
+
+ backing_src_types+=("shmem")
+
+ if [ "$hugepage_default_enabled" -eq 1 ]; then
+ backing_src_types+=("shared_hugetlb")
+ else
+ echo "skipping shared_hugetlb backing source type"
+ fi
+fi
+
+return_code=0
+for i in "${!backing_src_types[@]}"; do
+ src_type=${backing_src_types[$i]}
+ if [ "$i" -gt 0 ]; then
+ echo
+ fi
+
+ if ! run_tests "$test_executable" "$src_type" 1 1; then
+ return_code=$?
+ echo "Test failed for source type '$src_type'. Arguments: -s $src_type -m 1 -n 1" >&2
+ break
+ fi
+
+ if ! run_tests "$test_executable" "$src_type" 1 "$NUM_VCPUS_TO_TEST"; then
+ return_code=$?
+ echo "Test failed for source type '$src_type'. Arguments: -s $src_type -m 1 -n $NUM_VCPUS_TO_TEST" >&2
+ break
+ fi
+
+ if ! run_tests "$test_executable" "$src_type" "$NUM_MEMSLOTS_TO_TEST" "$NUM_VCPUS_TO_TEST"; then
+ return_code=$?
+ echo "Test failed for source type '$src_type'. Arguments: -s $src_type -m $NUM_MEMSLOTS_TO_TEST -n $NUM_VCPUS_TO_TEST" >&2
+ break
+ fi
+done
+
+exit "$return_code"
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 43/44] KVM: selftests: Update pre-fault test to work with per-guest_memfd attributes
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@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 3b2c4179d42ee..7b7352487fe12 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, 0);
pre_fault_memory(vcpu, gpa, 0, SZ_2M, 0, private);
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related
* [PATCH RFC v4 44/44] KVM: selftests: Update private memory exits test to work with per-gmem attributes
From: Ackerley Tng @ 2026-03-26 22:24 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, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Jason Gunthorpe,
Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, Ackerley Tng
In-Reply-To: <20260326-gmem-inplace-conversion-v4-0-e202fe950ffd@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 cbcb5d6d04436..ed1bf27d149dc 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, 0);
+ /* Request to access page privately. */
+ if (!kvm_has_gmem_attributes)
+ vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE, 0);
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.1018.g2bb0e51243-goog
^ permalink raw reply related
* Re: [PATCH V9 3/8] dax: add fsdev.c driver for fs-dax on character dax
From: Ira Weiny @ 2026-03-26 22:46 UTC (permalink / raw)
To: John Groves, Ira Weiny
Cc: Jonathan Cameron, John Groves, Miklos Szeredi, Dan Williams,
Bernd Schubert, Alison Schofield, John Groves, Jonathan Corbet,
Shuah Khan, Vishal Verma, Dave Jiang, Matthew Wilcox, Jan Kara,
Alexander Viro, David Hildenbrand, Christian Brauner,
Darrick J . Wong, Randy Dunlap, Jeff Layton, Amir Goldstein,
Stefan Hajnoczi, Joanne Koong, Josef Bacik, Bagas Sanjaya,
Chen Linxuan, James Morse, Fuad Tabba, Sean Christopherson,
Shivank Garg, Ackerley Tng, Gregory Price, Aravind Ramesh,
Ajay Joshi, venkataravis@micron.com, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, nvdimm@lists.linux.dev,
linux-cxl@vger.kernel.org, linux-fsdevel@vger.kernel.org
In-Reply-To: <acVDCKeolpJM9qg6@groves.net>
John Groves wrote:
> On 26/03/25 11:04AM, Ira Weiny wrote:
> > John Groves wrote:
> > > On 26/03/24 02:39PM, Jonathan Cameron wrote:
> > > > On Tue, 24 Mar 2026 00:38:31 +0000
> > > > John Groves <john@jagalactic.com> wrote:
> > > >
> > > > > From: John Groves <john@groves.net>
> > > > >
> > > > > The new fsdev driver provides pages/folios initialized compatibly with
> > > > > fsdax - normal rather than devdax-style refcounting, and starting out
> > > > > with order-0 folios.
> > > > >
> > > > > When fsdev binds to a daxdev, it is usually (always?) switching from the
> > > > > devdax mode (device.c), which pre-initializes compound folios according
> > > > > to its alignment. Fsdev uses fsdev_clear_folio_state() to switch the
> > > > > folios into a fsdax-compatible state.
> > > > >
> > > > > A side effect of this is that raw mmap doesn't (can't?) work on an fsdev
> > > > > dax instance. Accordingly, The fsdev driver does not provide raw mmap -
> > > > > devices must be put in 'devdax' mode (drivers/dax/device.c) to get raw
> > > > > mmap capability.
> > > > >
> > > > > In this commit is just the framework, which remaps pages/folios compatibly
> > > > > with fsdax.
> > > > >
> > > > > Enabling dax changes:
> > > > >
> > > > > - bus.h: add DAXDRV_FSDEV_TYPE driver type
> > > > > - bus.c: allow DAXDRV_FSDEV_TYPE drivers to bind to daxdevs
> > > > > - dax.h: prototype inode_dax(), which fsdev needs
> > > > >
> > > > > Suggested-by: Dan Williams <dan.j.williams@intel.com>
> > > > > Suggested-by: Gregory Price <gourry@gourry.net>
> > > > > Signed-off-by: John Groves <john@groves.net>
> > > >
> > > > I was kind of thinking you'd go with a hidden KCONFIG option with default
> > > > magic to do the same build condition to you had in the Makefil, but one the
> > > > user can opt in or out for is also fine.
> > > >
> > > > Comments on that below. Meh, I think this is better anyway :)
> > > >
> > > > Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> > > >
> > > >
> > > >
> > > > > diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig
> > > > > index d656e4c0eb84..7051b70980d5 100644
> > > > > --- a/drivers/dax/Kconfig
> > > > > +++ b/drivers/dax/Kconfig
> > > > > @@ -61,6 +61,17 @@ config DEV_DAX_HMEM_DEVICES
> > > > > depends on DEV_DAX_HMEM && DAX
> > > > > def_bool y
> > > > >
> > > > > +config DEV_DAX_FSDEV
> > > > > + tristate "FSDEV DAX: fs-dax compatible devdax driver"
> > > > > + depends on DEV_DAX && FS_DAX
> > > > > + help
> > > > > + Support fs-dax access to DAX devices via a character device
> > > > > + interface. Unlike device_dax (which pre-initializes compound folios
> > > > > + based on device alignment), this driver leaves folios at order-0 so
> > > > > + that fs-dax filesystems can manage folio order dynamically.
> > > > > +
> > > > > + Say M if unsure.
> > > > Fine like this, but if you wanted to hide it in interests of not
> > > > confusing users...
> > > >
> > > > config DEV_DAX_FSDEV
> > > > tristate
> > > > depends on DEV_DAX && FS_DAX
> > > > default DEV_DAX
> > >
> > > I like this better. I see no reason not to default to including fsdev.
> > > It does nothing other than frustrating famfs users if it's off - since
> > > building it still has no effect unless you put a daxdev in famfs mode.
> > >
> > > Ira, it's kinda in your hands at the moment. Do you feel like making this
> > > change?
> >
> > I don't mind making this change. But we have to deal with the breakage to
> > current device dax users.
> >
> > https://lore.kernel.org/all/69c36921255b6_e9d8d1009b@iweiny-mobl.notmuch/
> >
> > What am I missing?
> >
> > Ira
>
> OK, I can reproduce that failure with kernel 7.0.0-rc5 and
> straight ndctl v84. So it's not famfs.
No it is the fsdev_dax driver which causes the issue.
I can reload the driver and effectively change the order the drivers are
searched.
I can prove this with a simple print. With my test system (where
fsdev_dax _happens_ to be the first driver searched) the failure happens.
[ 526.564232] IKW searching drv type 0 ; type 1
[ 526.564515] IKW searching drv type 2 ; type 1
If I remove your driver (modprobe -r fsdev_dax) prior to running the test
I get.
[ 59.748171] IKW searching drv type 0 ; type 1
[ 59.749127] IKW searching drv type 1 ; type 1
And it passes. I can continue by loading fsdev_dax back and it will
continue to work. If you are getting this to pass it must be because in
your system that driver gets loaded first... not sure how.
This is with the same exact kernel just with your module removed at run
time.
dax_match_type() needs some other way of matching when the fsdev_dax
driver should be used.
I'm not seeing a clear path ATM.
>
> I also studied the verbose logs trying to figure out if famfs
> could cause it (while running a famfs kernel and ndctl), but
> I don't see it.
>
> Then I tried non-famfs kernel and ndctl and it's the same with
> or without famfs kernel and famfs ndctl.
:-/ I'm not seeing any failures with rc5.
Also I'm not running with famfs. Just the dax changes.
Ira
^ permalink raw reply
* Re: [PATCH v4 09/13] ima: Add support for staging measurements with prompt
From: steven chen @ 2026-03-26 22:44 UTC (permalink / raw)
To: Roberto Sassu, corbet, skhan, zohar, dmitry.kasatkin,
eric.snowberg, paul, jmorris, serge
Cc: linux-doc, linux-kernel, linux-integrity, linux-security-module,
gregorylumen, nramas, Roberto Sassu, steven chen
In-Reply-To: <20260326173011.1191815-10-roberto.sassu@huaweicloud.com>
On 3/26/2026 10:30 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Introduce the ability of staging the IMA measurement list and deleting them
> with a prompt.
>
> Staging means moving the current content of the measurement list to a
> separate location, and allowing users to read and delete it. This causes
> the measurement list to be atomically truncated before new measurements can
> be added. Staging can be done only once at a time. In the event of kexec(),
> staging is reverted and staged entries will be carried over to the new
> kernel.
>
> Introduce ascii_runtime_measurements_<algo>_staged and
> binary_runtime_measurements_<algo>_staged interfaces to stage and delete
> the measurements. Use 'echo A > <IMA interface>' and
> 'echo D > <IMA interface>' to respectively stage and delete the entire
> measurements list. Locking of these interfaces is also mediated with a call
> to _ima_measurements_open() and with ima_measurements_release().
>
> Implement the staging functionality by introducing the new global
> measurements list ima_measurements_staged, and ima_queue_stage() and
> ima_queue_delete_staged_all() to respectively move measurements from the
> current measurements list to the staged one, and to move staged
> measurements to the ima_measurements_trim list for deletion. Introduce
> ima_queue_delete() to delete the measurements.
>
> Finally, introduce the BINARY_STAGED AND BINARY_FULL binary measurements
> list types, to maintain the counters and the binary size of staged
> measurements and the full measurements list (including entries that were
> staged). BINARY still represents the current binary measurements list.
>
> Use the binary size for the BINARY + BINARY_STAGED types in
> ima_add_kexec_buffer(), since both measurements list types are copied to
> the secondary kernel during kexec. Use BINARY_FULL in
> ima_measure_kexec_event(), to generate a critical data record.
>
> It should be noted that the BINARY_FULL counter is not passed through
> kexec. Thus, the number of entries included in the kexec critical data
> records refers to the entries since the previous kexec records.
>
> Note: This code derives from the Alt-IMA Huawei project, whose license is
> GPL-2.0 OR MIT.
>
> Link: https://github.com/linux-integrity/linux/issues/1
> Suggested-by: Gregory Lumen <gregorylumen@linux.microsoft.com> (staging revert)
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> security/integrity/ima/Kconfig | 13 +++
> security/integrity/ima/ima.h | 8 +-
> security/integrity/ima/ima_fs.c | 167 ++++++++++++++++++++++++++---
> security/integrity/ima/ima_kexec.c | 22 +++-
> security/integrity/ima/ima_queue.c | 97 ++++++++++++++++-
> 5 files changed, 286 insertions(+), 21 deletions(-)
>
> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
> index 976e75f9b9ba..e714726f3384 100644
> --- a/security/integrity/ima/Kconfig
> +++ b/security/integrity/ima/Kconfig
> @@ -332,4 +332,17 @@ config IMA_KEXEC_EXTRA_MEMORY_KB
> If set to the default value of 0, an extra half page of memory for those
> additional measurements will be allocated.
>
> +config IMA_STAGING
> + bool "Support for staging the measurements list"
> + default y
> + help
> + Add support for staging the measurements list.
> +
> + It allows user space to stage the measurements list for deletion and
> + to delete the staged measurements after confirmation.
> +
> + On kexec, staging is reverted and staged measurements are prepended
> + to the current measurements list when measurements are copied to the
> + secondary kernel.
> +
> endif
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index 97b7d6024b5d..65db152a0a24 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -30,9 +30,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
>
> /*
> * BINARY: current binary measurements list
> + * BINARY_STAGED: staged binary measurements list
> + * BINARY_FULL: binary measurements list since IMA init (lost after kexec)
> */
> enum binary_lists {
> - BINARY, BINARY__LAST
> + BINARY, BINARY_STAGED, BINARY_FULL, BINARY__LAST
> };
>
> /* digest size for IMA, fits SHA1 or MD5 */
> @@ -125,6 +127,7 @@ struct ima_queue_entry {
> struct ima_template_entry *entry;
> };
> extern struct list_head ima_measurements; /* list of all measurements */
> +extern struct list_head ima_measurements_staged; /* list of staged meas. */
>
> /* Some details preceding the binary serialized measurement list */
> struct ima_kexec_hdr {
> @@ -314,6 +317,8 @@ struct ima_template_desc *ima_template_desc_current(void);
> struct ima_template_desc *ima_template_desc_buf(void);
> struct ima_template_desc *lookup_template_desc(const char *name);
> bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
> +int ima_queue_stage(void);
> +int ima_queue_staged_delete_all(void);
> int ima_restore_measurement_entry(struct ima_template_entry *entry);
> int ima_restore_measurement_list(loff_t bufsize, void *buf);
> int ima_measurements_show(struct seq_file *m, void *v);
> @@ -334,6 +339,7 @@ extern spinlock_t ima_queue_lock;
> extern atomic_long_t ima_num_entries[BINARY__LAST];
> extern atomic_long_t ima_num_violations;
> extern struct hlist_head __rcu *ima_htable;
> +extern struct mutex ima_extend_list_mutex;
>
> static inline unsigned int ima_hash_key(u8 *digest)
> {
> diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
> index 7709a4576322..39d9128e9f22 100644
> --- a/security/integrity/ima/ima_fs.c
> +++ b/security/integrity/ima/ima_fs.c
> @@ -24,6 +24,13 @@
>
> #include "ima.h"
>
> +/*
> + * Requests:
> + * 'A\n': stage the entire measurements list
> + * 'D\n': delete all staged measurements
> + */
> +#define STAGED_REQ_LENGTH 21
> +
> static DEFINE_MUTEX(ima_write_mutex);
> static DEFINE_MUTEX(ima_measure_mutex);
> static long ima_measure_users;
> @@ -97,6 +104,11 @@ static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
> return _ima_measurements_start(m, pos, &ima_measurements);
> }
>
> +static void *ima_measurements_staged_start(struct seq_file *m, loff_t *pos)
> +{
> + return _ima_measurements_start(m, pos, &ima_measurements_staged);
> +}
> +
> static void *_ima_measurements_next(struct seq_file *m, void *v, loff_t *pos,
> struct list_head *head)
> {
> @@ -118,6 +130,12 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
> return _ima_measurements_next(m, v, pos, &ima_measurements);
> }
>
> +static void *ima_measurements_staged_next(struct seq_file *m, void *v,
> + loff_t *pos)
> +{
> + return _ima_measurements_next(m, v, pos, &ima_measurements_staged);
> +}
> +
> static void ima_measurements_stop(struct seq_file *m, void *v)
> {
> }
> @@ -283,6 +301,68 @@ static const struct file_operations ima_measurements_ops = {
> .release = ima_measurements_release,
> };
>
> +static const struct seq_operations ima_measurments_staged_seqops = {
> + .start = ima_measurements_staged_start,
> + .next = ima_measurements_staged_next,
> + .stop = ima_measurements_stop,
> + .show = ima_measurements_show
> +};
> +
> +static int ima_measurements_staged_open(struct inode *inode, struct file *file)
> +{
> + return _ima_measurements_open(inode, file,
> + &ima_measurments_staged_seqops);
> +}
> +
> +static ssize_t ima_measurements_staged_write(struct file *file,
> + const char __user *buf,
> + size_t datalen, loff_t *ppos)
> +{
> + char req[STAGED_REQ_LENGTH];
> + int ret;
> +
> + if (*ppos > 0 || datalen < 2 || datalen > STAGED_REQ_LENGTH)
> + return -EINVAL;
> +
> + if (copy_from_user(req, buf, datalen) != 0)
> + return -EFAULT;
> +
> + if (req[datalen - 1] != '\n')
> + return -EINVAL;
> +
> + req[datalen - 1] = '\0';
> +
> + switch (req[0]) {
> + case 'A':
> + if (datalen != 2)
> + return -EINVAL;
> +
> + ret = ima_queue_stage();
> + break;
> + case 'D':
> + if (datalen != 2)
> + return -EINVAL;
> +
> + ret = ima_queue_staged_delete_all();
> + break;
I think the following two steps may not work because of race condition:
step1: ret = ima_queue_stage(); //this will put all logs in active list into staged list;
step2: ret = ima_queue_staged_delete_all(); //this will delete all logs in staged list;
The following is the step of race condition:
1. current active log list LA1;
2. user agent read the TPM quote QA1 match list LA1;
3. new event NewLog is added into active log list LA1+NewLog
4. user agent call ima_queue_stage() and generated staged list
including LA1+NewLog.
5. user agent call ima_queue_staged_delete_all();
The new log NewLog in step 3 is also deleted
Next time the attestation will fail if using the active log list in the
kernel.
Thanks,
Steven
> + default:
> + ret = -EINVAL;
> + }
> +
> + if (ret < 0)
> + return ret;
> +
> + return datalen;
> +}
> +
> +static const struct file_operations ima_measurements_staged_ops = {
> + .open = ima_measurements_staged_open,
> + .read = seq_read,
> + .write = ima_measurements_staged_write,
> + .llseek = seq_lseek,
> + .release = ima_measurements_release,
> +};
> +
> void ima_print_digest(struct seq_file *m, u8 *digest, u32 size)
> {
> u32 i;
> @@ -356,6 +436,28 @@ static const struct file_operations ima_ascii_measurements_ops = {
> .release = ima_measurements_release,
> };
>
> +static const struct seq_operations ima_ascii_measurements_staged_seqops = {
> + .start = ima_measurements_staged_start,
> + .next = ima_measurements_staged_next,
> + .stop = ima_measurements_stop,
> + .show = ima_ascii_measurements_show
> +};
> +
> +static int ima_ascii_measurements_staged_open(struct inode *inode,
> + struct file *file)
> +{
> + return _ima_measurements_open(inode, file,
> + &ima_ascii_measurements_staged_seqops);
> +}
> +
> +static const struct file_operations ima_ascii_measurements_staged_ops = {
> + .open = ima_ascii_measurements_staged_open,
> + .read = seq_read,
> + .write = ima_measurements_staged_write,
> + .llseek = seq_lseek,
> + .release = ima_measurements_release,
> +};
> +
> static ssize_t ima_read_policy(char *path)
> {
> void *data = NULL;
> @@ -459,10 +561,21 @@ static const struct seq_operations ima_policy_seqops = {
> };
> #endif
>
> -static int __init create_securityfs_measurement_lists(void)
> +static int __init create_securityfs_measurement_lists(bool staging)
> {
> + const struct file_operations *ascii_ops = &ima_ascii_measurements_ops;
> + const struct file_operations *binary_ops = &ima_measurements_ops;
> + mode_t permissions = S_IRUSR | S_IRGRP;
> + const char *file_suffix = "";
> int count = NR_BANKS(ima_tpm_chip);
>
> + if (staging) {
> + ascii_ops = &ima_ascii_measurements_staged_ops;
> + binary_ops = &ima_measurements_staged_ops;
> + file_suffix = "_staged";
> + permissions |= (S_IWUSR | S_IWGRP);
> + }
> +
> if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip))
> count++;
>
> @@ -473,29 +586,32 @@ static int __init create_securityfs_measurement_lists(void)
>
> if (algo == HASH_ALGO__LAST)
> snprintf(file_name, sizeof(file_name),
> - "ascii_runtime_measurements_tpm_alg_%x",
> - ima_tpm_chip->allocated_banks[i].alg_id);
> + "ascii_runtime_measurements_tpm_alg_%x%s",
> + ima_tpm_chip->allocated_banks[i].alg_id,
> + file_suffix);
> else
> snprintf(file_name, sizeof(file_name),
> - "ascii_runtime_measurements_%s",
> - hash_algo_name[algo]);
> - dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> + "ascii_runtime_measurements_%s%s",
> + hash_algo_name[algo], file_suffix);
> + dentry = securityfs_create_file(file_name, permissions,
> ima_dir, (void *)(uintptr_t)i,
> - &ima_ascii_measurements_ops);
> + ascii_ops);
> if (IS_ERR(dentry))
> return PTR_ERR(dentry);
>
> if (algo == HASH_ALGO__LAST)
> snprintf(file_name, sizeof(file_name),
> - "binary_runtime_measurements_tpm_alg_%x",
> - ima_tpm_chip->allocated_banks[i].alg_id);
> + "binary_runtime_measurements_tpm_alg_%x%s",
> + ima_tpm_chip->allocated_banks[i].alg_id,
> + file_suffix);
> else
> snprintf(file_name, sizeof(file_name),
> - "binary_runtime_measurements_%s",
> - hash_algo_name[algo]);
> - dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> + "binary_runtime_measurements_%s%s",
> + hash_algo_name[algo], file_suffix);
> +
> + dentry = securityfs_create_file(file_name, permissions,
> ima_dir, (void *)(uintptr_t)i,
> - &ima_measurements_ops);
> + binary_ops);
> if (IS_ERR(dentry))
> return PTR_ERR(dentry);
> }
> @@ -503,6 +619,23 @@ static int __init create_securityfs_measurement_lists(void)
> return 0;
> }
>
> +static int __init create_securityfs_staging_links(void)
> +{
> + struct dentry *dentry;
> +
> + dentry = securityfs_create_symlink("binary_runtime_measurements_staged",
> + ima_dir, "binary_runtime_measurements_sha1_staged", NULL);
> + if (IS_ERR(dentry))
> + return PTR_ERR(dentry);
> +
> + dentry = securityfs_create_symlink("ascii_runtime_measurements_staged",
> + ima_dir, "ascii_runtime_measurements_sha1_staged", NULL);
> + if (IS_ERR(dentry))
> + return PTR_ERR(dentry);
> +
> + return 0;
> +}
> +
> /*
> * ima_open_policy: sequentialize access to the policy file
> */
> @@ -595,7 +728,13 @@ int __init ima_fs_init(void)
> goto out;
> }
>
> - ret = create_securityfs_measurement_lists();
> + ret = create_securityfs_measurement_lists(false);
> + if (ret == 0 && IS_ENABLED(CONFIG_IMA_STAGING)) {
> + ret = create_securityfs_measurement_lists(true);
> + if (ret == 0)
> + ret = create_securityfs_staging_links();
> + }
> +
> if (ret != 0)
> goto out;
>
> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> index d7d0fb639d99..d5503dd5cc9b 100644
> --- a/security/integrity/ima/ima_kexec.c
> +++ b/security/integrity/ima/ima_kexec.c
> @@ -42,8 +42,8 @@ void ima_measure_kexec_event(const char *event_name)
> long len;
> int n;
>
> - buf_size = ima_get_binary_runtime_size(BINARY);
> - len = atomic_long_read(&ima_num_entries[BINARY]);
> + buf_size = ima_get_binary_runtime_size(BINARY_FULL);
> + len = atomic_long_read(&ima_num_entries[BINARY_FULL]);
>
> n = scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN,
> "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;"
> @@ -106,13 +106,26 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
>
> memset(&khdr, 0, sizeof(khdr));
> khdr.version = 1;
> - /* This is an append-only list, no need to hold the RCU read lock */
> - list_for_each_entry_rcu(qe, &ima_measurements, later, true) {
> + /* It can race with ima_queue_stage() and ima_queue_delete_staged(). */
> + mutex_lock(&ima_extend_list_mutex);
> +
> + list_for_each_entry_rcu(qe, &ima_measurements_staged, later,
> + lockdep_is_held(&ima_extend_list_mutex)) {
> ret = ima_dump_measurement(&khdr, qe);
> if (ret < 0)
> break;
> }
>
> + list_for_each_entry_rcu(qe, &ima_measurements, later,
> + lockdep_is_held(&ima_extend_list_mutex)) {
> + if (!ret)
> + ret = ima_dump_measurement(&khdr, qe);
> + if (ret < 0)
> + break;
> + }
> +
> + mutex_unlock(&ima_extend_list_mutex);
> +
> /*
> * fill in reserved space with some buffer details
> * (eg. version, buffer size, number of measurements)
> @@ -167,6 +180,7 @@ void ima_add_kexec_buffer(struct kimage *image)
> extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
>
> binary_runtime_size = ima_get_binary_runtime_size(BINARY) +
> + ima_get_binary_runtime_size(BINARY_STAGED) +
> extra_memory;
>
> if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
> index b6d10dceb669..50519ed837d4 100644
> --- a/security/integrity/ima/ima_queue.c
> +++ b/security/integrity/ima/ima_queue.c
> @@ -26,6 +26,7 @@
> static struct tpm_digest *digests;
>
> LIST_HEAD(ima_measurements); /* list of all measurements */
> +LIST_HEAD(ima_measurements_staged); /* list of staged measurements */
> #ifdef CONFIG_IMA_KEXEC
> static unsigned long binary_runtime_size[BINARY__LAST];
> #else
> @@ -45,11 +46,11 @@ atomic_long_t ima_num_violations = ATOMIC_LONG_INIT(0);
> /* key: inode (before secure-hashing a file) */
> struct hlist_head __rcu *ima_htable;
>
> -/* mutex protects atomicity of extending measurement list
> +/* mutex protects atomicity of extending and staging measurement list
> * and extending the TPM PCR aggregate. Since tpm_extend can take
> * long (and the tpm driver uses a mutex), we can't use the spinlock.
> */
> -static DEFINE_MUTEX(ima_extend_list_mutex);
> +DEFINE_MUTEX(ima_extend_list_mutex);
>
> /*
> * Used internally by the kernel to suspend measurements.
> @@ -174,12 +175,16 @@ static int ima_add_digest_entry(struct ima_template_entry *entry,
> lockdep_is_held(&ima_extend_list_mutex));
>
> atomic_long_inc(&ima_num_entries[BINARY]);
> + atomic_long_inc(&ima_num_entries[BINARY_FULL]);
> +
> if (update_htable) {
> key = ima_hash_key(entry->digests[ima_hash_algo_idx].digest);
> hlist_add_head_rcu(&qe->hnext, &htable[key]);
> }
>
> ima_update_binary_runtime_size(entry, BINARY);
> + ima_update_binary_runtime_size(entry, BINARY_FULL);
> +
> return 0;
> }
>
> @@ -280,6 +285,94 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
> return result;
> }
>
> +int ima_queue_stage(void)
> +{
> + int ret = 0;
> +
> + mutex_lock(&ima_extend_list_mutex);
> + if (!list_empty(&ima_measurements_staged)) {
> + ret = -EEXIST;
> + goto out_unlock;
> + }
> +
> + if (list_empty(&ima_measurements)) {
> + ret = -ENOENT;
> + goto out_unlock;
> + }
> +
> + list_replace(&ima_measurements, &ima_measurements_staged);
> + INIT_LIST_HEAD(&ima_measurements);
> +
> + atomic_long_set(&ima_num_entries[BINARY_STAGED],
> + atomic_long_read(&ima_num_entries[BINARY]));
> + atomic_long_set(&ima_num_entries[BINARY], 0);
> +
> + if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
> + binary_runtime_size[BINARY_STAGED] =
> + binary_runtime_size[BINARY];
> + binary_runtime_size[BINARY] = 0;
> + }
> +out_unlock:
> + mutex_unlock(&ima_extend_list_mutex);
> + return ret;
> +}
> +
> +static void ima_queue_delete(struct list_head *head);
> +
> +int ima_queue_staged_delete_all(void)
> +{
> + LIST_HEAD(ima_measurements_trim);
> +
> + mutex_lock(&ima_extend_list_mutex);
> + if (list_empty(&ima_measurements_staged)) {
> + mutex_unlock(&ima_extend_list_mutex);
> + return -ENOENT;
> + }
> +
> + list_replace(&ima_measurements_staged, &ima_measurements_trim);
> + INIT_LIST_HEAD(&ima_measurements_staged);
> +
> + atomic_long_set(&ima_num_entries[BINARY_STAGED], 0);
> +
> + if (IS_ENABLED(CONFIG_IMA_KEXEC))
> + binary_runtime_size[BINARY_STAGED] = 0;
> +
> + mutex_unlock(&ima_extend_list_mutex);
> +
> + ima_queue_delete(&ima_measurements_trim);
> + return 0;
> +}
> +
> +static void ima_queue_delete(struct list_head *head)
> +{
> + struct ima_queue_entry *qe, *qe_tmp;
> + unsigned int i;
> +
> + list_for_each_entry_safe(qe, qe_tmp, head, later) {
> + /*
> + * Safe to free template_data here without synchronize_rcu()
> + * because the only htable reader, ima_lookup_digest_entry(),
> + * accesses only entry->digests, not template_data. If new
> + * htable readers are added that access template_data, a
> + * synchronize_rcu() is required here.
> + */
> + for (i = 0; i < qe->entry->template_desc->num_fields; i++) {
> + kfree(qe->entry->template_data[i].data);
> + qe->entry->template_data[i].data = NULL;
> + qe->entry->template_data[i].len = 0;
> + }
> +
> + list_del(&qe->later);
> +
> + /* No leak if condition is false, referenced by ima_htable. */
> + if (IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) {
> + kfree(qe->entry->digests);
> + kfree(qe->entry);
> + kfree(qe);
> + }
> + }
> +}
> +
> int ima_restore_measurement_entry(struct ima_template_entry *entry)
> {
> int result = 0;
^ permalink raw reply
* Re: [PATCH] checkpatch: allow correctly handle full files on stdin
From: Joe Perches @ 2026-03-26 22:56 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Dwaipayan Ray, Lukas Bulwahn, Andy Whitcroft, Jonathan Corbet,
Shuah Khan, workflows, linux-doc, linux-kernel
In-Reply-To: <acWnbG3nGjfYeYXh@google.com>
On Thu, 2026-03-26 at 14:42 -0700, Dmitry Torokhov wrote:
> > > Because when I am editing a file I am not saving it all that often. I
> > > want to have buffer diagnostic updated when I leave insert mode in vim.
> >
> > I believe you are able to keep your own version of checkpatch.
>
> As well as my version of the kernel, gcc, clang, editor, git and so on.
>
> Do you have any constructive feedback?
I gave you feedback. You elided it.
> Right now checkpatch is broken
> when using "-f" with stdin and I offer a fix. If you have a better way
> in mind by all means share it.
Note the name. Feed it a patch. It works fine. It's not broken.
^ permalink raw reply
* Re: [PATCH v2] doc: Add CPU Isolation documentation
From: Steven Rostedt @ 2026-03-26 23:00 UTC (permalink / raw)
To: Randy Dunlap
Cc: Frederic Weisbecker, LKML, Anna-Maria Behnsen, Gabriele Monaco,
Ingo Molnar, Jonathan Corbet, Marcelo Tosatti, Marco Crivellari,
Michal Hocko, Paul E . McKenney, Peter Zijlstra, Phil Auld,
Thomas Gleixner, Valentin Schneider, Vlastimil Babka, Waiman Long,
linux-doc, Sebastian Andrzej Siewior, Bagas Sanjaya
In-Reply-To: <6d113021-6208-4dcc-a209-a2317d680e3f@infradead.org>
On Thu, 26 Mar 2026 14:42:32 -0700
Randy Dunlap <rdunlap@infradead.org> wrote:
> > +Those interferences, commonly pointed out as "noise", can be triggered
>
> nit: "noise,"
Really?
Even if it's grammatically correct, it still looks horrible.
Those interferences, commonly pointed out as "noise", can be triggered
vs
Those interferences, commonly pointed out as "noise," can be triggered
As the quotes are going around the noun, and placing the comma into the
quotes makes it look like the ',' is part of that noun and not a
punctuation of the sentence.
Being read by C programmers, I would keep he ',' out of the quotes as it
looks like a string literal "noun,".
-- Steve
^ permalink raw reply
* Re: [PATCH v2] doc: Add CPU Isolation documentation
From: Steven Rostedt @ 2026-03-26 23:01 UTC (permalink / raw)
To: Randy Dunlap
Cc: Frederic Weisbecker, LKML, Anna-Maria Behnsen, Gabriele Monaco,
Ingo Molnar, Jonathan Corbet, Marcelo Tosatti, Marco Crivellari,
Michal Hocko, Paul E . McKenney, Peter Zijlstra, Phil Auld,
Thomas Gleixner, Valentin Schneider, Vlastimil Babka, Waiman Long,
linux-doc, Sebastian Andrzej Siewior, Bagas Sanjaya
In-Reply-To: <20260326190022.4b249f94@gandalf.local.home>
On Thu, 26 Mar 2026 19:00:22 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:
> Being read by C programmers, I would keep he ',' out of the quotes as it
> looks like a string literal "noun,".
Or was that supposed to be: a string literal "noun,." ;-)
-- Steve
^ permalink raw reply
* Re: [PATCH v2] doc: Add CPU Isolation documentation
From: Randy Dunlap @ 2026-03-26 23:03 UTC (permalink / raw)
To: Steven Rostedt
Cc: Frederic Weisbecker, LKML, Anna-Maria Behnsen, Gabriele Monaco,
Ingo Molnar, Jonathan Corbet, Marcelo Tosatti, Marco Crivellari,
Michal Hocko, Paul E . McKenney, Peter Zijlstra, Phil Auld,
Thomas Gleixner, Valentin Schneider, Vlastimil Babka, Waiman Long,
linux-doc, Sebastian Andrzej Siewior, Bagas Sanjaya
In-Reply-To: <20260326190022.4b249f94@gandalf.local.home>
On 3/26/26 4:00 PM, Steven Rostedt wrote:
> On Thu, 26 Mar 2026 14:42:32 -0700
> Randy Dunlap <rdunlap@infradead.org> wrote:
>
>>> +Those interferences, commonly pointed out as "noise", can be triggered
>>
>> nit: "noise,"
>
> Really?
>
> Even if it's grammatically correct, it still looks horrible.
>
> Those interferences, commonly pointed out as "noise", can be triggered
>
> vs
>
> Those interferences, commonly pointed out as "noise," can be triggered
>
> As the quotes are going around the noun, and placing the comma into the
> quotes makes it look like the ',' is part of that noun and not a
> punctuation of the sentence.
>
> Being read by C programmers, I would keep he ',' out of the quotes as it
he ? :)
> looks like a string literal "noun,".
Stephen, all I can do is make recommendations. If it hurts your eyes, tough. ;)
--
~Randy
^ permalink raw reply
* Re: [PATCH] checkpatch: allow correctly handle full files on stdin
From: Dmitry Torokhov @ 2026-03-26 23:04 UTC (permalink / raw)
To: Joe Perches
Cc: Dwaipayan Ray, Lukas Bulwahn, Andy Whitcroft, Jonathan Corbet,
Shuah Khan, workflows, linux-doc, linux-kernel
In-Reply-To: <34318752a257b0f6b530eacf53d565de1ac84485.camel@perches.com>
On Thu, Mar 26, 2026 at 03:56:27PM -0700, Joe Perches wrote:
> On Thu, 2026-03-26 at 14:42 -0700, Dmitry Torokhov wrote:
> > > > Because when I am editing a file I am not saving it all that often. I
> > > > want to have buffer diagnostic updated when I leave insert mode in vim.
> > >
> > > I believe you are able to keep your own version of checkpatch.
> >
> > As well as my version of the kernel, gcc, clang, editor, git and so on.
> >
> > Do you have any constructive feedback?
>
> I gave you feedback. You elided it.
Could you please point me to it? All I saw is "just save it" and "keep
your own copy". Neither of this suggestions are particularly useful.
>
> > Right now checkpatch is broken
> > when using "-f" with stdin and I offer a fix. If you have a better way
> > in mind by all means share it.
>
> Note the name. Feed it a patch. It works fine. It's not broken.
This option is a bug then and should be removed:
"-f, --file treat FILE as regular source file"
right?
In all seriousness, if you will not make use of this mode it's fine. But
it allows keeping the source cleaner as one makes edits, so why not
enable this?
--
Dmitry
^ permalink raw reply
* Re: [PATCH v2] doc: Add CPU Isolation documentation
From: Steven Rostedt @ 2026-03-26 23:06 UTC (permalink / raw)
To: Randy Dunlap
Cc: Frederic Weisbecker, LKML, Anna-Maria Behnsen, Gabriele Monaco,
Ingo Molnar, Jonathan Corbet, Marcelo Tosatti, Marco Crivellari,
Michal Hocko, Paul E . McKenney, Peter Zijlstra, Phil Auld,
Thomas Gleixner, Valentin Schneider, Vlastimil Babka, Waiman Long,
linux-doc, Sebastian Andrzej Siewior, Bagas Sanjaya
In-Reply-To: <b5e6c518-c7c8-46f7-928c-d4be5a8365dd@infradead.org>
On Thu, 26 Mar 2026 16:03:18 -0700
Randy Dunlap <rdunlap@infradead.org> wrote:
> Stephen, all I can do is make recommendations. If it hurts your eyes, tough. ;)
Who's this "Stephen" you are talking to?
-- Steve
^ permalink raw reply
* Re: [PATCH v2] doc: Add CPU Isolation documentation
From: Randy Dunlap @ 2026-03-26 23:09 UTC (permalink / raw)
To: Steven Rostedt
Cc: Frederic Weisbecker, LKML, Anna-Maria Behnsen, Gabriele Monaco,
Ingo Molnar, Jonathan Corbet, Marcelo Tosatti, Marco Crivellari,
Michal Hocko, Paul E . McKenney, Peter Zijlstra, Phil Auld,
Thomas Gleixner, Valentin Schneider, Vlastimil Babka, Waiman Long,
linux-doc, Sebastian Andrzej Siewior, Bagas Sanjaya
In-Reply-To: <20260326190644.4b7c2b5f@gandalf.local.home>
On 3/26/26 4:06 PM, Steven Rostedt wrote:
> On Thu, 26 Mar 2026 16:03:18 -0700
> Randy Dunlap <rdunlap@infradead.org> wrote:
>
>> Stephen, all I can do is make recommendations. If it hurts your eyes, tough. ;)
>
> Who's this "Stephen" you are talking to?
Oops. I guess it's the one who accidentally wrote "he" instead of "the".
(Do you like where that period ^ is,
even though it's incorrect? :)
--
~Randy
^ permalink raw reply
* Re: [PATCH] checkpatch: allow correctly handle full files on stdin
From: Joe Perches @ 2026-03-26 23:10 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Dwaipayan Ray, Lukas Bulwahn, Andy Whitcroft, Jonathan Corbet,
Shuah Khan, workflows, linux-doc, linux-kernel
In-Reply-To: <acW6Iar6XOzO9IfN@google.com>
On Thu, 2026-03-26 at 16:04 -0700, Dmitry Torokhov wrote:
> On Thu, Mar 26, 2026 at 03:56:27PM -0700, Joe Perches wrote:
> > I gave you feedback. You elided it.
> Could you please point me to it? All I saw is "just save it"
Seems constructive to me.
^ permalink raw reply
* Re: [PATCH v2] doc: Add CPU Isolation documentation
From: Steven Rostedt @ 2026-03-26 23:16 UTC (permalink / raw)
To: Randy Dunlap
Cc: Frederic Weisbecker, LKML, Anna-Maria Behnsen, Gabriele Monaco,
Ingo Molnar, Jonathan Corbet, Marcelo Tosatti, Marco Crivellari,
Michal Hocko, Paul E . McKenney, Peter Zijlstra, Phil Auld,
Thomas Gleixner, Valentin Schneider, Vlastimil Babka, Waiman Long,
linux-doc, Sebastian Andrzej Siewior, Bagas Sanjaya
In-Reply-To: <17c061f5-b864-4652-b4a2-356c7534d42b@infradead.org>
On Thu, 26 Mar 2026 16:09:15 -0700
Randy Dunlap <rdunlap@infradead.org> wrote:
> On 3/26/26 4:06 PM, Steven Rostedt wrote:
> > On Thu, 26 Mar 2026 16:03:18 -0700
> > Randy Dunlap <rdunlap@infradead.org> wrote:
> >
> >> Stephen, all I can do is make recommendations. If it hurts your eyes, tough. ;)
> >
> > Who's this "Stephen" you are talking to?
>
> Oops. I guess it's the one who accidentally wrote "he" instead of "the".
> (Do you like where that period ^ is,
> even though it's incorrect? :)
>
Yes, Randi, I like where that period is. I also need to fix my 't' on my
keyboard as it seems to act shy sometimes.
-- Steve
^ permalink raw reply
* Re: [PATCH] checkpatch: allow correctly handle full files on stdin
From: Dmitry Torokhov @ 2026-03-26 23:19 UTC (permalink / raw)
To: Joe Perches, Andrew Morton
Cc: Dwaipayan Ray, Lukas Bulwahn, Andy Whitcroft, Jonathan Corbet,
Shuah Khan, workflows, linux-doc, linux-kernel
In-Reply-To: <3217a61e50f7b9fd387b908c0907bd0bf889bebb.camel@perches.com>
On Thu, Mar 26, 2026 at 04:10:05PM -0700, Joe Perches wrote:
> On Thu, 2026-03-26 at 16:04 -0700, Dmitry Torokhov wrote:
> > On Thu, Mar 26, 2026 at 03:56:27PM -0700, Joe Perches wrote:
> > > I gave you feedback. You elided it.
> > Could you please point me to it? All I saw is "just save it"
>
> Seems constructive to me.
As constructive as "You're holding it wrong". I want to be able to run
checkpatch as I am typing, not at some later time. My editor shows
diagnostics as a virtual text, so it is quite confusing that the error
is still shown even after I fixed the issue.
It looks like I forgot to add akpm to CC, let me add him...
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] checkpatch: allow correctly handle full files on stdin
From: Joe Perches @ 2026-03-26 23:19 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Dwaipayan Ray, Lukas Bulwahn, Andy Whitcroft, Jonathan Corbet,
Shuah Khan, workflows, linux-doc, linux-kernel
In-Reply-To: <acW6Iar6XOzO9IfN@google.com>
On Thu, 2026-03-26 at 16:04 -0700, Dmitry Torokhov wrote:
> In all seriousness, if you will not make use of this mode it's fine. But
> it allows keeping the source cleaner as one makes edits, so why not
> enable this?
Unnecessary complication.
^ permalink raw reply
* Re: [PATCH v4 11/13] ima: Support staging and deleting N measurements entries
From: steven chen @ 2026-03-26 23:19 UTC (permalink / raw)
To: Roberto Sassu, corbet, skhan, zohar, dmitry.kasatkin,
eric.snowberg, paul, jmorris, serge
Cc: linux-doc, linux-kernel, linux-integrity, linux-security-module,
gregorylumen, nramas, Roberto Sassu
In-Reply-To: <20260326173011.1191815-12-roberto.sassu@huaweicloud.com>
On 3/26/2026 10:30 AM, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Add support for sending a value N between 1 and ULONG_MAX to the staging
> interface. This value represents the number of measurements that should be
> deleted from the current measurements list.
>
> This staging method allows the remote attestation agents to easily separate
> the measurements that were verified (staged and deleted) from those that
> weren't due to the race between taking a TPM quote and reading the
> measurements list.
>
> In order to minimize the locking time of ima_extend_list_mutex, deleting
> N entries is realized by staging the entire current measurements list
> (with the lock), by determining the N-th staged entry (without the lock),
> and by splicing the entries in excess back to the current measurements list
> (with the lock). Finally, the N entries are deleted (without the lock).
>
> Flushing the hash table is not supported for N entries, since it would
> require removing the N entries one by one from the hash table under the
> ima_extend_list_mutex lock, which would increase the locking time.
>
> The ima_extend_list_mutex lock is necessary in ima_dump_measurement_list()
> because ima_queue_staged_delete_partial() uses __list_cut_position() to
> modify ima_measurements_staged, for which no RCU-safe variant exists. For
> the staging with prompt flavor alone, list_replace_rcu() could have been
> used instead, but since both flavors share the same kexec serialization
> path, the mutex is required regardless.
>
> Link: https://github.com/linux-integrity/linux/issues/1
> Suggested-by: Steven Chen <chenste@linux.microsoft.com>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> security/integrity/ima/Kconfig | 3 ++
> security/integrity/ima/ima.h | 1 +
> security/integrity/ima/ima_fs.c | 22 +++++++++-
> security/integrity/ima/ima_queue.c | 70 ++++++++++++++++++++++++++++++
> 4 files changed, 95 insertions(+), 1 deletion(-)
>
> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
> index e714726f3384..6ddb4e77bff5 100644
> --- a/security/integrity/ima/Kconfig
> +++ b/security/integrity/ima/Kconfig
> @@ -341,6 +341,9 @@ config IMA_STAGING
> It allows user space to stage the measurements list for deletion and
> to delete the staged measurements after confirmation.
>
> + Or, alternatively, it allows user space to specify N measurements
> + entries to be deleted.
> +
> On kexec, staging is reverted and staged measurements are prepended
> to the current measurements list when measurements are copied to the
> secondary kernel.
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index 699b735dec7d..de0693fce53c 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -319,6 +319,7 @@ struct ima_template_desc *lookup_template_desc(const char *name);
> bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
> int ima_queue_stage(void);
> int ima_queue_staged_delete_all(void);
> +int ima_queue_staged_delete_partial(unsigned long req_value);
> int ima_restore_measurement_entry(struct ima_template_entry *entry);
> int ima_restore_measurement_list(loff_t bufsize, void *buf);
> int ima_measurements_show(struct seq_file *m, void *v);
> diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
> index 39d9128e9f22..eb3f343c1138 100644
> --- a/security/integrity/ima/ima_fs.c
> +++ b/security/integrity/ima/ima_fs.c
> @@ -28,6 +28,7 @@
> * Requests:
> * 'A\n': stage the entire measurements list
> * 'D\n': delete all staged measurements
> + * '[1, ULONG_MAX]\n' delete N measurements entries
> */
> #define STAGED_REQ_LENGTH 21
>
> @@ -319,6 +320,7 @@ static ssize_t ima_measurements_staged_write(struct file *file,
> size_t datalen, loff_t *ppos)
> {
> char req[STAGED_REQ_LENGTH];
> + unsigned long req_value;
> int ret;
>
> if (*ppos > 0 || datalen < 2 || datalen > STAGED_REQ_LENGTH)
> @@ -346,7 +348,25 @@ static ssize_t ima_measurements_staged_write(struct file *file,
> ret = ima_queue_staged_delete_all();
> break;
> default:
> - ret = -EINVAL;
> + if (ima_flush_htable) {
> + pr_debug("Deleting staged N measurements not supported when flushing the hash table is requested\n");
> + return -EINVAL;
> + }
> +
> + ret = kstrtoul(req, 10, &req_value);
> + if (ret < 0)
> + return ret;
> +
> + if (req_value == 0) {
> + pr_debug("Must delete at least one entry\n");
> + return -EINVAL;
> + }
> +
> + ret = ima_queue_stage();
> + if (ret < 0)
> + return ret;
> +
> + ret = ima_queue_staged_delete_partial(req_value);
The default processing is "Trim N" idea plus performance improvement.
Here do everything in one time. And this is what I said in v3.
[PATCH v3 1/3] ima: Remove ima_h_table structure
<https://lore.kernel.org/linux-integrity/c61aeaa79929a98cb3a6d30835972891fac3570f.camel@linux.ibm.com/T/#t>
The important two parts of trimming is "trim N" and performance improvement.
The performance improvement include two parts:
hash table staging
active log list staging
And I think "Trim N" plus performance improvement is the right direction
to go.
Lots of code for two steps "stage and trim" "stage" part can be removed.
Also race condition may happen if not holding the list all time in user
space
during attestation period: from stage, read list, attestation and trimming.
So in order to improve the above user space lock time, "Trim T:N" can be
used
not to hold list long in user space during attestation.
For Trim T:N, T represent total log trimmed since system boot up. Please
refer to
https://lore.kernel.org/linux-integrity/20260205235849.7086-1-chenste@linux.microsoft.com/T/#t
Thanks,
Steven
> }
>
> if (ret < 0)
> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
> index f5c18acfbc43..4fb557d61a88 100644
> --- a/security/integrity/ima/ima_queue.c
> +++ b/security/integrity/ima/ima_queue.c
> @@ -371,6 +371,76 @@ int ima_queue_staged_delete_all(void)
> return 0;
> }
>
> +int ima_queue_staged_delete_partial(unsigned long req_value)
> +{
> + unsigned long req_value_copy = req_value;
> + unsigned long size_to_remove = 0, num_to_remove = 0;
> + struct list_head *cut_pos = NULL;
> + LIST_HEAD(ima_measurements_trim);
> + struct ima_queue_entry *qe;
> + int ret = 0;
> +
> + /*
> + * Safe walk (no concurrent write), not under ima_extend_list_mutex
> + * for performance reasons.
> + */
> + list_for_each_entry(qe, &ima_measurements_staged, later) {
> + size_to_remove += get_binary_runtime_size(qe->entry);
> + num_to_remove++;
> +
> + if (--req_value_copy == 0) {
> + /* qe->later always points to a valid list entry. */
> + cut_pos = &qe->later;
> + break;
> + }
> + }
> +
> + /* Nothing to remove, undoing staging. */
> + if (req_value_copy > 0) {
> + size_to_remove = 0;
> + num_to_remove = 0;
> + ret = -ENOENT;
> + }
> +
> + mutex_lock(&ima_extend_list_mutex);
> + if (list_empty(&ima_measurements_staged)) {
> + mutex_unlock(&ima_extend_list_mutex);
> + return -ENOENT;
> + }
> +
> + if (cut_pos != NULL)
> + /*
> + * ima_dump_measurement_list() does not modify the list,
> + * cut_pos remains the same even if it was computed before
> + * the lock.
> + */
> + __list_cut_position(&ima_measurements_trim,
> + &ima_measurements_staged, cut_pos);
> +
> + atomic_long_sub(num_to_remove, &ima_num_entries[BINARY_STAGED]);
> + atomic_long_add(atomic_long_read(&ima_num_entries[BINARY_STAGED]),
> + &ima_num_entries[BINARY]);
> + atomic_long_set(&ima_num_entries[BINARY_STAGED], 0);
> +
> + if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
> + binary_runtime_size[BINARY_STAGED] -= size_to_remove;
> + binary_runtime_size[BINARY] +=
> + binary_runtime_size[BINARY_STAGED];
> + binary_runtime_size[BINARY_STAGED] = 0;
> + }
> +
> + /*
> + * Splice (prepend) any remaining non-deleted staged entries to the
> + * active list (RCU not needed, there cannot be concurrent readers).
> + */
> + list_splice(&ima_measurements_staged, &ima_measurements);
> + INIT_LIST_HEAD(&ima_measurements_staged);
> + mutex_unlock(&ima_extend_list_mutex);
> +
> + ima_queue_delete(&ima_measurements_trim, false);
> + return ret;
> +}
> +
> static void ima_queue_delete(struct list_head *head, bool flush_htable)
> {
> struct ima_queue_entry *qe, *qe_tmp;
^ permalink raw reply
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