aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory-failure.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memory-failure.c')
-rw-r--r--mm/memory-failure.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 5055b940df5f..ed6e91c87a54 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -838,6 +838,16 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
838 * and in many cases impossible, so we just avoid it here. 838 * and in many cases impossible, so we just avoid it here.
839 */ 839 */
840 lock_page_nosync(p); 840 lock_page_nosync(p);
841
842 /*
843 * unpoison always clear PG_hwpoison inside page lock
844 */
845 if (!PageHWPoison(p)) {
846 action_result(pfn, "unpoisoned", IGNORED);
847 res = 0;
848 goto out;
849 }
850
841 wait_on_page_writeback(p); 851 wait_on_page_writeback(p);
842 852
843 /* 853 /*
@@ -893,3 +903,61 @@ void memory_failure(unsigned long pfn, int trapno)
893{ 903{
894 __memory_failure(pfn, trapno, 0); 904 __memory_failure(pfn, trapno, 0);
895} 905}
906
907/**
908 * unpoison_memory - Unpoison a previously poisoned page
909 * @pfn: Page number of the to be unpoisoned page
910 *
911 * Software-unpoison a page that has been poisoned by
912 * memory_failure() earlier.
913 *
914 * This is only done on the software-level, so it only works
915 * for linux injected failures, not real hardware failures
916 *
917 * Returns 0 for success, otherwise -errno.
918 */
919int unpoison_memory(unsigned long pfn)
920{
921 struct page *page;
922 struct page *p;
923 int freeit = 0;
924
925 if (!pfn_valid(pfn))
926 return -ENXIO;
927
928 p = pfn_to_page(pfn);
929 page = compound_head(p);
930
931 if (!PageHWPoison(p)) {
932 pr_debug("MCE: Page was already unpoisoned %#lx\n", pfn);
933 return 0;
934 }
935
936 if (!get_page_unless_zero(page)) {
937 if (TestClearPageHWPoison(p))
938 atomic_long_dec(&mce_bad_pages);
939 pr_debug("MCE: Software-unpoisoned free page %#lx\n", pfn);
940 return 0;
941 }
942
943 lock_page_nosync(page);
944 /*
945 * This test is racy because PG_hwpoison is set outside of page lock.
946 * That's acceptable because that won't trigger kernel panic. Instead,
947 * the PG_hwpoison page will be caught and isolated on the entrance to
948 * the free buddy page pool.
949 */
950 if (TestClearPageHWPoison(p)) {
951 pr_debug("MCE: Software-unpoisoned page %#lx\n", pfn);
952 atomic_long_dec(&mce_bad_pages);
953 freeit = 1;
954 }
955 unlock_page(page);
956
957 put_page(page);
958 if (freeit)
959 put_page(page);
960
961 return 0;
962}
963EXPORT_SYMBOL(unpoison_memory);