aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/memory-failure.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 3b4120e38d48..f2a591d87d00 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1421,7 +1421,8 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags)
1421 1421
1422 /* 1422 /*
1423 * Isolate the page, so that it doesn't get reallocated if it 1423 * Isolate the page, so that it doesn't get reallocated if it
1424 * was free. 1424 * was free. This flag should be kept set until the source page
1425 * is freed and PG_hwpoison on it is set.
1425 */ 1426 */
1426 set_migratetype_isolate(p, true); 1427 set_migratetype_isolate(p, true);
1427 /* 1428 /*
@@ -1444,7 +1445,6 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags)
1444 /* Not a free page */ 1445 /* Not a free page */
1445 ret = 1; 1446 ret = 1;
1446 } 1447 }
1447 unset_migratetype_isolate(p, MIGRATE_MOVABLE);
1448 unlock_memory_hotplug(); 1448 unlock_memory_hotplug();
1449 return ret; 1449 return ret;
1450} 1450}
@@ -1511,7 +1511,6 @@ static int soft_offline_huge_page(struct page *page, int flags)
1511 atomic_long_inc(&num_poisoned_pages); 1511 atomic_long_inc(&num_poisoned_pages);
1512 } 1512 }
1513 } 1513 }
1514 /* keep elevated page count for bad page */
1515 return ret; 1514 return ret;
1516} 1515}
1517 1516
@@ -1576,7 +1575,7 @@ int soft_offline_page(struct page *page, int flags)
1576 atomic_long_inc(&num_poisoned_pages); 1575 atomic_long_inc(&num_poisoned_pages);
1577 } 1576 }
1578 } 1577 }
1579 /* keep elevated page count for bad page */ 1578 unset_migratetype_isolate(page, MIGRATE_MOVABLE);
1580 return ret; 1579 return ret;
1581} 1580}
1582 1581
@@ -1642,7 +1641,22 @@ static int __soft_offline_page(struct page *page, int flags)
1642 if (ret > 0) 1641 if (ret > 0)
1643 ret = -EIO; 1642 ret = -EIO;
1644 } else { 1643 } else {
1644 /*
1645 * After page migration succeeds, the source page can
1646 * be trapped in pagevec and actual freeing is delayed.
1647 * Freeing code works differently based on PG_hwpoison,
1648 * so there's a race. We need to make sure that the
1649 * source page should be freed back to buddy before
1650 * setting PG_hwpoison.
1651 */
1652 if (!is_free_buddy_page(page))
1653 lru_add_drain_all();
1654 if (!is_free_buddy_page(page))
1655 drain_all_pages();
1645 SetPageHWPoison(page); 1656 SetPageHWPoison(page);
1657 if (!is_free_buddy_page(page))
1658 pr_info("soft offline: %#lx: page leaked\n",
1659 pfn);
1646 atomic_long_inc(&num_poisoned_pages); 1660 atomic_long_inc(&num_poisoned_pages);
1647 } 1661 }
1648 } else { 1662 } else {