From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 9F4CC36166F for ; Fri, 8 May 2026 17:04:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778259891; cv=none; b=RQ84dtxJb+M0iUEi9+GQrNtrPeLC604lwbGgQhLxfySOzxjNADXaavzeETqXsb7JT6J4OVZzVu3vzkXYQ/khgS6F4I19PW4hdOwCageye0MFfVS3yadQ/J6aOeyb2evjjXjTPjtdctvu+dSYOr+hUO6b8Uf+GHSW9VlrLQV7Ht0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778259891; c=relaxed/simple; bh=tKCECgQyNh8woAHWYEDsmlTRWapciE/tpTUtLCTX5lQ=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=J7FpNRzrFyk6kgMwB0Ph0rtLmIheio1IfdN9LQt6RbHYnATLpKKEiMzdoyj4eoULyiJD246czYae6U1iVoVnSyIj+9utxGP90S4MS+DQHzI2wBUyu2II4vLnHRHQFVz5FHxRTx9JqioW6jDbksInDkAM+Fp2mIUSfFBLyjGGktU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=O9ups9Jn; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="O9ups9Jn" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778259887; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=Uhqqq5zjmv++wjvi9vo5W4Deo40CH51hKj2PJiivblU=; b=O9ups9JneH/VvGw6Fvk8UxEM87eeOf1vR7g8U4GxM1d/HQnTUp7jYhts4cuSyfZ9+L4yvA ey8a3DLtfnSrJasxJNdPJzNj1uYbQ2hI76RJ+fXeFuWcjol4fLwfz+UV+Bdjm9DZ5It2Qj 4hzDKqgjOrJycJJVDVj8IuaERg7qT3w= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-632-p5EM7MKBMKSSwNgtKcwPFQ-1; Fri, 08 May 2026 13:04:43 -0400 X-MC-Unique: p5EM7MKBMKSSwNgtKcwPFQ-1 X-Mimecast-MFC-AGG-ID: p5EM7MKBMKSSwNgtKcwPFQ_1778259880 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 45DE11800343; Fri, 8 May 2026 17:04:39 +0000 (UTC) Received: from p1.redhat.com (unknown [10.44.22.7]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1F1B43002D2F; Fri, 8 May 2026 17:04:33 +0000 (UTC) From: Nico Pache To: linux-mm@kvack.org, linux-kernel@vger.kernel.org Cc: yuzhao@google.com, usamaarif642@gmail.com, lance.yang@linux.dev, baohua@kernel.org, dev.jain@arm.com, ryan.roberts@arm.com, liam@infradead.org, baolin.wang@linux.alibaba.com, ziy@nvidia.com, ljs@kernel.org, david@kernel.org, akpm@linux-foundation.org, Nico Pache Subject: [RFC] mm: restrict zero-page remapping to underused THP splits Date: Fri, 8 May 2026 11:05:09 -0600 Message-ID: <20260508170509.640851-1-npache@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 Since commit b1f202060afe ("mm: remap unused subpages to shared zeropage when splitting isolated thp"), splitting an anonymous THP remaps all zero-filled subpages to the shared zeropage via TTU_USE_SHARED_ZEROPAGE. This flag is set unconditionally for every anonymous folio split, including splits triggered by KSM. When KSM is enabled with THP=always, this causes two regressions: 1. use_zero_pages=1: KSM calls try_to_merge_one_page() which triggers split_huge_page(). The split remaps all 512 zero-filled subpages to the shared zeropage at once, freeing the entire 2MB THP when KSM only intended to process a single 4KB page. This bypasses KSM's pages_to_scan rate limiting, causing ~1GB to be freed almost instantly. 2. use_zero_pages=0: The same split side-effect occurs through the stable/unstable tree merge paths. Each pages_to_scan iteration triggers an expensive split_huge_page() that silently frees 2MB, while the scanner wastes cycles on tree searches for zero-filled pages that were already freed as a side-effect. Fix this by restricting TTU_USE_SHARED_ZEROPAGE to only the deferred split shrinker path (deferred_split_scan), which is the only caller that intentionally splits underused THPs to reclaim zero-filled subpages. Introduce folio_split_underused() as a dedicated entry point that passes is_underused_thp=true through __folio_split(), and use it from deferred_split_scan(). All other split callers (KSM, compaction, etc.) no longer get the zero-page remapping side-effect. Reviewers notes: this patch is one of two potential approaches. This patch turns off the zero-page freeing that has been done since the noted commit, in all the other callers, only leaving the underused shrinker to do such behavior. We can also take the opposite approach of with something like split_huge_page_no_zeropage() and call this within KSM. Fixes: b1f202060afe ("mm: remap unused subpages to shared zeropage when splitting isolated thp") Signed-off-by: Nico Pache --- include/linux/huge_mm.h | 2 +- mm/huge_memory.c | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index 2949e5acff35..4ae1b52d7411 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -378,7 +378,7 @@ int folio_check_splittable(struct folio *folio, unsigned int new_order, enum split_type split_type); int folio_split(struct folio *folio, unsigned int new_order, struct page *page, struct list_head *list); - +int folio_split_underused(struct folio *folio); static inline int split_huge_page_to_list_to_order(struct page *page, struct list_head *list, unsigned int new_order) { diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 970e077019b7..91f7fad72c8a 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -4045,7 +4045,8 @@ static int __folio_freeze_and_split_unmapped(struct folio *folio, unsigned int n */ static int __folio_split(struct folio *folio, unsigned int new_order, struct page *split_at, struct page *lock_at, - struct list_head *list, enum split_type split_type) + struct list_head *list, enum split_type split_type, + bool is_underused_thp) { XA_STATE(xas, &folio->mapping->i_pages, folio->index); struct folio *end_folio = folio_next(folio); @@ -4174,7 +4175,7 @@ static int __folio_split(struct folio *folio, unsigned int new_order, if (nr_shmem_dropped) shmem_uncharge(mapping->host, nr_shmem_dropped); - if (!ret && is_anon && !folio_is_device_private(folio)) + if (!ret && is_anon && !folio_is_device_private(folio) && is_underused_thp) ttu_flags = TTU_USE_SHARED_ZEROPAGE; remap_page(folio, 1 << old_order, ttu_flags); @@ -4309,7 +4310,7 @@ int __split_huge_page_to_list_to_order(struct page *page, struct list_head *list struct folio *folio = page_folio(page); return __folio_split(folio, new_order, &folio->page, page, list, - SPLIT_TYPE_UNIFORM); + SPLIT_TYPE_UNIFORM, false); } /** @@ -4340,7 +4341,13 @@ int folio_split(struct folio *folio, unsigned int new_order, struct page *split_at, struct list_head *list) { return __folio_split(folio, new_order, split_at, &folio->page, list, - SPLIT_TYPE_NON_UNIFORM); + SPLIT_TYPE_NON_UNIFORM, false); +} + +int folio_split_underused(struct folio *folio) +{ + return __folio_split(folio, 0, &folio->page, &folio->page, + NULL, SPLIT_TYPE_NON_UNIFORM, true); } /** @@ -4559,7 +4566,7 @@ static unsigned long deferred_split_scan(struct shrinker *shrink, } if (!folio_trylock(folio)) goto requeue; - if (!split_folio(folio)) { + if (!folio_split_underused(folio)) { did_split = true; if (underused) count_vm_event(THP_UNDERUSED_SPLIT_PAGE); -- 2.54.0