Skip to content

Commit 608cc7d

Browse files
Ma Wupenggregkh
Ma Wupeng
authored andcommitted
mm: memory-failure: update ttu flag inside unmap_poisoned_folio
commit b81679b upstream. Patch series "mm: memory_failure: unmap poisoned folio during migrate properly", v3. Fix two bugs during folio migration if the folio is poisoned. This patch (of 3): Commit 6da6b1d ("mm/hwpoison: convert TTU_IGNORE_HWPOISON to TTU_HWPOISON") introduce TTU_HWPOISON to replace TTU_IGNORE_HWPOISON in order to stop send SIGBUS signal when accessing an error page after a memory error on a clean folio. However during page migration, anon folio must be set with TTU_HWPOISON during unmap_*(). For pagecache we need some policy just like the one in hwpoison_user_mappings to set this flag. So move this policy from hwpoison_user_mappings to unmap_poisoned_folio to handle this warning properly. Warning will be produced during unamp poison folio with the following log: ------------[ cut here ]------------ WARNING: CPU: 1 PID: 365 at mm/rmap.c:1847 try_to_unmap_one+0x8fc/0xd3c Modules linked in: CPU: 1 UID: 0 PID: 365 Comm: bash Tainted: G W 6.13.0-rc1-00018-gacdb4bbda7ab #42 Tainted: [W]=WARN Hardware name: QEMU QEMU Virtual Machine, BIOS 0.0.0 02/06/2015 pstate: 20400005 (nzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : try_to_unmap_one+0x8fc/0xd3c lr : try_to_unmap_one+0x3dc/0xd3c Call trace: try_to_unmap_one+0x8fc/0xd3c (P) try_to_unmap_one+0x3dc/0xd3c (L) rmap_walk_anon+0xdc/0x1f8 rmap_walk+0x3c/0x58 try_to_unmap+0x88/0x90 unmap_poisoned_folio+0x30/0xa8 do_migrate_range+0x4a0/0x568 offline_pages+0x5a4/0x670 memory_block_action+0x17c/0x374 memory_subsys_offline+0x3c/0x78 device_offline+0xa4/0xd0 state_store+0x8c/0xf0 dev_attr_store+0x18/0x2c sysfs_kf_write+0x44/0x54 kernfs_fop_write_iter+0x118/0x1a8 vfs_write+0x3a8/0x4bc ksys_write+0x6c/0xf8 __arm64_sys_write+0x1c/0x28 invoke_syscall+0x44/0x100 el0_svc_common.constprop.0+0x40/0xe0 do_el0_svc+0x1c/0x28 el0_svc+0x30/0xd0 el0t_64_sync_handler+0xc8/0xcc el0t_64_sync+0x198/0x19c ---[ end trace 0000000000000000 ]--- [[email protected]: unmap_poisoned_folio(): remove shadowed local `mapping', per Miaohe] Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Fixes: 6da6b1d ("mm/hwpoison: convert TTU_IGNORE_HWPOISON to TTU_HWPOISON") Signed-off-by: Ma Wupeng <[email protected]> Suggested-by: David Hildenbrand <[email protected]> Acked-by: David Hildenbrand <[email protected]> Acked-by: Miaohe Lin <[email protected]> Cc: Ma Wupeng <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Naoya Horiguchi <[email protected]> Cc: Oscar Salvador <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 79636d2 commit 608cc7d

File tree

3 files changed

+36
-35
lines changed

3 files changed

+36
-35
lines changed

mm/internal.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,7 @@ static inline int find_next_best_node(int node, nodemask_t *used_node_mask)
11011101
* mm/memory-failure.c
11021102
*/
11031103
#ifdef CONFIG_MEMORY_FAILURE
1104-
void unmap_poisoned_folio(struct folio *folio, enum ttu_flags ttu);
1104+
int unmap_poisoned_folio(struct folio *folio, unsigned long pfn, bool must_kill);
11051105
void shake_folio(struct folio *folio);
11061106
extern int hwpoison_filter(struct page *p);
11071107

@@ -1123,8 +1123,9 @@ void add_to_kill_ksm(struct task_struct *tsk, struct page *p,
11231123
unsigned long page_mapped_in_vma(struct page *page, struct vm_area_struct *vma);
11241124

11251125
#else
1126-
static inline void unmap_poisoned_folio(struct folio *folio, enum ttu_flags ttu)
1126+
static inline int unmap_poisoned_folio(struct folio *folio, unsigned long pfn, bool must_kill)
11271127
{
1128+
return -EBUSY;
11281129
}
11291130
#endif
11301131

mm/memory-failure.c

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,11 +1554,35 @@ static int get_hwpoison_page(struct page *p, unsigned long flags)
15541554
return ret;
15551555
}
15561556

