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.shute...@linux.intel.com/ [2] https://lore.kernel.org/all/20240809114854.3745464-5-kirill.shute...@linux.intel.com/ [3] https://lore.kernel.org/all/20250405060610.860465-1-zhiquan1...@intel.com/ Signed-off-by: Zhiquan Li <zhiquan1...@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