From nobody Tue Feb 10 05:17:34 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 721C61F76A5 for ; Wed, 29 Jan 2025 22:42:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738190581; cv=none; b=u8yiOPhNGLvQ1fuOyq5G5/G5GuPlXp2s0SPPgbcnkNIycfxLBwVKyHK5LoIA3NdGnlQkY3LvOQ+S/9n6Zpwp0rENla1xvK12rwiQHPVMxfB1ph/ulesKx6DAM0iQ5DmO7d8IcgC7u17MeLn9nO8XjCJ925aJwBAT/3toyQ8xkRs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738190581; c=relaxed/simple; bh=fAeV/E1q5qgp9++nghxIuTERofsxLaqa501aimCgAt0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=TxeTxV+9Xh6Ro2T4gwU1LqWSSY3Gm4/wriRWMVqHzoX64zqzX5r5cf0qsU+s6ZbuwU02wSibDJph00qqos1v3oKjzqy5XjVQtmz5EUz2hSNSqGEUrkHjw1sWfLPlUzgSGVSVkVvcdTaingaIMJtjK7EKRwyL0T0hDWjidXqNsd8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--fvdl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=YVdd5y2T; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--fvdl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="YVdd5y2T" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-2f83e54432dso300449a91.2 for ; Wed, 29 Jan 2025 14:42:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1738190579; x=1738795379; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=L0ZG8uhT3OL4gz53zsZU4uOQev18QCwSpJ1z8Lyz6lA=; b=YVdd5y2TmtUS/rcA09wXsbtrlqVilt20LDNtT8kbdFXmuSXiK5Ixm0vp161ESJ77c1 hBuIaHgh4IU15dynbA3vIOuuFXJOadPF+0BzKXO0lcsaU3PwoaVF8KkhbSMK6GcM5tnp FwUB2lUmQMPLZbMg5JhoILerW6wY/KHPelH82+cAtnx/bjTC3SX9e+VGv0nzf4v3OmJ2 jLS35ctRPB+8qpwaxr2yRfxGW4/0LBoyobRc3Xq4yicZ4KPFK2XRkA+jF9VqGtO6nwj0 Dqzk5d+PEQ1mUfF4VdFHyNeHgL1pfq+UIh4EP7aW17nnr7IvTaOlAsBY1GVc1S/uYyA8 CzMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738190579; x=1738795379; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=L0ZG8uhT3OL4gz53zsZU4uOQev18QCwSpJ1z8Lyz6lA=; b=jc0KOn6baGBT6Lp+LNlaXpL4rmaJX1PZhGNvrZ725FAVDek9KGCaHgRSG2rlxOjtDy MyODFRd2kCNJEQj+6tdyY+xLFS58D6sGsTC4QKkw1TX2AsOb4cS71vx3p//7pWYpOHqm 5uegACzUxX9oxT6MGhcrd6X+4vabmi+KS39tE26x5/57WrK8xBxYQlSrxIqSJPr2DPPM yNLzHKK6xFEKfxw39zwQ5I3SGt7f+Gydqtk/2McJ9ebV4uP8s6lFM/3AyUKUCEeB1kgx v7fIGzQR7A412v8exhxo51/DTFpCT7m/ky0ze3EnQJQoNwgoTgM7KEEFaCvWBIgqsntR 0p4A== X-Forwarded-Encrypted: i=1; AJvYcCUI8sDDpEIQVCL5/mw0+NFn3DcyUkObz1XEeeftU3P4vFlZXlWz7QhOWWy+sJxTgJKqDV9hDTGqKa9N17U=@vger.kernel.org X-Gm-Message-State: AOJu0YyXv/tVqnTLqDb79J0XTixhuVSvF484z/gVkdPudH3PC6RqqEwK +pw9aMptFEEA/0hodQOe0jOl8V/lD0Nylih9lv/0brxyYWJbigKv3TV+mAmLnUIJ3ndMkg== X-Google-Smtp-Source: AGHT+IEuTmiv3H9rTX6kMAO3mmM4IDiqwCIIyWovC1QOoLLo+K5CwA7MUZZn4zxCiCikjDN8GtWu9oQz X-Received: from pfbcl4.prod.google.com ([2002:a05:6a00:32c4:b0:725:d033:af87]) (user=fvdl job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:3919:b0:725:df1a:282 with SMTP id d2e1a72fcca58-72fd0be3556mr6904654b3a.10.1738190578851; Wed, 29 Jan 2025 14:42:58 -0800 (PST) Date: Wed, 29 Jan 2025 22:41:56 +0000 In-Reply-To: <20250129224157.2046079-1-fvdl@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250129224157.2046079-1-fvdl@google.com> X-Mailer: git-send-email 2.48.1.262.g85cc9f2d1e-goog Message-ID: <20250129224157.2046079-28-fvdl@google.com> Subject: [PATCH v2 27/28] mm/hugetlb: enable bootmem allocation from CMA areas From: Frank van der Linden To: akpm@linux-foundation.org, muchun.song@linux.dev, linux-mm@kvack.org, linux-kernel@vger.kernel.org Cc: yuzhao@google.com, usamaarif642@gmail.com, joao.m.martins@oracle.com, roman.gushchin@linux.dev, Frank van der Linden , Madhavan Srinivasan , Michael Ellerman , linuxppc-dev@lists.ozlabs.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If hugetlb_cma_only is enabled, we know that hugetlb pages can only be allocated from CMA. Now that there is an interface to do early reservations from a CMA area (returning memblock memory), it can be used to allocate hugetlb pages from CMA. This also allows for doing pre-HVO on these pages (if enabled). Make sure to initialize the page structures and associated data correctly. Create a flag to signal that a hugetlb page has been allocated from CMA to make things a little easier. Some configurations of powerpc have a special hugetlb bootmem allocator, so introduce a boolean arch_specific_huge_bootmem_alloc that returns true if such an allocator is present. In that case, CMA bootmem allocations can't be used, so check that function before trying. Cc: Madhavan Srinivasan Cc: Michael Ellerman Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Frank van der Linden --- arch/powerpc/include/asm/book3s/64/hugetlb.h | 6 + include/linux/hugetlb.h | 17 +++ mm/hugetlb.c | 121 ++++++++++++++----- 3 files changed, 113 insertions(+), 31 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/hugetlb.h b/arch/powerpc/in= clude/asm/book3s/64/hugetlb.h index f0bba9c5f9c3..bb786694dd26 100644 --- a/arch/powerpc/include/asm/book3s/64/hugetlb.h +++ b/arch/powerpc/include/asm/book3s/64/hugetlb.h @@ -94,4 +94,10 @@ static inline int check_and_get_huge_psize(int shift) return mmu_psize; } =20 +#define arch_has_huge_bootmem_alloc arch_has_huge_bootmem_alloc + +static inline bool arch_has_huge_bootmem_alloc(void) +{ + return (firmware_has_feature(FW_FEATURE_LPAR) && !radix_enabled()); +} #endif diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 2512463bca49..6c6546b54934 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -591,6 +591,7 @@ enum hugetlb_page_flags { HPG_freed, HPG_vmemmap_optimized, HPG_raw_hwp_unreliable, + HPG_cma, __NR_HPAGEFLAGS, }; =20 @@ -650,6 +651,7 @@ HPAGEFLAG(Temporary, temporary) HPAGEFLAG(Freed, freed) HPAGEFLAG(VmemmapOptimized, vmemmap_optimized) HPAGEFLAG(RawHwpUnreliable, raw_hwp_unreliable) +HPAGEFLAG(Cma, cma) =20 #ifdef CONFIG_HUGETLB_PAGE =20 @@ -678,14 +680,18 @@ struct hstate { char name[HSTATE_NAME_LEN]; }; =20 +struct cma; + struct huge_bootmem_page { struct list_head list; struct hstate *hstate; unsigned long flags; + struct cma *cma; }; =20 #define HUGE_BOOTMEM_HVO 0x0001 #define HUGE_BOOTMEM_ZONES_VALID 0x0002 +#define HUGE_BOOTMEM_CMA 0x0004 =20 bool hugetlb_bootmem_page_zones_valid(int nid, struct huge_bootmem_page *m= ); =20 @@ -823,6 +829,17 @@ static inline pte_t arch_make_huge_pte(pte_t entry, un= signed int shift, } #endif =20 +#ifndef arch_has_huge_bootmem_alloc +/* + * Some architectures do their own bootmem allocation, so they can't use + * early CMA allocation. + */ +static inline bool arch_has_huge_bootmem_alloc(void) +{ + return false; +} +#endif + static inline struct hstate *folio_hstate(struct folio *folio) { VM_BUG_ON_FOLIO(!folio_test_hugetlb(folio), folio); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index c227d0b9cf1e..5a3e9f7deaba 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -132,8 +132,10 @@ static void hugetlb_free_folio(struct folio *folio) #ifdef CONFIG_CMA int nid =3D folio_nid(folio); =20 - if (cma_free_folio(hugetlb_cma[nid], folio)) + if (folio_test_hugetlb_cma(folio)) { + WARN_ON_ONCE(!cma_free_folio(hugetlb_cma[nid], folio)); return; + } #endif folio_put(folio); } @@ -1509,6 +1511,9 @@ static struct folio *alloc_gigantic_folio(struct hsta= te *h, gfp_t gfp_mask, break; } } + + if (folio) + folio_set_hugetlb_cma(folio); } #endif if (!folio) { @@ -3175,6 +3180,53 @@ struct folio *alloc_hugetlb_folio(struct vm_area_str= uct *vma, return ERR_PTR(-ENOSPC); } =20 +static bool __init hugetlb_early_cma(struct hstate *h) +{ + if (arch_has_huge_bootmem_alloc()) + return false; + + return (hstate_is_gigantic(h) && hugetlb_cma_only); +} + +static __init void *alloc_bootmem(struct hstate *h, int nid) +{ + struct huge_bootmem_page *m; + unsigned long flags; + struct cma *cma; + +#ifdef CONFIG_CMA + if (hugetlb_early_cma(h)) { + flags =3D HUGE_BOOTMEM_CMA; + cma =3D hugetlb_cma[nid]; + m =3D cma_reserve_early(cma, huge_page_size(h)); + } else +#endif + { + flags =3D 0; + cma =3D NULL; + m =3D memblock_alloc_try_nid_raw(huge_page_size(h), + huge_page_size(h), 0, MEMBLOCK_ALLOC_ACCESSIBLE, nid); + } + + if (m) { + /* + * Use the beginning of the huge page to store the + * huge_bootmem_page struct (until gather_bootmem + * puts them into the mem_map). + * + * Put them into a private list first because mem_map + * is not up yet. + */ + INIT_LIST_HEAD(&m->list); + list_add(&m->list, &huge_boot_pages[nid]); + m->hstate =3D h; + m->flags =3D flags; + m->cma =3D cma; + } + + return m; +} + int alloc_bootmem_huge_page(struct hstate *h, int nid) __attribute__ ((weak, alias("__alloc_bootmem_huge_page"))); int __alloc_bootmem_huge_page(struct hstate *h, int nid) @@ -3184,17 +3236,14 @@ int __alloc_bootmem_huge_page(struct hstate *h, int= nid) =20 /* do node specific alloc */ if (nid !=3D NUMA_NO_NODE) { - m =3D memblock_alloc_try_nid_raw(huge_page_size(h), huge_page_size(h), - 0, MEMBLOCK_ALLOC_ACCESSIBLE, nid); + m =3D alloc_bootmem(h, node); if (!m) return 0; goto found; } /* allocate from next node when distributing huge pages */ for_each_node_mask_to_alloc(&h->next_nid_to_alloc, nr_nodes, node, &node_= states[N_ONLINE]) { - m =3D memblock_alloc_try_nid_raw( - huge_page_size(h), huge_page_size(h), - 0, MEMBLOCK_ALLOC_ACCESSIBLE, node); + m =3D alloc_bootmem(h, node); if (m) break; } @@ -3203,7 +3252,6 @@ int __alloc_bootmem_huge_page(struct hstate *h, int n= id) return 0; =20 found: - /* * Only initialize the head struct page in memmap_init_reserved_pages, * rest of the struct pages will be initialized by the HugeTLB @@ -3213,18 +3261,6 @@ int __alloc_bootmem_huge_page(struct hstate *h, int = nid) */ memblock_reserved_mark_noinit(virt_to_phys((void *)m + PAGE_SIZE), huge_page_size(h) - PAGE_SIZE); - /* - * Use the beginning of the huge page to store the - * huge_bootmem_page struct (until gather_bootmem - * puts them into the mem_map). - * - * Put them into a private list first because mem_map - * is not up yet. - */ - INIT_LIST_HEAD(&m->list); - list_add(&m->list, &huge_boot_pages[node]); - m->hstate =3D h; - m->flags =3D 0; return 1; } =20 @@ -3265,13 +3301,25 @@ static void __init hugetlb_folio_init_vmemmap(struc= t folio *folio, prep_compound_head((struct page *)folio, huge_page_order(h)); } =20 +static bool __init hugetlb_bootmem_page_prehvo(struct huge_bootmem_page *m) +{ + return m->flags & HUGE_BOOTMEM_HVO; +} + +static bool __init hugetlb_bootmem_page_earlycma(struct huge_bootmem_page = *m) +{ + return m->flags & HUGE_BOOTMEM_CMA; +} + /* * memblock-allocated pageblocks might not have the migrate type set * if marked with the 'noinit' flag. Set it to the default (MIGRATE_MOVABL= E) - * here. + * here, or MIGRATE_CMA if this was a page allocated through an early CMA + * reservation. * - * Note that this will not write the page struct, it is ok (and necessary) - * to do this on vmemmap optimized folios. + * In case of vmemmap optimized folios, the tail vmemmap pages are mapped + * read-only, but that's ok - for sparse vmemmap this does not write to + * the page structure. */ static void __init hugetlb_bootmem_init_migratetype(struct folio *folio, struct hstate *h) @@ -3280,9 +3328,13 @@ static void __init hugetlb_bootmem_init_migratetype(= struct folio *folio, =20 WARN_ON_ONCE(!pageblock_aligned(folio_pfn(folio))); =20 - for (i =3D 0; i < nr_pages; i +=3D pageblock_nr_pages) - set_pageblock_migratetype(folio_page(folio, i), + for (i =3D 0; i < nr_pages; i +=3D pageblock_nr_pages) { + if (folio_test_hugetlb_cma(folio)) + init_cma_pageblock(folio_page(folio, i)); + else + set_pageblock_migratetype(folio_page(folio, i), MIGRATE_MOVABLE); + } } =20 static void __init prep_and_add_bootmem_folios(struct hstate *h, @@ -3328,10 +3380,16 @@ bool __init hugetlb_bootmem_page_zones_valid(int ni= d, return true; } =20 + if (hugetlb_bootmem_page_earlycma(m)) { + valid =3D cma_validate_zones(m->cma); + goto out; + } + start_pfn =3D virt_to_phys(m) >> PAGE_SHIFT; =20 valid =3D !pfn_range_intersects_zones(nid, start_pfn, pages_per_huge_page(m->hstate)); +out: if (!valid) hstate_boot_nrinvalid[hstate_index(m->hstate)]++; =20 @@ -3360,11 +3418,6 @@ static void __init hugetlb_bootmem_free_invalid_page= (int nid, struct page *page, } } =20 -static bool __init hugetlb_bootmem_page_prehvo(struct huge_bootmem_page *m) -{ - return (m->flags & HUGE_BOOTMEM_HVO); -} - /* * Put bootmem huge pages into the standard lists after mem_map is up. * Note: This only applies to gigantic (order > MAX_PAGE_ORDER) pages. @@ -3414,6 +3467,9 @@ static void __init gather_bootmem_prealloc_node(unsig= ned long nid) */ folio_set_hugetlb_vmemmap_optimized(folio); =20 + if (hugetlb_bootmem_page_earlycma(m)) + folio_set_hugetlb_cma(folio); + list_add(&folio->lru, &folio_list); =20 /* @@ -3606,8 +3662,11 @@ static void __init hugetlb_hstate_alloc_pages(struct= hstate *h) { unsigned long allocated; =20 - /* skip gigantic hugepages allocation if hugetlb_cma enabled */ - if (hstate_is_gigantic(h) && hugetlb_cma_size) { + /* + * Skip gigantic hugepages allocation if early CMA + * reservations are not available. + */ + if (hstate_is_gigantic(h) && hugetlb_cma_size && !hugetlb_early_cma(h)) { pr_warn_once("HugeTLB: hugetlb_cma is enabled, skip boot time allocation= \n"); return; } --=20 2.48.1.262.g85cc9f2d1e-goog