| From c8b9aff419303e4d4219b5ff64b1c7e062dee48e Mon Sep 17 00:00:00 2001 |
| From: Baolin Wang <baolin.wang@linux.alibaba.com> |
| Date: Thu, 18 Aug 2022 15:37:43 +0800 |
| Subject: mm/damon: validate if the pmd entry is present before accessing |
| |
| From: Baolin Wang <baolin.wang@linux.alibaba.com> |
| |
| commit c8b9aff419303e4d4219b5ff64b1c7e062dee48e upstream. |
| |
| pmd_huge() is used to validate if the pmd entry is mapped by a huge page, |
| also including the case of non-present (migration or hwpoisoned) pmd entry |
| on arm64 or x86 architectures. This means that pmd_pfn() can not get the |
| correct pfn number for a non-present pmd entry, which will cause |
| damon_get_page() to get an incorrect page struct (also may be NULL by |
| pfn_to_online_page()), making the access statistics incorrect. |
| |
| This means that the DAMON may make incorrect decision according to the |
| incorrect statistics, for example, DAMON may can not reclaim cold page |
| in time due to this cold page was regarded as accessed mistakenly if |
| DAMOS_PAGEOUT operation is specified. |
| |
| Moreover it does not make sense that we still waste time to get the page |
| of the non-present entry. Just treat it as not-accessed and skip it, |
| which maintains consistency with non-present pte level entries. |
| |
| So add pmd entry present validation to fix the above issues. |
| |
| Link: https://lkml.kernel.org/r/58b1d1f5fbda7db49ca886d9ef6783e3dcbbbc98.1660805030.git.baolin.wang@linux.alibaba.com |
| Fixes: 3f49584b262c ("mm/damon: implement primitives for the virtual memory address spaces") |
| Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com> |
| Reviewed-by: SeongJae Park <sj@kernel.org> |
| Reviewed-by: Muchun Song <songmuchun@bytedance.com> |
| Cc: Mike Kravetz <mike.kravetz@oracle.com> |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| mm/damon/vaddr.c | 10 ++++++++++ |
| 1 file changed, 10 insertions(+) |
| |
| --- a/mm/damon/vaddr.c |
| +++ b/mm/damon/vaddr.c |
| @@ -456,6 +456,11 @@ static int damon_mkold_pmd_entry(pmd_t * |
| |
| if (pmd_huge(*pmd)) { |
| ptl = pmd_lock(walk->mm, pmd); |
| + if (!pmd_present(*pmd)) { |
| + spin_unlock(ptl); |
| + return 0; |
| + } |
| + |
| if (pmd_huge(*pmd)) { |
| damon_pmdp_mkold(pmd, walk->mm, addr); |
| spin_unlock(ptl); |
| @@ -530,6 +535,11 @@ static int damon_young_pmd_entry(pmd_t * |
| #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
| if (pmd_huge(*pmd)) { |
| ptl = pmd_lock(walk->mm, pmd); |
| + if (!pmd_present(*pmd)) { |
| + spin_unlock(ptl); |
| + return 0; |
| + } |
| + |
| if (!pmd_huge(*pmd)) { |
| spin_unlock(ptl); |
| goto regular_page; |