diff options
-rw-r--r-- | mm/memory-failure.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index ceb0c7f1932f..2c13aa7a0164 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c | |||
@@ -1410,7 +1410,8 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags) | |||
1410 | 1410 | ||
1411 | /* | 1411 | /* |
1412 | * Isolate the page, so that it doesn't get reallocated if it | 1412 | * Isolate the page, so that it doesn't get reallocated if it |
1413 | * was free. | 1413 | * was free. This flag should be kept set until the source page |
1414 | * is freed and PG_hwpoison on it is set. | ||
1414 | */ | 1415 | */ |
1415 | set_migratetype_isolate(p, true); | 1416 | set_migratetype_isolate(p, true); |
1416 | /* | 1417 | /* |
@@ -1433,7 +1434,6 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags) | |||
1433 | /* Not a free page */ | 1434 | /* Not a free page */ |
1434 | ret = 1; | 1435 | ret = 1; |
1435 | } | 1436 | } |
1436 | unset_migratetype_isolate(p, MIGRATE_MOVABLE); | ||
1437 | unlock_memory_hotplug(); | 1437 | unlock_memory_hotplug(); |
1438 | return ret; | 1438 | return ret; |
1439 | } | 1439 | } |
@@ -1494,7 +1494,6 @@ static int soft_offline_huge_page(struct page *page, int flags) | |||
1494 | atomic_long_add(1 << compound_trans_order(hpage), | 1494 | atomic_long_add(1 << compound_trans_order(hpage), |
1495 | &num_poisoned_pages); | 1495 | &num_poisoned_pages); |
1496 | } | 1496 | } |
1497 | /* keep elevated page count for bad page */ | ||
1498 | return ret; | 1497 | return ret; |
1499 | } | 1498 | } |
1500 | 1499 | ||
@@ -1559,7 +1558,7 @@ int soft_offline_page(struct page *page, int flags) | |||
1559 | atomic_long_inc(&num_poisoned_pages); | 1558 | atomic_long_inc(&num_poisoned_pages); |
1560 | } | 1559 | } |
1561 | } | 1560 | } |
1562 | /* keep elevated page count for bad page */ | 1561 | unset_migratetype_isolate(page, MIGRATE_MOVABLE); |
1563 | return ret; | 1562 | return ret; |
1564 | } | 1563 | } |
1565 | 1564 | ||
@@ -1625,7 +1624,22 @@ static int __soft_offline_page(struct page *page, int flags) | |||
1625 | if (ret > 0) | 1624 | if (ret > 0) |
1626 | ret = -EIO; | 1625 | ret = -EIO; |
1627 | } else { | 1626 | } else { |
1627 | /* | ||
1628 | * After page migration succeeds, the source page can | ||
1629 | * be trapped in pagevec and actual freeing is delayed. | ||
1630 | * Freeing code works differently based on PG_hwpoison, | ||
1631 | * so there's a race. We need to make sure that the | ||
1632 | * source page should be freed back to buddy before | ||
1633 | * setting PG_hwpoison. | ||
1634 | */ | ||
1635 | if (!is_free_buddy_page(page)) | ||
1636 | lru_add_drain_all(); | ||
1637 | if (!is_free_buddy_page(page)) | ||
1638 | drain_all_pages(); | ||
1628 | SetPageHWPoison(page); | 1639 | SetPageHWPoison(page); |
1640 | if (!is_free_buddy_page(page)) | ||
1641 | pr_info("soft offline: %#lx: page leaked\n", | ||
1642 | pfn); | ||
1629 | atomic_long_inc(&num_poisoned_pages); | 1643 | atomic_long_inc(&num_poisoned_pages); |
1630 | } | 1644 | } |
1631 | } else { | 1645 | } else { |