diff options
-rw-r--r-- | include/linux/migrate.h | 4 | ||||
-rw-r--r-- | mm/memory-failure.c | 15 | ||||
-rw-r--r-- | mm/migrate.c | 65 |
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 *, | |||
15 | extern int migrate_pages(struct list_head *l, new_page_t x, | 15 | extern 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); |
18 | extern int migrate_huge_pages(struct list_head *l, new_page_t x, | 18 | extern 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) {} | |||
36 | static inline int migrate_pages(struct list_head *l, new_page_t x, | 36 | static 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; } |
39 | static inline int migrate_huge_pages(struct list_head *l, new_page_t x, | 39 | static 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 | } |
1449 | done: | 1441 | done: |
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 | |||
936 | out: | 935 | out: |
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 | ||
1019 | int migrate_huge_pages(struct list_head *from, | 1012 | int 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; | ||
1056 | out: | 1036 | out: |
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 |