hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I6XOIE CVE: NA
--------------------------------
The memory hotplug and memory failure will dissolve freed hugepages to buddy system, this is not the expected behavior for dynamic hugetlb. Skip the dissolve operation for hugepages belonging to dynamic hugetlb. For memory hotplug, the hotplug operation is not allowed, if dhugetlb pool existed. For memory failure, the hugepage will be discard directly.
Signed-off-by: Liu Shixin liushixin2@huawei.com --- include/linux/dynamic_hugetlb.h | 6 ++++++ mm/dynamic_hugetlb.c | 23 ++++++++++++++++++++++- mm/hugetlb.c | 7 +++++++ 3 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/include/linux/dynamic_hugetlb.h b/include/linux/dynamic_hugetlb.h index af523139ab3a..476a9014a83a 100644 --- a/include/linux/dynamic_hugetlb.h +++ b/include/linux/dynamic_hugetlb.h @@ -104,6 +104,7 @@ int dhugetlb_acct_memory(struct hstate *h, long delta, struct hugetlbfs_inode_in struct page *alloc_huge_page_from_dhugetlb_pool(struct hstate *h, struct dhugetlb_pool *hpool, bool need_unreserved); void free_huge_page_to_dhugetlb_pool(struct page *page, bool restore_reserve); +bool page_belong_to_dynamic_hugetlb(struct page *page);
#else
@@ -171,6 +172,11 @@ static inline void free_huge_page_to_dhugetlb_pool(struct page *page, bool restore_reserve) { } +static inline +bool page_belong_to_dynamic_hugetlb(struct page *page) +{ + return false; +} #endif
#endif /* CONFIG_DYNAMIC_HUGETLB */ diff --git a/mm/dynamic_hugetlb.c b/mm/dynamic_hugetlb.c index ff4fd0c9f11b..228b04b9c7b7 100644 --- a/mm/dynamic_hugetlb.c +++ b/mm/dynamic_hugetlb.c @@ -448,6 +448,19 @@ static struct dhugetlb_pool *find_hpool_by_dhugetlb_pagelist(struct page *page) return hpool; }
+bool page_belong_to_dynamic_hugetlb(struct page *page) +{ + struct dhugetlb_pool *hpool; + + if (!dhugetlb_enabled) + return false; + + hpool = find_hpool_by_dhugetlb_pagelist(page); + if (hpool) + return true; + return false; +} + static struct dhugetlb_pool *find_hpool_by_task(struct task_struct *tsk) { struct mem_cgroup *memcg; @@ -740,8 +753,15 @@ void free_huge_page_to_dhugetlb_pool(struct page *page, bool restore_reserve) }
spin_lock(&hpool->lock); + /* + * memory_failure will free the hwpoison hugepage, and then try to + * dissolve it and free subpage to buddy system. Since the page in + * dhugetlb_pool should not free to buudy system, we isolate the + * hugepage here directly, and skip the latter dissolution. + */ + if (PageHWPoison(page)) + goto out; ClearPagePool(page); - set_compound_page_dtor(page, NULL_COMPOUND_DTOR); if (hstate_is_gigantic(h)) hpages_pool = &hpool->hpages_pool[HUGE_PAGES_POOL_1G]; else @@ -757,6 +777,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); put_hpool(hpool); } diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 63880f3e682d..0f211d12de33 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2025,6 +2025,13 @@ int dissolve_free_huge_page(struct page *page) if (!PageHuge(page)) return 0;
+ /* + * the page belong to dynamic hugetlb will be isolated as a whole + * when free. See free_huge_page_to_dhugetlb_pool() for detail. + */ + if (page_belong_to_dynamic_hugetlb(page)) + return -EBUSY; + spin_lock_irq(&hugetlb_lock); if (!PageHuge(page)) { rc = 0;