Add check for pte_valid in saveable page after being checked for the rest. This is required as PTE is removed for pages allocated with dma_alloc_coherent with DMA_ATTR_NO_KERNEL_MAPPING flag set. This patch makes sure that these pages are not considered for snapshot. Signed-off-by: Vivek Kumar <quic_vivekuma@xxxxxxxxxxx> Signed-off-by: Prasanna Kumar <quic_kprasan@xxxxxxxxxxx> --- kernel/power/snapshot.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 2a40675..a6ad2a5 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1308,6 +1308,41 @@ static inline void *saveable_highmem_page(struct zone *z, unsigned long p) } #endif /* CONFIG_HIGHMEM */ +static bool kernel_pte_present(struct page *page) +{ + pgd_t *pgdp; + p4d_t *p4dp; + pud_t *pudp, pud; + pmd_t *pmdp, pmd; + pte_t *ptep; + unsigned long addr = (unsigned long)page_address(page); + + pgdp = pgd_offset_k(addr); + if (pgd_none(READ_ONCE(*pgdp))) + return false; + + p4dp = p4d_offset(pgdp, addr); + if (p4d_none(READ_ONCE(*p4dp))) + return false; + + pudp = pud_offset(p4dp, addr); + pud = READ_ONCE(*pudp); + if (pud_none(pud)) + return false; + if (pud_sect(pud)) + return true; + + pmdp = pmd_offset(pudp, addr); + pmd = READ_ONCE(*pmdp); + if (pmd_none(pmd)) + return false; + if (pmd_sect(pmd)) + return true; + + ptep = pte_offset_kernel(pmdp, addr); + return pte_valid(READ_ONCE(*ptep)); +} + /** * saveable_page - Check if the given page is saveable. * @@ -1341,6 +1376,14 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn) && (!kernel_page_present(page) || pfn_is_nosave(pfn))) return NULL; + /* + * Even if page is not reserved and if it's not present in kernel PTE; + * don't snapshot it ! This happens to the pages allocated using + * __dma_alloc_coherent with DMA_ATTR_NO_KERNEL_MAPPING flag set. + */ + if (!kernel_pte_present(page)) + return NULL; + if (page_is_guard(page)) return NULL; -- 2.7.4