From: Naoya Horiguchi naoya.horiguchi@nec.com
mainline inclusion from mainline-v5.10-rc1 commit 1f2481ddbe444de5bed72f167d7180d1b2708e56 category: bugfix bugzilla: 44803 CVE: NA
-------------------------------------------------
Soft offlining could fail with EIO due to the race condition with hugepage migration. This issuse became visible due to the change by previous patch that makes soft offline handler take page refcount by its own. We have no way to directly pin zero refcount page, and the page considered as a zero refcount page could be allocated just after the first check.
This patch adds the second check to find the race and gives us chance to handle it more reliably.
Reported-by: Qian Cai cai@lca.pw Signed-off-by: Naoya Horiguchi naoya.horiguchi@nec.com Signed-off-by: Andrew Morton akpm@linux-foundation.org Cc: "Aneesh Kumar K.V" aneesh.kumar@linux.ibm.com Cc: Aneesh Kumar K.V aneesh.kumar@linux.vnet.ibm.com Cc: Aristeu Rozanski aris@ruivo.org Cc: Dave Hansen dave.hansen@intel.com Cc: David Hildenbrand david@redhat.com Cc: Dmitry Yakunin zeil@yandex-team.ru Cc: Michal Hocko mhocko@kernel.org Cc: Mike Kravetz mike.kravetz@oracle.com Cc: Oscar Salvador osalvador@suse.com Cc: Tony Luck tony.luck@intel.com Link: https://lkml.kernel.org/r/20200922135650.1634-14-osalvador@suse.de Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Liu Shixin liushixin2@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- mm/memory-failure.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 148fdd929a19..fa091bfb5943 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1646,6 +1646,9 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags) } else if (is_free_buddy_page(p)) { pr_info("%s: %#lx free buddy page\n", __func__, pfn); ret = 0; + } else if (page_count(p)) { + /* raced with allocation */ + ret = -EBUSY; } else { pr_info("%s: %#lx: unknown zero refcount page type %lx\n", __func__, pfn, p->flags); @@ -1662,6 +1665,9 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags) { int ret = __get_any_page(page, pfn, flags);
+ if (ret == -EBUSY) + ret = __get_any_page(page, pfn, flags); + if (ret == 1 && !PageHuge(page) && !PageLRU(page) && !__PageMovable(page)) { /*