Skip to content

Commit 4f57516

Browse files
jchu314atgithubgregkh
authored andcommitted
mm/memory-failure: fix missing ->mf_stats count in hugetlb poison
commit a148a20 upstream. When a newly poisoned subpage ends up in an already poisoned hugetlb folio, 'num_poisoned_pages' is incremented, but the per node ->mf_stats is not. Fix the inconsistency by designating action_result() to update them both. While at it, define __get_huge_page_for_hwpoison() return values in terms of symbol names for better readibility. Also rename folio_set_hugetlb_hwpoison() to hugetlb_update_hwpoison() since the function does more than the conventional bit setting and the fact three possible return values are expected. Link: https://lkml.kernel.org/r/20260120232234.3462258-1-jane.chu@oracle.com Fixes: 18f41fa ("mm: memory-failure: bump memory failure stats to pglist_data") Signed-off-by: Jane Chu <jane.chu@oracle.com> Acked-by: Miaohe Lin <linmiaohe@huawei.com> Cc: Chris Mason <clm@meta.com> Cc: David Hildenbrand <david@kernel.org> Cc: David Rientjes <rientjes@google.com> Cc: Jiaqi Yan <jiaqiyan@google.com> Cc: Liam R. Howlett <Liam.Howlett@oracle.com> Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Mike Rapoport <rppt@kernel.org> Cc: Muchun Song <muchun.song@linux.dev> Cc: Naoya Horiguchi <nao.horiguchi@gmail.com> Cc: Oscar Salvador <osalvador@suse.de> Cc: Suren Baghdasaryan <surenb@google.com> Cc: William Roche <william.roche@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>
1 parent c71fae3 commit 4f57516

1 file changed

Lines changed: 56 additions & 37 deletions

File tree

mm/memory-failure.c

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1873,33 +1873,40 @@ static unsigned long __folio_free_raw_hwp(struct folio *folio, bool move_flag)
18731873
return count;
18741874
}
18751875

