Skip to content

Commit ea6d063

Browse files
nhoriguchitorvalds
authored andcommitted
mm/hwpoison: do not lock page again when me_huge_page() successfully recovers
Currently me_huge_page() temporary unlocks page to perform some actions then locks it again later. My testcase (which calls hard-offline on some tail page in a hugetlb, then accesses the address of the hugetlb range) showed that page allocation code detects this page lock on buddy page and printed out "BUG: Bad page state" message. check_new_page_bad() does not consider a page with __PG_HWPOISON as bad page, so this flag works as kind of filter, but this filtering doesn't work in this case because the "bad page" is not the actual hwpoisoned page. So stop locking page again. Actions to be taken depend on the page type of the error, so page unlocking should be done in ->action() callbacks. So let's make it assumed and change all existing callbacks that way. Link: https://lkml.kernel.org/r/20210609072029.74645-1-nao.horiguchi@gmail.com Fixes: commit 78bb920 ("mm: hwpoison: dissolve in-use hugepage in unrecoverable memory error") Signed-off-by: Naoya Horiguchi <naoya.horiguchi@nec.com> Cc: Oscar Salvador <osalvador@suse.de> Cc: Michal Hocko <mhocko@suse.com> Cc: Tony Luck <tony.luck@intel.com> Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 47af12b commit ea6d063

File tree

1 file changed

+30
-14
lines changed

1 file changed

+30
-14
lines changed

mm/memory-failure.c

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ static int truncate_error_page(struct page *p, unsigned long pfn,
658658
*/
659659
static int me_kernel(struct page *p, unsigned long pfn)
660660
{
661+
unlock_page(p);
661662
return MF_IGNORED;
662663
}
663664

@@ -667,6 +668,7 @@ static int me_kernel(struct page *p, unsigned long pfn)
667668
static int me_unknown(struct page *p, unsigned long pfn)
668669
{
669670
pr_err("Memory failure: %#lx: Unknown page state\n", pfn);
671+
unlock_page(p);
670672
return MF_FAILED;
671673
}
672674

@@ -675,6 +677,7 @@ static int me_unknown(struct page *p, unsigned long pfn)
675677
*/
676678
static int me_pagecache_clean(struct page *p, unsigned long pfn)
677679
{
680+
int ret;
678681
struct address_space *mapping;
679682

680683
delete_from_lru_cache(p);
@@ -683,8 +686,10 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
683686
* For anonymous pages we're done the only reference left
684687
* should be the one m_f() holds.
685688
*/
686-
if (PageAnon(p))
687-
return MF_RECOVERED;
689+
if (PageAnon(p)) {
690+
ret = MF_RECOVERED;
691+
goto out;
692+
}
688693

689694
/*
690695
* Now truncate the page in the page cache. This is really
@@ -698,15 +703,19 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
698703
/*
699704
* Page has been teared down in the meanwhile
700705
*/
701-
return MF_FAILED;
706+
ret = MF_FAILED;
707+
goto out;
702708
}
703709

704710
/*
705711
* Truncation is a bit tricky. Enable it per file system for now.
706712
*
707713
* Open: to take i_mutex or not for this? Right now we don't.
708714
*/
709-
return truncate_error_page(p, pfn, mapping);
715+
ret = truncate_error_page(p, pfn, mapping);
716+
out:
717+
unlock_page(p);
718+
return ret;
710719
}
711720

712721
/*
@@ -782,24 +791,26 @@ static int me_pagecache_dirty(struct page *p, unsigned long pfn)
782791
*/
783792
static int me_swapcache_dirty(struct page *p, unsigned long pfn)
784793
{
794+
int ret;
795+
785796
ClearPageDirty(p);
786797
/* Trigger EIO in shmem: */
787798
ClearPageUptodate(p);
788799

789-
if (!delete_from_lru_cache(p))
790-
return MF_DELAYED;
791-
else
792-
return MF_FAILED;
800+
ret = delete_from_lru_cache(p) ? MF_FAILED : MF_DELAYED;
801+
unlock_page(p);
802+
return ret;
793803
}
794804

795805
static int me_swapcache_clean(struct page *p, unsigned long pfn)
796806
{
807+
int ret;
808+
797809
delete_from_swap_cache(p);
798810

799-
if (!delete_from_lru_cache(p))
800-
return MF_RECOVERED;
801-
else
802-
return MF_FAILED;
811+
ret = delete_from_lru_cache(p) ? MF_FAILED : MF_RECOVERED;
812+
unlock_page(p);
813+
return ret;
803814
}
804815

805816
/*
@@ -820,6 +831,7 @@ static int me_huge_page(struct page *p, unsigned long pfn)
820831
mapping = page_mapping(hpage);
821832
if (mapping) {
822833
res = truncate_error_page(hpage, pfn, mapping);
834+
unlock_page(hpage);
823835
} else {
824836
res = MF_FAILED;
825837
unlock_page(hpage);
@@ -834,7 +846,6 @@ static int me_huge_page(struct page *p, unsigned long pfn)
834846
page_ref_inc(p);
835847
res = MF_RECOVERED;
836848
}
837-
lock_page(hpage);
838849
}
839850

840851
return res;
@@ -866,6 +877,8 @@ static struct page_state {
866877
unsigned long mask;
867878
unsigned long res;
868879
enum mf_action_page_type type;
880+
881+
/* Callback ->action() has to unlock the relevant page inside it. */
869882
int (*action)(struct page *p, unsigned long pfn);
870883
} error_states[] = {
871884
{ reserved, reserved, MF_MSG_KERNEL, me_kernel },
@@ -929,6 +942,7 @@ static int page_action(struct page_state *ps, struct page *p,
929942
int result;
930943
int count;
931944

945+
/* page p should be unlocked after returning from ps->action(). */
932946
result = ps->action(p, pfn);
933947

934948
count = page_count(p) - 1;
@@ -1313,7 +1327,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags)
13131327
goto out;
13141328
}
13151329

1316-
res = identify_page_state(pfn, p, page_flags);
1330+
return identify_page_state(pfn, p, page_flags);
13171331
out:
13181332
unlock_page(head);
13191333
return res;
@@ -1596,6 +1610,8 @@ int memory_failure(unsigned long pfn, int flags)
15961610

15971611
identify_page_state:
15981612
res = identify_page_state(pfn, p, page_flags);
1613+
mutex_unlock(&mf_mutex);
1614+
return res;
15991615
unlock_page:
16001616
unlock_page(p);
16011617
unlock_mutex:

0 commit comments

Comments
 (0)