mm/hugetlb: convert update_and_free_page() to folios

Make more progress on converting the free_huge_page() destructor to
operate on folios by converting update_and_free_page() to folios.

Link: https://lkml.kernel.org/r/20221129225039.82257-6-sidhartha.kumar@oracle.com
Signed-off-by: Sidhartha Kumar <sidhartha.kumar@oracle.com>\
Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Mina Almasry <almasrymina@google.com>
Cc: Muchun Song <songmuchun@bytedance.com>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Tarun Sahu <tsahu@linux.ibm.com>
Cc: Wei Chen <harperchen1110@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Sidhartha Kumar 2022-11-29 14:50:34 -08:00 committed by Andrew Morton
parent cfd5082b51
commit d6ef19e25d
1 changed files with 16 additions and 14 deletions

View File

@ -1478,7 +1478,7 @@ static void __remove_hugetlb_folio(struct hstate *h, struct folio *folio,
* apply.
*
* This handles the case where more than one ref is held when and
* after update_and_free_page is called.
* after update_and_free_hugetlb_folio is called.
*
* In the case of demote we do not ref count the page as it will soon
* be turned into a page of smaller size.
@ -1609,7 +1609,7 @@ static void __update_and_free_page(struct hstate *h, struct page *page)
}
/*
* As update_and_free_page() can be called under any context, so we cannot
* As update_and_free_hugetlb_folio() can be called under any context, so we cannot
* use GFP_KERNEL to allocate vmemmap pages. However, we can defer the
* actual freeing in a workqueue to prevent from using GFP_ATOMIC to allocate
* the vmemmap pages.
@ -1657,11 +1657,11 @@ static inline void flush_free_hpage_work(struct hstate *h)
flush_work(&free_hpage_work);
}
static void update_and_free_page(struct hstate *h, struct page *page,
static void update_and_free_hugetlb_folio(struct hstate *h, struct folio *folio,
bool atomic)
{
if (!HPageVmemmapOptimized(page) || !atomic) {
__update_and_free_page(h, page);
if (!folio_test_hugetlb_vmemmap_optimized(folio) || !atomic) {
__update_and_free_page(h, &folio->page);
return;
}
@ -1672,16 +1672,18 @@ static void update_and_free_page(struct hstate *h, struct page *page,
* empty. Otherwise, schedule_work() had been called but the workfn
* hasn't retrieved the list yet.
*/
if (llist_add((struct llist_node *)&page->mapping, &hpage_freelist))
if (llist_add((struct llist_node *)&folio->mapping, &hpage_freelist))
schedule_work(&free_hpage_work);
}
static void update_and_free_pages_bulk(struct hstate *h, struct list_head *list)
{
struct page *page, *t_page;
struct folio *folio;
list_for_each_entry_safe(page, t_page, list, lru) {
update_and_free_page(h, page, false);
folio = page_folio(page);
update_and_free_hugetlb_folio(h, folio, false);
cond_resched();
}
}
@ -1751,12 +1753,12 @@ void free_huge_page(struct page *page)
if (folio_test_hugetlb_temporary(folio)) {
remove_hugetlb_folio(h, folio, false);
spin_unlock_irqrestore(&hugetlb_lock, flags);
update_and_free_page(h, page, true);
update_and_free_hugetlb_folio(h, folio, true);
} else if (h->surplus_huge_pages_node[nid]) {
/* remove the page from active list */
remove_hugetlb_folio(h, folio, true);
spin_unlock_irqrestore(&hugetlb_lock, flags);
update_and_free_page(h, page, true);
update_and_free_hugetlb_folio(h, folio, true);
} else {
arch_clear_hugepage_flags(page);
enqueue_huge_page(h, page);
@ -2172,8 +2174,8 @@ retry:
spin_unlock_irq(&hugetlb_lock);
/*
* Normally update_and_free_page will allocate required vmemmmap
* before freeing the page. update_and_free_page will fail to
* Normally update_and_free_hugtlb_folio will allocate required vmemmmap
* before freeing the page. update_and_free_hugtlb_folio will fail to
* free the page if it can not allocate required vmemmap. We
* need to adjust max_huge_pages if the page is not freed.
* Attempt to allocate vmemmmap here so that we can take
@ -2181,7 +2183,7 @@ retry:
*/
rc = hugetlb_vmemmap_restore(h, &folio->page);
if (!rc) {
update_and_free_page(h, &folio->page, false);
update_and_free_hugetlb_folio(h, folio, false);
} else {
spin_lock_irq(&hugetlb_lock);
add_hugetlb_page(h, &folio->page, false);
@ -2818,7 +2820,7 @@ retry:
* Pages have been replaced, we can safely free the old one.
*/
spin_unlock_irq(&hugetlb_lock);
update_and_free_page(h, old_page, false);
update_and_free_hugetlb_folio(h, old_folio, false);
}
return ret;
@ -2827,7 +2829,7 @@ free_new:
spin_unlock_irq(&hugetlb_lock);
/* Page has a zero ref count, but needs a ref to be freed */
folio_ref_unfreeze(new_folio, 1);
update_and_free_page(h, new_page, false);
update_and_free_hugetlb_folio(h, new_folio, false);
return ret;
}