From nobody Fri Oct 2 10:08:52 2026 Received: from fhigh-a6-smtp.messagingengine.com (fhigh-a6-smtp.messagingengine.com [103.168.172.157]) (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 D897A33937D; Sun, 2 Aug 2026 19:53:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.157 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700384; cv=none; b=Y+t5xtcLRafELSA4Wx3CadqDOFUemu8TPbzccXU61mcdZ6JX0vt4NYmXZ1tZitcdhaNDpZ/daRPf+I7hrhbSg91jNRvpPXSUJmoj8RGsdDEBV/SVlTeUnHx2Q8GDUHHTFOKFl/C5/FCAag/pf3I5Qrf5BhioRzSApQmaCh2Vqu4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700384; c=relaxed/simple; bh=jlKjh7p6aPDqsyYVa1Q4E86BvV3zX9tl4A+ivSVKS20=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lO6/Povw/y4yQ1+JUoXEh7CLyXxiU/IqciSONrSsx1/3r3LUtFL1V+rzh47lW+naHTikepIfdduPIlVx5G6cdYS2+snz8lxBMOPeKETqRmHk4aNkmI792A0iYF2GCsOEzPwbtwJL2vdSIHce1jVkPQ7Lx/0Qxo2asEcHovNGhAQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=rGgZefwT; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=lGsyB/5G; arc=none smtp.client-ip=103.168.172.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="rGgZefwT"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="lGsyB/5G" Received: from phl-compute-08.internal (phl-compute-08.internal [10.202.2.48]) by mailfhigh.phl.internal (Postfix) with ESMTP id F34C91400056; Sun, 2 Aug 2026 15:53:01 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-08.internal (MEProxy); Sun, 02 Aug 2026 15:53:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1785700381; x= 1785786781; bh=exSxa18tvSalYuxDaP6ddzC4ErD/EJHfkXborP8h5XM=; b=r GgZefwTFg1VWLseoCMtP+k8C6/cIK1kf+cfzTrNvw3bskA4eoxwjknIHcJXPE5pG K2mf4ZVHcNoYukzxFBMjirQ/AT2GS3FZ29ScAzb7alsyJuVaoA1nTVV5eyJbtD+y 3JjbPRYZkhPltuAdA3XlRad/HzNxWoZuHrF1khpD0/2bn03WOwiFj/BJBlB6SbeP XxoywY52t7Q6OdQHteMLlYKViJ8P54rcSh6UdtEJoQWBb0onBCDPH6bLUXxK+kMG JL2oYpYiV/D3yelGm8G62Sx6pN8LCcUwMD2uoHFnrxvaoyh19zSFem55Hjg9uECE 5Hilbux+0Wz2FCZlRqjKw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1785700381; x=1785786781; bh=e xSxa18tvSalYuxDaP6ddzC4ErD/EJHfkXborP8h5XM=; b=lGsyB/5GX4Uy7xpSd WbHVbtTRX1nEuCxfzEOovNVjft8Cf3qN1n5cXWQ2qgSb8OdoOBI5IKR1YF8vt8ec YLHFx6smUguS+xLrtx1OcByGVDBuhGV1iPhmWnmUX9e7tpgrIsuSXTNUJlYc/dGK JzCmjH1QY/ovdbLUoZM334AcF06RDpByUm8T+Wtwcr9rx2VSfFqZQL6IuW4z0j81 BPt9c6ZRUq7+jw4iOLrpZByZVWyRj/s54mEe0tIjUiHDkso0hteht302MIiEOvHh oEECoo2Pp587vYY0nMZi+KRS5CHAAoZqQiQLT+mI+I/KIihH7MnDc5/NAgy12JbC Y9tEg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFcbv35QwNbwWPHQBcJdrWasH4YRFOBaNWig98oa0GgLD3LmQrthvyDgK5JnDhp96 dBkNywOXlTP9Hby+cm0vRQHofuB4BhsdtVcBrMer/A2AOpegfr9Hr7RYzI6OqquxWhxeXC aB5bOw4cR5G6EDzO4v2r94SJnXRDYvi2NMwyCB/quID+suEuw0TjLUMYjjQ5pFm1F3OqpQ Ctej7rOharBpUeBz9hjZojzUlseCYYYMV+BulSa6+jD3O5m4ZOeULsSyQlLb9bciCyrhiP bT+z0cGYr8PFizBGTpPnPZCe+jZkx/DQlEsoaoSV2SjHlZpE6q2+n/t1AcZaLqu1qPGmNP WeW4sbaB+hDCdok+K551BijkIgMPto0pUlo2Qa25tWIIjzZ5oFhMdk64zmrXWt9mXklEb5 kBG0XwjD99DtjoNRzDR/al+grOyrijltYB81RXtFyTi0Np5b/jcsHiGX0hP7wdkGelJZxM Us6Hnt+HK0e2facSWJMwzWMP3xu5Wl2WycLB/zP5Cr/nnWTkwwe6t0QWWxgIrnun83mayr sZgZ5XJD2niKDfEyqdMgUTgZS3RYPdauXRnwE8nsv1da2Wpr0VhZqSABZu9Deg4hGtekJT lF5aoyrN0Od7cgpjWEu0aDxBg/Xs2ii+sxGqemprvzvvV4bk3BVdZrzW06zA X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:00 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 01/16] selftests/mm: move is_backed_by_folio() into vm_util Date: Sun, 2 Aug 2026 20:52:33 +0100 Message-ID: <20260802195254.1937477-2-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Kiryl Shutsemau (Meta)" The khugepaged selftest is about to gain mTHP collapse coverage, which needs to verify that a VA range is backed by a folio of a given order. split_huge_page_test.c already has the building block for that: is_backed_by_folio() classifies the folio backing a page via /proc/kpageflags compound head/tail flags. Move it into vm_util so other tests can use it. No functional change. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) Acked-by: Mike Rapoport (Microsoft) --- .../selftests/mm/split_huge_page_test.c | 62 ------------------- tools/testing/selftests/mm/vm_util.c | 62 +++++++++++++++++++ tools/testing/selftests/mm/vm_util.h | 2 + 3 files changed, 64 insertions(+), 62 deletions(-) diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/test= ing/selftests/mm/split_huge_page_test.c index 32b991472f74..9b3885bd001b 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -42,68 +42,6 @@ const char *kpageflags_proc =3D "/proc/kpageflags"; int pagemap_fd; int kpageflags_fd; =20 -static bool is_backed_by_folio(char *vaddr, int order, int pagemap_fd, - int kpageflags_fd) -{ - const uint64_t folio_head_flags =3D KPF_THP | KPF_COMPOUND_HEAD; - const uint64_t folio_tail_flags =3D KPF_THP | KPF_COMPOUND_TAIL; - const unsigned long nr_pages =3D 1UL << order; - unsigned long pfn_head; - uint64_t pfn_flags; - unsigned long pfn; - unsigned long i; - - pfn =3D pagemap_get_pfn(pagemap_fd, vaddr); - - /* non present page */ - if (pfn =3D=3D -1UL) - return false; - - if (pageflags_get(pfn, kpageflags_fd, &pfn_flags)) - goto fail; - - /* check for order-0 pages */ - if (!order) { - if (pfn_flags & (folio_head_flags | folio_tail_flags)) - return false; - return true; - } - - /* non THP folio */ - if (!(pfn_flags & KPF_THP)) - return false; - - pfn_head =3D pfn & ~(nr_pages - 1); - - if (pageflags_get(pfn_head, kpageflags_fd, &pfn_flags)) - goto fail; - - /* head PFN has no compound_head flag set */ - if ((pfn_flags & folio_head_flags) !=3D folio_head_flags) - return false; - - /* check all tail PFN flags */ - for (i =3D 1; i < nr_pages; i++) { - if (pageflags_get(pfn_head + i, kpageflags_fd, &pfn_flags)) - goto fail; - if ((pfn_flags & folio_tail_flags) !=3D folio_tail_flags) - return false; - } - - /* - * check the PFN after this folio, but if its flags cannot be obtained, - * assume this folio has the expected order - */ - if (pageflags_get(pfn_head + nr_pages, kpageflags_fd, &pfn_flags)) - return true; - - /* If we find another tail page, then the folio is larger. */ - return (pfn_flags & folio_tail_flags) !=3D folio_tail_flags; -fail: - ksft_exit_fail_msg("Failed to get folio info\n"); - return false; -} - static int vaddr_pageflags_get(char *vaddr, int pagemap_fd, int kpageflags= _fd, uint64_t *flags) { diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests= /mm/vm_util.c index ef1ea11981a7..343a15e25a9f 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -303,6 +303,68 @@ int pageflags_get(unsigned long pfn, int kpageflags_fd= , uint64_t *flags) return 0; } =20 +bool is_backed_by_folio(char *vaddr, int order, int pagemap_fd, + int kpageflags_fd) +{ + const uint64_t folio_head_flags =3D KPF_THP | KPF_COMPOUND_HEAD; + const uint64_t folio_tail_flags =3D KPF_THP | KPF_COMPOUND_TAIL; + const unsigned long nr_pages =3D 1UL << order; + unsigned long pfn_head; + uint64_t pfn_flags; + unsigned long pfn; + unsigned long i; + + pfn =3D pagemap_get_pfn(pagemap_fd, vaddr); + + /* non present page */ + if (pfn =3D=3D -1UL) + return false; + + if (pageflags_get(pfn, kpageflags_fd, &pfn_flags)) + goto fail; + + /* check for order-0 pages */ + if (!order) { + if (pfn_flags & (folio_head_flags | folio_tail_flags)) + return false; + return true; + } + + /* non THP folio */ + if (!(pfn_flags & KPF_THP)) + return false; + + pfn_head =3D pfn & ~(nr_pages - 1); + + if (pageflags_get(pfn_head, kpageflags_fd, &pfn_flags)) + goto fail; + + /* head PFN has no compound_head flag set */ + if ((pfn_flags & folio_head_flags) !=3D folio_head_flags) + return false; + + /* check all tail PFN flags */ + for (i =3D 1; i < nr_pages; i++) { + if (pageflags_get(pfn_head + i, kpageflags_fd, &pfn_flags)) + goto fail; + if ((pfn_flags & folio_tail_flags) !=3D folio_tail_flags) + return false; + } + + /* + * check the PFN after this folio, but if its flags cannot be obtained, + * assume this folio has the expected order + */ + if (pageflags_get(pfn_head + nr_pages, kpageflags_fd, &pfn_flags)) + return true; + + /* If we find another tail page, then the folio is larger. */ + return (pfn_flags & folio_tail_flags) !=3D folio_tail_flags; +fail: + ksft_exit_fail_msg("Failed to get folio info\n"); + return false; +} + /* If `ioctls' non-NULL, the allowed ioctls will be returned into the var = */ int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len, bool miss, bool wp, bool minor, uint64_t *ioctls) diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests= /mm/vm_util.h index 7799154b67ee..5eb90e0d1d13 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -95,6 +95,8 @@ bool check_huge_file(void *addr, int nr_hpages, uint64_t = hpage_size); bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size); int64_t allocate_transhuge(void *ptr, int pagemap_fd); int pageflags_get(unsigned long pfn, int kpageflags_fd, uint64_t *flags); +bool is_backed_by_folio(char *vaddr, int order, int pagemap_fd, + int kpageflags_fd); =20 int uffd_register(int uffd, void *addr, uint64_t len, bool miss, bool wp, bool minor); --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fhigh-a6-smtp.messagingengine.com (fhigh-a6-smtp.messagingengine.com [103.168.172.157]) (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 D0BB72DA756; Sun, 2 Aug 2026 19:53:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.157 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700386; cv=none; b=F/19rgXI0A5RM2X35l4O2rMhEWvizS/wyx1Z02x4naAHdGvdH0pM2R7tk5aZ1KbagRQcwbOkb8Wv9QCNAJVmaE/QFsJfZLQQ8OGuXqyqv5Teac9yJpgZHTHlJfrnt0qUCTgcayZdZNQ+PXwg2B036ArRfdMVOEshTB0HKhSilU4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700386; c=relaxed/simple; bh=s8rCSiw4i0iBbRZGsHg90LacKElEqMwPhLS0IdNjAk8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UKAik1A3jBIEl+0w7kRR3XZz1MA1NwlZD9graZ+HiiMU0ZrF6i+20j+D1MwQqUx4eofA1a6lE/85Gqxp6Vmhfh/BdSdvOsaLyR9+1Kb5yr0mOdZKDy4VIhopf5yVGTORZiiUJHFd/1Ha/qyX1TDcBbsP2/aUDvWw9P+MRDsEe/o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=IzoNT2L3; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Czd9oGqE; arc=none smtp.client-ip=103.168.172.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="IzoNT2L3"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Czd9oGqE" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.phl.internal (Postfix) with ESMTP id 074461400051; Sun, 2 Aug 2026 15:53:04 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-02.internal (MEProxy); Sun, 02 Aug 2026 15:53:04 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1785700384; x= 1785786784; bh=1Yc9ml7CfBPQ/cIKQqowgz5k8tYCqly+NyaD0PaW07E=; b=I zoNT2L3/dKDrxX7QCfoolISbpCCpOFRTvHNf5Dnq+a8XqbxrCnYUxUddYdamsEZB e43GShQg/CJVZHtvALxDAOR+TvHgO/ZbjhNA+L9ljsf9UQ8hz2e+rbZ2v9Q40BCh sCfgSgrt5MQsN8IJF1iMV8Xc5hir5/o4Jixt23tf0J7ZC49LB4TiC/zU7JlZuqtk hEhn29ErswubY0ONplZ5nriMaH0aNyh3kW+wRhp5H0com66mpm3G4qV9DhLuLpfv cyq4cL9pfPwwL/iFVrDcymVigu6tNrTSEeBtlQj9vjB1DgJMTG/zxu/UU8CBF6Ci E9RWA8av7ULnOipUehZ+w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1785700384; x=1785786784; bh=1 Yc9ml7CfBPQ/cIKQqowgz5k8tYCqly+NyaD0PaW07E=; b=Czd9oGqEKgRLHKRhY Vna28jK1EghLAPWLC3G12/xNNsCNKeyR87+5UnvovqJF8JNUuN7Awd3p3CnvwlKQ bhTLTVzBbZm8Yc1BrSUfGhj0uRkkbXd6n/EUQWTmorqm51A/6qLumfMzDytHMHlI QvpiaBEGKsyxCtYMowGDaCNX24PT7LRq1wmVOeq4uc+bVZQaLbLdVJJ6zq6Nt6Fv jXTiV7rKtZjxaRWg2eZ48na9IMTXA3/Pn9/LF8/xAhFdjiQvm1WT/Jhg5sMP+nPj zIaNthRXA5VmxngAXSAIImfmMkAGj3zWJl81sVyIWs/ytgGfFT3Hb4RiQSXoQ0GH E1+gA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFcbv35QwNbwWPHQBcJdrWasH4YRFOBaNWig98oa0GgLD3LmQrthvyDgK5JnDhp96 dBkNywOXlTP9Hby+cm0vRQHofuB4BhsdtVcBrMer/A2AOpegfr9Hr7RYzI6OqquxWhxeXC aB5bOw4cR5G6EDzO4v2r94SJnXRDYvi2NMwyCB/quID+suEuw0TjLUMYjjQ5pFm1F3OqpQ Ctej7rOharBpUeBz9hjZojzUlseCYYYMV+BulSa6+jD3O5m4ZOeULsSyQlLb9bciCyrhiP bT+z0cGYr8PFizBGTpPnPZCe+jZkx/DQlEsoaoSV2SjHlZpE6q2+n/t1AcZaLqu1qPGmAT BkOOyujnxS1vXWxSunZU9KLceiCDM3h+HuZoPbLVK1NwQpUH6QHf7AUk1ebU1xyA5YckA7 gGQaE+poT7LDMsG+DAUtWkyoo4wwOimaqksPNvRtr/stXgEBnc7k4T0H7+F7Z64oIo0miP 9ztnIsPDlPqaDKCmUlYCmPvjgBg7XqIQpAWwO4dBOh3ys3GhMlcGlUno4TCvPOgEY7nDV3 YPirq6COLeiKL8FRcQrXzd3H095Q0sqWpKpY1afRicX7v6byx8vIArye4rkTK9GrfmQkxI RUCJx3S4l5xFQSIACt7scyxVovTD85vAtUxRClk36P4wyNgzln3DOcrAgjNQ X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:02 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 02/16] selftests/mm: add folio-order check for VA ranges Date: Sun, 2 Aug 2026 20:52:34 +0100 Message-ID: <20260802195254.1937477-3-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Kiryl Shutsemau (Meta)" is_backed_by_folio() answers "what order folio backs this page", but mTHP collapse tests need the range-level question: is every order-aligned window of this VA range backed by one folio of exactly that order, mapped head-to-tail? Add is_range_backed_by_folio_orders(): per window, require a present and naturally aligned head PFN, a contiguous PFN run across the window, and is_backed_by_folio() agreeing on the order. A window assembled from pieces of different folios, or mapping a folio outside its natural position, fails the check. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/vm_util.c | 46 ++++++++++++++++++++++++++++ tools/testing/selftests/mm/vm_util.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests= /mm/vm_util.c index 343a15e25a9f..793342095420 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -365,6 +365,52 @@ bool is_backed_by_folio(char *vaddr, int order, int pa= gemap_fd, return false; } =20 +/* + * Check whether the range [start, start + len) is backed by folios of + * exactly @order, mapped at their natural alignment. + * + * is_backed_by_folio() classifies the folio backing one page; here we + * additionally require that each order-aligned window of the range maps + * one such folio head-to-tail: the VA range must be naturally aligned, + * each window's PFN run must be contiguous, and the first PFN must be + * the (naturally aligned) folio head. + * + * This is the check "did this range collapse into order-@order folios": + * a window assembled from parts of several folios, or mapping a folio + * shifted from its natural position, fails. + */ +bool is_range_backed_by_folio_orders(char *start, size_t len, int order, + int pagemap_fd, int kpageflags_fd) +{ + const unsigned long nr_pages =3D 1UL << order; + const size_t window =3D nr_pages * psize(); + char *vaddr; + + if ((uintptr_t)start % window || len % window) + return false; + + for (vaddr =3D start; vaddr < start + len; vaddr +=3D window) { + unsigned long pfn =3D pagemap_get_pfn(pagemap_fd, vaddr); + unsigned long i; + + /* Not present, or not mapping the folio head. */ + if (pfn =3D=3D -1UL || pfn % nr_pages) + return false; + + for (i =3D 1; i < nr_pages; i++) { + if (pagemap_get_pfn(pagemap_fd, vaddr + i * psize()) !=3D + pfn + i) + return false; + } + + if (!is_backed_by_folio(vaddr, order, pagemap_fd, + kpageflags_fd)) + return false; + } + + return true; +} + /* If `ioctls' non-NULL, the allowed ioctls will be returned into the var = */ int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len, bool miss, bool wp, bool minor, uint64_t *ioctls) diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests= /mm/vm_util.h index 5eb90e0d1d13..76e9938a908e 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -97,6 +97,8 @@ int64_t allocate_transhuge(void *ptr, int pagemap_fd); int pageflags_get(unsigned long pfn, int kpageflags_fd, uint64_t *flags); bool is_backed_by_folio(char *vaddr, int order, int pagemap_fd, int kpageflags_fd); +bool is_range_backed_by_folio_orders(char *start, size_t len, int order, + int pagemap_fd, int kpageflags_fd); =20 int uffd_register(int uffd, void *addr, uint64_t len, bool miss, bool wp, bool minor); --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (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 0EDF333B969; Sun, 2 Aug 2026 19:53:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700389; cv=none; b=Z4biQszcMePc4tQ/7M23ga/lV2p2SqK2dkfMoFNEK9ZRkrdlJYWsjmogwTv2z+bBicELoOo+ZDIYVsiQp5dvtuXZxg8vsawDujmpu8/2U6GLxfU3c8SNMEPt3+SAc2i+9CZjxseBe+LJZgQLup+HKMAY3aAmE5MxcfaZk0ZslC8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700389; c=relaxed/simple; bh=yuS02wbrk5SjYQbmIiLyDHVXUtJHWVkqQiWY6etCn4A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qgh9cujNk7VRiwS/q+2nn2ylFEuKa6h1INEpfd6V/bI9CGg6GrEBoKJZtC75GKAT7HlGEKtm6dJ5VMimyIWEko8/F9fG2kbq6SNpbSwwK1p1/0JZllE55EDZsc9oFqCIyGDshL7M3QD0d0CtY7Scda4KyHfuTbL0vFnAtBAIayU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=0FFkWNBt; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=dOMh3TXg; arc=none smtp.client-ip=103.168.172.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="0FFkWNBt"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="dOMh3TXg" Received: from phl-compute-06.internal (phl-compute-06.internal [10.202.2.46]) by mailfout.phl.internal (Postfix) with ESMTP id 1A4BBEC0098; Sun, 2 Aug 2026 15:53:06 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-06.internal (MEProxy); Sun, 02 Aug 2026 15:53:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1785700386; x= 1785786786; bh=X1lpufIc87OrnILbrU6i86Hc6Ve8zguy5RpXlRq4bUw=; b=0 FFkWNBtuEAeEy7agVM5xXu/ZfKL2jk0304oi68XxN1udA5BoUYUbK4lTAyO/F+oe Q1CGxjk3wHF83cIUKVRTwaUfqYOuz2knSlhuFK1MvyX6g84JG0cEdZn6NKdR9a5a w3M2ytwlQNUFGVhwwn/SDENee0fNTT2Au4vWpo3G/W6iT0yQYmhJ7/tvfmdh3UTa naNwbVVVtZ/LzUouKnBt7Un+onnZbrj3iEaPx5hEMRwXLMsU6S3qzcGv9GU5tDDo /HESqvJbQWq2s1NZGCKL9GSH/28UuF5gmgH8VE4voRPoO08Tp52XoOyWiQU6g5Un TyJVPu+0pqtVCVxie1xuA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1785700386; x=1785786786; bh=X 1lpufIc87OrnILbrU6i86Hc6Ve8zguy5RpXlRq4bUw=; b=dOMh3TXgQ67ebPYjj H4bJFLFiOBfjVZsFO01sPcHaMNEBOGV/W8MV9aEHBmBVCjewrjlcp+zsYR1Gefn4 wSctehEQvt5cEWXwUl4+cZ2KbOwhwm2THw2NZP/yajoOR4t39hjb4dp0/Y23Nl7x aIShhQt8Fa7FdUeYWTODXk9Tj9TB7GHQf1nuwl7RTg3879F9/7JrotJoszJIQ7Pf r2Tl22RKZgCavGei2o5DioNID/ERvUciD64WnKUhxftZ6STjvZPIrojHXSNglaQE XOJaEorGqubnSbeO5mXx4ypOuda8SVCk2aRZT4kmsX7lTi6jSsM+AhMgrUkcoAHr QbznQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFcbv35QwNbwWPHQBcJdrWasH4YRFOBaNWig98oa0GgLD3LmQrthvyDgK5JnDhp96 dBkNywOXlTP9Hby+cm0vRQHofuB4BhsdtVcBrMer/A2AOpegfr9Hr7RYzI6OqquxWhxeXC aB5bOw4cR5G6EDzO4v2r94SJnXRDYvi2NMwyCB/quID+suEuw0TjLUMYjjQ5pFm1F3OqpQ Ctej7rOharBpUeBz9hjZojzUlseCYYYMV+BulSa6+jD3O5m4ZOeULsSyQlLb9bciCyrhiP bT+z0cGYr8PFizBGTpPnPZCe+jZkx/DQlEsoaoSV2SjHlZpE6q2+n/t1AcZaLqu1qPGmVx CMMjXLzjYN36YxfWnhiv4XcXVDFVH+QfDI8mV8HA2XV6Jt2xBvmsyuX+fq1a2CuTBLcIeO gqn9K2eRet/mR8/5QWcY73Z9uPBqhfttiYT1CIUo8F2pKQB4z6jeB6/WRzzvAkdmN5hql4 BAbVNgbizKm1GzsbQnfIyuDQ+gMMDcB0R3FiaJnj1cWqJkfrgeh42uFo3c8WyqZ1a8cvuf r7u1Yk4I9DIrDAXoLL9c6tyz4vO8e5JhPFT9DUIKpdl36ARtLETAQS1zF2EFZUCmoOnTGv B889LX947NZdGckA/k96rmNnbScoJNl1iTRElq8TApmf1wVKCNrw0abNqjiA X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:05 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 03/16] selftests/mm: add folio-order detection self-check Date: Sun, 2 Aug 2026 20:52:35 +0100 Message-ID: <20260802195254.1937477-4-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Kiryl Shutsemau (Meta)" The upcoming khugepaged mTHP tests detect collapse results with the vm_util folio-order helpers instead of smaps AnonHugePages, which only sees PMD mappings. Before any collapse test trusts those helpers, make sure they agree with the kernel about what backs a mapping. For every anon THP order the kernel supports, fault memory in with only that order enabled and require the helpers to classify the backing as exactly that order: not a neighbouring order, and 4K-backed memory as order 0. Runs in the thp category of run_vmtests.sh. Verified on x86-64 4K (orders 0, 2-9) and arm64 64K (orders 0, 2-13). Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/.gitignore | 1 + tools/testing/selftests/mm/Makefile | 1 + .../testing/selftests/mm/folio_order_check.c | 138 ++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 2 + 4 files changed, 142 insertions(+) create mode 100644 tools/testing/selftests/mm/folio_order_check.c diff --git a/tools/testing/selftests/mm/.gitignore b/tools/testing/selftest= s/mm/.gitignore index 9ccd9e1447e6..54eefd8f97bc 100644 --- a/tools/testing/selftests/mm/.gitignore +++ b/tools/testing/selftests/mm/.gitignore @@ -66,3 +66,4 @@ merge prctl_thp_disable rmap folio_split_race_test +folio_order_check diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index 25d10ced3b3b..33917c76b871 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -104,6 +104,7 @@ TEST_GEN_FILES +=3D guard-regions TEST_GEN_FILES +=3D merge TEST_GEN_FILES +=3D rmap TEST_GEN_FILES +=3D folio_split_race_test +TEST_GEN_FILES +=3D folio_order_check =20 ifneq ($(ARCH),arm64) TEST_GEN_FILES +=3D soft-dirty diff --git a/tools/testing/selftests/mm/folio_order_check.c b/tools/testing= /selftests/mm/folio_order_check.c new file mode 100644 index 000000000000..f70d766ff3eb --- /dev/null +++ b/tools/testing/selftests/mm/folio_order_check.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Self-check for the vm_util folio-order detection helpers, + * is_backed_by_folio() and is_range_backed_by_folio_orders(). + * + * For every anon THP order the kernel supports, fault memory in with only + * that order enabled and verify the helpers report exactly that order: + * not a neighbouring order, and plain 4K memory as order 0. The helpers + * are what the khugepaged mTHP tests use to detect collapse results, so + * they must agree with the kernel's own idea of the backing before any + * collapse test relies on them. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "kselftest.h" +#include "vm_util.h" +#include "hugepage_settings.h" + +static int pagemap_fd; +static int kpageflags_fd; + +/* mmap an anon VMA of exactly @size bytes at a @size-aligned address. */ +static char *alloc_aligned(size_t size) +{ + size_t len =3D size * 2; + uintptr_t aligned; + char *p; + + p =3D mmap(NULL, len, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (p =3D=3D MAP_FAILED) + ksft_exit_fail_perror("mmap()"); + + aligned =3D ((uintptr_t)p + size - 1) & ~(size - 1); + if (aligned !=3D (uintptr_t)p) + munmap(p, aligned - (uintptr_t)p); + if (aligned + size !=3D (uintptr_t)p + len) + munmap((char *)aligned + size, + (uintptr_t)p + len - aligned - size); + + return (char *)aligned; +} + +/* + * Enable only @order (order 0: nothing), fault one aligned window in and + * check the helpers see exactly @order. + */ +static void check_order(int order) +{ + struct thp_settings settings =3D *thp_current_settings(); + size_t size =3D psize() << order; + bool ok =3D true; + char *p; + int i; + + for (i =3D 0; i < NR_ORDERS; i++) + settings.hugepages[i].enabled =3D THP_NEVER; + if (order) + settings.hugepages[order].enabled =3D THP_ALWAYS; + thp_push_settings(&settings); + + p =3D alloc_aligned(size); + *p =3D 1; + + if (!is_range_backed_by_folio_orders(p, size, order, + pagemap_fd, kpageflags_fd)) { + ksft_print_msg("order %d not detected after fault\n", order); + ok =3D false; + } + + /* A lower order must be rejected: the folio is larger. */ + if (order && is_range_backed_by_folio_orders(p, size, order - 1, + pagemap_fd, + kpageflags_fd)) { + ksft_print_msg("order %d also reported as order %d\n", + order, order - 1); + ok =3D false; + } + + /* Order 0 pages must not look like any large folio, and vice versa. */ + if (order && is_range_backed_by_folio_orders(p, size, 0, + pagemap_fd, + kpageflags_fd)) { + ksft_print_msg("order %d also reported as order 0\n", order); + ok =3D false; + } + + munmap(p, size); + thp_pop_settings(); + + ksft_test_result(ok, "order %d classified\n", order); +} + +int main(void) +{ + struct thp_settings settings; + unsigned long orders; + int order; + + ksft_print_header(); + + if (!thp_available()) + ksft_exit_skip("Transparent Hugepages not available\n"); + + pagemap_fd =3D open("/proc/self/pagemap", O_RDONLY); + if (pagemap_fd < 0) + ksft_exit_fail_perror("open(\"/proc/self/pagemap\")"); + kpageflags_fd =3D open("/proc/kpageflags", O_RDONLY); + if (kpageflags_fd < 0) + ksft_exit_skip("open(\"/proc/kpageflags\") requires root\n"); + + orders =3D thp_supported_orders(); + if (!orders) + ksft_exit_skip("No supported THP orders\n"); + + ksft_set_plan(__builtin_popcountl(orders) + 1); + + thp_save_settings(); + thp_read_settings(&settings); + /* Base of the settings stack; the bottom entry is never popped. */ + thp_push_settings(&settings); + + check_order(0); + for (order =3D 1; order < NR_ORDERS; order++) { + if (!(orders & (1UL << order))) + continue; + check_order(order); + } + + thp_restore_settings(); + + ksft_finished(); +} diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/self= tests/mm/run_vmtests.sh index 687d115e3bd8..8bf898b71350 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -402,6 +402,8 @@ CATEGORY=3D"pfnmap" run_test ./pfnmap # COW tests CATEGORY=3D"cow" run_test ./cow =20 +CATEGORY=3D"thp" run_test ./folio_order_check + CATEGORY=3D"thp" run_test ./khugepaged =20 CATEGORY=3D"thp" run_test ./khugepaged -s 2 --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fhigh-a6-smtp.messagingengine.com (fhigh-a6-smtp.messagingengine.com [103.168.172.157]) (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 C2FDB33D4E8; Sun, 2 Aug 2026 19:53:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.157 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700390; cv=none; b=Yx0gEAy+4rAHgXad8Xa4RfFJxWBk3nL2BqetG8grrEltVWuOzE3u84n6IWjhQkC8M3xwPStbo/y6pjwYOmbV0ghjh2SeKBf0q3iDdW8Mmad16OCupxCr6HIGotM0+8GLhME70ekrjkcp2+zOqxY+86NF5VyzdystAZVim9mRLcw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700390; c=relaxed/simple; bh=zWuf4QWinvXnL9xDdVvSnp6S6SG/PTUhrw06pqnbno0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VlrBP7wsyXK4YOb+9vevH5WgJ/fElKREuYhQB2FjjNcUnWZ1Vx2efbt1gShH62hdb/0TXr5k3wcaYnh1iv+Jk6ifERcYF7k1fmkd7EVDF+19Gco63h0MkxfxXn0s8vJWkz9OuZ4Q23TzYf3zkAYvFYikEiAXFJs+L39ijHJk3x0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=FXvE9qPS; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Czh2r/Qd; arc=none smtp.client-ip=103.168.172.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="FXvE9qPS"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Czh2r/Qd" Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfhigh.phl.internal (Postfix) with ESMTP id E10EB1400053; Sun, 2 Aug 2026 15:53:07 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-05.internal (MEProxy); Sun, 02 Aug 2026 15:53:07 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1785700387; x=1785786787; bh=42Jk8anv09Ae+D5TcqeZWyKxnhTNFQk1 HNvbrY4yTeM=; b=FXvE9qPS4gNJi6Ok/gHuf/7o0xspxI0WUkdVusjcSFEXNj+b 28pPX9F0vM1KSfCXdUTSPJWUNrh7OTEwzjfHVJM85CODQ0RbgzDUpdt+IMwz5g11 aiGpehNWNyShrz8r0MFbrKTxyd1z910hGJAwoS1yokxpMke/WttknjxdthY9xRrD 43TifxNcPAuK+XHj6CzV1LeZKVP2Eow7xLXLx4NLaB4/rjJQzBBExqvcAq3CT8ui 9IrfE6Zuf1BHfWR/WfQOYaq024zapFgL0SxAzXqwVRACgZ2VwmgkKsTVu3oOe8kW GEAUFcf7s18OURwU65SCTY+UE5WzuwaEVw9h5w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1785700387; x= 1785786787; bh=42Jk8anv09Ae+D5TcqeZWyKxnhTNFQk1HNvbrY4yTeM=; b=C zh2r/QdDtG6XtCiiHkjqg3edJ0xn746ubXCkgvA+ClzatPMGvrWRBkUcHcQHotlG iZ/oQ3Mmyw2YNMjiga7mTzvpPBh8C5OFQx3sLmsxnhUu1XlPAxMKWJ9fgk2vM0IE qeBKUdCNlOsJDdx7MLUyEHSOGTQrP83PLeJcISOcL9QGetCIIRtPH9BDAAD6vSKC H19PLeG5oRSi+ETVts0PZEV2zrN28ev5zfFOO3u3FN0eAxGMWloeiCLQbnMHVf4N vlSuJNwzBwh2Cyo1jSo4oZIgX5z6qFM/xqYkE2ffd0NusfIfafstBgBpuS+9gmSq Uiy7yoItjPe9Nt2chg+uw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFFI2e4v0VL62gQn4LBnevEk7hs7RPV0r834Y3gUTCorNoKUtwVAeDj7rz+NLSQhu y/OAVYT+Jiel/qs6SnenOZvG6g0/cBirKvBT04HwvsU8h7D4yYwa5SFmotLmYkPQwKQLoR XyoVa9k9cCWRGnBS8/iQFE4ExZ0v8G70T6sZm1EWsdaZBvTMj2GHQiHvKs8tPPQK8XgZ9j RKmuu8fzg0HU9Cb/JfQjtmfbnMGFW/DwOIP3fzuIoiDtK7qjVWTEWpHzYz7Wp/+2gMhckz XQqrN9Qeyr78NcH0CzwZM7Ax6TTOlUlNfoUZ9kxKI2Wss6eEBOi+d/VU1OXEnW0ohbmjTH BtqE1+cv2cteR2qhShD+uyo8H1448/28Y7fN7vaw1d/k8RZxzBZzzXX0a1nsjsDAzfrfmK yuKzABaar3AaDK8VUd8UPrs8rPEBN7UGpq4If0b8rbkWaMhC71CSIh+Rpau7p+4gP7Aeko FiLGM7yAPhClmaahdy56j3JK17Il2bcE8GxCr72ym1yCvVLvSnohSuK6jQ9H52vBjX+uBC 314guuaTKgLAhbNOWky6B0t86FTmaLLPqpo2nOefoeO2a1W/vxWC/CTQnJVD73AYmpuc08 arqjR5DJPZDNOUYpP1ps5M0Bl601AoeEEsoo44bOOOMa6O+vnT+oss/yBBjA X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:07 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 04/16] selftests/mm: add order-parameterized khugepaged collapse cases Date: Sun, 2 Aug 2026 20:52:36 +0100 Message-ID: <20260802195254.1937477-5-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> 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="utf-8" Content-Transfer-Encoding: quoted-printable From: "Kiryl Shutsemau (Meta)" All khugepaged collapse cases are written against PMD collapse: the regions, the thresholds and the detection (smaps AnonHugePages, which only accounts PMD mappings) all assume the PMD-order product. The mTHP collapse support merged in 7.2 has no functional selftest coverage. Add an -o mode running order-parameterized anon collapse cases against khugepaged. The region is faulted to order 0 first (the target order is "inherit" under enabled=3Dmadvise, so pre-MADV_HUGEPAGE faults cannot produce large folios), then one full khugepaged pass is awaited via the full_scans barrier, and results are detected per aligned window with the vm_util folio-order helpers: - collapse_order_full: a fully populated PTE table collapses to the target order across the range; - collapse_order_single_window: only the populated window collapses, empty neighbours stay untouched; - collapse_order_partial_window: default max_ptes_none permits collapse of a window with a single present PTE; - collapse_order_max_ptes_none: with max_ptes_none=3D0, a full window collapses while one missing a single page must not. -o accepts any order up to the PMD order. At the PMD order the cases baseline the PMD collapse path with the same test text used for the mTHP orders; single_window and max_ptes_none, which place a second window beyond the one-hugepage area, have no room below the PMD and skip there via skip_at_pmd_order(), while full and partial_window run unchanged. The default and -s modes are untouched. Passes on x86-64 4K (-o 2, 3, 5, 8) and arm64 64K (-o 5, the 2M contPTE case); the default PMD suite is unchanged at 26/26. collapse_order_mixed_sources is an order-parameterized case too: a region faulted as smaller large folios collapses to the target order (collapse accepts source folios of any order below the target). It passes on the current kernel, so it rides here with the other order cases. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged.c | 289 +++++++++++++++++++++- tools/testing/selftests/mm/run_vmtests.sh | 2 + 2 files changed, 289 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index 10e8dedcb087..971e97a7330a 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -26,9 +26,13 @@ =20 #define BASE_ADDR ((void *)(1UL << 30)) static unsigned long hpage_pmd_size; +static int hpage_pmd_order; static unsigned long page_size; static int hpage_pmd_nr; static int anon_order; +static int anon_target_order; +static int pagemap_fd =3D -1; +static int kpageflags_fd =3D -1; =20 #define PID_SMAPS "/proc/self/smaps" #define TEST_FILE "collapse_test_file" @@ -1088,6 +1092,231 @@ static void madvise_retracted_page_tables(struct co= llapse_context *c, ksft_test_result_report(exit_status, "%s\n", __func__); } =20 +/* + * Order-parameterized collapse cases (-o ): khugepaged collapses + * 4K-faulted memory into folios of the given sub-PMD order. Detection is + * folio-based (vm_util), not smaps: AnonHugePages only accounts PMD + * mappings. + * + * The region is faulted before MADV_HUGEPAGE and the target order is + * configured "inherit" under enabled=3Dmadvise, so faults are always + * order 0 and the collapse product can only come from khugepaged. + */ +static size_t anon_order_size(void) +{ + return page_size << anon_target_order; +} + +static bool range_collapsed(void *p, size_t len) +{ + return is_range_backed_by_folio_orders(p, len, anon_target_order, + pagemap_fd, kpageflags_fd); +} + +/* No aligned window in [p, p + len) is backed at the target order. */ +static bool range_not_collapsed(void *p, size_t len) +{ + size_t window =3D anon_order_size(); + char *addr =3D p; + + for (; len >=3D window; addr +=3D window, len -=3D window) { + if (range_collapsed(addr, window)) + return false; + } + return true; +} + +/* + * Completion barrier: one full khugepaged pass that started after this + * call. Waiting for full_scans to advance by two guarantees it; a +1 + * step might complete a pass that scanned our mm before the setup. + */ +static bool khugepaged_wait_full_pass(void) +{ + int full_scans =3D thp_read_num("khugepaged/full_scans") + 2; + int timeout =3D 60; /* 30 seconds */ + + while (timeout--) { + if (thp_read_num("khugepaged/full_scans") >=3D full_scans) + return true; + printf("."); + usleep(TICK); + } + return false; +} + +/* + * Cases whose geometry needs a window strictly below the PMD skip at + * -o ; the rest run there unchanged, baselining the legacy + * PMD engine with the same test text used for the mTHP orders. + */ +static bool skip_at_pmd_order(const char *name) +{ + if (anon_target_order < hpage_pmd_order) + return false; + ksft_test_result_skip("%s: needs a window below the PMD\n", name); + return true; +} + +static void collapse_order_full(struct collapse_context *c, struct mem_ops= *ops) +{ + void *p; + + p =3D ops->setup_area(1); + ops->fault(p, 0, hpage_pmd_size); + if (!range_not_collapsed(p, hpage_pmd_size)) + ksft_exit_fail_msg("Unexpected large folio after fault\n"); + + madvise(p, hpage_pmd_size, MADV_HUGEPAGE); + ksft_print_msg("Collapse fully populated PTE table to target order..."); + if (!khugepaged_wait_full_pass()) + fail("Timeout"); + else if (range_collapsed(p, hpage_pmd_size)) + success("OK"); + else + fail("Fail"); + + validate_memory(p, 0, hpage_pmd_size); + ops->cleanup_area(p, hpage_pmd_size); + ksft_test_result_report(exit_status, "%s\n", __func__); +} + +static void collapse_order_single_window(struct collapse_context *c, + struct mem_ops *ops) +{ + size_t window =3D anon_order_size(); + void *p; + + if (skip_at_pmd_order(__func__)) + return; + + p =3D ops->setup_area(1); + ops->fault(p, window, 2 * window); + if (!range_not_collapsed(p, hpage_pmd_size)) + ksft_exit_fail_msg("Unexpected large folio after fault\n"); + + madvise(p, hpage_pmd_size, MADV_HUGEPAGE); + ksft_print_msg("Collapse one fully populated window..."); + if (!khugepaged_wait_full_pass()) + fail("Timeout"); + else if (range_collapsed(p + window, window) && + range_not_collapsed(p, window) && + range_not_collapsed(p + 2 * window, + hpage_pmd_size - 2 * window)) + success("OK"); + else + fail("Fail"); + + validate_memory(p, window, 2 * window); + ops->cleanup_area(p, hpage_pmd_size); + ksft_test_result_report(exit_status, "%s\n", __func__); +} + +static void collapse_order_partial_window(struct collapse_context *c, + struct mem_ops *ops) +{ + void *p; + + p =3D ops->setup_area(1); + ops->fault(p, 0, page_size); + if (!range_not_collapsed(p, hpage_pmd_size)) + ksft_exit_fail_msg("Unexpected large folio after fault\n"); + + madvise(p, hpage_pmd_size, MADV_HUGEPAGE); + ksft_print_msg("Collapse window with single PTE entry present..."); + if (!khugepaged_wait_full_pass()) + fail("Timeout"); + else if (range_collapsed(p, anon_order_size())) + success("OK"); + else + fail("Fail"); + + validate_memory(p, 0, page_size); + ops->cleanup_area(p, hpage_pmd_size); + ksft_test_result_report(exit_status, "%s\n", __func__); +} + +static void collapse_order_max_ptes_none(struct collapse_context *c, + struct mem_ops *ops) +{ + struct thp_settings settings =3D *thp_current_settings(); + size_t window =3D anon_order_size(); + void *p; + + if (skip_at_pmd_order(__func__)) + return; + + settings.khugepaged.max_ptes_none =3D 0; + thp_push_settings(&settings); + + p =3D ops->setup_area(1); + ops->fault(p, 0, 2 * window - page_size); + if (!range_not_collapsed(p, hpage_pmd_size)) + ksft_exit_fail_msg("Unexpected large folio after fault\n"); + + madvise(p, hpage_pmd_size, MADV_HUGEPAGE); + ksft_print_msg("Collapse full window, not the one missing a page..."); + if (!khugepaged_wait_full_pass()) + fail("Timeout"); + else if (range_collapsed(p, window) && + range_not_collapsed(p + window, window)) + success("OK"); + else + fail("Fail"); + + validate_memory(p, 0, 2 * window - page_size); + ops->cleanup_area(p, hpage_pmd_size); + thp_pop_settings(); + ksft_test_result_report(exit_status, "%s\n", __func__); +} + +/* Smallest order khugepaged will consider for mTHP collapse. */ +#define MIN_MTHP_ORDER 2 + +/* + * A region backed by large folios of a smaller order is a valid source + * for collapse to the target order: + * __collapse_huge_page_isolate() accepts any source folio of an order + * strictly below the candidate's. + */ +static void collapse_order_mixed_sources(struct collapse_context *c, + struct mem_ops *ops) +{ + struct thp_settings settings =3D *thp_current_settings(); + void *p; + + if (anon_target_order <=3D MIN_MTHP_ORDER) { + ksft_test_result_skip("%s: no source order below target\n", + __func__); + return; + } + + /* Fault the whole region as order-MIN_MTHP_ORDER folios. */ + settings.hugepages[MIN_MTHP_ORDER].enabled =3D THP_ALWAYS; + thp_push_settings(&settings); + p =3D ops->setup_area(1); + ops->fault(p, 0, hpage_pmd_size); + thp_pop_settings(); + + if (!is_range_backed_by_folio_orders(p, hpage_pmd_size, MIN_MTHP_ORDER, + pagemap_fd, kpageflags_fd)) + ksft_exit_fail_msg("Region not backed by order-%d folios after fault\n", + MIN_MTHP_ORDER); + + madvise(p, hpage_pmd_size, MADV_HUGEPAGE); + ksft_print_msg("Collapse region backed by smaller large folios..."); + if (!khugepaged_wait_full_pass()) + fail("Timeout"); + else if (range_collapsed(p, hpage_pmd_size)) + success("OK"); + else + fail("Fail"); + + validate_memory(p, 0, hpage_pmd_size); + ops->cleanup_area(p, hpage_pmd_size); + ksft_test_result_report(exit_status, "%s\n", __func__); +} + static void usage(void) { fprintf(stderr, "\nUsage: ./khugepaged [OPTIONS] [dir]\n\n"); @@ -1103,6 +1332,9 @@ static void usage(void) fprintf(stderr, "\t\t-h: This help message.\n"); fprintf(stderr, "\t\t-s: mTHP size, expressed as page order.\n"); fprintf(stderr, "\t\t Defaults to 0. Use this size for anon or shmem a= llocations.\n"); + fprintf(stderr, "\t\t-o: collapse target order for khugepaged:anon.\n"); + fprintf(stderr, "\t\t Runs the order-parameterized collapse cases inst= ead\n"); + fprintf(stderr, "\t\t of the PMD cases. Cannot be combined with -s.\n"= ); exit(1); } =20 @@ -1112,17 +1344,23 @@ static void parse_test_type(int argc, char **argv) char *buf; const char *token; =20 - while ((opt =3D getopt(argc, argv, "s:h")) !=3D -1) { + while ((opt =3D getopt(argc, argv, "s:o:h")) !=3D -1) { switch (opt) { case 's': anon_order =3D atoi(optarg); break; + case 'o': + anon_target_order =3D atoi(optarg); + break; case 'h': default: usage(); } } =20 + if (anon_target_order && anon_order) + usage(); + argv +=3D optind; argc -=3D optind; =20 @@ -1207,7 +1445,6 @@ static int nr_test_cases; =20 int main(int argc, char **argv) { - int hpage_pmd_order; struct thp_settings default_settings =3D { .thp_enabled =3D THP_MADVISE, .thp_defrag =3D THP_DEFRAG_ALWAYS, @@ -1244,6 +1481,13 @@ int main(int argc, char **argv) hpage_pmd_nr =3D hpage_pmd_size / page_size; hpage_pmd_order =3D __builtin_ctz(hpage_pmd_nr); =20 + if (anon_target_order && + !(thp_supported_orders() & (1UL << anon_target_order))) + ksft_exit_skip("Order %d is not a supported anon THP order\n", + anon_target_order); + if (anon_target_order > hpage_pmd_order) + ksft_exit_fail_msg("-o takes at most the PMD order\n"); + default_settings.khugepaged.max_ptes_none =3D hpage_pmd_nr - 1; default_settings.khugepaged.max_ptes_swap =3D hpage_pmd_nr / 8; default_settings.khugepaged.max_ptes_shared =3D hpage_pmd_nr / 2; @@ -1253,9 +1497,49 @@ int main(int argc, char **argv) default_settings.shmem_hugepages[hpage_pmd_order].enabled =3D SHMEM_INHER= IT; default_settings.shmem_hugepages[anon_order].enabled =3D SHMEM_ALWAYS; =20 + if (anon_target_order) { + /* + * Only the target order may produce large folios, and only + * from khugepaged: "inherit" under enabled=3Dmadvise keeps + * pre-MADV_HUGEPAGE faults at order 0. + */ + default_settings.hugepages[hpage_pmd_order].enabled =3D THP_NEVER; + default_settings.hugepages[anon_target_order].enabled =3D THP_INHERIT; + /* + * Order-parameterized cases are driven strictly by the + * khugepaged_full_pass() barrier, which wakes the daemon + * itself. A long scan_sleep keeps khugepaged from + * free-running between barrier steps, and a pages_to_scan + * covering everything makes one wake complete one full + * pass (the barrier's contract), so a run performs a + * deterministic number of passes =E2=80=94 what the stage A/B + * trace comparisons rely on. + */ + default_settings.khugepaged.scan_sleep_millisecs =3D 60000; + default_settings.khugepaged.pages_to_scan =3D 1UL << 24; + + pagemap_fd =3D open("/proc/self/pagemap", O_RDONLY); + if (pagemap_fd < 0) + ksft_exit_fail_perror("open(\"/proc/self/pagemap\")"); + kpageflags_fd =3D open("/proc/kpageflags", O_RDONLY); + if (kpageflags_fd < 0) + ksft_exit_skip("open(\"/proc/kpageflags\") requires root\n"); + } + save_settings(); thp_push_settings(&default_settings); =20 + if (anon_target_order) { + TEST(collapse_order_full, khugepaged_context, anon_ops); + TEST(collapse_order_single_window, khugepaged_context, anon_ops); + TEST(collapse_order_partial_window, khugepaged_context, anon_ops); + TEST(collapse_order_max_ptes_none, khugepaged_context, anon_ops); + TEST(collapse_order_mixed_sources, khugepaged_context, anon_ops); + + ksft_set_plan(nr_test_cases); + goto run; + } + TEST(collapse_full, khugepaged_context, anon_ops); TEST(collapse_full, khugepaged_context, read_only_file_ops); TEST(collapse_full, khugepaged_context, read_write_file_read_ops); @@ -1336,6 +1620,7 @@ int main(int argc, char **argv) ksft_set_plan(nr_test_cases + 1); =20 alloc_at_fault(); +run: for (int i =3D 0; i < nr_test_cases; i++) { struct test_case *t =3D &test_cases[i]; =20 diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/self= tests/mm/run_vmtests.sh index 8bf898b71350..6f42e35b5227 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -408,6 +408,8 @@ CATEGORY=3D"thp" run_test ./khugepaged =20 CATEGORY=3D"thp" run_test ./khugepaged -s 2 =20 +CATEGORY=3D"thp" run_test ./khugepaged -o 2 khugepaged:anon + CATEGORY=3D"thp" run_test ./khugepaged all:shmem =20 CATEGORY=3D"thp" run_test ./khugepaged -s 4 all:shmem --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fhigh-a6-smtp.messagingengine.com (fhigh-a6-smtp.messagingengine.com [103.168.172.157]) (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 D8CC033F5B4; Sun, 2 Aug 2026 19:53:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.157 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700392; cv=none; b=nMXYrN3rVlp0f3J67AobBO5D6M9FM/zOP4QAf/PNdgnZOONNJGxNKP49WlVqfcwwuBfvRggqlMC6kdeQwldoGZ7NqstKtibw4kL3KOHn+Lzl8bfNTM9PdKrhjyFia8O5iDK4gFN62nTs4yc243P3SyVTVUjXJ9FsX/yntxxMIPw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700392; c=relaxed/simple; bh=iyattW6oKr4b2TVY7k9aTcYvg47Dt3gKbAfEa1YdhiY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MNf3OqHtqhAg5yrHHxNqoIIhy1ICNinOnK+mzadHnM5SCj6H7Evuacju86qpJ2bPGDg8zYZYJdn+zCGNraEXHIy73ZJp0uN8FHpsPoDiYNdPk4lCMc2HuYPBy7BwLBpb1uJVhKLvpBmg3YuhQ9DvnHi0FTA/l0SE7Q8Rcb4e/70= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=PKtD8dK9; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=IS99VJzi; arc=none smtp.client-ip=103.168.172.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="PKtD8dK9"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="IS99VJzi" Received: from phl-compute-03.internal (phl-compute-03.internal [10.202.2.43]) by mailfhigh.phl.internal (Postfix) with ESMTP id D5D3B1400051; Sun, 2 Aug 2026 15:53:09 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-03.internal (MEProxy); Sun, 02 Aug 2026 15:53:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1785700389; x=1785786789; bh=0dYi27N+i5b6bGNiVCS2C3c2A+E2bw4k DWwDej24J7I=; b=PKtD8dK9m3RfY4oEkfEZhEjqQ8c8lFutW7eHyajN+koyWJgf RIQ5gZNn2B6jEyS7AHX1P8zJkHK5Wr2hLGeeL+z0pvZgUNSNwkEIItH7P0+o1NlZ I8AWCmjdNX330Yf9mKESvPtGbkdpCptbf0mTKtV1SKJXy/hFcgvufI/B9Z3+m8wC WtWxrCvo45MNNUQgGls0CR01xNWEkv2WIAegm4aH2/XKI+l1kP5GFrkB7QBkyaVE uKw8n8HKwbyJkmhIIwVR1j9kkXHPiOSpMM8aCIIWjGQyzwd7v1hPEKTHpzfUd29G ODhBgTBnoY5llR5+yz78vIM3DyoRO7Cog3oeUg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1785700389; x= 1785786789; bh=0dYi27N+i5b6bGNiVCS2C3c2A+E2bw4kDWwDej24J7I=; b=I S99VJziokR+RVM5fsh159gi0ByR5jhH0TVn0rqe6K/sCBqzJjkziFTbYghxnSUSt 4Bj0wpQ+/O6UvtXO5ScBTgDjJkZlRLQSceYOfaRzFhBW9ANRImdVnLXBn/GsrMok FhXxwlGDKZIgBhSdc1eqCgZUpxZOEXJdmqZx89u/sxBmUJ9B9DIP7bms6ByV38DB nntFiMtD7BC2dmJGRIAsq5pRu2UB/CxjVpyh9vSKqQ2UYRLOlB0bdLMQn+KUVzGm TAOLwY5cQQ9SUGHxbzptZL0q6ObJZFDeB1/dtvywatxDnc0sc/6SyZQT3TCxfeUP s/EAb2tfl4FdV+VjT8H8w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTF0jcSSKFGDg2KrIu5c43P4SsiipwcvDQBe+CHxos2n8PFgvSXAdv5YVW583HVAOz W5evq6qe09LpHqloXNM1K7VWF721j2bpam5IryqVMcYz9qouNwbpBEKv3Y5gifbeJAqW/Q YZQrbB51yLEk86mWZaGZ1Drq0Xy949i11wvFP7mkSWE3f4+XiyFqs+bTi+V6AVpUjNMMFr yeY2fCKzWlrX4GavSe/JRyGqxABGArlOuRBA0IP4mMA1yNK8fSDYGTdjzDrtr8AjwNqVIi 3BcHDiClTVSc/WD5f6J8XCsMYF+6dE+0Mr4gWnl6eMmh6FUU5GqCPEjsceh07AxGuRDdpm WM7Nc126E2mM/l6GiCehRFrkXzZFYZ4Ebb4FMbkX8kiMzGgzhz3DJpPl8z7yQZt2FsjMNw HZCGUFJ4vSj7vlngG9YRDlHJ+iO3T90jqZJ1YvC6bLwgYS7ApCXjzbhsjXb3AKnxIVwMTc VTa9+dsRanC053hSC/KEkGVMv+bZq+4RAGgSslAcMCCgZbfrx8Eb1xaE3qi4LjlljmSd0Y 3P2U+IEdMkzLs4n6ZYhjvbIvhLXKy3hrGxmvbBm4owHGFA6PiRWfI/gU9KKTY+jYK2AuOg AXjDt694f8YIpUefYRDa+UP1Mm7hyQQobzGZgwbPH/0juoEglBtB3Lj0X/Mg X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:09 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 05/16] selftests/mm: add khugepaged completion barrier helper Date: Sun, 2 Aug 2026 20:52:37 +0100 Message-ID: <20260802195254.1937477-6-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> 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="utf-8" Content-Transfer-Encoding: quoted-printable From: "Kiryl Shutsemau (Meta)" Race and functional tests need to drive khugepaged synchronously: set up a layout, let exactly one full scan pass over it, check the result. The khugepaged selftest already waits on full_scans advancing by two =E2=80= =94 a completion barrier for one pass that started after setup =E2=80=94 but it relies on a short configured scan_sleep_millisecs to make progress. Lift the pattern into a library helper, khugepaged_full_pass(), and drive it by the sysfs wake path: any store to scan_sleep_millisecs wakes the daemon, so the barrier completes promptly regardless of the configured scan cadence. Wake exactly once per missing pass: over-waking would queue a straggler pass behind the barrier that overlaps and perturbs whatever the caller sets up next. One wake completes one full pass only when the whole mm list fits in a single scan batch, so callers must pair the helper with a large pages_to_scan. Settings pushes and pops must not start passes nobody asked for either, so thp_write_settings() now writes each khugepaged knob only when it changes. Switch the khugepaged selftest order-parameterized cases to the helper. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- .../testing/selftests/mm/hugepage_settings.c | 66 ++++++++++++++++--- .../testing/selftests/mm/hugepage_settings.h | 2 + tools/testing/selftests/mm/khugepaged.c | 17 +---- 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/tools/testing/selftests/mm/hugepage_settings.c b/tools/testing= /selftests/mm/hugepage_settings.c index d7917dce3aba..a26a0cffa9c5 100644 --- a/tools/testing/selftests/mm/hugepage_settings.c +++ b/tools/testing/selftests/mm/hugepage_settings.c @@ -183,6 +183,17 @@ void thp_read_settings(struct thp_settings *settings) } } =20 +/* + * Write only on change: any store to a khugepaged sysfs knob wakes the + * daemon, and settings pushes/pops must not start scan passes nobody + * asked for =E2=80=94 khugepaged_full_pass() is the only sanctioned wake. + */ +static void thp_update_num(const char *name, unsigned long num) +{ + if (thp_read_num(name) !=3D num) + thp_write_num(name, num); +} + void thp_write_settings(struct thp_settings *settings) { struct khugepaged_settings *khugepaged =3D &settings->khugepaged; @@ -198,15 +209,15 @@ void thp_write_settings(struct thp_settings *settings) shmem_enabled_strings[settings->shmem_enabled]); thp_write_num("use_zero_page", settings->use_zero_page); =20 - thp_write_num("khugepaged/defrag", khugepaged->defrag); - thp_write_num("khugepaged/alloc_sleep_millisecs", - khugepaged->alloc_sleep_millisecs); - thp_write_num("khugepaged/scan_sleep_millisecs", - khugepaged->scan_sleep_millisecs); - thp_write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none); - thp_write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap); - thp_write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared); - thp_write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan); + thp_update_num("khugepaged/defrag", khugepaged->defrag); + thp_update_num("khugepaged/alloc_sleep_millisecs", + khugepaged->alloc_sleep_millisecs); + thp_update_num("khugepaged/scan_sleep_millisecs", + khugepaged->scan_sleep_millisecs); + thp_update_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none); + thp_update_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap); + thp_update_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared); + thp_update_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan); =20 if (dev_queue_read_ahead_path[0]) write_num(dev_queue_read_ahead_path, settings->read_ahead_kb); @@ -230,6 +241,43 @@ void thp_write_settings(struct thp_settings *settings) } } =20 +/* + * Completion barrier for khugepaged: wait until a full scan pass that + * started after this call has finished. full_scans must advance by two; + * a +1 step may complete a pass that examined this mm before the + * caller's setup was in place. + * + * Any store to scan_sleep_millisecs wakes the daemon, so the barrier + * works regardless of the configured scan cadence. It wakes exactly + * once per missing pass =E2=80=94 over-waking would queue a straggler pass + * behind the barrier, perturbing whatever the caller sets up next. + * One wake completes one full pass only if the whole mm list fits in + * one scan batch, so callers must pair this with a large + * pages_to_scan. + */ +bool khugepaged_full_pass(unsigned int timeout_s) +{ + unsigned long deadline_ms =3D timeout_s * 1000UL; + unsigned long sleep_ms =3D + thp_read_num("khugepaged/scan_sleep_millisecs"); + unsigned long elapsed_ms =3D 0; + int pass; + + for (pass =3D 0; pass < 2; pass++) { + unsigned long target =3D + thp_read_num("khugepaged/full_scans") + 1; + + thp_write_num("khugepaged/scan_sleep_millisecs", sleep_ms); + while (thp_read_num("khugepaged/full_scans") < target) { + if (elapsed_ms >=3D deadline_ms) + return false; + usleep(10 * 1000); + elapsed_ms +=3D 10; + } + } + return true; +} + struct thp_settings *thp_current_settings(void) { if (!settings_index) { diff --git a/tools/testing/selftests/mm/hugepage_settings.h b/tools/testing= /selftests/mm/hugepage_settings.h index 726c73c43c05..8de446affeec 100644 --- a/tools/testing/selftests/mm/hugepage_settings.h +++ b/tools/testing/selftests/mm/hugepage_settings.h @@ -83,6 +83,8 @@ static inline void thp_save_settings(void) hugepage_save_settings(/* thp =3D */ true, /* hugetlb =3D */ false); } =20 +bool khugepaged_full_pass(unsigned int timeout_s); + void thp_set_read_ahead_path(char *path); unsigned long thp_supported_orders(void); unsigned long thp_shmem_supported_orders(void); diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index 971e97a7330a..65fafab06410 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -1126,23 +1126,10 @@ static bool range_not_collapsed(void *p, size_t len) return true; } =20 -/* - * Completion barrier: one full khugepaged pass that started after this - * call. Waiting for full_scans to advance by two guarantees it; a +1 - * step might complete a pass that scanned our mm before the setup. - */ static bool khugepaged_wait_full_pass(void) { - int full_scans =3D thp_read_num("khugepaged/full_scans") + 2; - int timeout =3D 60; /* 30 seconds */ - - while (timeout--) { - if (thp_read_num("khugepaged/full_scans") >=3D full_scans) - return true; - printf("."); - usleep(TICK); - } - return false; + /* Wait up to 30 seconds for the pass to complete. */ + return khugepaged_full_pass(30); } =20 /* --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (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 68F59342146; Sun, 2 Aug 2026 19:53:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700394; cv=none; b=Z36cSxJsuMrhVbNM0m7tLtDhorh/t1gpiN6g+xNjTwcjR+cZsR0mRi/Koi3NYvM5E7ozJq3oH5bNTQ7cbvUpVaQh10vvES8qualEiWsjPrEvea+38Rj3pCQF3Z5E4QoPSNVOCly01pEcYw2rqe2ro8abKpjutkgDCXtLgg8PzXU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700394; c=relaxed/simple; bh=Mcwo4RSGfK8wgm54cuDrDDihLstb3SBDQiNEWcNjCP0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ob37BJfS83axUEZjjlFxCtFmyZR8WeoB12aT4B9+q+lv9R0T1jjNYbG3DKdEFThTZVSHB2VC3sttjYSeKttnAbuc8L4Eak3i42lR7rR5IzMXb36aIIOhoh9Rr6c24Gxe10CZCF1Qqm/e3JK/Hj/zZBxG5sJhFsi1N7s6XvEt+H4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=Wli25CZf; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=jkkO2faS; arc=none smtp.client-ip=103.168.172.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="Wli25CZf"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="jkkO2faS" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfout.phl.internal (Postfix) with ESMTP id B3673EC0098; Sun, 2 Aug 2026 15:53:11 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-02.internal (MEProxy); Sun, 02 Aug 2026 15:53:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1785700391; x=1785786791; bh=1WPM1DppkjKUgv0LPs11qP7SdNGZ55iE +fQR3xyAJ80=; b=Wli25CZfPZBdyUYeoHkMI6Vi/yyR0o4PVljO+K7aBBweqAKH vy4pt1FgkR5HHC28Sut7skVWp6hyML2cALp6sIb+AEAG7paGH9R/yKcOIgSMxFeS X2D0UfS+AsCbIROcqqYrfZPNsqRRG9z1WXaL43AdT9pM1fgJdo4Nvi4p2ngdG5ri xQWOi8nbDcGerKmTHb793NaaU9ti9UHrkqgKz88eEKoZDCRwCNFIdt4gAsgQ0WQX crMqCdzlwhteHTPuMrI4nUGFD3C/NGONv/d6BCIbqjxUL9otW288ktDN23UfjDty /QiMH0zGyHvogQdmfGb3yLo3nLIzIPnlQQnx3w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1785700391; x= 1785786791; bh=1WPM1DppkjKUgv0LPs11qP7SdNGZ55iE+fQR3xyAJ80=; b=j kkO2faSH2qqbw+T00QbtAO4xgPflQrLgoP/jfVuvCI/JzosxCvugK+gG0WRa1ylj 56Axndz04/lrJsVHMXezyCzcrCwRnRn4+pT2bMfRzJwCZqhCALMpmLGDFRKvWMLw fecC31hR0rY2Fu/FREdUIbHiaOvzoKlIfBq1UlPUW6QYku6t3L9aRXYHwnYaUuHX 1+0A3nm66TvNVO69Tw0XCPL3d4SOLoPCj7xCYJVausQiI2lGCt0IhUwsJ3REYWQ8 zFwHJ8DC68oL6N/oj2blWOBZ/pzo4DOulbVXM2c7fhiOTBENUZvxJipgGUBq5P4M fNCxabwMllF5ylrIfZ9Lw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTF0jcSSKFGDg2KrIu5c43P4SsiipwcvDQBe+CHxos2n8PFgvSXAdv5YVW583HVAOz W5evq6qe09LpHqloXNM1K7VWF721j2bpam5IryqVMcYz9qouNwbpBEKv3Y5gifbeJAqW/Q YZQrbB51yLEk86mWZaGZ1Drq0Xy949i11wvFP7mkSWE3f4+XiyFqs+bTi+V6AVpUjNMMFr yeY2fCKzWlrX4GavSe/JRyGqxABGArlOuRBA0IP4mMA1yNK8fSDYGTdjzDrtr8AjwNqVIi 3BcHDiClTVSc/WD5f6J8XCsMYF+6dE+0Mr4gWnl6eMmh6FUU5GqCPEjsceh07AxGuRDdN+ Mp3rzXyvTq+D0mEH5/Ucwuk1nG5jG3LFCFh30C0hEnfxRqaW+SrVC9nZQIVO1yWvGsXy9F r+nirxscbPhY67oKZa+lnbjq6d7SRR4ufPvzjKUEzGg7cxqAud2bfbq9sI5eoES8VJujED W6CgeZrF7vP4Z+MCGj+D+rXtWwOEiUkBy4spPxX3ShPUPosw0Cq/im07TlCwQgFT6VDqIL f8N7nijDyr6xCe8fXjY8DMvjYzCvkkh7x0DLLodIBHzNzBf4K4C6P0K+M1TesMrsICNIZo wfJLuZBVgQ5R7ie8ivhbe8NDc5pkn4wjFjqY1etOwigorFvV2gRqfYlnXQyQ X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:10 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 06/16] selftests/mm: add khugepaged race harness Date: Sun, 2 Aug 2026 20:52:38 +0100 Message-ID: <20260802195254.1937477-7-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> 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="utf-8" Content-Transfer-Encoding: quoted-printable From: "Kiryl Shutsemau (Meta)" Collapse serializes against faults, GUP, fork, mremap and zapping through a protocol of locks, TLB flushes and refcount checks; none of the khugepaged selftests exercise it under contention. Add khugepaged_race: two faulters, MADV_DONTNEED, transient FOLL_PIN (gup_test), fork and mremap threads race one of three collapse drivers over the same ranges: stepped khugepaged driven one full pass at a time via khugepaged_full_pass() =E2=80=94 deterministic extent per step; free free-running khugepaged (scan_sleep_millisecs=3D0) =E2=80=94 so= ak; madvise MADV_COLLAPSE + MADV_DONTNEED loop =E2=80=94 the PMD-order axis. All anon THP orders are enabled (inherit) and max_ptes_none is 0, so a window collapses only once fully populated; the racing MADV_DONTNEED then steers selection across orders as pages come and go. Every racing page must read as its pattern or zero, never anything else =E2=80=94 checked continuously by the faulters and fork children, and in a final sweep. The kernel-side assertions (DEBUG_VM, page_table_check, KASAN, lockdep) are the other half of the oracle; runners should inspect dmesg. The racing threads share three PMD-sized areas by default, plus one owned by the mremap thread; -a overrides the count for memory-constrained or emulated hosts, where a 512M PMD (arm64/64K) makes the default playground multi-gigabyte. Short runs are wired into run_vmtests.sh; soak length is -d. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/.gitignore | 1 + tools/testing/selftests/mm/Makefile | 1 + tools/testing/selftests/mm/khugepaged_race.c | 354 +++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 7 + 4 files changed, 363 insertions(+) create mode 100644 tools/testing/selftests/mm/khugepaged_race.c diff --git a/tools/testing/selftests/mm/.gitignore b/tools/testing/selftest= s/mm/.gitignore index 54eefd8f97bc..b3b26447cd23 100644 --- a/tools/testing/selftests/mm/.gitignore +++ b/tools/testing/selftests/mm/.gitignore @@ -67,3 +67,4 @@ prctl_thp_disable rmap folio_split_race_test folio_order_check +khugepaged_race diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index 33917c76b871..046bae8d1eff 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -105,6 +105,7 @@ TEST_GEN_FILES +=3D merge TEST_GEN_FILES +=3D rmap TEST_GEN_FILES +=3D folio_split_race_test TEST_GEN_FILES +=3D folio_order_check +TEST_GEN_FILES +=3D khugepaged_race =20 ifneq ($(ARCH),arm64) TEST_GEN_FILES +=3D soft-dirty diff --git a/tools/testing/selftests/mm/khugepaged_race.c b/tools/testing/s= elftests/mm/khugepaged_race.c new file mode 100644 index 000000000000..b586a114e4cd --- /dev/null +++ b/tools/testing/selftests/mm/khugepaged_race.c @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * khugepaged race harness. + * + * Runs collapse against concurrent faults, transient GUP pins + * (gup_test), fork, mremap and MADV_DONTNEED over the same ranges, in + * one of three driver modes: + * + * stepped khugepaged, driven synchronously one full pass at a time + * through khugepaged_full_pass() =E2=80=94 the primary driver: the + * full scan+collapse path with a deterministic extent per + * step; + * free free-running khugepaged (scan_sleep_millisecs=3D0) =E2=80=94 the + * soak; + * madvise MADV_COLLAPSE in a loop =E2=80=94 the legacy-PMD regression + * axis. + * + * All anon THP orders are enabled (inherit) and max_ptes_none is set + * mid-range, so the MADV_DONTNEED holes steer selection across orders. + * + * Correctness signals: every racing page must read as its pattern or + * zero (MADV_DONTNEED), never anything else =E2=80=94 checked continuousl= y by + * the faulters and the fork children and once at the end =E2=80=94 plus + * whatever DEBUG_VM / page_table_check / KASAN / lockdep report in + * dmesg, which the caller is expected to inspect. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kselftest.h" +#include "vm_util.h" +#include "hugepage_settings.h" +#include "../../../../mm/gup_test.h" + +#define BASE_ADDR ((void *)(1UL << 30)) +/* + * Shared playground for faults/pins/fork/dontneed: several PMD-sized + * areas the racing threads spread across, plus one area owned by the + * mremap thread. More areas means more independent regions collapsing + * at once; the default suits a normal machine. On a memory-constrained + * host -- or under emulation, where a 512M PMD (arm64/64K) makes the + * default playground multi-gigabyte -- pass -a to shrink it. + */ +#define DEFAULT_SHARED_AREAS 3 +static int nr_shared_areas; +static int nr_areas; + +static unsigned long hpage_pmd_size; +static unsigned long page_size; +static char *region; /* NR_AREAS * hpage_pmd_size */ +static char *mremap_area; /* region + NR_SHARED_AREAS areas */ +static char *mremap_scratch; /* well above the region */ +static int gup_fd =3D -1; +static volatile int stop; +static volatile int corrupted; + +static unsigned int pattern(unsigned long page_idx) +{ + unsigned int val =3D (unsigned int)page_idx * 2654435761U; + + return val ? val : 1; /* never collides with the zero-fill */ +} + +static void check_page(unsigned long page_idx) +{ + unsigned int val =3D *(unsigned int *)(region + page_idx * page_size); + + if (val && val !=3D pattern(page_idx)) { + corrupted =3D 1; + ksft_print_msg("Corruption at page %lu: %#x !=3D %#x\n", + page_idx, val, pattern(page_idx)); + } +} + +static unsigned long rand_page(unsigned int *seed) +{ + return (unsigned long)rand_r(seed) % + (nr_shared_areas * hpage_pmd_size / page_size); +} + +static void *faulter_fn(void *arg) +{ + unsigned int seed =3D (unsigned long)arg; + + while (!stop) { + unsigned long page_idx =3D rand_page(&seed); + + if (rand_r(&seed) & 1) + *(unsigned int *)(region + page_idx * page_size) =3D + pattern(page_idx); + else + check_page(page_idx); + } + return NULL; +} + +static void *dontneed_fn(void *arg) +{ + unsigned int seed =3D (unsigned long)arg; + + while (!stop) { + unsigned long page_idx =3D rand_page(&seed); + unsigned long nr =3D 1UL << (rand_r(&seed) % 6); /* 1..32 pages */ + + madvise(region + page_idx * page_size, nr * page_size, + MADV_DONTNEED); + usleep(rand_r(&seed) % 500); + } + return NULL; +} + +static void *pinner_fn(void *arg) +{ + unsigned int seed =3D (unsigned long)arg; + + while (!stop) { + struct gup_test gup =3D {}; + unsigned long page_idx =3D rand_page(&seed); + + gup.addr =3D (unsigned long)(region + page_idx * page_size); + gup.size =3D 16 * page_size; + gup.nr_pages_per_call =3D 16; + gup.gup_flags =3D 1; /* FOLL_WRITE */ + /* Racing MADV_DONTNEED makes transient failures expected. */ + ioctl(gup_fd, PIN_FAST_BENCHMARK, &gup); + usleep(rand_r(&seed) % 200); + } + return NULL; +} + +static void *forker_fn(void *arg) +{ + unsigned int seed =3D (unsigned long)arg; + + while (!stop) { + pid_t pid =3D fork(); + + if (pid =3D=3D 0) { + for (int i =3D 0; i < 16; i++) + check_page(rand_page(&seed)); + _exit(corrupted); + } + if (pid > 0) { + int wstatus; + + waitpid(pid, &wstatus, 0); + if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus)) + corrupted =3D 1; + } + usleep(rand_r(&seed) % 2000); + } + return NULL; +} + +static void *mremapper_fn(void *arg) +{ + unsigned int seed =3D (unsigned long)arg; + + while (!stop) { + void *p; + + p =3D mremap(mremap_area, hpage_pmd_size, hpage_pmd_size, + MREMAP_MAYMOVE | MREMAP_FIXED, mremap_scratch); + if (p =3D=3D MAP_FAILED) + ksft_exit_fail_perror("mremap() away"); + for (int i =3D 0; i < 8; i++) + mremap_scratch[(rand_r(&seed) % + (hpage_pmd_size / page_size)) * page_size] =3D 1; + p =3D mremap(mremap_scratch, hpage_pmd_size, hpage_pmd_size, + MREMAP_MAYMOVE | MREMAP_FIXED, mremap_area); + if (p =3D=3D MAP_FAILED) + ksft_exit_fail_perror("mremap() back"); + usleep(rand_r(&seed) % 2000); + } + return NULL; +} + +static unsigned long now_ms(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000UL + tv.tv_usec / 1000; +} + +static void usage(void) +{ + fprintf(stderr, + "Usage: khugepaged_race [-d seconds] [-m stepped|free|madvise] [-a areas= ]\n" + "\t-a: number of shared PMD-sized playground areas (default 3)\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + static const char * const thread_names[] =3D { + "faulter", "faulter2", "dontneed", "pinner", "forker", + "mremapper", + }; + void *(*const thread_fns[])(void *) =3D { + faulter_fn, faulter_fn, dontneed_fn, pinner_fn, forker_fn, + mremapper_fn, + }; + const int nr_threads =3D ARRAY_SIZE(thread_names); + pthread_t threads[ARRAY_SIZE(thread_names)]; + const char *mode =3D "stepped"; + struct thp_settings settings; + unsigned long end_ms; + int duration_s =3D 10; + unsigned long thread_mask =3D ~0UL; + int nr_areas_arg =3D 0; + unsigned long i; + int steps =3D 0; + int opt; + + while ((opt =3D getopt(argc, argv, "a:d:m:t:h")) !=3D -1) { + switch (opt) { + case 'a': + nr_areas_arg =3D atoi(optarg); + break; + case 'd': + duration_s =3D atoi(optarg); + break; + case 'm': + mode =3D optarg; + break; + case 't': + /* debug: bitmask of racing threads to start */ + thread_mask =3D strtoul(optarg, NULL, 0); + break; + default: + usage(); + } + } + if (strcmp(mode, "stepped") && strcmp(mode, "free") && + strcmp(mode, "madvise")) + usage(); + + ksft_print_header(); + if (!thp_available()) + ksft_exit_skip("Transparent Hugepages not available\n"); + + page_size =3D getpagesize(); + hpage_pmd_size =3D read_pmd_pagesize(); + if (!hpage_pmd_size) + ksft_exit_fail_msg("Reading PMD pagesize failed\n"); + + gup_fd =3D open("/sys/kernel/debug/gup_test", O_RDWR); + if (gup_fd < 0) + ksft_exit_skip("/sys/kernel/debug/gup_test requires CONFIG_GUP_TEST and = root\n"); + + nr_shared_areas =3D nr_areas_arg > 0 ? nr_areas_arg : DEFAULT_SHARED_AREA= S; + nr_areas =3D nr_shared_areas + 1; + + ksft_set_plan(1); + + thp_save_settings(); + thp_read_settings(&settings); + settings.thp_enabled =3D THP_MADVISE; + settings.thp_defrag =3D THP_DEFRAG_ALWAYS; + settings.shmem_enabled =3D SHMEM_NEVER; + settings.khugepaged.defrag =3D 1; + settings.khugepaged.scan_sleep_millisecs =3D + strcmp(mode, "free") ? 1000 : 0; + settings.khugepaged.alloc_sleep_millisecs =3D 10; + /* + * Strict occupancy: mTHP collapse only supports 0 or + * HPAGE_PMD_NR - 1 and coerces anything else to 0 anyway, and 0 + * also keeps khugepaged from burning the whole step in doomed + * PMD-sized allocations on 512M-PMD configs: under racing + * MADV_DONTNEED a fully populated PMD area is rare. + */ + settings.khugepaged.max_ptes_none =3D 0; + settings.khugepaged.pages_to_scan =3D + nr_areas * (hpage_pmd_size / page_size) * 8; + for (i =3D 0; i < NR_ORDERS; i++) { + if (thp_supported_orders() & (1UL << i)) + settings.hugepages[i].enabled =3D THP_INHERIT; + } + /* Base of the settings stack; the bottom entry is never popped. */ + thp_push_settings(&settings); + + region =3D mmap(BASE_ADDR, nr_areas * hpage_pmd_size, + PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, + -1, 0); + if (region !=3D BASE_ADDR) + ksft_exit_fail_msg("Failed to allocate VMA at %p\n", BASE_ADDR); + mremap_area =3D region + nr_shared_areas * hpage_pmd_size; + mremap_scratch =3D (char *)BASE_ADDR + 2 * nr_areas * hpage_pmd_size; + + /* Populate so the first pass has something to collapse. */ + for (i =3D 0; i < nr_shared_areas * hpage_pmd_size / page_size; i++) + *(unsigned int *)(region + i * page_size) =3D pattern(i); + memset(mremap_area, 1, hpage_pmd_size); + madvise(region, nr_areas * hpage_pmd_size, MADV_HUGEPAGE); + + for (i =3D 0; i < nr_threads; i++) { + if (!(thread_mask & (1UL << i))) { + threads[i] =3D 0; + continue; + } + if (pthread_create(&threads[i], NULL, thread_fns[i], + (void *)(i + 1))) + ksft_exit_fail_perror("pthread_create()"); + } + + end_ms =3D now_ms() + duration_s * 1000UL; + if (!strcmp(mode, "stepped")) { + while (now_ms() < end_ms && !corrupted) { + if (!khugepaged_full_pass(600)) + ksft_exit_fail_msg("khugepaged pass timed out\n"); + steps++; + } + } else if (!strcmp(mode, "free")) { + while (now_ms() < end_ms && !corrupted) + usleep(100 * 1000); + } else { /* madvise */ + while (now_ms() < end_ms && !corrupted) { + for (i =3D 0; i < nr_shared_areas; i++) { + madvise(region + i * hpage_pmd_size, + hpage_pmd_size, MADV_COLLAPSE); + } + madvise(region, nr_shared_areas * hpage_pmd_size, + MADV_DONTNEED); + steps++; + } + } + + stop =3D 1; + for (i =3D 0; i < nr_threads; i++) { + if (threads[i]) + pthread_join(threads[i], NULL); + } + + /* Final integrity sweep. */ + for (i =3D 0; i < nr_shared_areas * hpage_pmd_size / page_size; i++) + check_page(i); + + thp_restore_settings(); + + ksft_test_result(!corrupted, "%s: %ds, %d steps, no corruption\n", + mode, duration_s, steps); + ksft_finished(); +} diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/self= tests/mm/run_vmtests.sh index 6f42e35b5227..a8b6b839cb97 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -404,6 +404,13 @@ CATEGORY=3D"cow" run_test ./cow =20 CATEGORY=3D"thp" run_test ./folio_order_check =20 + +CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m stepped + +CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m free + +CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m madvise + CATEGORY=3D"thp" run_test ./khugepaged =20 CATEGORY=3D"thp" run_test ./khugepaged -s 2 --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (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 32AC1343888; Sun, 2 Aug 2026 19:53:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700395; cv=none; b=YZTfkBwlla7USa5tvlQYN/K5Bm3xrEn1HEgPbGdZWH0/SXrWc5cC4UsZSCsMAlY+uHjGeXTkLwv3XH231EBb9/I4w7uPKG9n7PuyXx5EfMrGuUrGneHw/1uuJYGVsUDVA87tzOWf3FAQnf9b8rnmSmSTX+Hhi0sD3Sgrg0kKRuU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700395; c=relaxed/simple; bh=HXgd0WDA3vQs38YRJ7329P0AWyTwtPeBxS195QpZQAs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nUq0uUPMS+vg+YKj97vkNyjbpUZq6gwiEWIwZTz3HYlKYk6bcT7D1NEvobMMXemGl20yOb5jBtfdbLDwEbHLkrT6cvOj+kXuFW4Vo/9aaUfrCdIkFuxA65ixElpR9ewkRmldfQ4EbuY1DmtbEEKyxwNwfXT3WpixOsrchvxmRXQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=C6nAz0He; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=mq6bfxHo; arc=none smtp.client-ip=103.168.172.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="C6nAz0He"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="mq6bfxHo" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfout.phl.internal (Postfix) with ESMTP id 472C9EC009A; Sun, 2 Aug 2026 15:53:13 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-02.internal (MEProxy); Sun, 02 Aug 2026 15:53:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1785700393; x= 1785786793; bh=/GalfQyREKxG2C3FQIdFi+JAjsDFcuy0z1FP7FGhoa0=; b=C 6nAz0Hegkhoqy/l4n6NMVUHb5XKpoUhF6jsII7z8lVkOIi8Fm8fRPmgN815q05qd /D7nbBInNNMae6GhET1Od88zeMBG/C+XsVssIt3zrq/UKMEaAW8Plna4lgHpoA8R /z5EbgL7AEVkc130Hks85wMKj1a0nkZtBa9Rkp/d4aMuEFBcMpsd4QLWUTGGZ9ZM XIjxPCCvklNfoUHGLtHFVZDZmviMNBpAYvYVLq8JaAb9hIZrFBOq8hYCWTKTsatn wu8IcegD5quLBx6zPhIV/elCEeQWDY1L1EtUS/yYKjzy4JI1HJgO4l2PKeisssoV XpksLbajYSFKc/7oce7Nw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1785700393; x=1785786793; bh=/ GalfQyREKxG2C3FQIdFi+JAjsDFcuy0z1FP7FGhoa0=; b=mq6bfxHonPq8Benoc 6tRjC91Qwl+i8dM2qyAL31SGbN9L3XxePb8tbua+ueWOf2UH460LXW5nYqgVp1zg DAuz24V4VRKKujqoQk8Iq6oL+gqXKSvJTfd2zqPnBKDAXLUwKDCD3iv4FQxBh5Wb ZUz5S2aCuefi1VkI3jXXxMeuSvv9WzYkSojirnQyJkMhr/2IQI3Y/B1dU0htROpO vT9Uh27K+OnD3S1FCZG3gbWI4cfdVaYq5ShWTHvPOMpCQfZ3ukNyMB3usbeAEexE kAdhJPFog0TsZeRgikS22iXkaXuTZHvGMqCcv9pcha7mtqfWPDmt3gJX5Yj/OBsZ sybcg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTGeN1xI4bt1iclSzDFip0Bk/XaIhvbS/8i3JSTXfor37WXDF+RcNWPPd9pfiJK8Zw 2BrRRh4rnHFGERiD1jpqkpu4TBSJEj+dkjcrMZ9PB457VyyAOaPr9tioF0eAgQ73LLdMGf ZnUc9d7R5xpl56ih9w8zQdF1AdPa5yFqJeaq79y1FNmaYwVg1fW3ZavvRb02VDPCTYSs5n EKi2mK0TcmJbPEDbjm1vybeof8AWtEC76nwVjuGNoLmfYq44vTWlCkOqLjX+gcHHM4Q7iT SPI3JBSpkIfgjo/e1nwt56byN8xWT3gnCcQMRcCsWQ2AE9kBILBwP01Qmf1NZFO2elKCXI XkLOto1aBOC0cyJ0aBcRedijAUCRu75ag49n4uds8B5vtLBgS8ErmJEmXjo7fYAYYWI7JS cu5tkEvFEJ2qbFcGnDKS6Lfnlp24okWHwGDHmIFrcJC3eAC0jJSvsTj1cJklnskvScRcrH qkaYHCr9eu/VM244yipyyQCQWmD8wcY+Qev1RTM2TJ0RYIocSEvBgjdN9BfMrMoNi0UKgc 57FC67cUXuny0o2J+9N6RkBtbtoLuv0BiPrIduS2c6ZfeaMaMAbmEMgvSelijkkEWQ86RA f0cFQ15eugH72v4Gm9qiXX2WIKLaYmb3RSpi75yCd8wTPoMezrbBSqcTOQDQ X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:12 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 07/16] selftests/mm: cover a shared-source collapse write race Date: Sun, 2 Aug 2026 20:52:39 +0100 Message-ID: <20260802195254.1937477-8-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Kiryl Shutsemau (Meta)" collapse_fork already checks that a fork-shared range collapses in the process that asks while a co-sharer keeps its own page, but with the co-sharer quiescent. Add a case that keeps a co-sharer writing to the shared range throughout the collapse: CoW must keep the two sides' content independent -- the collapsing child sees the pre-fork content, the writing parent sees only its own writes. This exercises the requirement that CoW keeps a shared source isolated from the collapsing side throughout the collapse, even under an actively writing co-sharer. Passes on the unmodified kernel, pinning down the CoW-isolation contract that khugepaged collapse already provides. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged.c | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index 65fafab06410..81001e15765c 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -1047,6 +1047,61 @@ static void collapse_max_ptes_shared(struct collapse= _context *c, struct mem_ops ksft_test_result_report(exit_status, "%s\n", __func__); } =20 +/* + * Content stays isolated while a co-sharer writes concurrently. A shared + * source is copied live (not frozen), relying on it being CoW - immutable + * for the duration of the copy; a co-sharer's write goes to a CoW copy. T= he + * collapsing child must see the pre-fork content, the writing parent only + * its own writes. + */ +static void collapse_fork_cow_race(struct collapse_context *c, struct mem_= ops *ops) +{ + const unsigned long shared =3D 64 * page_size; + const int stride =3D page_size / sizeof(int); + int wstatus, i, n =3D shared / page_size; + int *ip; + void *p; + + p =3D ops->setup_area(1); + ip =3D p; + ops->fault(p, 0, shared); /* shared prefix, pre-fork pattern */ + + ksft_print_msg("Fork, collapse in the child while the parent rewrites..."= ); + if (!fork()) { + ops->fault(p, shared, hpage_pmd_size); /* private remainder */ + c->collapse("Collapse a range shared with a writing co-sharer", + p, 1, ops, true); + for (i =3D 0; i < n; i++) + if (ip[i * stride] !=3D i + 0xdead0000) { + fail("Fail: child content"); + ops->cleanup_area(p, hpage_pmd_size); + _exit(exit_status); + } + success("OK"); + ops->cleanup_area(p, hpage_pmd_size); + _exit(exit_status); + } + + /* Hammer the parent's own writes over the shared prefix. */ + for (int it =3D 0; it < 200000; it++) + for (i =3D 0; i < n; i++) + ip[i * stride] =3D i + 0xbeef0000; + + wait(&wstatus); + exit_status =3D WEXITSTATUS(wstatus); + + ksft_print_msg("Check the parent sees only its own writes..."); + for (i =3D 0; i < n; i++) + if (ip[i * stride] !=3D i + 0xbeef0000) + break; + if (i =3D=3D n) + success("OK"); + else + fail("Fail: parent content"); + ops->cleanup_area(p, hpage_pmd_size); + ksft_test_result_report(exit_status, "%s\n", __func__); +} + static void madvise_collapse_existing_thps(struct collapse_context *c, struct mem_ops *ops) { @@ -1595,6 +1650,9 @@ int main(int argc, char **argv) TEST(collapse_max_ptes_shared, khugepaged_context, anon_ops); TEST(collapse_max_ptes_shared, madvise_context, anon_ops); =20 + TEST(collapse_fork_cow_race, khugepaged_context, anon_ops); + TEST(collapse_fork_cow_race, madvise_context, anon_ops); + TEST(madvise_collapse_existing_thps, madvise_context, anon_ops); TEST(madvise_collapse_existing_thps, madvise_context, read_only_file_ops); TEST(madvise_collapse_existing_thps, madvise_context, read_write_file_rea= d_ops); --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fhigh-a6-smtp.messagingengine.com (fhigh-a6-smtp.messagingengine.com [103.168.172.157]) (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 CD34F3451CD; Sun, 2 Aug 2026 19:53:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.157 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700398; cv=none; b=Bz1o78gjG4mLYALV0QqTfCr/DqdDoF95L6hhxZLiOeYGLzh8SzpjbZL+VBP4JEysYxHOWutZfL9CtWsFA8xtR/d9eZTJZbde0eJlqzwBg35z12Gz/b4mhm8HGU/tvEMV/KOQl0BTf/oXS5ejkmc+budPNR+T9gvT6LXejlo7Vvc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700398; c=relaxed/simple; bh=NC8VzDQn9z9kSsn3cPI4FjgH2RnxYYo76F3S1YhILfk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eFEab2ScvXc0OMuXBJ6gM1hTxkCCMtfN0TfQsoOXZH1JJJxjbn5s7nrz8FLLXAUroaXBrGYBt02UN2yslYuomX9lJ8ytQ6z2Hq4q9hk6TE6/TjS6o3dqwtJA533CigVzBgoLdWFf2e5E4gEMemE50kVF9afxaOtJjyWaWpXh+LY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=kNz7ivYD; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=V/LoVwbA; arc=none smtp.client-ip=103.168.172.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="kNz7ivYD"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="V/LoVwbA" Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfhigh.phl.internal (Postfix) with ESMTP id EC3AD1400056; Sun, 2 Aug 2026 15:53:15 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-04.internal (MEProxy); Sun, 02 Aug 2026 15:53:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1785700395; x= 1785786795; bh=H44JK26m4Zj+SfIrO6VuSUoR2cZlhVi4rAW+EimBh4E=; b=k Nz7ivYDag2BKut0ro5VbcV/4kBFwahLe2YjpLoej9Jyi+ixkAEdALVL2Af47PFux J/X1n2m1RE3Mtml3fpY28gaQ50mjwTFpplW6PcV0/jivcGK1o56SVk65a4aTZWjs 0blXcDeARdqn/juo34WKHZA3DpqC+q/VqME8byj4DKvM3J7BpCOCzczNGNvcEHnE EUt51VjqEokvRDWl/svtQ0CbWuk6oBFTY+bCJu0OoJgRK6kwTa9gEIFR3zHXkuWc B7OzMsDKcZpPzGR0CpVJynuWPWZ3ZL60OsnnSMBJ2V2V9d2lY33lG9tNk3V7/w/k zDGmIw1JlpxsvRPqeYy1A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1785700395; x=1785786795; bh=H 44JK26m4Zj+SfIrO6VuSUoR2cZlhVi4rAW+EimBh4E=; b=V/LoVwbA1IbgqMEGa H24kE8AQoXybM2lBxYJFwN4mDDGYX7JA5OUpVY2eSRJXJxHvqfW4Iz8p74d8maUf TYIYFENy1CIp/Zbav4g7hx4Ei+NrlGhHEtzzJrwZ9E0we3CoV8ExZUAlJpIPCrqU bAljleKHnp4Dz9xoFpNfqaT7Gj9+RVEgCCSRVETi0TiiED1q1aMWOul5bnGF1KUD hNr9aaOrJESiBPIArQ55pX15/frvXqG5vWKPamWLsbzmsuwGihV3jI7/eS44aJak gjZXnJrtyZA7YcvOA/f7K2TJT5H6wCaRddNOomMcSVYwGIaZh4SDTy8zOD75mKo8 bP8pw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFcbv35QwNbwWPHQBcJdrWasH4YRFOBaNWig98oa0GgLD3LmQrthvyDgK5JnDhp96 dBkNywOXlTP9Hby+cm0vRQHofuB4BhsdtVcBrMer/A2AOpegfr9Hr7RYzI6OqquxWhxeXC aB5bOw4cR5G6EDzO4v2r94SJnXRDYvi2NMwyCB/quID+suEuw0TjLUMYjjQ5pFm1F3OqpQ Ctej7rOharBpUeBz9hjZojzUlseCYYYMV+BulSa6+jD3O5m4ZOeULsSyQlLb9bciCyrhiP bT+z0cGYr8PFizBGTpPnPZCe+jZkx/DQlEsoaoSV2SjHlZpE6q2+n/t1AcZaLqu1qPGmas PhunGhbdXSVZZ0JW2Q7u2nd7H4XKfvnaBGal6+JQcn3sAZmJmQi/ZpIuGEya+WRJ2S+d86 vxuCjftE5heNijEnl+FTv2HJYJjIZgU9pge1DM+9loyjS1KVWWWm/0TYqsnaUEWxQ+MIWw gG8Bj5uTuWOLL9k/NeM8rR66FsqQ09OYUZ8FlGkoxsmuh/Uuke9lLp3v92RwsVo8ecKtww TryvXTNqp/4AxVhP0g4gAko7bDM6IlXDicRZiOqygUSyw9IXXAuAeTnh/OHn8my296Jwm1 uEBU/1jc1apLoQukcKLULVKlskI2rytGv0n8FgG4Xq9cXjyfAtOoDLD4jhCA X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:14 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 08/16] selftests/mm: skip collapse_compound_extreme where the PMD is too large Date: Sun, 2 Aug 2026 20:52:40 +0100 Message-ID: <20260802195254.1937477-9-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Kiryl Shutsemau (Meta)" Its fault-time THP construction (x hpage_pmd_nr) cannot hand out a 512M order-13 page on arm64/64K, bailing the whole binary. Skip when hpage_pmd_size > 32M; MADV_COLLAPSE-driven cases still exercise PMD-order collapse there. No effect on 4K (2M) or 16K (32M) PMDs. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index 81001e15765c..b43e060b4118 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -857,6 +857,21 @@ static void collapse_compound_extreme(struct collapse_= context *c, struct mem_ops void *p; int i; =20 + /* + * Builds a PMD's worth of distinct PTE-mapped compound pages by cycling + * hpage_pmd_nr fault-time THPs through mremap. Fault-time THP allocation + * is best-effort, and this needs hpage_pmd_nr PMD-order pages in a row: + * fine at a 2M (4K base) or 32M (16K base) PMD, but a 512M PMD (arm64/64= K) + * is an order-13 allocation the allocator cannot reliably hand out even + * once, let alone 8192 times. Cap at a 32M PMD; MADV_COLLAPSE-driven cas= es + * still cover PMD-order collapse on the larger configs. + */ + if (hpage_pmd_size > (32UL << 20)) { + ksft_test_result_skip("%s: PMD too large for fault-time THP construction= \n", + __func__); + return; + } + p =3D ops->setup_area(1); ksft_print_msg("Construct PTE page table full of different PTE-mapped com= pound pages\n"); for (i =3D 0; i < hpage_pmd_nr; i++) { --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (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 9A1103446C3; Sun, 2 Aug 2026 19:53:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700401; cv=none; b=QnBocaib2T+0LuyI1VASVluRde0FBzno1usqnXwi0mK43oFcf+ebVAcmSao3T+lgAUVTeemE+q1XV1g2q1B8BB4LZq/1HyQqgieyLXfdo/KeqBn0Qxf0TTkl8tardPyMRuhFkl3ng8HpPy84xQ/ScwKuSAQcRwOCggvZJGF9aOw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700401; c=relaxed/simple; bh=0o1ANBHb+OcjUVgiryl/ohA7RJ33c27OTtBRvP71Ung=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rYY1nGvU5ZHDB1XpSu+wAOCVU06pSzIhzMP83hgDIw5y7bpjKTtDrPUHty8gaJ79RHskRhfxM3TZFUtfniv9+Tn903Eh5KSwuQApkj2FnWucN0dLPPpf5swhe3Zs9O2YWHWwPr8oX+GDxCpMdKg6HimwZh9P6JeH2cuvS0P10hQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=bqON5889; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=hE8VvX7+; arc=none smtp.client-ip=103.168.172.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="bqON5889"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="hE8VvX7+" Received: from phl-compute-06.internal (phl-compute-06.internal [10.202.2.46]) by mailfout.phl.internal (Postfix) with ESMTP id B1C69EC009A; Sun, 2 Aug 2026 15:53:18 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-06.internal (MEProxy); Sun, 02 Aug 2026 15:53:18 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1785700398; x= 1785786798; bh=6xebinTgPoV/REKfvrBQ0nYwvMKhYoD/4B/S862zW6w=; b=b qON5889okXS8B1oWXPaDR8qp+/n5teUB2zsyksoLxyqoYewTu1ztJjQNfZlnmEuL m1xL2ZvhoRdixkCDocemXyVc0XqVo7pBGtxibKQE7NbXKZ1K3kWf3Y/tgnIXK1PP tjHuUAsh3NFyiCHQ6qiEZzLE6Gy0jW5XE4Nt0S+ETtWS1gSa1zQmAVYfDyl4ypNJ lPWDziMWZneU3JIDQ43EmUDNHBPlfIFOE7YfJ/+09KSL99Z4tIvqaiAohISXFreb VwSSRpAqJ0Me0z98SZDxQV0CQP3CRLO50kz3/SYOTGQF/ywTYeinQ4kcVFw+79MV K5MlXvjO99sWOJHeGxOqQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1785700398; x=1785786798; bh=6 xebinTgPoV/REKfvrBQ0nYwvMKhYoD/4B/S862zW6w=; b=hE8VvX7+zKm4CDLIy t7tRCnXrDMfIeObKHuUH/IhinMtuAv99EJqQexlcfzBnPqrfBQeoOzs9eAppC1iA hfAEb4IJntTrBrTkaDyH5K0PQ9wKRImh0dxLtJwkXfanA2rPg/OsYmqtThEhf65I zk74HJX2dsTVv7eJHUIJH/oMGSGGCyxHn5JRbxnBcnzeJ5fw418MYVR7HdEErjb4 G6ZHVX8TtJsLT5V6ApPURJncyT31kxsBXnyspFQJjPJEELvnXrxYaG3S4FjnSc9+ bhY+HwEsFsnQo3ErpvgXswvvB51UoSSobLNhLbv4kpfaBdq/gyzbD43LOt3FrSx3 hhCRw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTGeN1xI4bt1iclSzDFip0Bk/XaIhvbS/8i3JSTXfor37WXDF+RcNWPPd9pfiJK8Zw 2BrRRh4rnHFGERiD1jpqkpu4TBSJEj+dkjcrMZ9PB457VyyAOaPr9tioF0eAgQ73LLdMGf ZnUc9d7R5xpl56ih9w8zQdF1AdPa5yFqJeaq79y1FNmaYwVg1fW3ZavvRb02VDPCTYSs5n EKi2mK0TcmJbPEDbjm1vybeof8AWtEC76nwVjuGNoLmfYq44vTWlCkOqLjX+gcHHM4Q7iT SPI3JBSpkIfgjo/e1nwt56byN8xWT3gnCcQMRcCsWQ2AE9kBILBwP01Qmf1NZFO2elKCT3 V5Arm3Bh+UsFV8y9PS9UPHiLgvZro7zrpchUVgZEU5FRJZjfxrFJ14Bw/Qv2jtwqIdSkfi gvYyr7fENXm5B3vCTZS+UKdbhNWKrdW9LM5SC75XCXLj5IlwDB0ne4onZl2G8UCpFqpLpb TCzHqQqshfIgGbJOzFWns+sDWv98eKqOFQjuI0wqxeerYwpp5cupmK6wYoDxn686kqIX+X KPfziR/xF7gzZIYMjNdbekv2d9+QKyMejmWv2smFLNMWjMiP/GMQrKzSqLSPgZfNrQs6L2 Q5n0Zg+rfsTR61F4b+w2mB6W+KYCgdrgGji/OGSvYfiSa4n9qryCLyr/TqVg X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:17 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 09/16] selftests/mm: skip khugepaged swap tests when no swap is configured Date: Sun, 2 Aug 2026 20:52:41 +0100 Message-ID: <20260802195254.1937477-10-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Kiryl Shutsemau (Meta)" collapse_swapin_single_pte and collapse_max_ptes_swap swap pages out with MADV_PAGEOUT and then require them to be swapped. With no swap area configured MADV_PAGEOUT is a no-op, so check_swap() finds nothing and the tests report a failure that only reflects the environment, not khugepaged. Skip both when /proc/swaps shows no swap area, so a missing swap device yields a SKIP rather than a spurious failure. A real swap-out failure with swap present still fails as before. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index b43e060b4118..b074b005b62f 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -181,6 +181,21 @@ static void get_finfo(const char *dir) ksft_exit_fail_msg("%s: Could not read: %s\n", __func__, path); } =20 +static bool has_swap(void) +{ + FILE *fp =3D fopen("/proc/swaps", "r"); + char line[MAX_LINE_LENGTH]; + bool ret =3D false; + + if (!fp) + return false; + /* First line is the header; any following line is a swap area. */ + if (fgets(line, sizeof(line), fp) && fgets(line, sizeof(line), fp)) + ret =3D true; + fclose(fp); + return ret; +} + static bool check_swap(void *addr, unsigned long size) { bool swap =3D false; @@ -739,6 +754,10 @@ static void collapse_swapin_single_pte(struct collapse= _context *c, struct mem_op void *p; =20 p =3D ops->setup_area(1); + if (!has_swap()) { + skip("Skip (no swap configured)"); + goto out; + } ops->fault(p, 0, hpage_pmd_size); =20 ksft_print_msg("Swapout one page..."); @@ -765,6 +784,10 @@ static void collapse_max_ptes_swap(struct collapse_con= text *c, struct mem_ops *o void *p; =20 p =3D ops->setup_area(1); + if (!has_swap()) { + skip("Skip (no swap configured)"); + goto out; + } ops->fault(p, 0, hpage_pmd_size); =20 ksft_print_msg("Swapout %d of %d pages...", max_ptes_swap + 1, hpage_pmd_= nr); --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fhigh-a6-smtp.messagingengine.com (fhigh-a6-smtp.messagingengine.com [103.168.172.157]) (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 BD785346FA0; Sun, 2 Aug 2026 19:53:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.157 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700403; cv=none; b=ipoSvxCehbVfOSRM8U84YRdSGLSutQCFFSJQvoNrm8KCLyoDi338YdTueXt2gYrKXi9kKEFKVnkJ7DInJNZKxVi6FX9Bzig6nPLymt8Ogas/fbw2GVlhrZLG1lMlKnO+8WGGg7lcYM3NbpvAI0oJrCETCqzibPJaaq0syXHuqZc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700403; c=relaxed/simple; bh=3OSEY9JdpD9xMaNN4p0R0xp0oGrLn9q9Dsw4dH/D/Co=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=p1mh/RYUvovgiQr/Ct+IiSg4wpBotWo+glzCa1rGgf36n5v/w8MrQeKL+JMWEAJEim90FDJJx0U2Yi0fxq7kzX2GUJM9l/UIPnIOehXwBjkdunYdRyetaxl+ZU7hlyV9Y1wb1WU/vPDc9AbNbo9zBk/JaEKw7QSRk4y/wtN0s/I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=VhPJ2BnO; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=XOYp3Bno; arc=none smtp.client-ip=103.168.172.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="VhPJ2BnO"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="XOYp3Bno" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfhigh.phl.internal (Postfix) with ESMTP id C75D41400051; Sun, 2 Aug 2026 15:53:20 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-02.internal (MEProxy); Sun, 02 Aug 2026 15:53:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1785700400; x=1785786800; bh=FubTz6hs1ouD8czSiv6S3nBYtEo7V5uw GpnAX260wY8=; b=VhPJ2BnOSUlF7S7/VxwA+6X6T5nSkK7Cf9K71AdLO3L9u/o0 0oudXXMwxTg/21kHJLP7CwX2hQhBA/onS9XxJ0VOE++8I8GlLHVZAiUR+Q4HA77B xRoiF59GSKE+MKu3bb4xLg/xu26Ao5NoBedEpMVkjZi58eor33YLsQmpaWIImglM bN7h7oWSZxTNuRMFX2IxhrqKifRIdY+bUWFI5KiPxDVjbkRqAzwVGi8qO7f6nger pmc0simfsS/iMBLt1KC+DHmIj8ad8Iwoi50qf25tLnA7K7e6iWoh85Xl55frM/hS Sv8RZyYvCwVgrn+jc6fhcNRVaaDHx3PULm5KCg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1785700400; x= 1785786800; bh=FubTz6hs1ouD8czSiv6S3nBYtEo7V5uwGpnAX260wY8=; b=X OYp3BnoHDvVZpEtrXQVEca4G7F09FA4oCSv19Mi//qjnSGaivdAtF2CmnP77qAtW NXjdi+jjDXS8GfUiE58Js+r94i+TV1/UCKAnNPcXSRJH/fkaaHcNtux8mKxJklkO NHqLobvyXV+Yv3jza79ytJhqkdaQvqOf0da2jnPLCsSC1zni8NihZ1aGkQ85sUSP Vt3MQlX9a6Oq1XIC1okz9MetQ60/Li4072FxGkQ2rvWEhvar2qDucsQUwajWpSkE IxP0iUeh3dJ9gCcmeeIiigwe9p8M9RhzDYNHxSoG0patD8tgbmj/pyUhOS+Ivnb2 ubfKN3BEvraT40ewb3vgg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFRqBzYArQKIzPxb/MEmNdGCT9ToZWR2Z9MFKXceCJ1pZ0XPHz+Tzow2tPL6GklJ1 ebwaY4MKncGqyHJ1wskc6iYnqwrXZWvu+eDTzjBDdq3qg5JzcpKLV2w5UXl++0ReGOv608 KE0HsICS0VS04Z0PWJwgXozgbjanng2s7GWgtPtWep1u75VG+5Ccb7pmOLAYQRehnk8s/n Wx2YaYakwl8jPSznTBPTV6Ns7Dgzgr24rNO0/DjwxE75tlmTUYoBr01HkosW3AQHBZRkOJ RXiFIhKzFvuBcF0iyrVURvrOvHy+xWjdSnjKWHJiNPnoaoE8xNEOGhdnSZ1IPeyDLmLLYX uUJVTW0Me7paWo9F03nzroIpuGs/8s3+DVGsUJ1sotkmj5uha2nRl+rGCTU9tpEsvZ6AXh To1ne1wwU99aZMzofS7ZEb/alPh7L54FPvN1weItXQ0zXILe8QRfJAlyczSjfjxlI0KL0a /2YnCaVyD2VWzv2lmDzEKXNKIzP5rfPCCE7V729mBGyFl1cwkzoARw/5IrmeoozAUaj/ht /5mkdade7oOJcMOp2TYWCVFM8GaepmTcVVYIcmTXf5NWk/k47ntqNI/8AYYXTQxC6yf3q8 LadlRDdJ5Q16q7lF1dK3EsCKWE+TQXlPNNFsJHFzKAs98+IDdxjjUr/NClKw X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:20 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 10/16] selftests/mm: verify synchronous khugepaged driving is attributable Date: Sun, 2 Aug 2026 20:52:42 +0100 Message-ID: <20260802195254.1937477-11-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> 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="utf-8" Content-Transfer-Encoding: quoted-printable From: "Kiryl Shutsemau (Meta)" The khugepaged tests attribute per-attempt outcomes through the huge_memory tracepoints. The anon-path events carry no virtual address, but an attempt is identifiable anyway: mm_collapse_huge_page_isolate() reports a source folio PFN and order, which the test matches against the PFNs it recorded from pagemap before the pass. Count an attempt from whichever attribution signal fires, so the check does not depend on which of the anon tracepoints a given kernel emits. Add minimal tracefs helpers to vm_util (enable/clear one event subsystem, open the trace buffer) and a khugepaged_sync_check test: per step, prepare one aligned window, record its source PFNs, run one khugepaged_full_pass() barrier and require the window collapsed with exactly one attributed attempt. Five steps; scan_sleep_millisecs is set high so the test only completes inside its timeout if the sysfs store really wakes the daemon. Passes 5/5 on x86-64 4K and arm64 64K. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/.gitignore | 1 + tools/testing/selftests/mm/Makefile | 1 + .../selftests/mm/khugepaged_sync_check.c | 198 ++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 2 + tools/testing/selftests/mm/vm_util.c | 49 +++++ tools/testing/selftests/mm/vm_util.h | 3 + 6 files changed, 254 insertions(+) create mode 100644 tools/testing/selftests/mm/khugepaged_sync_check.c diff --git a/tools/testing/selftests/mm/.gitignore b/tools/testing/selftest= s/mm/.gitignore index b3b26447cd23..616043a0fcd2 100644 --- a/tools/testing/selftests/mm/.gitignore +++ b/tools/testing/selftests/mm/.gitignore @@ -67,4 +67,5 @@ prctl_thp_disable rmap folio_split_race_test folio_order_check +khugepaged_sync_check khugepaged_race diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index 046bae8d1eff..026d4b61414d 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -105,6 +105,7 @@ TEST_GEN_FILES +=3D merge TEST_GEN_FILES +=3D rmap TEST_GEN_FILES +=3D folio_split_race_test TEST_GEN_FILES +=3D folio_order_check +TEST_GEN_FILES +=3D khugepaged_sync_check TEST_GEN_FILES +=3D khugepaged_race =20 ifneq ($(ARCH),arm64) diff --git a/tools/testing/selftests/mm/khugepaged_sync_check.c b/tools/tes= ting/selftests/mm/khugepaged_sync_check.c new file mode 100644 index 000000000000..13215cb370ce --- /dev/null +++ b/tools/testing/selftests/mm/khugepaged_sync_check.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Synchronous khugepaged driving check. + * + * Race tests drive khugepaged through the existing sysfs controls: a + * store to scan_sleep_millisecs wakes the daemon, and full_scans + * advancing by two is a completion barrier for one full pass that + * started after setup (khugepaged_full_pass()). Verify the pair gives + * deterministic, attributable results: one barrier step over one + * prepared window produces exactly one collapse attempt on that + * window's source pages =E2=80=94 mm_collapse_huge_page_isolate events + * filtered by source PFN and order =E2=80=94 and the window is collapsed + * afterwards, repeatably. + * + * scan_sleep_millisecs is set to 60s to prove the wake path: without + * the wake, one barrier step would sleep multiples of that and blow + * the timeout. It also keeps the daemon from free-running between + * steps, per the khugepaged_full_pass() discipline. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "kselftest.h" +#include "vm_util.h" +#include "hugepage_settings.h" + +#define BASE_ADDR ((void *)(1UL << 30)) +#define TARGET_ORDER 2 /* smallest order khugepaged considers */ +#define NR_ITERATIONS 5 + +static int pagemap_fd; +static int kpageflags_fd; +static unsigned long hpage_pmd_size; + +/* + * Count collapse attempts attributable to our window: legacy-engine + * isolate events whose scan_pfn is one of the window's source PFNs, + * plus batch-engine per-candidate install events at the window's + * address. Either engine reports exactly once per attempt. + */ +static int count_attributed(unsigned long *pfns, int nr_pfns, + unsigned long addr, unsigned int order) +{ + char line[1024]; + int count =3D 0; + FILE *fp; + + fp =3D tracing_open_trace(); + if (!fp) + ksft_exit_fail_msg("Cannot open trace buffer\n"); + + while (fgets(line, sizeof(line), fp)) { + char *s; + unsigned long val; + unsigned int ord; + char *o; + int i; + + s =3D strstr(line, "mm_collapse_huge_page_isolate:"); + if (s) { + if (sscanf(s, "mm_collapse_huge_page_isolate: scan_pfn=3D0x%lx", + &val) !=3D 1) + continue; + o =3D strstr(s, "order=3D"); + if (!o || sscanf(o, "order=3D%u", &ord) !=3D 1 || + ord !=3D order) + continue; + for (i =3D 0; i < nr_pfns; i++) { + if (val =3D=3D pfns[i]) { + count++; + break; + } + } + continue; + } + + s =3D strstr(line, "mm_collapse_candidate:"); + if (s) { + if (!strstr(s, "pass=3Dinstall") || + !strstr(s, "result=3Dsucceeded")) + continue; + o =3D strstr(s, "addr=3D"); + if (!o || sscanf(o, "addr=3D0x%lx", &val) !=3D 1 || + val !=3D addr) + continue; + o =3D strstr(s, "order=3D"); + if (!o || sscanf(o, "order=3D%u", &ord) !=3D 1 || + ord !=3D order) + continue; + count++; + } + } + fclose(fp); + return count; +} + +static void one_step(int iteration) +{ + const size_t window =3D getpagesize() << TARGET_ORDER; + const int nr_pages =3D 1 << TARGET_ORDER; + unsigned long pfns[1 << TARGET_ORDER]; + bool collapsed; + int attributed; + char *p; + int i; + + p =3D mmap(BASE_ADDR, hpage_pmd_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (p !=3D BASE_ADDR) + ksft_exit_fail_msg("Failed to allocate VMA at %p\n", + BASE_ADDR); + + /* Prepare one window; record its source PFNs. */ + for (i =3D 0; i < nr_pages; i++) { + p[i * getpagesize()] =3D i + 1; + pfns[i] =3D pagemap_get_pfn(pagemap_fd, p + i * getpagesize()); + if (pfns[i] =3D=3D -1UL) + ksft_exit_fail_msg("Source page not present\n"); + } + + if (tracing_events_start("huge_memory")) + ksft_exit_fail_msg("Cannot enable huge_memory events\n"); + + madvise(p, hpage_pmd_size, MADV_HUGEPAGE); + /* Wait up to 120 seconds for the pass to complete. */ + if (!khugepaged_full_pass(120)) + ksft_exit_fail_msg("khugepaged did not complete a full pass\n"); + + tracing_events_stop("huge_memory"); + + collapsed =3D is_range_backed_by_folio_orders(p, window, TARGET_ORDER, + pagemap_fd, kpageflags_fd); + attributed =3D count_attributed(pfns, nr_pages, (unsigned long)p, + TARGET_ORDER); + + ksft_test_result(collapsed && attributed =3D=3D 1, + "step %d: window collapsed, %d attributed result(s)\n", + iteration, attributed); + + munmap(p, hpage_pmd_size); +} + +int main(void) +{ + struct thp_settings settings; + int i; + + ksft_print_header(); + + if (!thp_available()) + ksft_exit_skip("Transparent Hugepages not available\n"); + if (!(thp_supported_orders() & (1UL << TARGET_ORDER))) + ksft_exit_skip("Order %d is not a supported anon THP order\n", + TARGET_ORDER); + + hpage_pmd_size =3D read_pmd_pagesize(); + if (!hpage_pmd_size) + ksft_exit_fail_msg("Reading PMD pagesize failed\n"); + pagemap_fd =3D open("/proc/self/pagemap", O_RDONLY); + if (pagemap_fd < 0) + ksft_exit_fail_perror("open(\"/proc/self/pagemap\")"); + kpageflags_fd =3D open("/proc/kpageflags", O_RDONLY); + if (kpageflags_fd < 0) + ksft_exit_skip("open(\"/proc/kpageflags\") requires root\n"); + if (tracing_events_start("huge_memory")) + ksft_exit_skip("tracefs unavailable\n"); + tracing_events_stop("huge_memory"); + + ksft_set_plan(NR_ITERATIONS); + + thp_save_settings(); + thp_read_settings(&settings); + settings.thp_enabled =3D THP_MADVISE; + settings.thp_defrag =3D THP_DEFRAG_ALWAYS; + settings.khugepaged.defrag =3D 1; + settings.khugepaged.scan_sleep_millisecs =3D 60000; + settings.khugepaged.alloc_sleep_millisecs =3D 60000; + settings.khugepaged.max_ptes_none =3D (hpage_pmd_size / getpagesize()) - = 1; + /* One wake must complete one full pass; see khugepaged_full_pass(). */ + settings.khugepaged.pages_to_scan =3D 1UL << 24; + for (i =3D 0; i < NR_ORDERS; i++) + settings.hugepages[i].enabled =3D THP_NEVER; + settings.hugepages[TARGET_ORDER].enabled =3D THP_INHERIT; + /* Base of the settings stack; the bottom entry is never popped. */ + thp_push_settings(&settings); + + for (i =3D 0; i < NR_ITERATIONS; i++) + one_step(i); + + thp_restore_settings(); + + ksft_finished(); +} diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/self= tests/mm/run_vmtests.sh index a8b6b839cb97..f61ec76d8e00 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -405,6 +405,8 @@ CATEGORY=3D"cow" run_test ./cow CATEGORY=3D"thp" run_test ./folio_order_check =20 =20 +CATEGORY=3D"thp" run_test ./khugepaged_sync_check + CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m stepped =20 CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m free diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests= /mm/vm_util.c index 793342095420..886fb3de9c01 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -411,6 +411,55 @@ bool is_range_backed_by_folio_orders(char *start, size= _t len, int order, return true; } =20 +#define TRACEFS_ROOT "/sys/kernel/tracing" + +static int tracing_events_write(const char *subsys, const char *val) +{ + char path[256]; + int fd; + + snprintf(path, sizeof(path), TRACEFS_ROOT "/events/%s/enable", + subsys); + fd =3D open(path, O_WRONLY); + if (fd < 0) + return -1; + if (write(fd, val, 1) !=3D 1) { + close(fd); + return -1; + } + close(fd); + return 0; +} + +/* + * Enable one ftrace event subsystem (e.g. "huge_memory") and clear the + * trace buffer. Returns -1 if tracefs is unavailable; parse the results + * via tracing_open_trace() after tracing_events_stop(). + */ +int tracing_events_start(const char *subsys) +{ + int fd; + + if (tracing_events_write(subsys, "1")) + return -1; + + fd =3D open(TRACEFS_ROOT "/trace", O_WRONLY | O_TRUNC); + if (fd < 0) + return -1; + close(fd); + return 0; +} + +int tracing_events_stop(const char *subsys) +{ + return tracing_events_write(subsys, "0"); +} + +FILE *tracing_open_trace(void) +{ + return fopen(TRACEFS_ROOT "/trace", "r"); +} + /* If `ioctls' non-NULL, the allowed ioctls will be returned into the var = */ int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len, bool miss, bool wp, bool minor, uint64_t *ioctls) diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests= /mm/vm_util.h index 76e9938a908e..4ff5a1c5ab8e 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -115,6 +115,9 @@ int close_procmap(struct procmap_fd *procmap); int write_sysfs(const char *file_path, unsigned long val); int read_sysfs(const char *file_path, unsigned long *val); bool softdirty_supported(void); +int tracing_events_start(const char *subsys); +int tracing_events_stop(const char *subsys); +FILE *tracing_open_trace(void); =20 static inline int open_self_procmap(struct procmap_fd *procmap_out) { --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (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 51F32348C4A; Sun, 2 Aug 2026 19:53:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700404; cv=none; b=rBhCfvCdwAdK7Fw0GcuSagZtxDYXI4MMfEZOjBYfLuXcmfmN6AUoaX/YyqY9ZcLaFP0TESxgX8Q3zb11QkTKoaTtYx8n3UC4XaJi6GjWRPTirC/pAzAfW9q2JVLthRMuZfaK8W1vAtKWlWr25XDbIAROTCGE26jXqf74J5RFJTQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700404; c=relaxed/simple; bh=+TLAK/GDr3G0C1+pKt2j54nz1GcAD4bsMbGOy3A6TMU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=PZpOFrxjbJ17yYtsALrtvusMyehXQUjLhIq2UcP3Wmup1r02AgQIB1eJVaStxy0Z/5QhGa04E9sAD7OUYlLJBRHSvQXK6AmMA3jTwhqz/jfYuMPtvI8OgVkdpKuOfs82s5ACyKio1uW3b1V41ZYKpAnt+lZfKPpbD1qLwoysg+0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=XkYwMRGB; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=QDs3xIqJ; arc=none smtp.client-ip=103.168.172.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="XkYwMRGB"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="QDs3xIqJ" Received: from phl-compute-06.internal (phl-compute-06.internal [10.202.2.46]) by mailfout.phl.internal (Postfix) with ESMTP id 74673EC0098; Sun, 2 Aug 2026 15:53:22 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-06.internal (MEProxy); Sun, 02 Aug 2026 15:53:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1785700402; x=1785786802; bh=wFWqzaBwQsPmRIRQNia5eoBYA1PeMAY8 pSf2InhjqsA=; b=XkYwMRGBnv/+b50lORIU5B1aYoK9N7essibAphyEATL2SBLM O2vtkaB8RoAcpo58b0Ak84ICAUVxuZRuSnSb4e41vTG4A8ECOKL+FH29mmZavmu8 RUMtNDXtvizZ78K9CKlaczJGm58ZRI8/tzGACQmNc0ToaUSBV+OBSSnCmsrTrLl/ n+LyB6ndxuoClSZo7hWvXcILHMFxXmIQrVX7ymJ9dgRADZrdiaCZDjlfWTNqo5rH Bt/A6UJtP0TWk+Ow0x5i2bJ4gzLd2Nac2bwZr/coeUzbFj1knb2Kr7dyyJ5pBG+j HoJpU2k7D1ZbgNsR1d6ud1wyiVPoKrK2JZ5xlA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1785700402; x= 1785786802; bh=wFWqzaBwQsPmRIRQNia5eoBYA1PeMAY8pSf2InhjqsA=; b=Q Ds3xIqJpXhUjexTGnanmmJ56sfkLB2O7nV+E2goGt9tIEkpk6zXijSbNtJVwuegQ GVB24014FcJ/zcu7keGOQBJlm+/H5txT4UK/gZNlG6N8XpPV4nvdbCuaMBtJbBuV SoxfxYeeXtSw1Fhh3QaT/PqsSoboftuZoVzp0iLVAKTVbkr/O6bOwZqBc8NuNbV7 mUlJGvdCreQ9GPQntJMEosmshuvcWiqlT/z3WGoWUQEy7LPspxbIPq2Oj5VbZFwr /PkNNuf2MqNIrFRORBZznAYZsZWWgAbVKJB39jN17Z396NqA9/+O+eL26p6IsDXv fVGt0V1EtnMvkqprpBViw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTF0jcSSKFGDg2KrIu5c43P4SsiipwcvDQBe+CHxos2n8PFgvSXAdv5YVW583HVAOz W5evq6qe09LpHqloXNM1K7VWF721j2bpam5IryqVMcYz9qouNwbpBEKv3Y5gifbeJAqW/Q YZQrbB51yLEk86mWZaGZ1Drq0Xy949i11wvFP7mkSWE3f4+XiyFqs+bTi+V6AVpUjNMMFr yeY2fCKzWlrX4GavSe/JRyGqxABGArlOuRBA0IP4mMA1yNK8fSDYGTdjzDrtr8AjwNqVIi 3BcHDiClTVSc/WD5f6J8XCsMYF+6dE+0Mr4gWnl6eMmh6FUU5GqCPEjsceh07AxGuRDdDW 62fQ2/9u74au2+y6Z30vcyT9WnM7oG3rlL7aGZfWCmvUWi+wMupUoEIfvLx/IqqiGyIemc Ty9SF6MQ5p667l9OtKFnlBZxuF1mkS8qOiorfNmNnjpw8vuHcv3za+r3fP8FtNFupylMzl 3RlNjEvfVrNWCr7HNpVq2nxOxHR5Q92OZzR8Cu1jf4A7kRK2zdcAwwLpk09w/b7mFfe2kZ uHnSoJKaG2LOlo+SkX1PVf4o+wkujht7ZlXjd/x7J1vxXIox3CSFWwvrjxiDkMkDu+g5pm Npp2Ng46lR0baSURacZG5yYvzaF7ymHXFmVMFowsFxya14L1fuY3g5LgAVPg X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:21 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 11/16] selftests/mm: race-harness variant for permissive hole occupancy Date: Sun, 2 Aug 2026 20:52:43 +0100 Message-ID: <20260802195254.1937477-12-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> 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="utf-8" Content-Transfer-Encoding: quoted-printable From: "Kiryl Shutsemau (Meta)" The race harness runs with max_ptes_none=3D0: strict occupancy keeps selection honest under racing MADV_DONTNEED and avoids doomed PMD-sized allocations on 512M-PMD configs. That regime never exercises collapse of partially populated windows -- every candidate it emits is fully occupied. Collapsing a window that contains holes is a different path: the hole is not copied from anywhere, it is zero-filled into the new folio, and the slot has to be re-checked under the page table lock at install time because a racing fault may have filled it in the meantime. None of that is reached at max_ptes_none=3D0. Add -z, which selects the other supported end of the occupancy scale (HPAGE_PMD_NR - 1, scaled per order): selection then emits hole-heavy windows and those paths take the brunt of the racing faults and zaps. Also drop the stale claim that max_ptes_none sits "mid-range" from the header comment; the harness has always pinned it to an end of the scale. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged_race.c | 33 ++++++++++++++------ tools/testing/selftests/mm/run_vmtests.sh | 2 ++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/mm/khugepaged_race.c b/tools/testing/s= elftests/mm/khugepaged_race.c index b586a114e4cd..2e36e242caa7 100644 --- a/tools/testing/selftests/mm/khugepaged_race.c +++ b/tools/testing/selftests/mm/khugepaged_race.c @@ -15,8 +15,12 @@ * madvise MADV_COLLAPSE in a loop =E2=80=94 the legacy-PMD regression * axis. * - * All anon THP orders are enabled (inherit) and max_ptes_none is set - * mid-range, so the MADV_DONTNEED holes steer selection across orders. + * All anon THP orders are enabled (inherit). max_ptes_none is 0 by + * default =E2=80=94 racing MADV_DONTNEED then steers selection across ord= ers =E2=80=94 + * or the permissive limit with -z, which floods the batch engine with + * hole and zeropage slots so the population paths (park-time zeropage + * clear, zero-filled copy, install-time pte_none() verify and abort) + * race the faulters directly. * * Correctness signals: every racing page must read as its pattern or * zero (MADV_DONTNEED), never anything else =E2=80=94 checked continuousl= y by @@ -196,7 +200,8 @@ static unsigned long now_ms(void) static void usage(void) { fprintf(stderr, - "Usage: khugepaged_race [-d seconds] [-m stepped|free|madvise] [-a areas= ]\n" + "Usage: khugepaged_race [-d seconds] [-m stepped|free|madvise] [-z] [-a = areas]\n" + "\t-z: permissive max_ptes_none (hole-heavy windows)\n" "\t-a: number of shared PMD-sized playground areas (default 3)\n"); exit(1); } @@ -219,11 +224,12 @@ int main(int argc, char **argv) int duration_s =3D 10; unsigned long thread_mask =3D ~0UL; int nr_areas_arg =3D 0; + bool permissive_none =3D false; unsigned long i; int steps =3D 0; int opt; =20 - while ((opt =3D getopt(argc, argv, "a:d:m:t:h")) !=3D -1) { + while ((opt =3D getopt(argc, argv, "a:d:m:t:zh")) !=3D -1) { switch (opt) { case 'a': nr_areas_arg =3D atoi(optarg); @@ -238,6 +244,9 @@ int main(int argc, char **argv) /* debug: bitmask of racing threads to start */ thread_mask =3D strtoul(optarg, NULL, 0); break; + case 'z': + permissive_none =3D true; + break; default: usage(); } @@ -274,13 +283,17 @@ int main(int argc, char **argv) strcmp(mode, "free") ? 1000 : 0; settings.khugepaged.alloc_sleep_millisecs =3D 10; /* - * Strict occupancy: mTHP collapse only supports 0 or - * HPAGE_PMD_NR - 1 and coerces anything else to 0 anyway, and 0 - * also keeps khugepaged from burning the whole step in doomed - * PMD-sized allocations on 512M-PMD configs: under racing - * MADV_DONTNEED a fully populated PMD area is rare. + * mTHP collapse only supports the two ends of the occupancy + * scale: 0 or HPAGE_PMD_NR - 1 (anything else coerces to 0). + * Strict is the default =E2=80=94 it also keeps khugepaged from burning + * the whole step in doomed PMD-sized allocations on 512M-PMD + * configs, where a fully populated area is rare under racing + * MADV_DONTNEED. -z selects the permissive end: selection then + * emits hole-heavy windows and the engine's population paths + * take the brunt of the racing faults and zaps. */ - settings.khugepaged.max_ptes_none =3D 0; + settings.khugepaged.max_ptes_none =3D permissive_none ? + (hpage_pmd_size / page_size) - 1 : 0; settings.khugepaged.pages_to_scan =3D nr_areas * (hpage_pmd_size / page_size) * 8; for (i =3D 0; i < NR_ORDERS; i++) { diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/self= tests/mm/run_vmtests.sh index f61ec76d8e00..83a04b1e2520 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -413,6 +413,8 @@ CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m free =20 CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m madvise =20 +CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m stepped -z + CATEGORY=3D"thp" run_test ./khugepaged =20 CATEGORY=3D"thp" run_test ./khugepaged -s 2 --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (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 6A44D34BA28; Sun, 2 Aug 2026 19:53:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700407; cv=none; b=psElRogDcKQbYXMK9/Bf92TXnxLyddzWSr8nOE9HCtgZ8PHQkEbN1xj+hHaH3++ub77DIFKLjSPGvF05DRkznQzps/6FEhCt/2rsWR3Ck0scyhhDv7iclOk4ib/OhHBxOMyPKHwswXsA5PalJxz2/5mUwWJSNia06MCTAsGveOM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700407; c=relaxed/simple; bh=97307fGTriEvyv1xdaKU7b4a1B4CW2nWC3qM5u9GDXg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=l0zFxOQyflWVmqCmOQEeh8HR3VIkfgUPsW+vNPetT868u8YMd9uMJdjZWU7W8XnK+p5/3chfkhOfssF6lq4QvzcWQM5qD94YcqVPzMx8i2K8smkOrXRnqXnZr+CDOu46G9ctxZQKvwjEZBtXLV5jdAwr6Cw01AyGq7q6ODAFA5M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=yWrm+U/7; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=G26MfNUC; arc=none smtp.client-ip=103.168.172.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="yWrm+U/7"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="G26MfNUC" Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfout.phl.internal (Postfix) with ESMTP id 6C4B4EC009A; Sun, 2 Aug 2026 15:53:24 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-04.internal (MEProxy); Sun, 02 Aug 2026 15:53:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1785700404; x=1785786804; bh=2c04viUKNcyHIhwoJZycJfPOVi3SeTtB J4GmRbTe/aM=; b=yWrm+U/7nm6MzG1dXJJW53fouBM8wh4F7u9str+PDJ4CIhIK CBDnuAh8AV/AsITnaObFEMo039h9MkMDpECGa5EcfSXeFpLpAwYOqMuo8dTLc2Bv opUWnoAIV85ZbyATG9pyFt37VxSjjvLiovfwJFUPxumglyfzalfNLf6zuN9QTXUR htbv/TxFNwvJ7Tv2Y5aAuCyCZliLLGOOOAuZtmc32cAa75H79+4/hWVnXt+4QOlN PLIvFEhSIxdjj0oDDIysdIa0GyXY0aUZJLEHjKN18xTLAEXsgSjX4x6q22THnuiL gJIobAElp/bjoB3+fDpBAoaRs+J0gUUJWorf+Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1785700404; x= 1785786804; bh=2c04viUKNcyHIhwoJZycJfPOVi3SeTtBJ4GmRbTe/aM=; b=G 26MfNUCRsWMe8prJiJZmMIaQugODfgLH3p7bJ93/tFtPvqqc3Ms9f+zq1XJwKQiD fG2At1k/PFT7t0KWSECXJVWvmw+UsZl/KBeo+DSNkF9hFJ7uzqT79BISfr+FS+QT eT2FvlA5PYcawn1LLBgs0jcIEsI+TGk/zA+ou8YOZNtCLJiAdSCP4tgfMUGGPxSa r0PG6ZLXiFgWcY6AqukRGIHaoAe3Ezc7i29tDIEAJC2tVxNo9c4uD5Fq204t/fZ2 8NgO9XZNgmxPEG3k+M5KXHoYVc/JztypgEbuVprpQM6pNz6Ye0GA9yEQNPAAkSGb 5FGyvBuDPl7Ph+L2alwPQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTF0jcSSKFGDg2KrIu5c43P4SsiipwcvDQBe+CHxos2n8PFgvSXAdv5YVW583HVAOz W5evq6qe09LpHqloXNM1K7VWF721j2bpam5IryqVMcYz9qouNwbpBEKv3Y5gifbeJAqW/Q YZQrbB51yLEk86mWZaGZ1Drq0Xy949i11wvFP7mkSWE3f4+XiyFqs+bTi+V6AVpUjNMMFr yeY2fCKzWlrX4GavSe/JRyGqxABGArlOuRBA0IP4mMA1yNK8fSDYGTdjzDrtr8AjwNqVIi 3BcHDiClTVSc/WD5f6J8XCsMYF+6dE+0Mr4gWnl6eMmh6FUU5GqCPEjsceh07AxGuRDdTX XdmLUZnQtOIo3U12N6vnFLsjhbT6fpNHt4ncCPLjHXv3aD+KUCMK6s6F3lRJxFNOMbgc/U 7M8qiCi4FTGopPjRHwo8pszqIV5/QQBgCpl3sYpkredorGFz5WdT1fT+V/MeK8EskgLaNh UYmt/EhKngGhHufRIXqnTlZUgWgEgyc/ng55idQJ5FtdW3FytevGVbGVrEOEddplajbHt9 2gnOmC6xkFWB58lo1pGQWWNw8KdkvTh3Vb6cSHwZYFrchM0fhW2zPSkGx7BwwtCejS0vay 7vHahGFctGxRqhClNQrtPMmAyXmh5oQR0cZQvY0pdTmCITbLENM8FG+aEWRQ X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:23 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 12/16] selftests/mm: add memory-pressure threads to the khugepaged race harness Date: Sun, 2 Aug 2026 20:52:44 +0100 Message-ID: <20260802195254.1937477-13-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> 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="utf-8" Content-Transfer-Encoding: quoted-printable From: "Kiryl Shutsemau (Meta)" The race harness exercises collapse against faults, pins, fork, mremap and MADV_DONTNEED, but nothing in it ever elevates a source folio's refcount from the reclaim or compaction side: LRU isolation, migration of a source folio out from under the collapse, or swap traffic churning the LRU while a collapse is in progress. Add -p, which starts two more racing threads: - pageout: cycles MADV_PAGEOUT over a dedicated neighbor region (4 PMD areas, clamped to [16M, 64M]), faulting everything back in and verifying content each round -- swap traffic and LRU churn with an exact correctness check, since a page's pattern must survive the round trip through swap. Disabled with a note when the host has no swap: without it there is no anon reclaim to drive. - compactor: writes to /proc/sys/vm/compact_memory in a loop. Compaction isolates and migrates folios, so it competes with a collapse for the very pages it is trying to gather, with transient refcount elevations and migration entries of its own. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged_race.c | 109 ++++++++++++++++++- tools/testing/selftests/mm/run_vmtests.sh | 2 + 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/mm/khugepaged_race.c b/tools/testing/s= elftests/mm/khugepaged_race.c index 2e36e242caa7..304c72b4ee3c 100644 --- a/tools/testing/selftests/mm/khugepaged_race.c +++ b/tools/testing/selftests/mm/khugepaged_race.c @@ -22,6 +22,12 @@ * clear, zero-filled copy, install-time pte_none() verify and abort) * race the faulters directly. * + * -p adds memory pressure to any of the above: MADV_PAGEOUT cycling + * on a dedicated neighbor region (swap traffic and LRU churn; skipped + * with a note when the host has no swap) and a compact_memory trigger + * loop (compaction migrates source folios, racing collapse's freeze + * with refcount elevation and migration entries of its own). + * * Correctness signals: every racing page must read as its pattern or * zero (MADV_DONTNEED), never anything else =E2=80=94 checked continuousl= y by * the faulters and the fork children and once at the end =E2=80=94 plus @@ -64,6 +70,8 @@ static unsigned long page_size; static char *region; /* NR_AREAS * hpage_pmd_size */ static char *mremap_area; /* region + NR_SHARED_AREAS areas */ static char *mremap_scratch; /* well above the region */ +static char *pageout_area; /* -p: dedicated pressure region */ +static size_t pageout_size; static int gup_fd =3D -1; static volatile int stop; static volatile int corrupted; @@ -189,6 +197,70 @@ static void *mremapper_fn(void *arg) return NULL; } =20 +/* + * -p: swap traffic and LRU churn on a region of our own. The content + * check is exact =E2=80=94 a page out and back through swap must preserve= the + * pattern, and nothing else ever writes here. + */ +static void *pageout_fn(void *arg) +{ + unsigned int seed =3D (unsigned long)arg; + unsigned long nr =3D pageout_size / page_size; + unsigned long i; + + for (i =3D 0; i < nr; i++) + *(unsigned int *)(pageout_area + i * page_size) =3D pattern(i); + + while (!stop) { + madvise(pageout_area, pageout_size, MADV_PAGEOUT); + for (i =3D 0; i < nr && !stop; i++) { + unsigned int val =3D *(unsigned int *)(pageout_area + + i * page_size); + + if (val !=3D pattern(i)) { + corrupted =3D 1; + ksft_print_msg("Pageout corruption at page %lu: %#x !=3D %#x\n", + i, val, pattern(i)); + } + } + usleep(rand_r(&seed) % 2000); + } + return NULL; +} + +/* -p: compaction migrates the collapse sources out from under us. */ +static void *compactor_fn(void *arg) +{ + unsigned int seed =3D (unsigned long)arg; + int fd =3D open("/proc/sys/vm/compact_memory", O_WRONLY); + + if (fd < 0) { + ksft_print_msg("No compact_memory; compactor idle\n"); + return NULL; + } + while (!stop) { + if (write(fd, "1", 1) < 0) + break; + usleep(10000 + rand_r(&seed) % 100000); + } + close(fd); + return NULL; +} + +static bool swap_available(void) +{ + char line[256]; + int lines =3D 0; + FILE *fp =3D fopen("/proc/swaps", "r"); + + if (!fp) + return false; + while (fgets(line, sizeof(line), fp)) + lines++; + fclose(fp); + return lines > 1; +} + static unsigned long now_ms(void) { struct timeval tv; @@ -200,8 +272,9 @@ static unsigned long now_ms(void) static void usage(void) { fprintf(stderr, - "Usage: khugepaged_race [-d seconds] [-m stepped|free|madvise] [-z] [-a = areas]\n" + "Usage: khugepaged_race [-d seconds] [-m stepped|free|madvise] [-z] [-p]= [-a areas]\n" "\t-z: permissive max_ptes_none (hole-heavy windows)\n" + "\t-p: memory pressure (pageout + compaction) threads\n" "\t-a: number of shared PMD-sized playground areas (default 3)\n"); exit(1); } @@ -210,12 +283,13 @@ int main(int argc, char **argv) { static const char * const thread_names[] =3D { "faulter", "faulter2", "dontneed", "pinner", "forker", - "mremapper", + "mremapper", "pageout", "compactor", }; void *(*const thread_fns[])(void *) =3D { faulter_fn, faulter_fn, dontneed_fn, pinner_fn, forker_fn, - mremapper_fn, + mremapper_fn, pageout_fn, compactor_fn, }; + const unsigned long pageout_bit =3D 1UL << 6, compactor_bit =3D 1UL << 7; const int nr_threads =3D ARRAY_SIZE(thread_names); pthread_t threads[ARRAY_SIZE(thread_names)]; const char *mode =3D "stepped"; @@ -225,11 +299,12 @@ int main(int argc, char **argv) unsigned long thread_mask =3D ~0UL; int nr_areas_arg =3D 0; bool permissive_none =3D false; + bool pressure =3D false; unsigned long i; int steps =3D 0; int opt; =20 - while ((opt =3D getopt(argc, argv, "a:d:m:t:zh")) !=3D -1) { + while ((opt =3D getopt(argc, argv, "a:d:m:t:zph")) !=3D -1) { switch (opt) { case 'a': nr_areas_arg =3D atoi(optarg); @@ -247,6 +322,9 @@ int main(int argc, char **argv) case 'z': permissive_none =3D true; break; + case 'p': + pressure =3D true; + break; default: usage(); } @@ -271,6 +349,14 @@ int main(int argc, char **argv) nr_shared_areas =3D nr_areas_arg > 0 ? nr_areas_arg : DEFAULT_SHARED_AREA= S; nr_areas =3D nr_shared_areas + 1; =20 + if (!pressure) { + thread_mask &=3D ~(pageout_bit | compactor_bit); + } else if (!swap_available()) { + /* No swap, no anon reclaim: compaction-only pressure. */ + ksft_print_msg("-p without swap: pageout thread disabled\n"); + thread_mask &=3D ~pageout_bit; + } + ksft_set_plan(1); =20 thp_save_settings(); @@ -311,6 +397,21 @@ int main(int argc, char **argv) mremap_area =3D region + nr_shared_areas * hpage_pmd_size; mremap_scratch =3D (char *)BASE_ADDR + 2 * nr_areas * hpage_pmd_size; =20 + if (thread_mask & pageout_bit) { + /* + * Big enough to cycle real reclaim, small enough not to + * dominate a TCG guest: 4 PMD areas, clamped to [16M, 64M]. + */ + pageout_size =3D 4 * hpage_pmd_size; + pageout_size =3D pageout_size < (16UL << 20) ? (16UL << 20) : + pageout_size > (64UL << 20) ? (64UL << 20) : + pageout_size; + pageout_area =3D mmap(NULL, pageout_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (pageout_area =3D=3D MAP_FAILED) + ksft_exit_fail_perror("mmap() pageout area"); + } + /* Populate so the first pass has something to collapse. */ for (i =3D 0; i < nr_shared_areas * hpage_pmd_size / page_size; i++) *(unsigned int *)(region + i * page_size) =3D pattern(i); diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/self= tests/mm/run_vmtests.sh index 83a04b1e2520..f826cf940c3d 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -415,6 +415,8 @@ CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m mad= vise =20 CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m stepped -z =20 +CATEGORY=3D"thp" run_test ./khugepaged_race -d 5 -m stepped -p + CATEGORY=3D"thp" run_test ./khugepaged =20 CATEGORY=3D"thp" run_test ./khugepaged -s 2 --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (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 3399D341068; Sun, 2 Aug 2026 19:53:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700409; cv=none; b=FtE9GCd71ySOJyakdy8mtjtvqvB31XyxsKNoJ5hR6Iar9PlTdz5KhwDky1VvsXHhwXf3Q7MHyW89zFZl6XQSdFatQQRKQ7QrTJ/Ezguiw0GRKVIR15UcGZhPmOOHCKhb8dgwa+nTAjUWIIphNuXSWfSXd0+9X2/vZfTUVkHNynM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700409; c=relaxed/simple; bh=OatVueuV+ZJUrbO11bCLUn/PhhtbZzHu8sg0gT4N1OA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Di7i8cp7cCZ8fFv4qpFVgN2r5j6iIR33DXXLRApyAEczd+0PoPKLCp1MtcjdkGCdjVJitpTjTVsqXbpZQDB2Zzinbnq9R72tSPhK08r3cDMhHiT6brvmUjmJq3LLt4kfER0thY/h656jY9O9pkDS3V8uCE0xGkevvDi0PuPliVw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=sxFVV3Ci; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=NSpTRmU+; arc=none smtp.client-ip=103.168.172.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="sxFVV3Ci"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="NSpTRmU+" Received: from phl-compute-12.internal (phl-compute-12.internal [10.202.2.52]) by mailfout.phl.internal (Postfix) with ESMTP id 4833EEC001F; Sun, 2 Aug 2026 15:53:26 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-12.internal (MEProxy); Sun, 02 Aug 2026 15:53:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1785700406; x= 1785786806; bh=RZMR9To8koVR0ozlGuqUF74GOHYuMZBcuhN135RFhM8=; b=s xFVV3Civr8W4Sm6v+k3T1ur/Fehmz1wu5+YEs+OpJ/CjQP6xVH3rakZYf9WeAo4T mpaXBGKHwickFAr1eQELYW1hije+5eRjlQhRhGDJfhuiyPqLLyQXCjZe/G7tOO0p gBiU96CIqHs1ReDrG53/8Vo+zj3t0qXFqhJviGYQaFmuMatMBRjntEufRxQCzBWG My0pDO9bCBrDxFYkP97sSu8F/4yVmcwE096XsDsMgBleOVHKR8pfGhJsdHeg0wQa b8JwzOSkP/c3n+Efd5txCrXHzN3xWWbH0kJ9Ks+iS2xSZPt1KV/4a//ZN+j+hk1p PJVJVLEAGm+586YH6E7Qw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1785700406; x=1785786806; bh=R ZMR9To8koVR0ozlGuqUF74GOHYuMZBcuhN135RFhM8=; b=NSpTRmU+uLh3MB/6E 507fh5YAKwvX1CTAqfZF7pk1rlEcSCvw+uJeAooRjkT4ZO2qZlNZhg6/cYblmQVY 4HMMAEVj6apavFviqf1y85SjYu6sS3E2hijwzob2Sf9emcclpR0UacENRGiwh10M UudXIVgEwBGmR8T64b74LUc17PJETnbDjvaM8vZxzuJvptZDOmtlLQ1liH41y0rO PXRQfJEY9W4wWmPFhaSamIi6oMbfEREYB7jq35p9SHYGC4fh4R7Q7sNVav7SQ4ig eYDyfh+2VW3w79FFFipn/Mo8guczxv9i5B6IE94OP/1x4AQIr7A+tnR76DGh95n7 8fUFA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFcbv35QwNbwWPHQBcJdrWasH4YRFOBaNWig98oa0GgLD3LmQrthvyDgK5JnDhp96 dBkNywOXlTP9Hby+cm0vRQHofuB4BhsdtVcBrMer/A2AOpegfr9Hr7RYzI6OqquxWhxeXC aB5bOw4cR5G6EDzO4v2r94SJnXRDYvi2NMwyCB/quID+suEuw0TjLUMYjjQ5pFm1F3OqpQ Ctej7rOharBpUeBz9hjZojzUlseCYYYMV+BulSa6+jD3O5m4ZOeULsSyQlLb9bciCyrhiP bT+z0cGYr8PFizBGTpPnPZCe+jZkx/DQlEsoaoSV2SjHlZpE6q2+n/t1AcZaLqu1qPGmpu ip4XUMH5XVLjzf0IyhU7nep9P+nlGRQBRreBEgwvXRs67QkZeK9Gmz2zBZg2RKa00u3uu6 7gC+UVdjdeDtkGj/sLdBd8qs7uz4dTfnFPvj0zAUyAP+4VcH0urtzCzw0jnvCmOiKBLy/g edZwSCB6w7MNUYSIQ5swxIIWQlFKG4xU0V9NepiEx72r9KQHpctpYaXVpJB6jHPOSTM82e oKhkRKZBvWXX9WwcxxS/+dKTUnFPDX9Ea6K5zIbNOLFFpVlXMrdNegc7GaNlEk2RFEBhnq ogxJ1urSAV0BPpw5IKope93csKKmM4b05PqDvET00/uOjtX+g50OCOI+SZLw X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:25 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 13/16] selftests/mm: parameterize the mixed-source collapse case by source order Date: Sun, 2 Aug 2026 20:52:45 +0100 Message-ID: <20260802195254.1937477-14-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Kiryl Shutsemau (Meta)" collapse_order_mixed_sources faults its region as order-2 folios and collapses them to the -o target, covering collapse of sources that are already large folios of an order below the target. But it only ever tests one source order, and order 2 sits below the contpte threshold on both arm64 page-size configs -- so a source-side contpte unfold is never exercised deterministically by this suite. Let -s name the source order when combined with -o (it was rejected before): the mixed-source case then faults at order @anon_order instead of the fixed order 2, keeping order 2 as the default when -s is absent. -s stays constrained to a supported mTHP order strictly below the target; the other order-parameterized cases keep their order-0 sources (the source order is enabled locally, not globally), so -s under -o is a knob on the mixed-source case alone. This makes e.g. -s 5 -o 7 on arm64/64K collapse contpte-mapped sources into a larger mTHP, covering the source-unfold path directly. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged.c | 42 +++++++++++++++++++------ 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index b074b005b62f..21a8fb24dc43 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -1363,28 +1363,32 @@ static void collapse_order_mixed_sources(struct col= lapse_context *c, struct mem_ops *ops) { struct thp_settings settings =3D *thp_current_settings(); + int source_order =3D anon_order ? anon_order : MIN_MTHP_ORDER; void *p; =20 - if (anon_target_order <=3D MIN_MTHP_ORDER) { + /* Sources must be a supported mTHP order strictly below the target. */ + if (source_order >=3D anon_target_order || + !(thp_supported_orders() & (1UL << source_order))) { ksft_test_result_skip("%s: no source order below target\n", __func__); return; } =20 - /* Fault the whole region as order-MIN_MTHP_ORDER folios. */ - settings.hugepages[MIN_MTHP_ORDER].enabled =3D THP_ALWAYS; + /* Fault the whole region as order-@source_order folios. */ + settings.hugepages[source_order].enabled =3D THP_ALWAYS; thp_push_settings(&settings); p =3D ops->setup_area(1); ops->fault(p, 0, hpage_pmd_size); thp_pop_settings(); =20 - if (!is_range_backed_by_folio_orders(p, hpage_pmd_size, MIN_MTHP_ORDER, + if (!is_range_backed_by_folio_orders(p, hpage_pmd_size, source_order, pagemap_fd, kpageflags_fd)) ksft_exit_fail_msg("Region not backed by order-%d folios after fault\n", - MIN_MTHP_ORDER); + source_order); =20 madvise(p, hpage_pmd_size, MADV_HUGEPAGE); - ksft_print_msg("Collapse region backed by smaller large folios..."); + ksft_print_msg("Collapse region backed by order-%d sources...", + source_order); if (!khugepaged_wait_full_pass()) fail("Timeout"); else if (range_collapsed(p, hpage_pmd_size)) @@ -1414,7 +1418,9 @@ static void usage(void) fprintf(stderr, "\t\t Defaults to 0. Use this size for anon or shmem a= llocations.\n"); fprintf(stderr, "\t\t-o: collapse target order for khugepaged:anon.\n"); fprintf(stderr, "\t\t Runs the order-parameterized collapse cases inst= ead\n"); - fprintf(stderr, "\t\t of the PMD cases. Cannot be combined with -s.\n"= ); + fprintf(stderr, "\t\t of the PMD cases.\n"); + fprintf(stderr, "\t\t With -s, -s names the mTHP source order for the\= n"); + fprintf(stderr, "\t\t mixed-source case (source order below the target= ).\n"); exit(1); } =20 @@ -1438,7 +1444,15 @@ static void parse_test_type(int argc, char **argv) } } =20 - if (anon_target_order && anon_order) + /* + * -s and -o compose: -s then names the mTHP source order for the + * mixed-source case, which needs a source strictly below the + * target (and at or above the smallest mTHP order). Alone, -s is + * the source order for the default PMD suite; alone, -o is the + * collapse target for the order-parameterized suite. + */ + if (anon_target_order && anon_order && + (anon_order < MIN_MTHP_ORDER || anon_order >=3D anon_target_order)) usage(); =20 argv +=3D optind; @@ -1573,9 +1587,17 @@ int main(int argc, char **argv) default_settings.khugepaged.max_ptes_shared =3D hpage_pmd_nr / 2; default_settings.khugepaged.pages_to_scan =3D hpage_pmd_nr * 8; default_settings.hugepages[hpage_pmd_order].enabled =3D THP_INHERIT; - default_settings.hugepages[anon_order].enabled =3D THP_ALWAYS; default_settings.shmem_hugepages[hpage_pmd_order].enabled =3D SHMEM_INHER= IT; - default_settings.shmem_hugepages[anon_order].enabled =3D SHMEM_ALWAYS; + /* + * Under -o the order-parameterized cases want order-0 sources by + * default; the mixed-source case enables its own (possibly -s + * selected) source order locally. Enabling it globally here would + * make every case fault that order. + */ + if (!anon_target_order) { + default_settings.hugepages[anon_order].enabled =3D THP_ALWAYS; + default_settings.shmem_hugepages[anon_order].enabled =3D SHMEM_ALWAYS; + } =20 if (anon_target_order) { /* --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fhigh-a6-smtp.messagingengine.com (fhigh-a6-smtp.messagingengine.com [103.168.172.157]) (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 CD05434DB74; Sun, 2 Aug 2026 19:53:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.157 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700410; cv=none; b=jSas9dcEGpSbCJWX5bGJbU6NgaEyj3d7a6+k4r8Q81r0laupGltQUNrNgVllyCVE5C944/1B232yB8UdEaFkp51/gDsCq6/+RE+7a8GzRQS/ZHQ0RSyj/xY/05GA7u0CeaUJ5z2FU3dz4aYDdQMaSCPqtzHKvxbpVabWU/TPIPY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700410; c=relaxed/simple; bh=TdqOYszDCN/y4qNxCAGzohdTUPV2FSK1kiUwmYTHmsg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EdtB2W4377ai5Rl1wMCOtiwsnRsQRgYovGFDfanP/BXgbDFFXFl/0+Zwwx32hSxnHK3AMcIQTvR7RH51dKV6h205xZvNEtiL6Uj3roDHJWZNJcOk2JLBUn/feC139pVHsX7o3wsE4FzCWcZ5HQCP38A4DLyOG94sVPGSbHG5k+c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=Pwt1XfR9; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=IIyIrBG7; arc=none smtp.client-ip=103.168.172.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="Pwt1XfR9"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="IIyIrBG7" Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfhigh.phl.internal (Postfix) with ESMTP id DEB671400051; Sun, 2 Aug 2026 15:53:27 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-05.internal (MEProxy); Sun, 02 Aug 2026 15:53:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1785700407; x=1785786807; bh=a2Jw/mn+UfsKcDTO+dGnQEf7SQYHheMb TSYp9dOdyHA=; b=Pwt1XfR927N4rs7e9ppzMF0mFPF2QC616AAkWDcjo0sXt7if eKQZhjKtcPkPgiG69y9DcADkO3G9/XQR9R0VP8+asAV7NASoH0mtJAGWcYfP/R7n beOQc+1Uy0063uWVRWqSTgCitYzQoY691uQoLlFHvzDqdJebW2aJ2ei7Rhi4N17u dUTEEZrdOZWz0yPW/zO5UbSTvYVcupLCZwbOzq89jz0j9K/YkuNRbBznkqOQMCX+ a5X3pZFlalVUcbRyvQyyZlELIgg/3K/iKVqqlPQExqItOY+z9Quyp4xKXcCGZpF5 1WTQPY55OflfiMKGeBbxo2SPj9tak+qmqmBGng== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1785700407; x= 1785786807; bh=a2Jw/mn+UfsKcDTO+dGnQEf7SQYHheMbTSYp9dOdyHA=; b=I IyIrBG7CPap1NwdJClTpvaxTmQKXxZxFUysfUkBFxrKXhz4QmgmhuW+Puo7b9rO9 tFfZPSK9DNXc01kkdI6h9ls1YkcxSj4tAc03YPqci8BQ5egrHIz4xXh7+2cJcREj wrrnL3ztiRGSHasUvo3gU1qVykspwb41YIICfxEmTsiXhGpvqIQzQeujIHc6MbC2 Ya2HFFs/TO8omJqOLZCZK7+FS+5SFL/oGQAE/5ZbMLjaP6CinPl18Sb5aCGZpT3K Ke4Si89gt3rsvUTV0l7Ci63mKZ9CmIxfjSi37r3EVVPxYIlnTyWsMtCl4bFbj/f0 EJ2Q5u48bSdHI680JjfXg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTF0jcSSKFGDg2KrIu5c43P4SsiipwcvDQBe+CHxos2n8PFgvSXAdv5YVW583HVAOz W5evq6qe09LpHqloXNM1K7VWF721j2bpam5IryqVMcYz9qouNwbpBEKv3Y5gifbeJAqW/Q YZQrbB51yLEk86mWZaGZ1Drq0Xy949i11wvFP7mkSWE3f4+XiyFqs+bTi+V6AVpUjNMMFr yeY2fCKzWlrX4GavSe/JRyGqxABGArlOuRBA0IP4mMA1yNK8fSDYGTdjzDrtr8AjwNqVIi 3BcHDiClTVSc/WD5f6J8XCsMYF+6dE+0Mr4gWnl6eMmh6FUU5GqCPEjsceh07AxGuRDdh+ EfRV12s7ikyQpMRWBYerSeFU2WBXxwmZE2LSsp5hy0hwP/rtpbErwtxuMvwEAS95+EE44V wr/cr8b/Uj/n7txdJMzlDjK2GRMySkFpK+xQTR6kTq9FyioT1d0lGAzRCmwklzvYIFPHue b/sz8gYxpIjRubmuFCDvAt3N5F676Rjh6sI5Q1NCHcULkgi970rianfQBc4MP7/ZcNd0as ZiYLbRwIgFAwoUdb+2NjIHD1mIkQXuYKVl7Hr0jZj6jOVzy/N1jN24aUOJuJjOLsxIVqMq Oz4v4aokkX+9Og1Ez1qdRHcAVRF97BiFz3KosqyvJRDcMOSxgWigX64K07sA X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:27 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 14/16] selftests/mm: zap whole PTE tables in the khugepaged race harness Date: Sun, 2 Aug 2026 20:52:46 +0100 Message-ID: <20260802195254.1937477-15-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> 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="utf-8" Content-Transfer-Encoding: quoted-printable From: "Kiryl Shutsemau (Meta)" The race harness's MADV_DONTNEED thread zaps 1..32 pages at a time =E2=80= =94 never a whole PMD-aligned area, so the empty-table reclaim (CONFIG_PT_RECLAIM), which only engages when a zap spans the full table, never ran against a collapse in any soak. Fuzzing had to find the resulting class instead: the table vanishing between the engine's park and install passes. Make the thread zap a whole PMD-aligned area once every 64 iterations, keeping the fine-grained zaps as the common case. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged_race.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/mm/khugepaged_race.c b/tools/testing/s= elftests/mm/khugepaged_race.c index 304c72b4ee3c..2aa45c9e8a77 100644 --- a/tools/testing/selftests/mm/khugepaged_race.c +++ b/tools/testing/selftests/mm/khugepaged_race.c @@ -124,8 +124,23 @@ static void *dontneed_fn(void *arg) unsigned long page_idx =3D rand_page(&seed); unsigned long nr =3D 1UL << (rand_r(&seed) % 6); /* 1..32 pages */ =20 - madvise(region + page_idx * page_size, nr * page_size, - MADV_DONTNEED); + /* + * Once in a while zap a whole PMD-aligned area: only a + * zap spanning the full table triggers the empty-table + * reclaim (CONFIG_PT_RECLAIM), which can free a table + * out from under a parked collapse =E2=80=94 sub-table zaps + * never reach that path. + */ + if (!(rand_r(&seed) % 64)) { + unsigned long area =3D page_idx / + (hpage_pmd_size / page_size); + + madvise(region + area * hpage_pmd_size, + hpage_pmd_size, MADV_DONTNEED); + } else { + madvise(region + page_idx * page_size, + nr * page_size, MADV_DONTNEED); + } usleep(rand_r(&seed) % 500); } return NULL; --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (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 6389B350A05; Sun, 2 Aug 2026 19:53:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700411; cv=none; b=UHUmWTNhvhPk0MtMnX+LgTi+wOHBmqobLb5vql0PZcGqmg7KM8bv3cK2IOE/B3JcK1oU8ba0fHMPOatEehtag/PSma9RVoU4p9AiPfIUooaLAcaLlT6buSKa3D2o5q5S4ghqOENkenLYoXJTLJNT3KDqv64xAo12tyLzc0IeFdg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700411; c=relaxed/simple; bh=yVAibKXUJAe4Ssb1Y/vqUcEG83HlhIVvVZNLrC9b9R4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JFTilBEYlul8hnjLBWTqkV4r6F2CZqmmkG4IpQE6C85wJjqzcBmywzGUcYnRbWS55Zc4eo8TKoqTsSpN6QIr4tD06pGtEtS198Mc13zx00FEgR2WtbScu2PcT9Ek2iAOKO0TjrOsoIgwbFZU2ubMs2QnLMggRYlnRI2qj3q5mEM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=stznTiNQ; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=FoLVHw5n; arc=none smtp.client-ip=103.168.172.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="stznTiNQ"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="FoLVHw5n" Received: from phl-compute-01.internal (phl-compute-01.internal [10.202.2.41]) by mailfout.phl.internal (Postfix) with ESMTP id B1220EC003D; Sun, 2 Aug 2026 15:53:29 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-01.internal (MEProxy); Sun, 02 Aug 2026 15:53:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1785700409; x= 1785786809; bh=7FZW+EYif6AgDaxVaWyDapT5OvK8OdUCwgMiwqQSV3U=; b=s tznTiNQmqF5b2CZryy0KpGRsiV6OViYY7o2g+BDGldsxmmE3On+itwE4ig1lX7j7 nQ8oNIvIRWhEls4xFBRnQ18I6s2Ov4YvwoqLRuS6q/tLkGcD6Gnyda5UtY77dHuK fvf7QIF8DFKFroWfbD7iZj7KZtAIqA8Iplv68qAP9WxzzAzGY/G6p8i+5rc7ENcg /fKraQHor5yns8BLROut5dlPG927qSWXcN1l0n1AmjtZcnMtMeGp8kNpZScQkFne VyCAEnBwHPClEs0x7MWgp7k9vUq0TK5ZnLuntmcvf0lUN7RTouUvQaMVLUHcZVDV jLrKdWxquKnCtW3WYXSxw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1785700409; x=1785786809; bh=7 FZW+EYif6AgDaxVaWyDapT5OvK8OdUCwgMiwqQSV3U=; b=FoLVHw5nxx/F5py0v Qv+Z9yvEyjLh5uS3jW3LdLWXa30gKKbt/hdQDMutG7HrtIq8nNxzrN1B0YcEh/5R 9UII/tnCBHRmkz/26Sc59oQl/zCOt4TyV0whjBkVJhu0IG4+PAl8zbzI+sM2wv2k +4z5Pxb1/3rjpIuvC1issdjLxznGlugOsqiGxc7jESe31jBvWQ2HtaQxQ+HL8edF jhC/0e1ZqmuATBUUVcvUfaYSeAQI8+PT+0Fj0OgOXMFbh4SrqyiE0OTBRDbzLelf vF0ovbSJPC7Ww1005CQcY8IKxFPkPYCkwIgGZfchYhEAwG3lOX9wm9oGk3E1Hj+p ssQIA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFcbv35QwNbwWPHQBcJdrWasH4YRFOBaNWig98oa0GgLD3LmQrthvyDgK5JnDhp96 dBkNywOXlTP9Hby+cm0vRQHofuB4BhsdtVcBrMer/A2AOpegfr9Hr7RYzI6OqquxWhxeXC aB5bOw4cR5G6EDzO4v2r94SJnXRDYvi2NMwyCB/quID+suEuw0TjLUMYjjQ5pFm1F3OqpQ Ctej7rOharBpUeBz9hjZojzUlseCYYYMV+BulSa6+jD3O5m4ZOeULsSyQlLb9bciCyrhiP bT+z0cGYr8PFizBGTpPnPZCe+jZkx/DQlEsoaoSV2SjHlZpE6q2+n/t1AcZaLqu1qPGmNN z90saZGKqwnA0OHicr5CRo1m0XGloodzuJN6K3LrYMdUc32o5HezHN5D6o7GxvEMVTCrqo Jg90XFZhCqxBOFcbyFx5zBccvUWjXs5XaDA8rcb4iouA/s3MarmqACnbgM0PLpelAVMi+k Hb7R+HOIQZfzGBH8GXPcKatXrPoj0/+8lcDKqGgqfAtsuODUcwMISJY2sznO+z4F83XX4V 1zQ1kwEbWNbWIGFIs3sqYovc74Vqk85aYRlhMPALItw6p9oAb8/rNKP7CUhnrWRwko+1LA S1ErpvDI1RaQzESTmJ9TKO5XZAP5eeplJlBuAO8tJO3oOWoilwQuzOJdVKjQ X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:28 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 15/16] selftests/mm: scale khugepaged's collapse wait with the PMD size Date: Sun, 2 Aug 2026 20:52:47 +0100 Message-ID: <20260802195254.1937477-16-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Kiryl Shutsemau (Meta)" wait_for_scan() gives khugepaged a fixed three seconds, whatever a huge page costs to build. collapse_full() asks for four of them, which is 8M at a 2M PMD and 2G at a 512M PMD -- arm64 with 64K base pages -- and three seconds does not cover copying 2G. The escape hatch does not help either: it wants two full khugepaged passes inside the same three seconds, and one pass over a 512M PMD takes about that long by itself. So collapse_full fails there on a collapse that works. Measured with a probe that faults 4 x 512M, marks it MADV_HUGEPAGE and polls: all four PMDs collapse, with collapse_alloc=3D4 at the PMD size and no allocation failures. Raising only this budget makes the test pass, and it does not turn into a "Fail" -- which is what khugepaged completing two passes without collapsing would produce. Scale the budget with the memory to be collapsed: keep three seconds as the floor and add a second per 64M. That leaves a 2M PMD at exactly the three seconds it has now, and gives 35s at a 512M PMD, where the collapse measures under 3s. Keying it on nr_hpages * hpage_pmd_size rather than the PMD size alone matters because the callers ask for one or four; scaling linearly on PMD size alone would ask for 768s, which is not a budget so much as a hang. This also brings the helper in line with khugepaged_full_pass(), which already allows 30s and is why the order-parameterized cases pass at a 512M PMD while this one did not. arm64/64K: khugepaged all:anon 21 pass/1 fail -> 22 pass/0 fail. x86-64 unchanged, 129 ok. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index 21a8fb24dc43..9213ce1658d0 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -573,8 +573,17 @@ static void madvise_collapse(const char *msg, char *p,= int nr_hpages, static bool wait_for_scan(const char *msg, char *p, int nr_hpages, struct mem_ops *ops) { + /* + * The budget has to cover khugepaged copying nr_hpages * + * hpage_pmd_size, plus two of its passes over the mm. Three seconds + * does that at a 2M PMD, but the same test moves 2G at a 512M PMD + * (arm64 with 64K base pages) and 3s is then marginal: it fails on a + * collapse that completes correctly, just not inside the budget. + * Allow a further second per 64M to collapse. + */ + const unsigned long bytes =3D (unsigned long)nr_hpages * hpage_pmd_size; + int timeout =3D 6 + 2 * (bytes / (64UL << 20)); int full_scans; - int timeout =3D 6; /* 3 seconds */ =20 /* Sanity check */ if (!ops->check_huge(p, 0)) --=20 2.54.0 From nobody Fri Oct 2 10:08:52 2026 Received: from fout-a6-smtp.messagingengine.com (fout-a6-smtp.messagingengine.com [103.168.172.149]) (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 0DAAB34BA5A; Sun, 2 Aug 2026 19:53:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700413; cv=none; b=tumfEwOxjve4S2BUfNMgbWyW7Jua6UN/IdMJpuL4du4vq1hv6NHw42k3YaN1Ib6HNtk7MDz32e8pf7/7rM18DtvHksCc9i4y5oczha6NNVbd5h2RRDrbvVGc7Ax0neJ8U9Im87VMgKV23bHr2tawcP0pUROCOTFO/I/6AaGiG6c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700413; c=relaxed/simple; bh=Z78GI0z//ddridqQ0Fw2lwHzt8ABTBUgMh3xKppDT00=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eDUg0lGq3FTb15JpjDd1a/kQ0gc4w7RVsbolZMPYFfIvVC7iUmIMO1/vzijx/3tDmh4ub5nVMuJkkmB82iUqklixUasPGNngbkk8Ycg2UdAlb41V9XtyR6GYtUssiF74kWuPc72Vmx8cE+07IMby7QrOpNBXT4EYfBeXw4TlGEo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name; spf=pass smtp.mailfrom=shutemov.name; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b=UaP/pzs6; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=MKLkO1jE; arc=none smtp.client-ip=103.168.172.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=shutemov.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=shutemov.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=shutemov.name header.i=@shutemov.name header.b="UaP/pzs6"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="MKLkO1jE" Received: from phl-compute-01.internal (phl-compute-01.internal [10.202.2.41]) by mailfout.phl.internal (Postfix) with ESMTP id 5CD99EC004C; Sun, 2 Aug 2026 15:53:31 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-01.internal (MEProxy); Sun, 02 Aug 2026 15:53:31 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shutemov.name; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1785700411; x= 1785786811; bh=6K0rFA/42GWVg7pW/IyikAsYoBS9+Tp+qGJZ8yXnCxI=; b=U aP/pzs6zz0h0LRGxpIBr0UfOSA3k4RPcZ+eWdASVlXPduLOEja+rMbkgH+a+Lol5 h4p8XVS5DX81DzyulmjCS/yF/gnumDchdKasWwuT47Y180r62cnpA98HuavD4Zdo Vz5xJ++O66i4VW1XVPuwSK005NT4r72SbndJLZc/2HzWAhuZGlqmMzTBmpv940le GdEjVMTURcktf3paxYxdasDsft4oKb+rLuK/XpT4USitZozQTN+0UlaW76BTN94A H7HtRTwj5GylftKchYfi2tAPRPLkTlBwEjybmZWoPIITGd8/oyi4RmHOp6b8Uzor aYQMeC6zSETuDd4EliC6w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1785700411; x=1785786811; bh=6 K0rFA/42GWVg7pW/IyikAsYoBS9+Tp+qGJZ8yXnCxI=; b=MKLkO1jE/0Otbu/yq AHbx0+VXJ72xtZx1soDo9qTL7rAx5XMYwp4I3hN2qLVrYIWbV402IcJDodXO6qjL Lnlgl5RZ2BmhpnxwxK09hgUgvs5ew6Py2MN5Uk/KdcezdV46auopTVBZx3fmDhEI RUAcrAQvBZyBQjjiWEseXsgvYXFlgRvzwTUC9CgPba8+x8J6kyQY2z11wp0Gwyct MHbCDWS51F/+HYDwuY/160mejO67GvXUTS/NNKZwq4m543vc7zgwpA5RGiYKzFlh qyXRYF7gvxhp7ERmU9eD5Arp9whY6VHjCuQgMmBHqiNKcbKmhTqf/4iOn1gLzr3n 8weIA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTFcbv35QwNbwWPHQBcJdrWasH4YRFOBaNWig98oa0GgLD3LmQrthvyDgK5JnDhp96 dBkNywOXlTP9Hby+cm0vRQHofuB4BhsdtVcBrMer/A2AOpegfr9Hr7RYzI6OqquxWhxeXC aB5bOw4cR5G6EDzO4v2r94SJnXRDYvi2NMwyCB/quID+suEuw0TjLUMYjjQ5pFm1F3OqpQ Ctej7rOharBpUeBz9hjZojzUlseCYYYMV+BulSa6+jD3O5m4ZOeULsSyQlLb9bciCyrhiP bT+z0cGYr8PFizBGTpPnPZCe+jZkx/DQlEsoaoSV2SjHlZpE6q2+n/t1AcZaLqu1qPGmmt J2A/ADzeAiJhREncqeCCozBMQV4vTj29Vg4C2eydWSSmaXBZYHSHzRhPGmFPpD43WFfAwZ VwO3prtQD7GXV9g5gi5N27oooKCPfcRAmxgWJ007AmrvaYUBHwSNdhNmfCQckaH+ClI1OJ LWjqa0LTLqe+LATNodWdp0RjOGRX+pPDo8Ajrtx3OVLFoKpEtGEYN2Q3kkTy8qjEvH/oWT U+TfvKX6dR1zXawrKnT+E6TJGIopcnWbyQhJTF83FDkAsugu5d9o2cDPuxokC61Bj+OJJR xMbu5MMFTRIXi/8Fp03WZ/pdmqUvQ0oEvj4PqNS5Cx5lPbKZ4cMwaR0aJpuw X-ME-Proxy: Feedback-ID: ie3994620:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 2 Aug 2026 15:53:30 -0400 (EDT) From: Kiryl Shutsemau To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , Nico Pache Cc: Baolin Wang , Barry Song , Dev Jain , Hugh Dickins , Lance Yang , "Liam R. Howlett" , Michal Hocko , Mike Rapoport , Ryan Roberts , Shuah Khan , Suren Baghdasaryan , Usama Arif , Vlastimil Babka , Zi Yan , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, "Kiryl Shutsemau (Meta)" Subject: [PATCH 16/16] selftests/mm: skip khugepaged shmem cases without a PMD page cache folio Date: Sun, 2 Aug 2026 20:52:48 +0100 Message-ID: <20260802195254.1937477-17-kirill@shutemov.name> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260802195254.1937477-1-kirill@shutemov.name> References: <20260802195254.1937477-1-kirill@shutemov.name> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Kiryl Shutsemau (Meta)" The page cache caps folio order at MAX_PAGECACHE_ORDER, and xas_split_alloc() puts that cap below the PMD order where a PMD is 512M -- arm64 with 64K base pages, as include/linux/pagemap.h says outright. shmem_huge_global_enabled() then offers no PMD order at all, so MADV_COLLAPSE of a shmem range answers -EINVAL and khugepaged passes over it. The shmem cases nonetheless ask for a PMD-sized shmem folio, so on such a configuration four of them fail and the run bails out in the middle: not ok 2 collapse_full not ok 4 collapse_single_pte_entry # Allocate huge page...Bail out! madvise(MADV_COLLAPSE): Invalid argument (22) That is the kernel declining something it deliberately does not support, not a collapse defect. Skip those cases where the PMD order is not a shmem order, which thp_shmem_supported_orders() already reports -- it reads the same per-size shmem_enabled controls the kernel only publishes for orders the page cache can hold. A tmpfs-backed file argument is skipped on the same grounds, and a run left with nothing to collapse into skips outright. Anonymous collapse is unaffected: its orders are not capped this way, and the anonymous cases pass at a 512M PMD. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) --- tools/testing/selftests/mm/khugepaged.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index 9213ce1658d0..c5a3c3922581 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -1584,6 +1584,27 @@ int main(int argc, char **argv) hpage_pmd_nr =3D hpage_pmd_size / page_size; hpage_pmd_order =3D __builtin_ctz(hpage_pmd_nr); =20 + /* + * The page cache caps folio order at MAX_PAGECACHE_ORDER, which + * xas_split_alloc() puts below the PMD order on arm64 with 64K pages. + * A PMD-sized page cache folio is then impossible, so the kernel + * refuses these collapses by design and there is nothing to test. + */ + if (!(thp_shmem_supported_orders() & (1UL << hpage_pmd_order))) { + if (shmem_ops) { + ksft_print_msg("no PMD-order page cache folio: skipping shmem\n"); + shmem_ops =3D NULL; + } + if (finfo.type =3D=3D VMA_SHMEM && read_only_file_ops) { + ksft_print_msg("no PMD-order page cache folio: skipping tmpfs file\n"); + read_only_file_ops =3D NULL; + read_write_file_read_ops =3D NULL; + read_write_file_write_ops =3D NULL; + } + if (!anon_ops && !shmem_ops && !read_only_file_ops) + ksft_exit_skip("Nothing left to collapse into\n"); + } + if (anon_target_order && !(thp_supported_orders() & (1UL << anon_target_order))) ksft_exit_skip("Order %d is not a supported anon THP order\n", --=20 2.54.0