Skip to content

Commit 34d9e35

Browse files
mjkravetztorvalds
authored andcommitted
hugetlb: add demote bool to gigantic page routines
The routines remove_hugetlb_page and destroy_compound_gigantic_page will remove a gigantic page and make the set of base pages ready to be returned to a lower level allocator. In the process of doing this, they make all base pages reference counted. The routine prep_compound_gigantic_page creates a gigantic page from a set of base pages. It assumes that all these base pages are reference counted. During demotion, a gigantic page will be split into huge pages of a smaller size. This logically involves use of the routines, remove_hugetlb_page, and destroy_compound_gigantic_page followed by prep_compound*_page for each smaller huge page. When pages are reference counted (ref count >= 0), additional speculative ref counts could be taken as described in previous commits [1] and [2]. This could result in errors while demoting a huge page. Quite a bit of code would need to be created to handle all possible issues. Instead of dealing with the possibility of speculative ref counts, avoid the possibility by keeping ref counts at zero during the demote process. Add a boolean 'demote' to the routines remove_hugetlb_page, destroy_compound_gigantic_page and prep_compound_gigantic_page. If the boolean is set, the remove and destroy routines will not reference count pages and the prep routine will not expect reference counted pages. '*_for_demote' wrappers of the routines will be added in a subsequent patch where this functionality is used. [1] https://lore.kernel.org/linux-mm/20210622021423.154662-3-mike.kravetz@oracle.com/ [2] https://lore.kernel.org/linux-mm/20210809184832.18342-3-mike.kravetz@oracle.com/ Link: https://lkml.kernel.org/r/20211007181918.136982-5-mike.kravetz@oracle.com Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> Reviewed-by: Oscar Salvador <osalvador@suse.de> Cc: "Aneesh Kumar K . V" <aneesh.kumar@linux.ibm.com> Cc: David Hildenbrand <david@redhat.com> Cc: David Rientjes <rientjes@google.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Muchun Song <songmuchun@bytedance.com> Cc: Naoya Horiguchi <naoya.horiguchi@linux.dev> Cc: Nghia Le <nghialm78@gmail.com> Cc: Zi Yan <ziy@nvidia.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent a01f439 commit 34d9e35

File tree

1 file changed

+43
-11
lines changed

1 file changed

+43
-11
lines changed

mm/hugetlb.c

+43-11
Original file line numberDiff line numberDiff line change
@@ -1271,8 +1271,8 @@ static int hstate_next_node_to_free(struct hstate *h, nodemask_t *nodes_allowed)
12711271
nr_nodes--)
12721272

12731273
#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
1274-
static void destroy_compound_gigantic_page(struct page *page,
1275-
unsigned int order)
1274+
static void __destroy_compound_gigantic_page(struct page *page,
1275+
unsigned int order, bool demote)
12761276
{
12771277
int i;
12781278
int nr_pages = 1 << order;
@@ -1284,14 +1284,21 @@ static void destroy_compound_gigantic_page(struct page *page,
12841284
for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
12851285
p->mapping = NULL;
12861286
clear_compound_head(p);
1287-
set_page_refcounted(p);
1287+
if (!demote)
1288+
set_page_refcounted(p);
12881289
}
12891290

12901291
set_compound_order(page, 0);
12911292
page[1].compound_nr = 0;
12921293
__ClearPageHead(page);
12931294
}
12941295

1296+
static void destroy_compound_gigantic_page(struct page *page,
1297+
unsigned int order)
1298+
{
1299+
__destroy_compound_gigantic_page(page, order, false);
1300+
}
1301+
12951302
static void free_gigantic_page(struct page *page, unsigned int order)
12961303
{
12971304
/*
@@ -1364,12 +1371,15 @@ static inline void destroy_compound_gigantic_page(struct page *page,
13641371

13651372
/*
13661373
* Remove hugetlb page from lists, and update dtor so that page appears
1367-
* as just a compound page. A reference is held on the page.
1374+
* as just a compound page.
1375+
*
1376+
* A reference is held on the page, except in the case of demote.
13681377
*
13691378
* Must be called with hugetlb lock held.
13701379
*/
1371-
static void remove_hugetlb_page(struct hstate *h, struct page *page,
1372-
bool adjust_surplus)
1380+
static void __remove_hugetlb_page(struct hstate *h, struct page *page,
1381+
bool adjust_surplus,
1382+
bool demote)
13731383
{
13741384
int nid = page_to_nid(page);
13751385

@@ -1407,8 +1417,12 @@ static void remove_hugetlb_page(struct hstate *h, struct page *page,
14071417
*
14081418
* This handles the case where more than one ref is held when and
14091419
* after update_and_free_page is called.
1420+
*
1421+
* In the case of demote we do not ref count the page as it will soon
1422+
* be turned into a page of smaller size.
14101423
*/
1411-
set_page_refcounted(page);
1424+
if (!demote)
1425+
set_page_refcounted(page);
14121426
if (hstate_is_gigantic(h))
14131427
set_compound_page_dtor(page, NULL_COMPOUND_DTOR);
14141428
else
@@ -1418,6 +1432,12 @@ static void remove_hugetlb_page(struct hstate *h, struct page *page,
14181432
h->nr_huge_pages_node[nid]--;
14191433
}
14201434

1435+
static void remove_hugetlb_page(struct hstate *h, struct page *page,
1436+
bool adjust_surplus)
1437+
{
1438+
__remove_hugetlb_page(h, page, adjust_surplus, false);
1439+
}
1440+
14211441
static void add_hugetlb_page(struct hstate *h, struct page *page,
14221442
bool adjust_surplus)
14231443
{
@@ -1681,7 +1701,8 @@ static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
16811701
spin_unlock_irq(&hugetlb_lock);
16821702
}
16831703

1684-
static bool prep_compound_gigantic_page(struct page *page, unsigned int order)
1704+
static bool __prep_compound_gigantic_page(struct page *page, unsigned int order,
1705+
bool demote)
16851706
{
16861707
int i, j;
16871708
int nr_pages = 1 << order;
@@ -1719,10 +1740,16 @@ static bool prep_compound_gigantic_page(struct page *page, unsigned int order)
17191740
* the set of pages can not be converted to a gigantic page.
17201741
* The caller who allocated the pages should then discard the
17211742
* pages using the appropriate free interface.
1743+
*
1744+
* In the case of demote, the ref count will be zero.
17221745
*/
1723-
if (!page_ref_freeze(p, 1)) {
1724-
pr_warn("HugeTLB page can not be used due to unexpected inflated ref count\n");
1725-
goto out_error;
1746+
if (!demote) {
1747+
if (!page_ref_freeze(p, 1)) {
1748+
pr_warn("HugeTLB page can not be used due to unexpected inflated ref count\n");
1749+
goto out_error;
1750+
}
1751+
} else {
1752+
VM_BUG_ON_PAGE(page_count(p), p);
17261753
}
17271754
set_page_count(p, 0);
17281755
set_compound_head(p, page);
@@ -1747,6 +1774,11 @@ static bool prep_compound_gigantic_page(struct page *page, unsigned int order)
17471774
return false;
17481775
}
17491776

1777+
static bool prep_compound_gigantic_page(struct page *page, unsigned int order)
1778+
{
1779+
return __prep_compound_gigantic_page(page, order, false);
1780+
}
1781+
17501782
/*
17511783
* PageHuge() only returns true for hugetlbfs pages, but not for normal or
17521784
* transparent huge pages. See the PageTransHuge() documentation for more

0 commit comments

Comments
 (0)