aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/migrate.h4
-rw-r--r--mm/memory-failure.c15
-rw-r--r--mm/migrate.c65
3 files changed, 27 insertions, 57 deletions
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 855c337b20c3..ce7e6671968b 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -15,7 +15,7 @@ extern int migrate_page(struct address_space *,
15extern int migrate_pages(struct list_head *l, new_page_t x, 15extern int migrate_pages(struct list_head *l, new_page_t x,
16 unsigned long private, bool offlining, 16 unsigned long private, bool offlining,
17 enum migrate_mode mode); 17 enum migrate_mode mode);
18extern int migrate_huge_pages(struct list_head *l, new_page_t x, 18extern int migrate_huge_page(struct page *, new_page_t x,
19 unsigned long private, bool offlining, 19 unsigned long private, bool offlining,
20 enum migrate_mode mode); 20 enum migrate_mode mode);
21 21
@@ -36,7 +36,7 @@ static inline void putback_lru_pages(struct list_head *l) {}
36static inline int migrate_pages(struct list_head *l, new_page_t x, 36static inline int migrate_pages(struct list_head *l, new_page_t x,
37 unsigned long private, bool offlining, 37 unsigned long private, bool offlining,
38 enum migrate_mode mode) { return -ENOSYS; } 38 enum migrate_mode mode) { return -ENOSYS; }
39static inline int migrate_huge_pages(struct list_head *l, new_page_t x, 39static inline int migrate_huge_page(struct page *page, new_page_t x,
40 unsigned long private, bool offlining, 40 unsigned long private, bool offlining,
41 enum migrate_mode mode) { return -ENOSYS; } 41 enum migrate_mode mode) { return -ENOSYS; }
42 42
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 6de0d613bbe6..b04ff2d6f73d 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1416,7 +1416,6 @@ static int soft_offline_huge_page(struct page *page, int flags)
1416 int ret; 1416 int ret;
1417 unsigned long pfn = page_to_pfn(page); 1417 unsigned long pfn = page_to_pfn(page);
1418 struct page *hpage = compound_head(page); 1418 struct page *hpage = compound_head(page);
1419 LIST_HEAD(pagelist);
1420 1419
1421 ret = get_any_page(page, pfn, flags); 1420 ret = get_any_page(page, pfn, flags);
1422 if (ret < 0) 1421 if (ret < 0)
@@ -1431,24 +1430,18 @@ static int soft_offline_huge_page(struct page *page, int flags)
1431 } 1430 }
1432 1431
1433 /* Keep page count to indicate a given hugepage is isolated. */ 1432 /* Keep page count to indicate a given hugepage is isolated. */
1434 1433 ret = migrate_huge_page(hpage, new_page, MPOL_MF_MOVE_ALL, false,
1435 list_add(&hpage->lru, &pagelist);
1436 ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, false,
1437 MIGRATE_SYNC); 1434 MIGRATE_SYNC);
1435 put_page(hpage);
1438 if (ret) { 1436 if (ret) {
1439 struct page *page1, *page2;
1440 list_for_each_entry_safe(page1, page2, &pagelist, lru)
1441 put_page(page1);
1442
1443 pr_info("soft offline: %#lx: migration failed %d, type %lx\n", 1437 pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
1444 pfn, ret, page->flags); 1438 pfn, ret, page->flags);
1445 if (ret > 0)
1446 ret = -EIO;
1447 return ret; 1439 return ret;
1448 } 1440 }
1449done: 1441done:
1450 if (!PageHWPoison(hpage)) 1442 if (!PageHWPoison(hpage))
1451 atomic_long_add(1 << compound_trans_order(hpage), &mce_bad_pages); 1443 atomic_long_add(1 << compound_trans_order(hpage),
1444 &mce_bad_pages);
1452 set_page_hwpoison_huge_page(hpage); 1445 set_page_hwpoison_huge_page(hpage);
1453 dequeue_hwpoisoned_huge_page(hpage); 1446 dequeue_hwpoisoned_huge_page(hpage);
1454 /* keep elevated page count for bad page */ 1447 /* keep elevated page count for bad page */
diff --git a/mm/migrate.c b/mm/migrate.c
index be26d5cbe56b..fdce3a29fc4c 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -932,15 +932,8 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
932 if (anon_vma) 932 if (anon_vma)
933 put_anon_vma(anon_vma); 933 put_anon_vma(anon_vma);
934 unlock_page(hpage); 934 unlock_page(hpage);
935
936out: 935out:
937 if (rc != -EAGAIN) {
938 list_del(&hpage->lru);
939 put_page(hpage);
940 }
941
942 put_page(new_hpage); 936 put_page(new_hpage);
943
944 if (result) { 937 if (result) {
945 if (rc) 938 if (rc)
946 *result = rc; 939 *result = rc;
@@ -1016,48 +1009,32 @@ out:
1016 return nr_failed + retry; 1009 return nr_failed + retry;
1017} 1010}
1018 1011
1019int migrate_huge_pages(struct list_head *from, 1012int migrate_huge_page(struct page *hpage, new_page_t get_new_page,
1020 new_page_t get_new_page, unsigned long private, bool offlining, 1013 unsigned long private, bool offlining,
1021 enum migrate_mode mode) 1014 enum migrate_mode mode)
1022{ 1015{
1023 int retry = 1; 1016 int pass, rc;
1024 int nr_failed = 0; 1017
1025 int pass = 0; 1018 for (pass = 0; pass < 10; pass++) {
1026 struct page *page; 1019 rc = unmap_and_move_huge_page(get_new_page,
1027 struct page *page2; 1020 private, hpage, pass > 2, offlining,
1028 int rc; 1021 mode);
1029 1022 switch (rc) {
1030 for (pass = 0; pass < 10 && retry; pass++) { 1023 case -ENOMEM:
1031 retry = 0; 1024 goto out;
1032 1025 case -EAGAIN:
1033 list_for_each_entry_safe(page, page2, from, lru) { 1026 /* try again */
1034 cond_resched(); 1027 cond_resched();
1035 1028 break;
1036 rc = unmap_and_move_huge_page(get_new_page, 1029 case 0:
1037 private, page, pass > 2, offlining, 1030 goto out;
1038 mode); 1031 default:
1039 1032 rc = -EIO;
1040 switch(rc) { 1033 goto out;
1041 case -ENOMEM:
1042 goto out;
1043 case -EAGAIN:
1044 retry++;
1045 break;
1046 case 0:
1047 break;
1048 default:
1049 /* Permanent failure */
1050 nr_failed++;
1051 break;
1052 }
1053 } 1034 }
1054 } 1035 }
1055 rc = 0;
1056out: 1036out:
1057 if (rc) 1037 return rc;
1058 return rc;
1059
1060 return nr_failed + retry;
1061} 1038}
1062 1039
1063#ifdef CONFIG_NUMA 1040#ifdef CONFIG_NUMA