From 582febffa8b3567339148c2bb916fc70f2fc546e Mon Sep 17 00:00:00 2001 From: Johan Erlandsson Date: Fri, 20 Oct 2023 19:10:52 +0200 Subject: [PATCH] zram: Fixes for lookup_swap_cache() Fix the following three issues: (1) swap cache missing page tree offset The radix or xarray start at an offset inside struct address_space. (2) swap cache entries are pointer to struct page The entries in radix, xarray (swap cache) are address to struct page. (3) exclude shadow entries from swap cache lookup radix or xarray can contain shadow entries from previous page entries. These should be ignored when looking for a page pointer. Without the patch, - lookup_swap_cache() returns NULL since do_xarray() call returns FALSE, - in try_zram_decompress(), since 'entry' is NULL, page is filled with 0, if (!entry || (flags & ZRAM_FLAG_SAME_BIT)) { and pages in swap cache will be seen to be a 'zero' page. Signed-off-by: Johan Erlandsson Signed-off-by: Kazuhito Hagio --- diskdump.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/diskdump.c b/diskdump.c index f20f3ac5..660c2572 100644 --- a/diskdump.c +++ b/diskdump.c @@ -27,6 +27,7 @@ #include "diskdump.h" #include "xen_dom0.h" #include "vmcore.h" +#include "maple_tree.h" #define BITMAP_SECT_LEN 4096 @@ -2877,11 +2878,16 @@ zram_object_addr(ulong pool, ulong handle, unsigned char *zram_buf) return zram_buf; } +static inline bool radix_tree_exceptional_entry(ulong entry) +{ + return entry & RADIX_TREE_EXCEPTIONAL_ENTRY; +} + static unsigned char * lookup_swap_cache(ulonglong pte_val, unsigned char *zram_buf) { ulonglong swp_offset; - ulong swp_type, swp_space, page; + ulong swp_type, swp_space; struct list_pair lp; physaddr_t paddr; static int is_xarray = -1; @@ -2907,10 +2913,13 @@ lookup_swap_cache(ulonglong pte_val, unsigned char *zram_buf) swp_space += (swp_offset >> SWAP_ADDRESS_SPACE_SHIFT) * SIZE(address_space); lp.index = swp_offset; - if ((is_xarray ? do_xarray : do_radix_tree)(swp_space, RADIX_TREE_SEARCH, &lp)) { - readmem((ulong)lp.value, KVADDR, &page, sizeof(void *), - "swap_cache page", FAULT_ON_ERROR); - if (!is_page_ptr(page, &paddr)) { + if ((is_xarray ? do_xarray : do_radix_tree) + (swp_space+OFFSET(address_space_page_tree), RADIX_TREE_SEARCH, &lp)) { + if ((is_xarray ? xa_is_value : radix_tree_exceptional_entry)((ulong)lp.value)) { + /* ignore shadow values */ + return NULL; + } + if (!is_page_ptr((ulong)lp.value, &paddr)) { error(WARNING, "radix page: %lx: not a page pointer\n", lp.value); return NULL; }