Skip to content

Commit b81679b

Browse files
Ma Wupengakpm00
Ma Wupeng
authored andcommitted
mm: memory-failure: update ttu flag inside unmap_poisoned_folio
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]>
1 parent a564ccf commit b81679b

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
@@ -1115,7 +1115,7 @@ static inline int find_next_best_node(int node, nodemask_t *used_node_mask)
11151115
* mm/memory-failure.c
11161116
*/
11171117
#ifdef CONFIG_MEMORY_FAILURE
1118-
void unmap_poisoned_folio(struct folio *folio, enum ttu_flags ttu);
1118+
int unmap_poisoned_folio(struct folio *folio, unsigned long pfn, bool must_kill);
11191119
void shake_folio(struct folio *folio);
11201120
extern int hwpoison_filter(struct page *p);
11211121

@@ -1138,8 +1138,9 @@ unsigned long page_mapped_in_vma(const struct page *page,
11381138
struct vm_area_struct *vma);
11391139

11401140
#else
1141-
static inline void unmap_poisoned_folio(struct folio *folio, enum ttu_flags ttu)
1141+
static inline int unmap_poisoned_folio(struct folio *folio, unsigned long pfn, bool must_kill)
11421142
{
1143+
return -EBUSY;
11431144
}
11441145
#endif
11451146

mm/memory-failure.c

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

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

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

15781602
try_to_unmap(folio, ttu|TTU_RMAP_LOCKED);
15791603
i_mmap_unlock_write(mapping);
15801604
} else {
15811605
try_to_unmap(folio, ttu);
15821606
}
1607+
1608+
return folio_mapped(folio) ? -EBUSY : 0;
15831609
}
15841610

15851611
/*
@@ -1589,8 +1615,6 @@ void unmap_poisoned_folio(struct folio *folio, enum ttu_flags ttu)
15891615
static bool hwpoison_user_mappings(struct folio *folio, struct page *p,
15901616
unsigned long pfn, int flags)
15911617
{
1592-
enum ttu_flags ttu = TTU_IGNORE_MLOCK | TTU_SYNC | TTU_HWPOISON;
1593-
struct address_space *mapping;
15941618
LIST_HEAD(tokill);
15951619
bool unmap_success;
15961620
int forcekill;
@@ -1613,39 +1637,14 @@ static bool hwpoison_user_mappings(struct folio *folio, struct page *p,
16131637
if (!folio_mapped(folio))
16141638
return true;
16151639

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

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

mm/memory_hotplug.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1833,7 +1833,8 @@ static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
18331833
if (WARN_ON(folio_test_lru(folio)))
18341834
folio_isolate_lru(folio);
18351835
if (folio_mapped(folio))
1836-
unmap_poisoned_folio(folio, TTU_IGNORE_MLOCK);
1836+
unmap_poisoned_folio(folio, pfn, false);
1837+
18371838
continue;
18381839
}
18391840

0 commit comments

Comments
 (0)