[Devel,rh7] mm/memcontrol/numa_migrate: split transparent huge pages before migrating

Submitted by Andrey Ryabinin on Nov. 22, 2016, 2:25 p.m.

Details

Message ID 1479824752-29430-1-git-send-email-aryabinin@virtuozzo.com
State New
Series "mm/memcontrol/numa_migrate: split transparent huge pages before migrating"
Headers show

Commit Message

Andrey Ryabinin Nov. 22, 2016, 2:25 p.m.
When migrate_pages() steps on transparent huge page it splits the page and
migrates only a head page. Therefore after migration NR_ISOLATED_ANON counter
is dropped by one.
When memcg_numa_isolate_pages() isolates huge page it increase NR_ISOLATED_ANON
counter by the number of sub-pages in hugepage, which is never dropped by
migrate_pages() as above.
Eventually this leads to complete lockup, because every allocation will stuck
in too_many_isolated() loop.

This patch fixes this by splitting huge page before migration and adding
sub-pages to migration list.

https://jira.sw.ru/browse/PSBM-54455

Fixes: a2d6b96306e3 ("mm: memcontrol: add memory.numa_migrate file")
Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 mm/memcontrol.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index cdf1b48..6366cc0 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -5740,12 +5740,13 @@  static long memcg_numa_isolate_pages(struct lruvec *lruvec, enum lru_list lru,
 {
 	struct list_head *src = &lruvec->lists[lru];
 	struct zone *zone = lruvec_zone(lruvec);
+	struct page *page;
 	long scanned = 0, taken = 0;
 
 	spin_lock_irq(&zone->lru_lock);
 	while (!list_empty(src) && scanned < nr_to_scan && taken < nr_to_scan) {
-		struct page *page = list_last_entry(src, struct page, lru);
 		int nr_pages;
+		page = list_last_entry(src, struct page, lru);
 
 		scanned++;
 
@@ -5769,6 +5770,15 @@  static long memcg_numa_isolate_pages(struct lruvec *lruvec, enum lru_list lru,
 	__mod_zone_page_state(zone, NR_ISOLATED_ANON + is_file_lru(lru), taken);
 	spin_unlock_irq(&zone->lru_lock);
 
+	list_for_each_entry(page, dst, lru) {
+		if (PageTransHuge(page) && split_huge_page_to_list(page, dst)) {
+			list_del(&page->lru);
+			mod_zone_page_state(zone, NR_ISOLATED_ANON,
+					HPAGE_PMD_NR);
+			putback_lru_page(page);
+		}
+	}
+
 	return scanned;
 }