From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 02C7D242D7B for ; Sat, 4 Apr 2026 11:12:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775301121; cv=none; b=CAceJpvKTfGIicU2Y8Q7yJTqkMhGlbvgfsArdzWuD1VuExcLL+vT10uXR6PxA5DDtuO6Q/LV3CKKcCF/hgM+tuXJZj2cX6nVxsO7fzH1A8a7hGO9h7wUuZG0LJd4yCbvjjTkXRTV+kX+OXxEb68R2XDbW8F1oCf9X63iST6SZ5w= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775301121; c=relaxed/simple; bh=upjC2amcChzNkJvjB78yT+nyj/Ctg5hG5pkRSw8QFPU=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=SHk+23Vd3WOfTYhNg2dcQ0rrx2mBYoxg1eFQsYB1Qtx8GZjs2x6IGvrfiALBoQ8N3h+eq1Hcom1N70paYVEMAr91+g/3SrwGQha6Lqr/z2J/gXYxUFKDhr7x73Tjb/YHtoN0S9Va8r5Vqt0ZOZ2qMCDDCLDEa5ObZy5CdX9OJGg= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gIv6D33+; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gIv6D33+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 21AF1C19421; Sat, 4 Apr 2026 11:11:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775301120; bh=upjC2amcChzNkJvjB78yT+nyj/Ctg5hG5pkRSw8QFPU=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=gIv6D33+nZsaQW3qEMSmPdTuvPhm55MyusGZPe/mhf/rnqzMA+MK7R4UzVn2B6N2d a4cg+dLsOjHKVSZm6DutiPdxwf8DNHomGOwnwNn5CKkM3nReXQcXy0M+eLcXJbNTmf rh1FY8NhGEw1N9imYU0e8VuxM8iU2h7g+qY0oyJ/FL3LTo3gSxoTWV5buDGi0gGWtB UiaLZes5ET1xmmU0qWqgsqVSZ+J+r1B0yBTm7nl3WBy/03F2aqknMed2OMulnloMG+ H5e4Wv3i6bbL4aVl3U4XbrRBhgXSn8A0x/L/0l4pZQpjjtSPdAEk7pa0484KSIsg8U yUfZmXg8pEWEw== Date: Sat, 4 Apr 2026 14:11:52 +0300 From: Mike Rapoport To: Yuan Liu Cc: David Hildenbrand , Oscar Salvador , Wei Yang , linux-mm@kvack.org, Yong Hu , Nanhai Zou , Tim Chen , Qiuxu Zhuo , Yu C Chen , Pan Deng , Tianyou Li , Chen Zhang , linux-kernel@vger.kernel.org Subject: Re: [PATCH v2] mm/memory hotplug/unplug: Optimize zone contiguous check when changing pfn range Message-ID: References: <20260401070155.1420929-1-yuan1.liu@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20260401070155.1420929-1-yuan1.liu@intel.com> On Wed, Apr 01, 2026 at 03:01:55AM -0400, Yuan Liu wrote: > When move_pfn_range_to_zone() or remove_pfn_range_from_zone() updates a > zone, set_zone_contiguous() rescans the entire zone pageblock-by-pageblock > to rebuild zone->contiguous. For large zones this is a significant cost > during memory hotplug and hot-unplug. ... > diff --git a/Documentation/mm/physical_memory.rst b/Documentation/mm/physical_memory.rst > index b76183545e5b..e47e96ef6a6d 100644 > --- a/Documentation/mm/physical_memory.rst > +++ b/Documentation/mm/physical_memory.rst > @@ -483,6 +483,17 @@ General > ``present_pages`` should use ``get_online_mems()`` to get a stable value. It > is initialized by ``calculate_node_totalpages()``. > > +``pages_with_online_memmap`` > + Tracks pages within the zone that have an online memmap (present pages and Please spell out "memory map" rather then memmap in the documentation and in the comments. > + memory holes whose memmap has been initialized). When ``spanned_pages`` == > + ``pages_with_online_memmap``, ``pfn_to_page()`` can be performed without > + further checks on any PFN within the zone span. > + > + Note: this counter may temporarily undercount when pages with an online > + memmap exist outside the current zone span. Growing the zone to cover such > + pages and later shrinking it back may result in a "too small" value. This is > + safe: it merely prevents detecting a contiguous zone. > + > ``present_early_pages`` > The present pages existing within the zone located on memory available since > early boot, excluding hotplugged memory. Defined only when ... > +/* > + * Initialize unavailable range [spfn, epfn) while accounting only the pages > + * that fall within the zone span towards pages_with_online_memmap. Pages > + * outside the zone span are still initialized but not accounted. > + */ > +static void __init init_unavailable_range_for_zone(struct zone *zone, > + unsigned long spfn, > + unsigned long epfn) > +{ > + int nid = zone_to_nid(zone); > + int zid = zone_idx(zone); > + unsigned long in_zone_start; > + unsigned long in_zone_end; > + > + in_zone_start = clamp(spfn, zone->zone_start_pfn, zone_end_pfn(zone)); > + in_zone_end = clamp(epfn, zone->zone_start_pfn, zone_end_pfn(zone)); > + > + if (spfn < in_zone_start) > + init_unavailable_range(spfn, in_zone_start, zid, nid); > + > + if (in_zone_start < in_zone_end) > + zone->pages_with_online_memmap += > + init_unavailable_range(in_zone_start, in_zone_end, > + zid, nid); > + > + if (in_zone_end < epfn) > + init_unavailable_range(in_zone_end, epfn, zid, nid); > } I think we can make it simpler, see below. > /* > @@ -956,9 +986,10 @@ static void __init memmap_init_zone_range(struct zone *zone, > memmap_init_range(end_pfn - start_pfn, nid, zone_id, start_pfn, > zone_end_pfn, MEMINIT_EARLY, NULL, MIGRATE_MOVABLE, > false); > + zone->pages_with_online_memmap += end_pfn - start_pfn; > > if (*hole_pfn < start_pfn) > - init_unavailable_range(*hole_pfn, start_pfn, zone_id, nid); > + init_unavailable_range_for_zone(zone, *hole_pfn, start_pfn); Here *hole_pfn is either inside zone span or below it and in the second case it's enough to adjust page count returned by init_unavailable_range() by (zone_start_pfn - *hole_pfn). > *hole_pfn = end_pfn; > } > @@ -996,8 +1027,11 @@ static void __init memmap_init(void) > #else > end_pfn = round_up(end_pfn, MAX_ORDER_NR_PAGES); > #endif > - if (hole_pfn < end_pfn) > - init_unavailable_range(hole_pfn, end_pfn, zone_id, nid); > + if (hole_pfn < end_pfn) { > + struct zone *zone = &NODE_DATA(nid)->node_zones[zone_id]; > + > + init_unavailable_range_for_zone(zone, hole_pfn, end_pfn); Here we know that the range is not in any zone span. > + } > } > -- Sincerely yours, Mike.