[PATCH makedumpfile] Add confidential VM unaccepted free pages support on Linux 6.16 and later
Zhiquan Li
zhiquan1.li at intel.com
Sun Jun 8 22:02:44 PDT 2025
UEFI Specification version 2.9 introduces the concept of memory
acceptance: some Virtual Machine platforms, such as Intel TDX or AMD
SEV-SNP, requiring memory to be accepted before it can be used by the
guest. Accepting happens via a protocol specific for the Virtual
Machine platform[1].
Before unaccepted memory is accepted by guest, any access from guest
will result in the guest failed, as well as the kexec'ed kernel. So,
the kexec'ed kernel will skip these pages and fill in zero data for the
reader of vmcore.
However, it introduces a problem. When exclude a page filled with zero,
a pd_zero, which sizeof(page_desc_t) is 24 bytes, will be written into
cd_header and this part is not compressed by design. As the unaccepted
pages are exported as zero pages, which means ~1/170 of the capacity of
unaccepted memory will be added into vmcore additionally. In fact, they
should be considered as free pages and most of the time should be
excluded.
Unaccepted memory is unusable free memory, so they are not managed by
buddy, instead, they are added to a new list zone.unaccepted_pages only
when the order is MAX_PAGE_ORDER each time conventionally. The new
page type, PGTY_unaccepted can be used to identify whether a page is
unaccepted[2]. Therefore, add following changes to exclude them like
free pages:
1. Add NUMBER(PAGE_UNACCEPTED_MAPCOUNT_VALUE) to identify a page is
unaccepted, a kernel patch[3] to export the value of page type
PAGE_UNACCEPTED_MAPCOUNT_VALUE since kernel 6.16.
2. Add a condition to exclude these unaccepted free pages.
Dumping host kernel will not be impacted by the modification, because it
cannot enable CONFIG_UNACCEPTED_MEMORY, so the page type
PAGE_UNACCEPTED_MAPCOUNT_VALUE cannot be found in vmcoreinfo and skip
the step.
Here is a vmcore size statistic of a freshly booted TD VM with different
memory sizes:
VM.mem | Before After
-------+----------------
512G | ~4.9G ~2.0G
256G | ~2.0G ~1.1G
[1] https://lore.kernel.org/all/20230606142637.5171-1-kirill.shutemov@linux.intel.com/
[2] https://lore.kernel.org/all/20240809114854.3745464-5-kirill.shutemov@linux.intel.com/
[3] https://lore.kernel.org/all/20250405060610.860465-1-zhiquan1.li@intel.com/
Signed-off-by: Zhiquan Li <zhiquan1.li at intel.com>
---
makedumpfile.c | 14 ++++++++++++++
makedumpfile.h | 3 +++
2 files changed, 17 insertions(+)
diff --git a/makedumpfile.c b/makedumpfile.c
index 2d3b08bb5d52..97ec2f06108b 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -2533,6 +2533,8 @@ write_vmcoreinfo_data(void)
WRITE_NUMBER("PAGE_BUDDY_MAPCOUNT_VALUE", PAGE_BUDDY_MAPCOUNT_VALUE);
WRITE_NUMBER("PAGE_OFFLINE_MAPCOUNT_VALUE",
PAGE_OFFLINE_MAPCOUNT_VALUE);
+ WRITE_NUMBER("PAGE_UNACCEPTED_MAPCOUNT_VALUE",
+ PAGE_UNACCEPTED_MAPCOUNT_VALUE);
WRITE_NUMBER("phys_base", phys_base);
WRITE_NUMBER("KERNEL_IMAGE_SIZE", KERNEL_IMAGE_SIZE);
@@ -2990,6 +2992,7 @@ read_vmcoreinfo(void)
READ_NUMBER("PAGE_HUGETLB_MAPCOUNT_VALUE", PAGE_HUGETLB_MAPCOUNT_VALUE);
READ_NUMBER("PAGE_OFFLINE_MAPCOUNT_VALUE", PAGE_OFFLINE_MAPCOUNT_VALUE);
READ_NUMBER("PAGE_SLAB_MAPCOUNT_VALUE", PAGE_SLAB_MAPCOUNT_VALUE);
+ READ_NUMBER("PAGE_UNACCEPTED_MAPCOUNT_VALUE", PAGE_UNACCEPTED_MAPCOUNT_VALUE);
READ_NUMBER("phys_base", phys_base);
READ_NUMBER("KERNEL_IMAGE_SIZE", KERNEL_IMAGE_SIZE);
@@ -6630,6 +6633,17 @@ check_order:
nr_pages = 1 << private;
pfn_counter = &pfn_free;
}
+ /*
+ * Exclude the unaccepted free pages not managed by buddy.
+ * By convention, pages can be added to the zone.unaccepted_pages list
+ * only when the order is MAX_ORDER_NR_PAGES. Otherwise, the page is
+ * accepted immediately without being on the list.
+ */
+ else if ((info->dump_level & DL_EXCLUDE_FREE)
+ && isUnaccepted(_mapcount)) {
+ nr_pages = 1 << (ARRAY_LENGTH(zone.free_area) - 1);
+ pfn_counter = &pfn_free;
+ }
/*
* Exclude the non-private cache page.
*/
diff --git a/makedumpfile.h b/makedumpfile.h
index 944397a6f865..26940e7a3f81 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -163,6 +163,8 @@ test_bit(int nr, unsigned long addr)
&& (NUMBER(PG_hwpoison) != NOT_FOUND_NUMBER))
#define isAnon(mapping, flags, _mapcount) \
(((unsigned long)mapping & PAGE_MAPPING_ANON) != 0 && !isSlab(flags, _mapcount))
+#define isUnaccepted(_mapcount) (_mapcount == (int)NUMBER(PAGE_UNACCEPTED_MAPCOUNT_VALUE) \
+ && (NUMBER(PAGE_UNACCEPTED_MAPCOUNT_VALUE) != NOT_FOUND_NUMBER))
#define PTOB(X) (((unsigned long long)(X)) << PAGESHIFT())
#define BTOP(X) (((unsigned long long)(X)) >> PAGESHIFT())
@@ -2257,6 +2259,7 @@ struct number_table {
long PAGE_HUGETLB_MAPCOUNT_VALUE;
long PAGE_OFFLINE_MAPCOUNT_VALUE;
long PAGE_SLAB_MAPCOUNT_VALUE;
+ long PAGE_UNACCEPTED_MAPCOUNT_VALUE;
long SECTION_SIZE_BITS;
long MAX_PHYSMEM_BITS;
long HUGETLB_PAGE_DTOR;
--
2.25.1
More information about the kexec
mailing list