From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-181.mta0.migadu.com (out-181.mta0.migadu.com [91.218.175.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9434E21CFE0 for ; Thu, 30 Jul 2026 13:09:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.181 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785416976; cv=none; b=tJvdscUO5uXbQnKfTd3VLB2KAz6FFGwbObjoWWKNuaUe3iS+qUeU9afJP/SgM/Ro2ZINnMw1Z6Dg4B23COdd+GZ4oefDBiNrfCbJ+QBAsMEvBqcOtN89RhTowJpDR696D1cRudOWpdbW5K/9mYJTbiVtpecalNNy60we5mVz7Rc= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785416976; c=relaxed/simple; bh=aAM/ttbWVCnNd5QIFBXPdUQu/ocbYSwjZKBMIf7vEvY=; h=Content-Type:Mime-Version:Subject:From:In-Reply-To:Date:Cc: Message-Id:References:To; b=ikzr8aqatYP/Op9MQYit8MyUoh4lQ4hi3bRHdOAXTN46E7yY7mvlZELIMWdyQkae72D1Mz479/3KkR5WcnJapgURtLA9wx+f3Fs1mwxlhtBOilfkXSuRRx5k+9vx+ZZexKzXywOLHz7vuZn7LuSYQxBYYdyIVDTXDw5dM+d9l3g= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=lc6BcPe5; arc=none smtp.client-ip=91.218.175.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="lc6BcPe5" Content-Type: text/plain; charset=utf-8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1785416972; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=n80UyXrjaxZDblcYgL2RK7KkUgNXXLilUukX1cXCVmg=; b=lc6BcPe55LdO7JYMgKr2B/atyloWVgQfyyC1LGUztckrBLxzZMRUuP3OaQFVnkhxZhAzr4 P/J16ys7HJiigGJj474/AIhFIIhHBfIg8Bi4ZMKkhzagA89U5sz6zWi+zcTsZzZiGMx2/g LJACO2VRe0wZah1AkMXOEceKKNriTRE= Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.600.51.1.1\)) Subject: Re: [PATCH v2 03/17] mm/mm_init: skip initializing shared vmemmap tail pages X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Muchun Song In-Reply-To: <178540851830.2154539.6359871825839331816.b4-reply@b4> Date: Thu, 30 Jul 2026 21:09:00 +0800 Cc: Muchun Song , Andrew Morton , Oscar Salvador , David Hildenbrand , Vlastimil Babka , Lorenzo Stoakes , Michal Hocko , David Laight , linux-mm@kvack.org, linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Message-Id: <3FCC8989-95DB-450F-95C3-183787DF4D08@linux.dev> References: <20260720093127.540540-1-songmuchun@bytedance.com> <20260720093127.540540-4-songmuchun@bytedance.com> <5005C7D3-B3ED-4C62-B611-8465D2BC69FD@linux.dev> <178540851830.2154539.6359871825839331816.b4-reply@b4> To: Mike Rapoport X-Migadu-Flow: FLOW_OUT > On Jul 30, 2026, at 18:48, Mike Rapoport wrote: >=20 > Hi Muchun, Hi, >=20 > On 2026-07-26 12:30:17+08:00, Muchun Song wrote: >>> On Jul 20, 2026, at 17:31, Muchun Song = wrote: >>>=20 >>> memmap_init_range() initializes every struct page in the target = range. >>> For compound pages with vmemmap optimization, the tail struct pages = are >>> backed by a shared vmemmap page. >>>=20 >>> Initializing those tail struct pages would overwrite the shared >>> vmemmap page contents, requiring users such as HugeTLB to restore = the >>> metadata afterwards. >>>=20 >>> Track the compound order for HVO-backed sections and use that = metadata >>> to detect struct pages that fall into the shared tail vmemmap range. >>> Skip those shared tail pages in memmap_init_range(), then initialize >>> pageblock migratetypes for the processed range with a helper after = the >>> per-page initialization loop. >>>=20 >>> The !SPARSEMEM __pfn_to_section() stub is needed only for the build: >>> memmap_init_range() references __pfn_to_section() after checking >>> pfn_vmemmap_optimizable(), and !SPARSEMEM builds still have to = compile >>> that code even though pfn_vmemmap_optimizable() folds to false. >>>=20 >>> This is a preparatory change for consolidating handling across users = of >>> vmemmap optimization, and it also avoids redundant initialization of >>> shared tail vmemmap pages during early boot. >>>=20 >>> Signed-off-by: Muchun Song >>> --- >>> v2: >>> - Fold section order tracking into the first user instead of keeping = a >>> standalone API-only patch (suggested by Mike Rapoport) >>> - Rename page_vmemmap_optimizable() to pfn_vmemmap_optimizable() and >>> pass a PFN directly (suggested by Mike Rapoport) >>> - Initialize pageblock migratetypes from a helper after the per-page >>> loop (suggested by Mike Rapoport) >>> - Use a 1G PFN chunk for cond_resched() in the pageblock helper >>> (suggested by Mike Rapoport) >>> - Guard section_order() with CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP so >>> it returns 0 when HVO is disabled and lets the compiler optimize the >>> code as much as possible (suggested by Mike Rapoport) >>> - Explain why the !SPARSEMEM __pfn_to_section() stub belongs here >>> (suggested by Mike Rapoport) >>> --- >>> include/linux/mmzone.h | 14 ++++++++++++++ >>> mm/mm_init.c | 33 +++++++++++++++++---------------- >>> mm/sparse.h | 23 +++++++++++++++++++++++ >>> 3 files changed, 54 insertions(+), 16 deletions(-) >>>=20 >>> diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h >>> index 82b0155d886f..2a32101d55e6 100644 >>> --- a/include/linux/mmzone.h >>> +++ b/include/linux/mmzone.h >>> @@ -2011,6 +2011,14 @@ struct mem_section { >>> unsigned long section_mem_map; >>>=20 >>> struct mem_section_usage *usage; >>> +#ifdef CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP >>> + /* >>> + * Normally, sections hold regular (order-0) pages. However, for >>> + * sections with HVO enabled, this tracks the compound page = order >>> + * to enable deduplication of redundant vmemmap pages. >>> + */ >>> + unsigned int order; >>> +#endif >>> #ifdef CONFIG_PAGE_EXTENSION >>> /* >>> * If SPARSEMEM, pgdat doesn't have page_ext pointer. We use >>> @@ -2365,8 +2373,14 @@ static inline unsigned long = next_present_section_nr(unsigned long section_nr) >>> #endif >>>=20 >>> #else >>> +struct mem_section; >>> + >>> #define sparse_vmemmap_init_nid_early(_nid) do {} while (0) >>> #define pfn_in_present_section pfn_valid >>> +static inline struct mem_section *__pfn_to_section(unsigned long = pfn) >>> +{ >>> + return NULL; >>> +} >>=20 >> I'd like to propose an alternative implementation that doesn't = require >> exposing the mem_section. The idea is to add a new helper function, >> pfn_to_section_order(), so that for non-sparse-memory configurations, >> the mem_section concept stays hidden internally. I'd really = appreciate >> any thoughts or concerns =E2=80=94 if everyone is comfortable with = it, I can go >> ahead and implement this in the next version. >=20 > A helper that keeps mem_section hidden from !SPARSMEM makes perfect > sense to me. >=20 > I'd even take it one step further and make it return how many pfns > should be skipped in pfn_vmemmap_optimizable case. To make sure we're on the same page, let me walk you through the = specific changes I have in mind. My initial plan is to introduce = pfn_to_section_order, and the expected diff changes are as follow to keep mem_sectionhidden = from !SPARSEMEM. diff --git a/mm/mm_init.c b/mm/mm_init.c index dcb757b36902..0b0c2996d080 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -884,7 +884,7 @@ void __meminit memmap_init_range(unsigned long size, = int nid, unsigned long zone } if (pfn_vmemmap_optimizable(pfn)) { - unsigned int order =3D = section_order(__pfn_to_section(pfn)); + unsigned int order =3D = pfn_to_section_order(pfn); pfn =3D min(ALIGN(pfn, 1UL << order), end_pfn); continue; diff --git a/mm/sparse.h b/mm/sparse.h index 030248030dc7..c5fbcdde3cee 100644 --- a/mm/sparse.h +++ b/mm/sparse.h @@ -47,6 +47,11 @@ static inline void __section_mark_present(struct = mem_section *ms, ms->section_mem_map |=3D SECTION_MARKED_PRESENT; } + +static inline unsigned int pfn_to_section_order(unsigned long pfn) +{ + return section_order(__pfn_to_section(pfn)); +} #else static inline void sparse_init(void) {} #endif /* CONFIG_SPARSEMEM */ Since we also use __pfn_to_section in the patch 14 in this series for !SPARSEMEM, we need to make corresponding adjustments=E2=80=94specifically= , by using pfn_to_section_order to determine whether the vmemmap of a given section = is optimizable. This new helper will be called from several places, so I'm = afraid its introduction is unavoidable. That said, I've also considered an alternative: introducing another = helper that returns the exact number of PFNs to skip, and using it solely within memmap_init_range(). However, that approach doesn't seem to offer much = in terms of code simplification. If I'm missing something or if my reasoning = doesn't align with your expectations, I would really appreciate your guidance. Thank = you for your patience! Thanks, Muchun