1557-
void unmap_poisoned_folio(struct folio *folio, enum ttu_flags ttu)
1557+
int unmap_poisoned_folio(struct folio *folio, unsigned long pfn, bool must_kill)
15581558
{
1559-
if (folio_test_hugetlb(folio) && !folio_test_anon(folio)) {
1560-
struct address_space *mapping;
1559+
enum ttu_flags ttu = TTU_IGNORE_MLOCK | TTU_SYNC | TTU_HWPOISON;
1560+
struct address_space *mapping;
1561+
1562+
if (folio_test_swapcache(folio)) {
1563+
pr_err("%#lx: keeping poisoned page in swap cache\n", pfn);
1564+
ttu &= ~TTU_HWPOISON;
1565+
}
15611566

1567+
/*
1568+
* Propagate the dirty bit from PTEs to struct page first, because we
1569+
* need this to decide if we should kill or just drop the page.
1570+
* XXX: the dirty test could be racy: set_page_dirty() may not always
1571+
* be called inside page lock (it's recommended but not enforced).
1572+
*/
1573+
mapping = folio_mapping(folio);
1574+
if (!must_kill && !folio_test_dirty(folio) && mapping &&
1575+
mapping_can_writeback(mapping)) {
1576+
if (folio_mkclean(folio)) {
1577+
folio_set_dirty(folio);
1578+
} else {
1579+
ttu &= ~TTU_HWPOISON;
1580+
pr_info("%#lx: corrupted page was clean: dropped without side effects\n",
1581+
pfn);
1582+
}
1583+
}
1584+
1585+
if (folio_test_hugetlb(folio) && !folio_test_anon(folio)) {
15621586
/*
15631587
* For hugetlb folios in shared mappings, try_to_unmap
15641588
* could potentially call huge_pmd_unshare. Because of
@@ -1570,14 +1594,16 @@ void unmap_poisoned_folio(struct folio *folio, enum ttu_flags ttu)
15701594
if (!mapping) {
15711595
pr_info("%#lx: could not lock mapping for mapped hugetlb folio\n",
15721596
folio_pfn(folio));
1573-
return;
1597+
return -EBUSY;
15741598
}
15751599

15761600
try_to_unmap(folio, ttu|TTU_RMAP_LOCKED);
15771601
i_mmap_unlock_write(mapping);
15781602
} else {
15791603
try_to_unmap(folio, ttu);
15801604
}
1605+
1606+
return folio_mapped(folio) ? -EBUSY : 0;
15811607
}
15821608

15831609
/*
@@ -1587,8 +1613,6 @@ void unmap_poisoned_folio(struct folio *folio, enum ttu_flags ttu)
15871613
static bool hwpoison_user_mappings(struct folio *folio, struct page *p,
15881614
unsigned long pfn, int flags)
15891615
{
1590-
enum ttu_flags ttu = TTU_IGNORE_MLOCK | TTU_SYNC | TTU_HWPOISON;
1591-
struct address_space *mapping;
15921616
LIST_HEAD(tokill);
15931617
bool unmap_success;
15941618
int forcekill;
@@ -1611,39 +1635,14 @@ static bool hwpoison_user_mappings(struct folio *folio, struct page *p,
16111635
if (!folio_mapped(folio))
16121636
return true;
16131637

1614-
if (folio_test_swapcache(folio)) {
1615-
pr_err("%#lx: keeping poisoned page in swap cache\n", pfn);
1616-
ttu &= ~TTU_HWPOISON;
1617-
}
1618-
1619-
/*
1620-
* Propagate the dirty bit from PTEs to struct page first, because we
1621-
* need this to decide if we should kill or just drop the page.
1622-
* XXX: the dirty test could be racy: set_page_dirty() may not always
1623-
* be called inside page lock (it's recommended but not enforced).
1624-
*/
1625-
mapping = folio_mapping(folio);
1626-
if (!(flags & MF_MUST_KILL) && !folio_test_dirty(folio) && mapping &&
1627-
mapping_can_writeback(mapping)) {
1628-
if (folio_mkclean(folio)) {
1629-
folio_set_dirty(folio);
1630-
} else {
1631-
ttu &= ~TTU_HWPOISON;
1632-
pr_info("%#lx: corrupted page was clean: dropped without side effects\n",
1633-
pfn);
1634-
}
1635-
}
1636-
16371638
/*
16381639
* First collect all the processes that have the page
16391640
* mapped in dirty form. This has to be done before try_to_unmap,
16401641
* because ttu takes the rmap data structures down.
16411642
*/
16421643
collect_procs(folio, p, &tokill, flags & MF_ACTION_REQUIRED);
16431644

1644-
unmap_poisoned_folio(folio, ttu);
1645-
1646-
unmap_success = !folio_mapped(folio);
1645+
unmap_success = !unmap_poisoned_folio(folio, pfn, flags & MF_MUST_KILL);
16471646
if (!unmap_success)
16481647
pr_err("%#lx: failed to unmap page (folio mapcount=%d)\n",
16491648
pfn, folio_mapcount(folio));

mm/memory_hotplug.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1806,7 +1806,8 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
18061806
if (WARN_ON(folio_test_lru(folio)))
18071807
folio_isolate_lru(folio);
18081808
if (folio_mapped(folio))
1809-
unmap_poisoned_folio(folio, TTU_IGNORE_MLOCK);
1809+
unmap_poisoned_folio(folio, pfn, false);
1810+
18101811
continue;
18111812
}
18121813

0 commit comments

Comments
 (0)