diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index d595606728f9..0eb1a1df649d 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/mm_inline.h> | 30 | #include <linux/mm_inline.h> |
31 | #include <linux/firmware-map.h> | 31 | #include <linux/firmware-map.h> |
32 | #include <linux/stop_machine.h> | 32 | #include <linux/stop_machine.h> |
33 | #include <linux/hugetlb.h> | ||
33 | 34 | ||
34 | #include <asm/tlbflush.h> | 35 | #include <asm/tlbflush.h> |
35 | 36 | ||
@@ -1230,10 +1231,12 @@ static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn) | |||
1230 | } | 1231 | } |
1231 | 1232 | ||
1232 | /* | 1233 | /* |
1233 | * Scanning pfn is much easier than scanning lru list. | 1234 | * Scan pfn range [start,end) to find movable/migratable pages (LRU pages |
1234 | * Scan pfn from start to end and Find LRU page. | 1235 | * and hugepages). We scan pfn because it's much easier than scanning over |
1236 | * linked list. This function returns the pfn of the first found movable | ||
1237 | * page if it's found, otherwise 0. | ||
1235 | */ | 1238 | */ |
1236 | static unsigned long scan_lru_pages(unsigned long start, unsigned long end) | 1239 | static unsigned long scan_movable_pages(unsigned long start, unsigned long end) |
1237 | { | 1240 | { |
1238 | unsigned long pfn; | 1241 | unsigned long pfn; |
1239 | struct page *page; | 1242 | struct page *page; |
@@ -1242,6 +1245,13 @@ static unsigned long scan_lru_pages(unsigned long start, unsigned long end) | |||
1242 | page = pfn_to_page(pfn); | 1245 | page = pfn_to_page(pfn); |
1243 | if (PageLRU(page)) | 1246 | if (PageLRU(page)) |
1244 | return pfn; | 1247 | return pfn; |
1248 | if (PageHuge(page)) { | ||
1249 | if (is_hugepage_active(page)) | ||
1250 | return pfn; | ||
1251 | else | ||
1252 | pfn = round_up(pfn + 1, | ||
1253 | 1 << compound_order(page)) - 1; | ||
1254 | } | ||
1245 | } | 1255 | } |
1246 | } | 1256 | } |
1247 | return 0; | 1257 | return 0; |
@@ -1262,6 +1272,19 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) | |||
1262 | if (!pfn_valid(pfn)) | 1272 | if (!pfn_valid(pfn)) |
1263 | continue; | 1273 | continue; |
1264 | page = pfn_to_page(pfn); | 1274 | page = pfn_to_page(pfn); |
1275 | |||
1276 | if (PageHuge(page)) { | ||
1277 | struct page *head = compound_head(page); | ||
1278 | pfn = page_to_pfn(head) + (1<<compound_order(head)) - 1; | ||
1279 | if (compound_order(head) > PFN_SECTION_SHIFT) { | ||
1280 | ret = -EBUSY; | ||
1281 | break; | ||
1282 | } | ||
1283 | if (isolate_huge_page(page, &source)) | ||
1284 | move_pages -= 1 << compound_order(head); | ||
1285 | continue; | ||
1286 | } | ||
1287 | |||
1265 | if (!get_page_unless_zero(page)) | 1288 | if (!get_page_unless_zero(page)) |
1266 | continue; | 1289 | continue; |
1267 | /* | 1290 | /* |
@@ -1294,7 +1317,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) | |||
1294 | } | 1317 | } |
1295 | if (!list_empty(&source)) { | 1318 | if (!list_empty(&source)) { |
1296 | if (not_managed) { | 1319 | if (not_managed) { |
1297 | putback_lru_pages(&source); | 1320 | putback_movable_pages(&source); |
1298 | goto out; | 1321 | goto out; |
1299 | } | 1322 | } |
1300 | 1323 | ||
@@ -1305,7 +1328,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn) | |||
1305 | ret = migrate_pages(&source, alloc_migrate_target, 0, | 1328 | ret = migrate_pages(&source, alloc_migrate_target, 0, |
1306 | MIGRATE_SYNC, MR_MEMORY_HOTPLUG); | 1329 | MIGRATE_SYNC, MR_MEMORY_HOTPLUG); |
1307 | if (ret) | 1330 | if (ret) |
1308 | putback_lru_pages(&source); | 1331 | putback_movable_pages(&source); |
1309 | } | 1332 | } |
1310 | out: | 1333 | out: |
1311 | return ret; | 1334 | return ret; |
@@ -1548,8 +1571,8 @@ repeat: | |||
1548 | drain_all_pages(); | 1571 | drain_all_pages(); |
1549 | } | 1572 | } |
1550 | 1573 | ||
1551 | pfn = scan_lru_pages(start_pfn, end_pfn); | 1574 | pfn = scan_movable_pages(start_pfn, end_pfn); |
1552 | if (pfn) { /* We have page on LRU */ | 1575 | if (pfn) { /* We have movable pages */ |
1553 | ret = do_migrate_range(pfn, end_pfn); | 1576 | ret = do_migrate_range(pfn, end_pfn); |
1554 | if (!ret) { | 1577 | if (!ret) { |
1555 | drain = 1; | 1578 | drain = 1; |
@@ -1568,6 +1591,11 @@ repeat: | |||
1568 | yield(); | 1591 | yield(); |
1569 | /* drain pcp pages, this is synchronous. */ | 1592 | /* drain pcp pages, this is synchronous. */ |
1570 | drain_all_pages(); | 1593 | drain_all_pages(); |
1594 | /* | ||
1595 | * dissolve free hugepages in the memory block before doing offlining | ||
1596 | * actually in order to make hugetlbfs's object counting consistent. | ||
1597 | */ | ||
1598 | dissolve_free_huge_pages(start_pfn, end_pfn); | ||
1571 | /* check again */ | 1599 | /* check again */ |
1572 | offlined_pages = check_pages_isolated(start_pfn, end_pfn); | 1600 | offlined_pages = check_pages_isolated(start_pfn, end_pfn); |
1573 | if (offlined_pages < 0) { | 1601 | if (offlined_pages < 0) { |