aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory_hotplug.c
diff options
context:
space:
mode:
authorNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>2013-09-11 17:22:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-11 18:57:48 -0400
commitc8721bbbdd36382de51cd6b7a56322e0acca2414 (patch)
tree8fb7b55974defcde9a4b07f571f0dd2dd1ad591f /mm/memory_hotplug.c
parent71ea2efb1e936a127690a0a540b3a6162f95e48a (diff)
mm: memory-hotplug: enable memory hotplug to handle hugepage
Until now we can't offline memory blocks which contain hugepages because a hugepage is considered as an unmovable page. But now with this patch series, a hugepage has become movable, so by using hugepage migration we can offline such memory blocks. What's different from other users of hugepage migration is that we need to decompose all the hugepages inside the target memory block into free buddy pages after hugepage migration, because otherwise free hugepages remaining in the memory block intervene the memory offlining. For this reason we introduce new functions dissolve_free_huge_page() and dissolve_free_huge_pages(). Other than that, what this patch does is straightforwardly to add hugepage migration code, that is, adding hugepage code to the functions which scan over pfn and collect hugepages to be migrated, and adding a hugepage allocation function to alloc_migrate_target(). As for larger hugepages (1GB for x86_64), it's not easy to do hotremove over them because it's larger than memory block. So we now simply leave it to fail as it is. [yongjun_wei@trendmicro.com.cn: remove duplicated include] Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Acked-by: Andi Kleen <ak@linux.intel.com> Cc: Hillf Danton <dhillf@gmail.com> Cc: Wanpeng Li <liwanp@linux.vnet.ibm.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Hugh Dickins <hughd@google.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Michal Hocko <mhocko@suse.cz> Cc: Rik van Riel <riel@redhat.com> Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r--mm/memory_hotplug.c42
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 */
1236static unsigned long scan_lru_pages(unsigned long start, unsigned long end) 1239static 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 }
1310out: 1333out:
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) {