1876-
static int folio_set_hugetlb_hwpoison(struct folio *folio, struct page *page)
1876+
#define MF_HUGETLB_FREED 0 /* freed hugepage */
1877+
#define MF_HUGETLB_IN_USED 1 /* in-use hugepage */
1878+
#define MF_HUGETLB_NON_HUGEPAGE 2 /* not a hugepage */
1879+
#define MF_HUGETLB_FOLIO_PRE_POISONED 3 /* folio already poisoned */
1880+
#define MF_HUGETLB_PAGE_PRE_POISONED 4 /* exact page already poisoned */
1881+
#define MF_HUGETLB_RETRY 5 /* hugepage is busy, retry */
1882+
/*
1883+
* Set hugetlb folio as hwpoisoned, update folio private raw hwpoison list
1884+
* to keep track of the poisoned pages.
1885+
*/
1886+
static int hugetlb_update_hwpoison(struct folio *folio, struct page *page)
18771887
{
18781888
struct llist_head *head;
18791889
struct raw_hwp_page *raw_hwp;
18801890
struct raw_hwp_page *p;
1881-
int ret = folio_test_set_hwpoison(folio) ? -EHWPOISON : 0;
1891+
int ret = folio_test_set_hwpoison(folio) ? MF_HUGETLB_FOLIO_PRE_POISONED : 0;
18821892

18831893
/*
18841894
* Once the hwpoison hugepage has lost reliable raw error info,
18851895
* there is little meaning to keep additional error info precisely,
18861896
* so skip to add additional raw error info.
18871897
*/
18881898
if (folio_test_hugetlb_raw_hwp_unreliable(folio))
1889-
return -EHWPOISON;
1899+
return MF_HUGETLB_FOLIO_PRE_POISONED;
18901900
head = raw_hwp_list_head(folio);
18911901
llist_for_each_entry(p, head->first, node) {
18921902
if (p->page == page)
1893-
return -EHWPOISON;
1903+
return MF_HUGETLB_PAGE_PRE_POISONED;
18941904
}
18951905

18961906
raw_hwp = kmalloc(sizeof(struct raw_hwp_page), GFP_ATOMIC);
18971907
if (raw_hwp) {
18981908
raw_hwp->page = page;
18991909
llist_add(&raw_hwp->node, head);
1900-
/* the first error event will be counted in action_result(). */
1901-
if (ret)
1902-
num_poisoned_pages_inc(page_to_pfn(page));
19031910
} else {
19041911
/*
19051912
* Failed to save raw error info. We no longer trace all
@@ -1947,42 +1954,39 @@ void folio_clear_hugetlb_hwpoison(struct folio *folio)
19471954

19481955
/*
19491956
* Called from hugetlb code with hugetlb_lock held.
1950-
*
1951-
* Return values:
1952-
* 0 - free hugepage
1953-
* 1 - in-use hugepage
1954-
* 2 - not a hugepage
1955-
* -EBUSY - the hugepage is busy (try to retry)
1956-
* -EHWPOISON - the hugepage is already hwpoisoned
19571957
*/
19581958
int __get_huge_page_for_hwpoison(unsigned long pfn, int flags,
19591959
bool *migratable_cleared)
19601960
{
19611961
struct page *page = pfn_to_page(pfn);
19621962
struct folio *folio = page_folio(page);
1963-
int ret = 2; /* fallback to normal page handling */
19641963
bool count_increased = false;
1964+
int ret, rc;
19651965

1966-
if (!folio_test_hugetlb(folio))
1966+
if (!folio_test_hugetlb(folio)) {
1967+
ret = MF_HUGETLB_NON_HUGEPAGE;
19671968
goto out;
1968-
1969-
if (flags & MF_COUNT_INCREASED) {
1970-
ret = 1;
1969+
} else if (flags & MF_COUNT_INCREASED) {
1970+
ret = MF_HUGETLB_IN_USED;
19711971
count_increased = true;
19721972
} else if (folio_test_hugetlb_freed(folio)) {
1973-
ret = 0;
1973+
ret = MF_HUGETLB_FREED;
19741974
} else if (folio_test_hugetlb_migratable(folio)) {
1975-
ret = folio_try_get(folio);
1976-
if (ret)
1975+
if (folio_try_get(folio)) {
1976+
ret = MF_HUGETLB_IN_USED;
19771977
count_increased = true;
1978+
} else {
1979+
ret = MF_HUGETLB_FREED;
1980+
}
19781981
} else {
1979-
ret = -EBUSY;
1982+
ret = MF_HUGETLB_RETRY;
19801983
if (!(flags & MF_NO_RETRY))
19811984
goto out;
19821985
}
19831986

1984-
if (folio_set_hugetlb_hwpoison(folio, page)) {
1985-
ret = -EHWPOISON;
1987+
rc = hugetlb_update_hwpoison(folio, page);
1988+
if (rc >= MF_HUGETLB_FOLIO_PRE_POISONED) {
1989+
ret = rc;
19861990
goto out;
19871991
}
19881992

@@ -2007,10 +2011,16 @@ int __get_huge_page_for_hwpoison(unsigned long pfn, int flags,
20072011
* with basic operations like hugepage allocation/free/demotion.
20082012
* So some of prechecks for hwpoison (pinning, and testing/setting
20092013
* PageHWPoison) should be done in single hugetlb_lock range.
2014+
* Returns:
2015+
* 0 - not hugetlb, or recovered
2016+
* -EBUSY - not recovered
2017+
* -EOPNOTSUPP - hwpoison_filter'ed
2018+
* -EHWPOISON - folio or exact page already poisoned
2019+
* -EFAULT - kill_accessing_process finds current->mm null
20102020
*/
20112021
static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb)
20122022
{
2013-
int res;
2023+
int res, rv;
20142024
struct page *p = pfn_to_page(pfn);
20152025
struct folio *folio;
20162026
unsigned long page_flags;
@@ -2019,22 +2029,31 @@ static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb
20192029
*hugetlb = 1;
20202030
retry:
20212031
res = get_huge_page_for_hwpoison(pfn, flags, &migratable_cleared);
2022-
if (res == 2) { /* fallback to normal page handling */
2032+
switch (res) {
2033+
case MF_HUGETLB_NON_HUGEPAGE: /* fallback to normal page handling */
20232034
*hugetlb = 0;
20242035
return 0;
2025-
} else if (res == -EHWPOISON) {
2026-
if (flags & MF_ACTION_REQUIRED) {
2027-
folio = page_folio(p);
2028-
res = kill_accessing_process(current, folio_pfn(folio), flags);
2029-
}
2030-
action_result(pfn, MF_MSG_ALREADY_POISONED, MF_FAILED);
2031-
return res;
2032-
} else if (res == -EBUSY) {
2036+
case MF_HUGETLB_RETRY:
20332037
if (!(flags & MF_NO_RETRY)) {
20342038
flags |= MF_NO_RETRY;
20352039
goto retry;
20362040
}
20372041
return action_result(pfn, MF_MSG_GET_HWPOISON, MF_IGNORED);
2042+
case MF_HUGETLB_FOLIO_PRE_POISONED:
2043+
case MF_HUGETLB_PAGE_PRE_POISONED:
2044+
rv = -EHWPOISON;
2045+
if (flags & MF_ACTION_REQUIRED) {
2046+
folio = page_folio(p);
2047+
rv = kill_accessing_process(current, folio_pfn(folio), flags);
2048+
}
2049+
if (res == MF_HUGETLB_PAGE_PRE_POISONED)
2050+
action_result(pfn, MF_MSG_ALREADY_POISONED, MF_FAILED);
2051+
else
2052+
action_result(pfn, MF_MSG_HUGE, MF_FAILED);
2053+
return rv;
2054+
default:
2055+
WARN_ON((res != MF_HUGETLB_FREED) && (res != MF_HUGETLB_IN_USED));
2056+
break;
20382057
}
20392058

20402059
folio = page_folio(p);
@@ -2045,7 +2064,7 @@ static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb
20452064
if (migratable_cleared)
20462065
folio_set_hugetlb_migratable(folio);
20472066
folio_unlock(folio);
2048-
if (res == 1)
2067+
if (res == MF_HUGETLB_IN_USED)
20492068
folio_put(folio);
20502069
return -EOPNOTSUPP;
20512070
}
@@ -2054,7 +2073,7 @@ static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb
20542073
* Handling free hugepage. The possible race with hugepage allocation
20552074
* or demotion can be prevented by PageHWPoison flag.
20562075
*/
2057-
if (res == 0) {
2076+
if (res == MF_HUGETLB_FREED) {
20582077
folio_unlock(folio);
20592078
if (__page_handle_poison(p) > 0) {
20602079
page_ref_inc(p);

0 commit comments

Comments
 (0)