Re: [PATCH v6 4/8] hugetlb: perform vmemmap restoration on a list of pages

From: Mike Kravetz
Date: Fri Sep 29 2023 - 18:12:02 EST


On 09/25/23 16:48, Mike Kravetz wrote:
<snip>
> +static void update_and_free_pages_bulk(struct hstate *h,
> + struct list_head *folio_list)
> +{
> + long ret;
> + struct folio *folio, *t_folio;
> + LIST_HEAD(non_hvo_folios);
>
> /*
> - * If vmemmmap allocation was performed on any folio above, take lock
> - * to clear destructor of all folios on list. This avoids the need to
> - * lock/unlock for each individual folio.
> - * The assumption is vmemmap allocation was performed on all or none
> - * of the folios on the list. This is true expect in VERY rare cases.
> + * First allocate required vmemmmap (if necessary) for all folios.
> + * Carefully handle errors and free up any available hugetlb pages
> + * in an effort to make forward progress.
> */
> - if (clear_dtor) {
> +retry:
> + ret = hugetlb_vmemmap_restore_folios(h, folio_list, &non_hvo_folios);
> + if (ret < 0) {
> + bulk_vmemmap_restore_error(h, folio_list, &non_hvo_folios);
> + goto retry;
> + }
> +
> + /*
> + * At this point, list should be empty, ret should be >= 0 and there
> + * should only be pages on the non_hvo_folios list.
> + * Do note that the non_hvo_folios list could be empty.
> + * Without HVO enabled, ret will be 0 and there is no need to call
> + * __clear_hugetlb_destructor as this was done previously.
> + */
> + VM_WARN_ON(!list_empty(folio_list));
> + VM_WARN_ON(ret < 0);
> + if (!list_empty(&non_hvo_folios) && ret) {
> spin_lock_irq(&hugetlb_lock);
> - list_for_each_entry(folio, list, lru)
> + list_for_each_entry(folio, &non_hvo_folios, lru)
> __clear_hugetlb_destructor(h, folio);
> spin_unlock_irq(&hugetlb_lock);
> }
>
> - /*
> - * Free folios back to low level allocators. vmemmap and destructors
> - * were taken care of above, so update_and_free_hugetlb_folio will
> - * not need to take hugetlb lock.
> - */
> - list_for_each_entry_safe(folio, t_folio, list, lru) {
> + list_for_each_entry_safe(folio, t_folio, &non_hvo_folios, lru) {
> update_and_free_hugetlb_folio(h, folio, false);
> cond_resched();
> }
<snip>
> diff --git a/mm/hugetlb_vmemmap.h b/mm/hugetlb_vmemmap.h
> index c512e388dbb4..0b7710f90e38 100644
> --- a/mm/hugetlb_vmemmap.h
> +++ b/mm/hugetlb_vmemmap.h
> @@ -19,6 +19,9 @@
>
> #ifdef CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
> int hugetlb_vmemmap_restore(const struct hstate *h, struct page *head);
> +long hugetlb_vmemmap_restore_folios(const struct hstate *h,
> + struct list_head *folio_list,
> + struct list_head *non_hvo_folios);
> void hugetlb_vmemmap_optimize(const struct hstate *h, struct page *head);
> void hugetlb_vmemmap_optimize_folios(struct hstate *h, struct list_head *folio_list);
>
> @@ -45,6 +48,13 @@ static inline int hugetlb_vmemmap_restore(const struct hstate *h, struct page *h
> return 0;
> }
>
> +static long hugetlb_vmemmap_restore_folios(const struct hstate *h,
> + struct list_head *folio_list,
> + struct list_head *non_hvo_folios)
> +{
> + return 0;
> +}

update_and_free_pages_bulk depends on pages with complete vmemmap being
moved from folio_list to non_hvo_folios. In the case where we return 0,
it expects ALL pages to be moved. Therefore, in the case where
!CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP the stub above must perform

list_splice_init(folio_list, non_hvo_folios);

before returning 0.

I will update and send a new version along with any changes needed to
address the arm64 boot issue reported with patch 2.
--
Mike Kravetz