Backport some bugfix to enhance the feature.
v1->v2: Correct the fixtag to pass checkformat and checkdepend.
Liu Shixin (6): mm/dynamic_hugetlb: reduce the number of migration attempts mm/dynamic_hugetlb: add cond_resched() in hpool_merge_page() mm/dynamic_hugetlb: add lru_add_drain_all() before migration mm/dynamic_hugetlb: check NULL pointer for early parameter mm/dynamic_hugetlb: make free_huge_page_to_dhugetlb_pool irq safe mm/dynamic_hugetlb: refine error info in the destruction
Ma Wupeng (1): mm/dpool: Use helper function to lock/unlock
mm/dynamic_hugetlb.c | 176 ++++++++++++++++++++++++++++++------------- mm/hugetlb.c | 4 +- 2 files changed, 124 insertions(+), 56 deletions(-)
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/8039 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/H...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/8039 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/H...
From: Ma Wupeng mawupeng1@huawei.com
hulk inclusion category: cleanup bugzilla: https://gitee.com/openeuler/kernel/issues/I9K8D1 CVE: NA
--------------------------------
Use helper function to lock/unlock hugetlb related locks.
No function changed.
Signed-off-by: Ma Wupeng mawupeng1@huawei.com --- mm/dynamic_hugetlb.c | 79 ++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 21 deletions(-)
diff --git a/mm/dynamic_hugetlb.c b/mm/dynamic_hugetlb.c index 8199ef893f4a..802a36081c1b 100644 --- a/mm/dynamic_hugetlb.c +++ b/mm/dynamic_hugetlb.c @@ -19,6 +19,53 @@ bool enable_dhugetlb = false; DEFINE_STATIC_KEY_FALSE(dhugetlb_enabled_key);
+/* + * Lock this to prevert any page allocation from percpu pool. + * + * Before we lock percpu_pool, must be sure hpool lock is released. + */ +static inline void dhugetlb_percpu_pool_lock_all(struct dhugetlb_pool *hpool) +{ + int i; + + for (i = 0; i < NR_PERCPU_POOL; i++) + spin_lock(&hpool->percpu_pool[i].lock); +} + +static inline void dhugetlb_percpu_pool_unlock_all(struct dhugetlb_pool *hpool) +{ + int i; + + for (i = NR_PERCPU_POOL - 1; i >= 0; i--) + spin_unlock(&hpool->percpu_pool[i].lock); +} + +/* + * Lock all before r/w percpu_pool. + * + * Each percpu_pool lock is used to block page allocated/freed by others. + * The hpool lock is used to block page allocated/freed by percpu_pool. + * + * We need to lock all in following situation: + * a) when merging pages, we have to make sure no one can alloc page from + each pool. + * b) when get the accurate pagecount. + * hpool->lock & all percpu_pool lock must be released before this. + */ +static inline void dhugetlb_lock_all(struct dhugetlb_pool *hpool) +{ + dhugetlb_percpu_pool_lock_all(hpool); + spin_lock(&hpool->lock); +} + +static inline void dhugetlb_unlock_all(struct dhugetlb_pool *hpool) +{ + lockdep_assert_held(&hpool->lock); + + spin_unlock(&hpool->lock); + dhugetlb_percpu_pool_unlock_all(hpool); +} + #define hugepage_index(pfn) ((pfn) >> (PUD_SHIFT - PAGE_SHIFT)) static void add_new_page_to_pool(struct dhugetlb_pool *hpool, struct page *page, int hpages_pool_idx) { @@ -231,9 +278,7 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo */ if (hpages_pool_idx == HUGE_PAGES_POOL_2M) { spin_unlock(&hpool->lock); - for (i = 0; i < NR_PERCPU_POOL; i++) - spin_lock(&hpool->percpu_pool[i].lock); - spin_lock(&hpool->lock); + dhugetlb_lock_all(hpool); for (i = 0; i < NR_PERCPU_POOL; i++) { percpu_pool = &hpool->percpu_pool[i]; reclaim_pages_from_percpu_pool(hpool, percpu_pool, @@ -251,14 +296,12 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo goto migrate; } } - if (hpages_pool_idx == HUGE_PAGES_POOL_2M) { + if (hpages_pool_idx == HUGE_PAGES_POOL_2M) /* * All target 4K page are in src_hpages_pool, we * can unlock percpu pool. */ - for (i = 0; i < NR_PERCPU_POOL; i++) - spin_unlock(&hpool->percpu_pool[i].lock); - } + dhugetlb_percpu_pool_unlock_all(hpool);
list_del(&split_page->head_pages); hpages_pool->split_normal_pages--; @@ -291,11 +334,10 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo trace_dynamic_hugetlb_split_merge(hpool, page, DHUGETLB_MERGE, page_size(page)); return 0; next: - if (hpages_pool_idx == HUGE_PAGES_POOL_2M) { + if (hpages_pool_idx == HUGE_PAGES_POOL_2M) /* Unlock percpu pool before try next */ - for (i = 0; i < NR_PERCPU_POOL; i++) - spin_unlock(&hpool->percpu_pool[i].lock); - } + dhugetlb_percpu_pool_unlock_all(hpool); + continue; migrate: /* page migration only used for HUGE_PAGES_POOL_2M */ @@ -313,9 +355,7 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo }
/* Unlock and try migration. */ - for (i = 0; i < NR_PERCPU_POOL; i++) - spin_unlock(&hpool->percpu_pool[i].lock); - spin_unlock(&hpool->lock); + dhugetlb_unlock_all(hpool);
for (i = 0; i < nr_pages; i+= block_size) { p = pfn_to_page(split_page->start_pfn + i); @@ -652,8 +692,9 @@ void link_hpool(struct hugetlbfs_inode_info *p, struct hstate *h) p->hpool = find_hpool_by_task(current); if (!get_hpool_unless_zero(p->hpool)) p->hpool = NULL; - } else + } else { p->hpool = NULL; + } }
void unlink_hpool(struct hugetlbfs_inode_info *p) @@ -1137,9 +1178,7 @@ int hugetlb_pool_info_show(struct seq_file *m, void *v) if (!get_hpool_unless_zero(hpool)) return 0;
- for (i = 0; i < NR_PERCPU_POOL; i++) - spin_lock(&hpool->percpu_pool[i].lock); - spin_lock(&hpool->lock); + dhugetlb_lock_all(hpool);
free_pages = hpool->hpages_pool[HUGE_PAGES_POOL_4K].free_normal_pages; for (i = 0; i < NR_PERCPU_POOL; i++) { @@ -1175,9 +1214,7 @@ int hugetlb_pool_info_show(struct seq_file *m, void *v) free_pages, used_pages);
- spin_unlock(&hpool->lock); - for (i = NR_PERCPU_POOL - 1; i >= 0; i--) - spin_unlock(&hpool->percpu_pool[i].lock); + dhugetlb_unlock_all(hpool); put_hpool(hpool); return 0; }
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9K8D1 CVE: NA
--------------------------------
do_migrate_range() will firstly isolate pages and then migrate pages. If a pages is failed to isolate, it may not be successful in a short time even if tried many times. Since migrate_pages() has already tried 10 times to migrate the pages, there is also no need to migrate pages many times.
So just call do_migrate_range() once. This will reduce the log of migration failures.
Fixes: cdbeee51d044 ("mm/dynamic_hugetlb: add migration function") Signed-off-by: Liu Shixin liushixin2@huawei.com --- mm/dynamic_hugetlb.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/mm/dynamic_hugetlb.c b/mm/dynamic_hugetlb.c index 802a36081c1b..dc4cf48a332e 100644 --- a/mm/dynamic_hugetlb.c +++ b/mm/dynamic_hugetlb.c @@ -231,9 +231,6 @@ static void reclaim_pages_from_percpu_pool(struct dhugetlb_pool *hpool, } }
-/* We only try 5 times to reclaim pages */ -#define HPOOL_RECLAIM_RETRIES 5 - static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bool force_merge) { struct huge_pages_pool *hpages_pool, *src_hpages_pool; @@ -242,7 +239,8 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo struct page *page, *next, *p; struct percpu_pages_pool *percpu_pool; bool need_migrate = false, need_initial = false; - int i, try; + bool tried_migrate, can_merge; + int i; LIST_HEAD(wait_page_list);
lockdep_assert_held(&hpool->lock); @@ -269,9 +267,11 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo return -ENOMEM;
list_for_each_entry_safe(split_page, split_next, &hpages_pool->hugepage_splitlists, head_pages) { - try = 0; + tried_migrate = false;
merge: + can_merge = true; + /* * If we are merging 4K page to 2M page, we need to get * lock of percpu pool sequentially and clear percpu pool. @@ -290,8 +290,14 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo for (i = 0; i < nr_pages; i+= block_size) { p = pfn_to_page(split_page->start_pfn + i); if (PagePool(p)) { - if (!need_migrate) - goto next; + /* + * Some pages still in use, can't merge. + * If don't need migration or have tried, + * then skip merging these pages. + */ + can_merge = false; + if (!need_migrate || tried_migrate) + break; else goto migrate; } @@ -303,6 +309,9 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo */ dhugetlb_percpu_pool_unlock_all(hpool);
+ if (!can_merge) + continue; + list_del(&split_page->head_pages); hpages_pool->split_normal_pages--; for (i = 0; i < nr_pages; i+= block_size) { @@ -333,16 +342,8 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo add_new_page_to_pool(hpool, page, hpages_pool_idx); trace_dynamic_hugetlb_split_merge(hpool, page, DHUGETLB_MERGE, page_size(page)); return 0; -next: - if (hpages_pool_idx == HUGE_PAGES_POOL_2M) - /* Unlock percpu pool before try next */ - dhugetlb_percpu_pool_unlock_all(hpool); - - continue; migrate: - /* page migration only used for HUGE_PAGES_POOL_2M */ - if (try++ >= HPOOL_RECLAIM_RETRIES) - goto next; + tried_migrate = true;
/* Isolate free page first. */ INIT_LIST_HEAD(&wait_page_list);
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9K8D1 CVE: NA
--------------------------------
hpool_merge_page() will traver hugepage_splitlists and try to merge pages. The number of pages may be large and it will try to migrate pages which are in used. So the process can take a long times. To avoid softlockup, add cond_resched() before loop and migration.
Fixes: cdbeee51d044 ("mm/dynamic_hugetlb: add migration function") Signed-off-by: Liu Shixin liushixin2@huawei.com --- mm/dynamic_hugetlb.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/mm/dynamic_hugetlb.c b/mm/dynamic_hugetlb.c index dc4cf48a332e..fd8a994ecf63 100644 --- a/mm/dynamic_hugetlb.c +++ b/mm/dynamic_hugetlb.c @@ -272,18 +272,21 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo merge: can_merge = true;
+ spin_unlock(&hpool->lock); + cond_resched(); /* * If we are merging 4K page to 2M page, we need to get * lock of percpu pool sequentially and clear percpu pool. */ if (hpages_pool_idx == HUGE_PAGES_POOL_2M) { - spin_unlock(&hpool->lock); dhugetlb_lock_all(hpool); for (i = 0; i < NR_PERCPU_POOL; i++) { percpu_pool = &hpool->percpu_pool[i]; reclaim_pages_from_percpu_pool(hpool, percpu_pool, percpu_pool->free_pages); } + } else { + spin_lock(&hpool->lock); }
page = pfn_to_page(split_page->start_pfn); @@ -360,12 +363,14 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo
for (i = 0; i < nr_pages; i+= block_size) { p = pfn_to_page(split_page->start_pfn + i); - if (PagePool(p)) + if (PagePool(p)) { + cond_resched(); /* * TODO: fatal migration failures should bail * out */ do_migrate_range(page_to_pfn(p), page_to_pfn(p) + block_size); + } } spin_lock(&hpool->lock);
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9K8D1 CVE: NA
--------------------------------
Since the pages in pagevec will failed to isolate, call lru_add_drain_all() before migration can increase the probability of migration success.
Fixes: cdbeee51d044 ("mm/dynamic_hugetlb: add migration function") Signed-off-by: Liu Shixin liushixin2@huawei.com --- mm/dynamic_hugetlb.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/mm/dynamic_hugetlb.c b/mm/dynamic_hugetlb.c index fd8a994ecf63..bf217db405fb 100644 --- a/mm/dynamic_hugetlb.c +++ b/mm/dynamic_hugetlb.c @@ -7,6 +7,7 @@ #include <linux/migrate.h> #include <linux/memblock.h> #include <linux/memory_hotplug.h> +#include <linux/swap.h> #include <linux/dynamic_hugetlb.h>
#include "internal.h" @@ -365,6 +366,7 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo p = pfn_to_page(split_page->start_pfn + i); if (PagePool(p)) { cond_resched(); + lru_add_drain_all(); /* * TODO: fatal migration failures should bail * out
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9K8D1 CVE: NA
--------------------------------
Add null pointer check for early parameter.
Fixes: a8a836a36072 ("mm/dynamic_hugetlb: establish the dynamic hugetlb feature framework") Signed-off-by: Liu Shixin liushixin2@huawei.com --- mm/dynamic_hugetlb.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/mm/dynamic_hugetlb.c b/mm/dynamic_hugetlb.c index bf217db405fb..dbdd8546994e 100644 --- a/mm/dynamic_hugetlb.c +++ b/mm/dynamic_hugetlb.c @@ -1250,6 +1250,9 @@ void __init dynamic_hugetlb_init(void)
static int __init dynamic_hugetlb_setup(char *s) { + if (!s) + return 0; + if (!strcmp(s, "on")) enable_dhugetlb = true; return 0;
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9K8D1 CVE: NA
--------------------------------
Like commit db71ef79b59b ("hugetlb: make free_huge_page irq safe") said, the spinlock may be interrupt by hugetlb freeing path, which will results deadlock. This patch fix such deadlock scenarios by changing spin_lock to spin_lock_irq in every path.
Fixes: a8a836a36072 ("mm/dynamic_hugetlb: establish the dynamic hugetlb feature framework") Signed-off-by: Liu Shixin liushixin2@huawei.com --- mm/dynamic_hugetlb.c | 33 ++++++++++++++++++--------------- mm/hugetlb.c | 4 ++-- 2 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/mm/dynamic_hugetlb.c b/mm/dynamic_hugetlb.c index dbdd8546994e..c40d436b1d2b 100644 --- a/mm/dynamic_hugetlb.c +++ b/mm/dynamic_hugetlb.c @@ -30,7 +30,7 @@ static inline void dhugetlb_percpu_pool_lock_all(struct dhugetlb_pool *hpool) int i;
for (i = 0; i < NR_PERCPU_POOL; i++) - spin_lock(&hpool->percpu_pool[i].lock); + spin_lock_nested(&hpool->percpu_pool[i].lock, i); }
static inline void dhugetlb_percpu_pool_unlock_all(struct dhugetlb_pool *hpool) @@ -55,6 +55,7 @@ static inline void dhugetlb_percpu_pool_unlock_all(struct dhugetlb_pool *hpool) */ static inline void dhugetlb_lock_all(struct dhugetlb_pool *hpool) { + local_irq_disable(); dhugetlb_percpu_pool_lock_all(hpool); spin_lock(&hpool->lock); } @@ -65,6 +66,7 @@ static inline void dhugetlb_unlock_all(struct dhugetlb_pool *hpool)
spin_unlock(&hpool->lock); dhugetlb_percpu_pool_unlock_all(hpool); + local_irq_enable(); }
#define hugepage_index(pfn) ((pfn) >> (PUD_SHIFT - PAGE_SHIFT)) @@ -273,7 +275,7 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo merge: can_merge = true;
- spin_unlock(&hpool->lock); + spin_unlock_irq(&hpool->lock); cond_resched(); /* * If we are merging 4K page to 2M page, we need to get @@ -287,7 +289,7 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo percpu_pool->free_pages); } } else { - spin_lock(&hpool->lock); + spin_lock_irq(&hpool->lock); }
page = pfn_to_page(split_page->start_pfn); @@ -374,7 +376,7 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo do_migrate_range(page_to_pfn(p), page_to_pfn(p) + block_size); } } - spin_lock(&hpool->lock); + spin_lock_irq(&hpool->lock);
/* * Move all isolate pages to src_hpages_pool and then try @@ -733,7 +735,7 @@ int dhugetlb_acct_memory(struct hstate *h, long delta, struct hugetlbfs_inode_in if (delta == 0) return 0;
- spin_lock(&hpool->lock); + spin_lock_irq(&hpool->lock); if (hstate_is_gigantic(h)) hpages_pool = &hpool->hpages_pool[HUGE_PAGES_POOL_1G]; else @@ -750,7 +752,7 @@ int dhugetlb_acct_memory(struct hstate *h, long delta, struct hugetlbfs_inode_in trace_dynamic_hugetlb_acct_memory(hpool, hpages_pool->resv_huge_pages, DHUGETLB_UNRESV, huge_page_size(h)); } - spin_unlock(&hpool->lock); + spin_unlock_irq(&hpool->lock);
return ret; } @@ -801,6 +803,7 @@ void free_huge_page_to_dhugetlb_pool(struct page *page, bool restore_reserve) struct hstate *h = page_hstate(page); struct huge_pages_pool *hpages_pool; struct dhugetlb_pool *hpool; + unsigned long flags;
hpool = find_hpool_by_dhugetlb_pagelist(page);
@@ -809,7 +812,7 @@ void free_huge_page_to_dhugetlb_pool(struct page *page, bool restore_reserve) return; }
- spin_lock(&hpool->lock); + spin_lock_irqsave(&hpool->lock, flags); /* * memory_failure will free the hwpoison hugepage, and then try to * dissolve it and free subpage to buddy system. Since the page in @@ -835,7 +838,7 @@ void free_huge_page_to_dhugetlb_pool(struct page *page, bool restore_reserve) trace_dynamic_hugetlb_alloc_free(hpool, page, hpages_pool->free_huge_pages, DHUGETLB_FREE, huge_page_size(h)); out: - spin_unlock(&hpool->lock); + spin_unlock_irqrestore(&hpool->lock, flags); put_hpool(hpool); }
@@ -851,7 +854,7 @@ static int alloc_hugepage_from_hugetlb(struct dhugetlb_pool *hpool, if (!h) return -ENOMEM;
- spin_lock(&hpool->lock); + spin_lock_irq(&hpool->lock); spin_lock(&hugetlb_lock); if (h->free_huge_pages_node[nid] - h->resv_huge_pages_node[nid] < nr_pages) { ret = -ENOMEM; @@ -877,7 +880,7 @@ static int alloc_hugepage_from_hugetlb(struct dhugetlb_pool *hpool,
out_unlock: spin_unlock(&hugetlb_lock); - spin_unlock(&hpool->lock); + spin_unlock_irq(&hpool->lock); return ret; }
@@ -983,15 +986,15 @@ int hugetlb_pool_destroy(struct cgroup *cgrp) */ mem_cgroup_force_empty(hpool->attach_memcg);
- spin_lock(&hpool->lock); + spin_lock_irq(&hpool->lock); ret = hugetlb_pool_merge_all_pages(hpool); if (ret) { - spin_unlock(&hpool->lock); + spin_unlock_irq(&hpool->lock); return -ENOMEM; } ret = free_hugepage_to_hugetlb(hpool); memcg->hpool = NULL; - spin_unlock(&hpool->lock); + spin_unlock_irq(&hpool->lock); put_hpool(hpool); return ret; } @@ -1058,7 +1061,7 @@ static ssize_t update_reserved_pages(struct mem_cgroup *memcg, char *buf, int hp return -EINVAL;
mutex_lock(&hpool->reserved_lock); - spin_lock(&hpool->lock); + spin_lock_irq(&hpool->lock); hpages_pool = &hpool->hpages_pool[hpages_pool_idx]; if (nr_pages > hpages_pool->nr_huge_pages) { delta = nr_pages - hpages_pool->nr_huge_pages; @@ -1092,7 +1095,7 @@ static ssize_t update_reserved_pages(struct mem_cgroup *memcg, char *buf, int hp hpages_pool->free_huge_pages -= delta; hpages_pool->free_normal_pages += delta; } - spin_unlock(&hpool->lock); + spin_unlock_irq(&hpool->lock); mutex_unlock(&hpool->reserved_lock); put_hpool(hpool); return 0; diff --git a/mm/hugetlb.c b/mm/hugetlb.c index a333caf66d15..e04c21f735ad 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1597,14 +1597,14 @@ void free_huge_page(struct page *page) ClearHPageRestoreReserve(page);
if (dhugetlb_enabled && PagePool(page)) { - spin_lock(&hugetlb_lock); + spin_lock_irqsave(&hugetlb_lock, flags); ClearHPageMigratable(page); list_del(&page->lru); hugetlb_cgroup_uncharge_page(hstate_index(h), pages_per_huge_page(h), page); hugetlb_cgroup_uncharge_page_rsvd(hstate_index(h), pages_per_huge_page(h), page); - spin_unlock(&hugetlb_lock); + spin_unlock_irqrestore(&hugetlb_lock, flags); free_huge_page_to_dhugetlb_pool(page, restore_reserve); return; }
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9K8D1 CVE: NA
--------------------------------
Add check of resv_huge_pages in hugetlb_pool_merge_all_pages() and print more accurate error information. Reset the counter to prevent allocation.
Fixes: 29617b44eb8a ("mm/dynamic_hugetlb: add merge page function") Signed-off-by: Liu Shixin liushixin2@huawei.com --- mm/dynamic_hugetlb.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/mm/dynamic_hugetlb.c b/mm/dynamic_hugetlb.c index c40d436b1d2b..72061fd0395e 100644 --- a/mm/dynamic_hugetlb.c +++ b/mm/dynamic_hugetlb.c @@ -393,32 +393,49 @@ static int hpool_merge_page(struct dhugetlb_pool *hpool, int hpages_pool_idx, bo
static int hugetlb_pool_merge_all_pages(struct dhugetlb_pool *hpool) { + struct huge_pages_pool *hpages_pool; int ret = 0;
lockdep_assert_held(&hpool->lock);
- while (hpool->hpages_pool[HUGE_PAGES_POOL_2M].split_normal_pages) { + hpages_pool = &hpool->hpages_pool[HUGE_PAGES_POOL_2M]; + while (hpages_pool->split_normal_pages) { ret = hpool_merge_page(hpool, HUGE_PAGES_POOL_2M, true); if (ret) { - pr_err("dynamic_hugetlb: some 4K pages are still in use, delete memcg: %s failed!\n", + pr_err("dynamic_hugetlb: %s: merge 4K failed!\n", hpool->attach_memcg->css.cgroup->kn->name); goto out; } } - while (hpool->hpages_pool[HUGE_PAGES_POOL_1G].split_normal_pages) { + if (hpages_pool->used_huge_pages || hpages_pool->resv_huge_pages) { + ret = -ENOMEM; + pr_err("dynamic_hugetlb: %s: 2M pages in use or resv\n", + hpool->attach_memcg->css.cgroup->kn->name); + goto out; + } + hpages_pool->free_normal_pages += hpages_pool->nr_huge_pages; + hpages_pool->nr_huge_pages = 0; + hpages_pool->free_huge_pages = 0; + + hpages_pool = &hpool->hpages_pool[HUGE_PAGES_POOL_1G]; + while (hpages_pool->split_normal_pages) { ret = hpool_merge_page(hpool, HUGE_PAGES_POOL_1G, true); if (ret) { - pr_err("dynamic_hugetlb: some 2M pages are still in use, delete memcg: %s failed!\n", + pr_err("dynamic_hugetlb: %s: merge 2M failed!\n", hpool->attach_memcg->css.cgroup->kn->name); goto out; } } - if (hpool->hpages_pool[HUGE_PAGES_POOL_1G].used_huge_pages) { + if (hpages_pool->used_huge_pages || hpages_pool->resv_huge_pages) { ret = -ENOMEM; - pr_err("dynamic_hugetlb: some 1G pages are still in use, delete memcg: %s failed!\n", + pr_err("dynamic_hugetlb: %s: 1G pages in use or resv\n", hpool->attach_memcg->css.cgroup->kn->name); goto out; } + hpages_pool->free_normal_pages += hpages_pool->nr_huge_pages; + hpages_pool->nr_huge_pages = 0; + hpages_pool->free_huge_pages = 0; + out: return ret; }