linux-kselftest.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Better split_huge_page_test result check
@ 2025-08-06  2:20 Zi Yan
  2025-08-06  2:20 ` [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug Zi Yan
                   ` (3 more replies)
  0 siblings, 4 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-06  2:20 UTC (permalink / raw)
  To: David Hildenbrand, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Shuah Khan, linux-kernel, linux-kselftest

David asked me if there is a way of checking split_huge_page_test
results instead of the existing smap check[1]. This patchset uses
kpageflags to get after-split folio orders for a better
split_huge_page_test result check. The added gather_folio_orders() scans
through a VPN range and collects the numbers of folios at different orders.
check_folio_orders() compares the result of gather_folio_orders() to
a given list of numbers of different orders.

split_huge_page_test needs the FORCE_READ fix in [2] to work correctly.

This patchset also:
1. added new order and in folio offset to the split huge page debugfs's
   pr_debug()s;
2. changed split_huge_pages_pid() to skip the rest of a folio if it is
   split by folio_split() (not changing split_folio_to_order() part
   since split_pte_mapped_thp test relies on its behavior).


[1] https://lore.kernel.org/linux-mm/e2f32bdb-e4a4-447c-867c-31405cbba151@redhat.com/
[2] https://lore.kernel.org/linux-mm/20250805175140.241656-1-ziy@nvidia.com/

Zi Yan (4):
  mm/huge_memory: add new_order and offset to split_huge_pages*()
    pr_debug.
  mm/huge_memory: move to next folio after folio_split() succeeds.
  selftests/mm: add check_folio_orders() helper.
  selftests/mm: check after-split folio orders in split_huge_page_test.

 mm/huge_memory.c                              |  22 +--
 .../selftests/mm/split_huge_page_test.c       |  67 ++++++---
 tools/testing/selftests/mm/vm_util.c          | 139 ++++++++++++++++++
 tools/testing/selftests/mm/vm_util.h          |   2 +
 4 files changed, 200 insertions(+), 30 deletions(-)

-- 
2.47.2


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug.
  2025-08-06  2:20 [PATCH 0/4] Better split_huge_page_test result check Zi Yan
@ 2025-08-06  2:20 ` Zi Yan
  2025-08-06 12:42   ` David Hildenbrand
                     ` (2 more replies)
  2025-08-06  2:20 ` [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds Zi Yan
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-06  2:20 UTC (permalink / raw)
  To: David Hildenbrand, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Shuah Khan, linux-kernel, linux-kselftest

They are useful information for debugging split huge page tests.

Signed-off-by: Zi Yan <ziy@nvidia.com>
---
 mm/huge_memory.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 2b4ea5a2ce7d..8a11c2d402d4 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4327,8 +4327,8 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
 		goto out;
 	}
 
-	pr_debug("Split huge pages in pid: %d, vaddr: [0x%lx - 0x%lx]\n",
-		 pid, vaddr_start, vaddr_end);
+	pr_debug("Split huge pages in pid: %d, vaddr: [0x%lx - 0x%lx], new_order: %u, in_folio_offset %ld\n",
+		 pid, vaddr_start, vaddr_end, new_order, in_folio_offset);
 
 	mmap_read_lock(mm);
 	/*
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-06  2:20 [PATCH 0/4] Better split_huge_page_test result check Zi Yan
  2025-08-06  2:20 ` [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug Zi Yan
@ 2025-08-06  2:20 ` Zi Yan
  2025-08-06 12:47   ` David Hildenbrand
                     ` (2 more replies)
  2025-08-06  2:20 ` [PATCH 3/4] selftests/mm: add check_folio_orders() helper Zi Yan
  2025-08-06  2:20 ` [PATCH 4/4] selftests/mm: check after-split folio orders in split_huge_page_test Zi Yan
  3 siblings, 3 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-06  2:20 UTC (permalink / raw)
  To: David Hildenbrand, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Shuah Khan, linux-kernel, linux-kselftest

Current behavior is to move to next PAGE_SIZE and split, but that makes it
hard to check after-split folio orders. This is a preparation patch to
allow more precise split_huge_page_test check in an upcoming commit.

split_folio_to_order() part is not changed, since split_pte_mapped_thp test
relies on its current behavior.

Signed-off-by: Zi Yan <ziy@nvidia.com>
---
 mm/huge_memory.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 8a11c2d402d4..b2ce8ac0c5a9 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4341,6 +4341,7 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
 		struct folio *folio;
 		struct address_space *mapping;
 		unsigned int target_order = new_order;
+		long nr_pages;
 
 		if (!vma)
 			break;
@@ -4358,6 +4359,8 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
 		if (!is_transparent_hugepage(folio))
 			goto next;
 
+		nr_pages = folio_nr_pages(folio);
+
 		if (!folio_test_anon(folio)) {
 			mapping = folio->mapping;
 			target_order = max(new_order,
@@ -4385,15 +4388,16 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
 		if (!folio_test_anon(folio) && folio->mapping != mapping)
 			goto unlock;
 
-		if (in_folio_offset < 0 ||
-		    in_folio_offset >= folio_nr_pages(folio)) {
+		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
 			if (!split_folio_to_order(folio, target_order))
 				split++;
 		} else {
-			struct page *split_at = folio_page(folio,
-							   in_folio_offset);
-			if (!folio_split(folio, target_order, split_at, NULL))
+			struct page *split_at =
+				folio_page(folio, in_folio_offset);
+			if (!folio_split(folio, target_order, split_at, NULL)) {
 				split++;
+				addr += PAGE_SIZE * nr_pages;
+			}
 		}
 
 unlock:
@@ -4438,8 +4442,8 @@ static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,
 	if (IS_ERR(candidate))
 		goto out;
 
-	pr_debug("split file-backed THPs in file: %s, page offset: [0x%lx - 0x%lx]\n",
-		 file_path, off_start, off_end);
+	pr_debug("split file-backed THPs in file: %s, page offset: [0x%lx - 0x%lx], new_order %u in_folio_offset %ld\n",
+		 file_path, off_start, off_end, new_order, in_folio_offset);
 
 	mapping = candidate->f_mapping;
 	min_order = mapping_min_folio_order(mapping);
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 3/4] selftests/mm: add check_folio_orders() helper.
  2025-08-06  2:20 [PATCH 0/4] Better split_huge_page_test result check Zi Yan
  2025-08-06  2:20 ` [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug Zi Yan
  2025-08-06  2:20 ` [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds Zi Yan
@ 2025-08-06  2:20 ` Zi Yan
  2025-08-07  3:00   ` wang lian
  2025-08-07  6:49   ` Baolin Wang
  2025-08-06  2:20 ` [PATCH 4/4] selftests/mm: check after-split folio orders in split_huge_page_test Zi Yan
  3 siblings, 2 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-06  2:20 UTC (permalink / raw)
  To: David Hildenbrand, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Shuah Khan, linux-kernel, linux-kselftest

The helper gathers an folio order statistics of folios within a virtual
address range and checks it against a given order list. It aims to provide
a more precise folio order check instead of just checking the existence of
PMD folios.

Signed-off-by: Zi Yan <ziy@nvidia.com>
---
 tools/testing/selftests/mm/vm_util.c | 139 +++++++++++++++++++++++++++
 tools/testing/selftests/mm/vm_util.h |   2 +
 2 files changed, 141 insertions(+)

diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index 9dafa7669ef9..373621145b2a 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -17,6 +17,12 @@
 #define STATUS_FILE_PATH "/proc/self/status"
 #define MAX_LINE_LENGTH 500
 
+#define PGMAP_PRESENT		(1UL << 63)
+#define KPF_COMPOUND_HEAD	(1UL << 15)
+#define KPF_COMPOUND_TAIL	(1UL << 16)
+#define KPF_THP			(1UL << 22)
+#define PFN_MASK     ((1UL<<55)-1)
+
 unsigned int __page_size;
 unsigned int __page_shift;
 
@@ -338,6 +344,139 @@ int detect_hugetlb_page_sizes(size_t sizes[], int max)
 	return count;
 }
 
+static int get_page_flags(uint64_t vpn, int pagemap_file, int kpageflags_file,
+			  uint64_t *flags)
+{
+	uint64_t pfn;
+	size_t count;
+
+	count = pread(pagemap_file, &pfn, sizeof(pfn),
+		      vpn * sizeof(pfn));
+
+	if (count != sizeof(pfn))
+		return -1;
+
+	/*
+	 * Treat non-present page as a page without any flag, so that
+	 * gather_folio_orders() just record the current folio order.
+	 */
+	if (!(pfn & PGMAP_PRESENT)) {
+		*flags = 0;
+		return 0;
+	}
+
+	count = pread(kpageflags_file, flags, sizeof(*flags),
+		      (pfn & PFN_MASK) * sizeof(*flags));
+
+	if (count != sizeof(*flags))
+		return -1;
+
+	return 0;
+}
+
+static int gather_folio_orders(uint64_t vpn_start, size_t nr_pages,
+			       int pagemap_file, int kpageflags_file,
+			       int orders[], int nr_orders)
+{
+	uint64_t page_flags = 0;
+	int cur_order = -1;
+	uint64_t vpn;
+
+	if (!pagemap_file || !kpageflags_file)
+		return -1;
+	if (nr_orders <= 0)
+		return -1;
+
+	for (vpn = vpn_start; vpn < vpn_start + nr_pages; ) {
+		uint64_t next_folio_vpn;
+		int status;
+
+		if (get_page_flags(vpn, pagemap_file, kpageflags_file, &page_flags))
+			return -1;
+
+		/* all order-0 pages with possible false postive (non folio) */
+		if (!(page_flags & (KPF_COMPOUND_HEAD | KPF_COMPOUND_TAIL))) {
+			orders[0]++;
+			vpn++;
+			continue;
+		}
+
+		/* skip non thp compound pages */
+		if (!(page_flags & KPF_THP)) {
+			vpn++;
+			continue;
+		}
+
+		/* vpn points to part of a THP at this point */
+		if (page_flags & KPF_COMPOUND_HEAD)
+			cur_order = 1;
+		else {
+			/* not a head nor a tail in a THP? */
+			if (!(page_flags & KPF_COMPOUND_TAIL))
+				return -1;
+			continue;
+		}
+
+		next_folio_vpn = vpn + (1 << cur_order);
+
+		if (next_folio_vpn >= vpn_start + nr_pages)
+			break;
+
+		while (!(status = get_page_flags(next_folio_vpn, pagemap_file,
+						 kpageflags_file,
+						 &page_flags))) {
+			/* next compound head page or order-0 page */
+			if ((page_flags & KPF_COMPOUND_HEAD) ||
+			    !(page_flags & (KPF_COMPOUND_HEAD |
+			      KPF_COMPOUND_TAIL))) {
+				if (cur_order < nr_orders) {
+					orders[cur_order]++;
+					cur_order = -1;
+					vpn = next_folio_vpn;
+				}
+				break;
+			}
+
+			/* not a head nor a tail in a THP? */
+			if (!(page_flags & KPF_COMPOUND_TAIL))
+				return -1;
+
+			cur_order++;
+			next_folio_vpn = vpn + (1 << cur_order);
+		}
+
+		if (status)
+			return status;
+	}
+	if (cur_order > 0 && cur_order < nr_orders)
+		orders[cur_order]++;
+	return 0;
+}
+
+int check_folio_orders(uint64_t vpn_start, size_t nr_pages, int pagemap_file,
+			int kpageflags_file, int orders[], int nr_orders)
+{
+	int vpn_orders[nr_orders];
+	int status;
+	int i;
+
+	memset(vpn_orders, 0, sizeof(int) * nr_orders);
+	status = gather_folio_orders(vpn_start, nr_pages, pagemap_file,
+				     kpageflags_file, vpn_orders, nr_orders);
+	if (status)
+		return status;
+
+	status = 0;
+	for (i = 0; i < nr_orders; i++)
+		if (vpn_orders[i] != orders[i]) {
+			ksft_print_msg("order %d: expected: %d got %d\n", i,
+				       orders[i], vpn_orders[i]);
+			status = -1;
+		}
+
+	return status;
+}
+
 /* 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 b55d1809debc..dee9504a6129 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -85,6 +85,8 @@ bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size);
 int64_t allocate_transhuge(void *ptr, int pagemap_fd);
 unsigned long default_huge_page_size(void);
 int detect_hugetlb_page_sizes(size_t sizes[], int max);
+int check_folio_orders(uint64_t vpn_start, size_t nr_pages, int pagemap_file,
+			int kpageflags_file, int orders[], int nr_orders);
 
 int uffd_register(int uffd, void *addr, uint64_t len,
 		  bool miss, bool wp, bool minor);
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 4/4] selftests/mm: check after-split folio orders in split_huge_page_test.
  2025-08-06  2:20 [PATCH 0/4] Better split_huge_page_test result check Zi Yan
                   ` (2 preceding siblings ...)
  2025-08-06  2:20 ` [PATCH 3/4] selftests/mm: add check_folio_orders() helper Zi Yan
@ 2025-08-06  2:20 ` Zi Yan
  3 siblings, 0 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-06  2:20 UTC (permalink / raw)
  To: David Hildenbrand, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Zi Yan, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Shuah Khan, linux-kernel, linux-kselftest

Instead of just checking the existence of PMD folios before and after folio
split tests, use check_folio_orders() to check after-split folio orders.

The following tests are not changed:
1. split_pte_mapped_thp: the test already uses kpageflags to check;
2. split_file_backed_thp: no vaddr available.

Signed-off-by: Zi Yan <ziy@nvidia.com>
---
 .../selftests/mm/split_huge_page_test.c       | 67 +++++++++++++------
 1 file changed, 46 insertions(+), 21 deletions(-)

diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c
index 3c761228e451..cd34000279fe 100644
--- a/tools/testing/selftests/mm/split_huge_page_test.c
+++ b/tools/testing/selftests/mm/split_huge_page_test.c
@@ -25,6 +25,10 @@
 uint64_t pagesize;
 unsigned int pageshift;
 uint64_t pmd_pagesize;
+unsigned int pmd_order;
+unsigned int max_order;
+
+#define NR_ORDERS (max_order + 1)
 
 #define SPLIT_DEBUGFS "/sys/kernel/debug/split_huge_pages"
 #define SMAP_PATH "/proc/self/smaps"
@@ -38,6 +42,11 @@ uint64_t pmd_pagesize;
 #define KPF_THP      (1UL<<22)
 #define GET_ORDER(nr_pages)    (31 - __builtin_clz(nr_pages))
 
+const char *pagemap_proc = "/proc/self/pagemap";
+const char *kpageflags_proc = "/proc/kpageflags";
+int pagemap_fd;
+int kpageflags_fd;
+
 int is_backed_by_thp(char *vaddr, int pagemap_file, int kpageflags_file)
 {
 	uint64_t paddr;
@@ -153,6 +162,7 @@ void split_pmd_thp_to_order(int order)
 	char *one_page;
 	size_t len = 4 * pmd_pagesize;
 	size_t i;
+	int orders[NR_ORDERS];
 
 	one_page = memalign(pmd_pagesize, len);
 	if (!one_page)
@@ -174,6 +184,12 @@ void split_pmd_thp_to_order(int order)
 		if (one_page[i] != (char)i)
 			ksft_exit_fail_msg("%ld byte corrupted\n", i);
 
+	memset(orders, 0, sizeof(int) * NR_ORDERS);
+	orders[order] = 4 << (pmd_order - order);
+	if (check_folio_orders((uint64_t)one_page >> pageshift,
+			       len >> pageshift, pagemap_fd, kpageflags_fd,
+			       orders, NR_ORDERS))
+		ksft_exit_fail_msg("Unexpected THP split\n");
 
 	if (!check_huge_anon(one_page, 0, pmd_pagesize))
 		ksft_exit_fail_msg("Still AnonHugePages not split\n");
@@ -188,22 +204,6 @@ void split_pte_mapped_thp(void)
 	size_t len = 4 * pmd_pagesize;
 	uint64_t thp_size;
 	size_t i;
-	const char *pagemap_template = "/proc/%d/pagemap";
-	const char *kpageflags_proc = "/proc/kpageflags";
-	char pagemap_proc[255];
-	int pagemap_fd;
-	int kpageflags_fd;
-
-	if (snprintf(pagemap_proc, 255, pagemap_template, getpid()) < 0)
-		ksft_exit_fail_msg("get pagemap proc error: %s\n", strerror(errno));
-
-	pagemap_fd = open(pagemap_proc, O_RDONLY);
-	if (pagemap_fd == -1)
-		ksft_exit_fail_msg("read pagemap: %s\n", strerror(errno));
-
-	kpageflags_fd = open(kpageflags_proc, O_RDONLY);
-	if (kpageflags_fd == -1)
-		ksft_exit_fail_msg("read kpageflags: %s\n", strerror(errno));
 
 	one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE,
 			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
@@ -261,8 +261,6 @@ void split_pte_mapped_thp(void)
 
 	ksft_test_result_pass("Split PTE-mapped huge pages successful\n");
 	munmap(one_page, len);
-	close(pagemap_fd);
-	close(kpageflags_fd);
 }
 
 void split_file_backed_thp(int order)
@@ -471,6 +469,7 @@ void split_thp_in_pagecache_to_order_at(size_t fd_size, const char *fs_loc,
 	size_t i;
 	char testfile[INPUT_MAX];
 	int err = 0;
+	int orders[NR_ORDERS];
 
 	err = snprintf(testfile, INPUT_MAX, "%s/test", fs_loc);
 
@@ -482,12 +481,21 @@ void split_thp_in_pagecache_to_order_at(size_t fd_size, const char *fs_loc,
 		return;
 	err = 0;
 
-	if (offset == -1)
+	memset(orders, 0, sizeof(int) * NR_ORDERS);
+	if (offset == -1) {
 		write_debugfs(PID_FMT, getpid(), (uint64_t)addr,
 			      (uint64_t)addr + fd_size, order);
-	else
+		orders[order] = fd_size / (pagesize << order);
+	} else {
+		int times = fd_size / pmd_pagesize;
+
 		write_debugfs(PID_FMT_OFFSET, getpid(), (uint64_t)addr,
 			      (uint64_t)addr + fd_size, order, offset);
+		for (i = order + 1; i < pmd_order; i++)
+			orders[i] = times;
+
+		orders[order] = 2 * times;
+	}
 
 	for (i = 0; i < fd_size; i++)
 		if (*(addr + i) != (char)i) {
@@ -496,6 +504,12 @@ void split_thp_in_pagecache_to_order_at(size_t fd_size, const char *fs_loc,
 			goto out;
 		}
 
+	if (check_folio_orders((uint64_t)addr >> pageshift,
+				fd_size >> pageshift, pagemap_fd, kpageflags_fd,
+				orders, NR_ORDERS))
+		ksft_exit_fail_msg("Unexpected THP split\n");
+
+
 	if (!check_huge_file(addr, 0, pmd_pagesize)) {
 		ksft_print_msg("Still FilePmdMapped not split\n");
 		err = EXIT_FAILURE;
@@ -526,7 +540,6 @@ int main(int argc, char **argv)
 	const char *fs_loc;
 	bool created_tmp;
 	int offset;
-	unsigned int max_order;
 	unsigned int nr_pages;
 	unsigned int tests;
 
@@ -543,6 +556,7 @@ int main(int argc, char **argv)
 	pagesize = getpagesize();
 	pageshift = ffs(pagesize) - 1;
 	pmd_pagesize = read_pmd_pagesize();
+	pmd_order = GET_ORDER(pmd_pagesize / pagesize);
 	if (!pmd_pagesize)
 		ksft_exit_fail_msg("Reading PMD pagesize failed\n");
 
@@ -551,6 +565,14 @@ int main(int argc, char **argv)
 	tests = 2 + (max_order - 1) + (2 * max_order) + (max_order - 1) * 4 + 2;
 	ksft_set_plan(tests);
 
+	pagemap_fd = open(pagemap_proc, O_RDONLY);
+	if (pagemap_fd == -1)
+		ksft_exit_fail_msg("read pagemap: %s\n", strerror(errno));
+
+	kpageflags_fd = open(kpageflags_proc, O_RDONLY);
+	if (kpageflags_fd == -1)
+		ksft_exit_fail_msg("read kpageflags: %s\n", strerror(errno));
+
 	fd_size = 2 * pmd_pagesize;
 
 	split_pmd_zero_pages();
@@ -575,6 +597,9 @@ int main(int argc, char **argv)
 			split_thp_in_pagecache_to_order_at(fd_size, fs_loc, i, offset);
 	cleanup_thp_fs(fs_loc, created_tmp);
 
+	close(pagemap_fd);
+	close(kpageflags_fd);
+
 	ksft_finished();
 
 	return 0;
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug.
  2025-08-06  2:20 ` [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug Zi Yan
@ 2025-08-06 12:42   ` David Hildenbrand
  2025-08-06 16:51   ` Lorenzo Stoakes
  2025-08-07  6:50   ` Baolin Wang
  2 siblings, 0 replies; 21+ messages in thread
From: David Hildenbrand @ 2025-08-06 12:42 UTC (permalink / raw)
  To: Zi Yan, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Baolin Wang, Liam R. Howlett,
	Nico Pache, Ryan Roberts, Dev Jain, Barry Song, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
	linux-kernel, linux-kselftest

On 06.08.25 04:20, Zi Yan wrote:
> They are useful information for debugging split huge page tests.
> 
> Signed-off-by: Zi Yan <ziy@nvidia.com>
> ---

Acked-by: David Hildenbrand <david@redhat.com>

-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-06  2:20 ` [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds Zi Yan
@ 2025-08-06 12:47   ` David Hildenbrand
  2025-08-06 14:29     ` Zi Yan
  2025-08-07  8:45   ` Wei Yang
  2025-08-07  8:55   ` Wei Yang
  2 siblings, 1 reply; 21+ messages in thread
From: David Hildenbrand @ 2025-08-06 12:47 UTC (permalink / raw)
  To: Zi Yan, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Baolin Wang, Liam R. Howlett,
	Nico Pache, Ryan Roberts, Dev Jain, Barry Song, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
	linux-kernel, linux-kselftest

On 06.08.25 04:20, Zi Yan wrote:
> Current behavior is to move to next PAGE_SIZE and split, but that makes it
> hard to check after-split folio orders. This is a preparation patch to
> allow more precise split_huge_page_test check in an upcoming commit.
> 
> split_folio_to_order() part is not changed, since split_pte_mapped_thp test
> relies on its current behavior.
> 
> Signed-off-by: Zi Yan <ziy@nvidia.com>
> ---

[...]

>   
> +		nr_pages = folio_nr_pages(folio);
> +
>   		if (!folio_test_anon(folio)) {
>   			mapping = folio->mapping;
>   			target_order = max(new_order,
> @@ -4385,15 +4388,16 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
>   		if (!folio_test_anon(folio) && folio->mapping != mapping)
>   			goto unlock;
>   
> -		if (in_folio_offset < 0 ||
> -		    in_folio_offset >= folio_nr_pages(folio)) {
> +		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
>   			if (!split_folio_to_order(folio, target_order))
>   				split++;
>   		} else {
> -			struct page *split_at = folio_page(folio,
> -							   in_folio_offset);
> -			if (!folio_split(folio, target_order, split_at, NULL))
> +			struct page *split_at =
> +				folio_page(folio, in_folio_offset);

Can we add an empty line here, and just have this in a single line, 
please (feel free to exceed 80chars if it makes the code look less ugly).

> +			if (!folio_split(folio, target_order, split_at, NULL)) {
>   				split++;
> +				addr += PAGE_SIZE * nr_pages;

Hm, but won't we do another "addr += PAGE_SIZE" in the for loop?


-- 
Cheers,

David / dhildenb


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-06 12:47   ` David Hildenbrand
@ 2025-08-06 14:29     ` Zi Yan
  0 siblings, 0 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-06 14:29 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: linux-mm, Andrew Morton, Lorenzo Stoakes, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Shuah Khan, linux-kernel, linux-kselftest

On 6 Aug 2025, at 8:47, David Hildenbrand wrote:

> On 06.08.25 04:20, Zi Yan wrote:
>> Current behavior is to move to next PAGE_SIZE and split, but that makes it
>> hard to check after-split folio orders. This is a preparation patch to
>> allow more precise split_huge_page_test check in an upcoming commit.
>>
>> split_folio_to_order() part is not changed, since split_pte_mapped_thp test
>> relies on its current behavior.
>>
>> Signed-off-by: Zi Yan <ziy@nvidia.com>
>> ---
>
> [...]
>
>>  +		nr_pages = folio_nr_pages(folio);
>> +
>>   		if (!folio_test_anon(folio)) {
>>   			mapping = folio->mapping;
>>   			target_order = max(new_order,
>> @@ -4385,15 +4388,16 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
>>   		if (!folio_test_anon(folio) && folio->mapping != mapping)
>>   			goto unlock;
>>  -		if (in_folio_offset < 0 ||
>> -		    in_folio_offset >= folio_nr_pages(folio)) {
>> +		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
>>   			if (!split_folio_to_order(folio, target_order))
>>   				split++;
>>   		} else {
>> -			struct page *split_at = folio_page(folio,
>> -							   in_folio_offset);
>> -			if (!folio_split(folio, target_order, split_at, NULL))
>> +			struct page *split_at =
>> +				folio_page(folio, in_folio_offset);
>
> Can we add an empty line here, and just have this in a single line, please (feel free to exceed 80chars if it makes the code look less ugly).

Sure.

>
>> +			if (!folio_split(folio, target_order, split_at, NULL)) {
>>   				split++;
>> +				addr += PAGE_SIZE * nr_pages;
>
> Hm, but won't we do another "addr += PAGE_SIZE" in the for loop?

You are right. Will fix it with addr += PAGE_SIZE * (nr_pages - 1);

Thanks.

Best Regards,
Yan, Zi

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug.
  2025-08-06  2:20 ` [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug Zi Yan
  2025-08-06 12:42   ` David Hildenbrand
@ 2025-08-06 16:51   ` Lorenzo Stoakes
  2025-08-07  6:50   ` Baolin Wang
  2 siblings, 0 replies; 21+ messages in thread
From: Lorenzo Stoakes @ 2025-08-06 16:51 UTC (permalink / raw)
  To: Zi Yan
  Cc: David Hildenbrand, linux-mm, Andrew Morton, Baolin Wang,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Shuah Khan, linux-kernel, linux-kselftest

On Tue, Aug 05, 2025 at 10:20:42PM -0400, Zi Yan wrote:
> They are useful information for debugging split huge page tests.
>
> Signed-off-by: Zi Yan <ziy@nvidia.com>

Seems reasonable, so:

Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>

> ---
>  mm/huge_memory.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 2b4ea5a2ce7d..8a11c2d402d4 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -4327,8 +4327,8 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
>  		goto out;
>  	}
>
> -	pr_debug("Split huge pages in pid: %d, vaddr: [0x%lx - 0x%lx]\n",
> -		 pid, vaddr_start, vaddr_end);
> +	pr_debug("Split huge pages in pid: %d, vaddr: [0x%lx - 0x%lx], new_order: %u, in_folio_offset %ld\n",
> +		 pid, vaddr_start, vaddr_end, new_order, in_folio_offset);
>
>  	mmap_read_lock(mm);
>  	/*
> --
> 2.47.2
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* RE:[PATCH 3/4] selftests/mm: add check_folio_orders() helper.
  2025-08-06  2:20 ` [PATCH 3/4] selftests/mm: add check_folio_orders() helper Zi Yan
@ 2025-08-07  3:00   ` wang lian
  2025-08-07 17:00     ` [PATCH " Zi Yan
  2025-08-07  6:49   ` Baolin Wang
  1 sibling, 1 reply; 21+ messages in thread
From: wang lian @ 2025-08-07  3:00 UTC (permalink / raw)
  To: ziy
  Cc: Liam.Howlett, akpm, baohua, baolin.wang, david, dev.jain,
	linux-kernel, linux-kselftest, linux-mm, lorenzo.stoakes, mhocko,
	npache, rppt, ryan.roberts, shuah, surenb, vbabka, wang lian

Hi Zi,

Thanks for the patch.

I have a nit suggestion to centralize some of the macro definitions
for better consistency and reusability.

On [Date of patch], Zi Yan wrote:
> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
> ...
> +#define PGMAP_PRESENT		(1UL << 63)
> +#define KPF_COMPOUND_HEAD	(1UL << 15)
> +#define KPF_COMPOUND_TAIL	(1UL << 16)
> +#define KPF_THP			(1UL << 22)
> +#define PFN_MASK		((1UL<<55)-1)

Currently, these macros and `PGMAP_PRESENT` are defined locally in
`vm_util.c`. It would be cleaner to move them to the shared header
`vm_util.h`.

This would also allow us to consistently use `PM_PRESENT` (from the
header) instead of the local `PGMAP_PRESENT` duplicate. I noticed the
patch is already moving in this direction, and we can complete this
cleanup.

How about a change like this?

--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -17,17 +17,6 @@
 #define STATUS_FILE_PATH "/proc/self/status"
 #define MAX_LINE_LENGTH 500
 
-#define PGMAP_PRESENT          (1UL << 63)
-#define KPF_COMPOUND_HEAD      (1UL << 15)
-#define KPF_COMPOUND_TAIL      (1UL << 16)
-#define KPF_THP                        (1UL << 22)
-#define PFN_MASK     ((1UL<<55)-1)
-
 unsigned int __page_size;
 unsigned int __page_shift;
 
@@ -360,7 +349,7 @@ static int get_page_flags(uint64_t vpn, int pagemap_file, int kpageflags_file,
 	 * Treat non-present page as a page without any flag, so that
 	 * gather_folio_orders() just record the current folio order.
 	 */
-	if (!(pfn & PGMAP_PRESENT)) {
+	if (!(pfn & PM_PRESENT)) {
 		*flags = 0;
 		return 0;
 	}
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -17,6 +17,11 @@
 #define PM_FILE                        BIT_ULL(61)
 #define PM_SWAP                        BIT_ULL(62)
 #define PM_PRESENT             BIT_ULL(63)
+#define KPF_COMPOUND_HEAD      (1UL << 15)
+#define KPF_COMPOUND_TAIL      (1UL << 16)
+#define KPF_THP                        (1UL << 22)
+#define PFN_MASK     ((1UL<<55)-1)
 
 extern unsigned int __page_size;
 extern unsigned int __page_shift;


Best regards,
wang lian

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 3/4] selftests/mm: add check_folio_orders() helper.
  2025-08-06  2:20 ` [PATCH 3/4] selftests/mm: add check_folio_orders() helper Zi Yan
  2025-08-07  3:00   ` wang lian
@ 2025-08-07  6:49   ` Baolin Wang
  2025-08-07 17:02     ` Zi Yan
  1 sibling, 1 reply; 21+ messages in thread
From: Baolin Wang @ 2025-08-07  6:49 UTC (permalink / raw)
  To: Zi Yan, David Hildenbrand, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Nico Pache,
	Ryan Roberts, Dev Jain, Barry Song, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
	linux-kernel, linux-kselftest



On 2025/8/6 10:20, Zi Yan wrote:
> The helper gathers an folio order statistics of folios within a virtual
> address range and checks it against a given order list. It aims to provide
> a more precise folio order check instead of just checking the existence of
> PMD folios.
> 
> Signed-off-by: Zi Yan <ziy@nvidia.com>
> ---
>   tools/testing/selftests/mm/vm_util.c | 139 +++++++++++++++++++++++++++
>   tools/testing/selftests/mm/vm_util.h |   2 +
>   2 files changed, 141 insertions(+)
> 
> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
> index 9dafa7669ef9..373621145b2a 100644
> --- a/tools/testing/selftests/mm/vm_util.c
> +++ b/tools/testing/selftests/mm/vm_util.c
> @@ -17,6 +17,12 @@
>   #define STATUS_FILE_PATH "/proc/self/status"
>   #define MAX_LINE_LENGTH 500
>   
> +#define PGMAP_PRESENT		(1UL << 63)
> +#define KPF_COMPOUND_HEAD	(1UL << 15)
> +#define KPF_COMPOUND_TAIL	(1UL << 16)
> +#define KPF_THP			(1UL << 22)
> +#define PFN_MASK     ((1UL<<55)-1)
> +
>   unsigned int __page_size;
>   unsigned int __page_shift;
>   
> @@ -338,6 +344,139 @@ int detect_hugetlb_page_sizes(size_t sizes[], int max)
>   	return count;
>   }
>   
> +static int get_page_flags(uint64_t vpn, int pagemap_file, int kpageflags_file,
> +			  uint64_t *flags)
> +{
> +	uint64_t pfn;
> +	size_t count;
> +
> +	count = pread(pagemap_file, &pfn, sizeof(pfn),
> +		      vpn * sizeof(pfn));
> +
> +	if (count != sizeof(pfn))
> +		return -1;
> +
> +	/*
> +	 * Treat non-present page as a page without any flag, so that
> +	 * gather_folio_orders() just record the current folio order.
> +	 */
> +	if (!(pfn & PGMAP_PRESENT)) {
> +		*flags = 0;
> +		return 0;
> +	}

It looks like you can reuse the helper pagemap_get_pfn() in this file?

> +
> +	count = pread(kpageflags_file, flags, sizeof(*flags),
> +		      (pfn & PFN_MASK) * sizeof(*flags));
> +
> +	if (count != sizeof(*flags))
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static int gather_folio_orders(uint64_t vpn_start, size_t nr_pages,

In this file, other helper functions use userspace virtual address as 
parameters, so can we consistently use virtual address for calculations 
instead of the 'vpn_start'?

> +			       int pagemap_file, int kpageflags_file,
> +			       int orders[], int nr_orders)
> +{
> +	uint64_t page_flags = 0;
> +	int cur_order = -1;
> +	uint64_t vpn;
> +
> +	if (!pagemap_file || !kpageflags_file)
> +		return -1;
> +	if (nr_orders <= 0)
> +		return -1;
> +
> +	for (vpn = vpn_start; vpn < vpn_start + nr_pages; ) {
> +		uint64_t next_folio_vpn;
> +		int status;
> +
> +		if (get_page_flags(vpn, pagemap_file, kpageflags_file, &page_flags))
> +			return -1;
> +
> +		/* all order-0 pages with possible false postive (non folio) */
> +		if (!(page_flags & (KPF_COMPOUND_HEAD | KPF_COMPOUND_TAIL))) {
> +			orders[0]++;
> +			vpn++;
> +			continue;
> +		}
> +
> +		/* skip non thp compound pages */
> +		if (!(page_flags & KPF_THP)) {
> +			vpn++;
> +			continue;
> +		}
> +
> +		/* vpn points to part of a THP at this point */
> +		if (page_flags & KPF_COMPOUND_HEAD)
> +			cur_order = 1;
> +		else {
> +			/* not a head nor a tail in a THP? */
> +			if (!(page_flags & KPF_COMPOUND_TAIL))
> +				return -1;
> +			continue;
> +		}
> +
> +		next_folio_vpn = vpn + (1 << cur_order);
> +
> +		if (next_folio_vpn >= vpn_start + nr_pages)
> +			break;
> +
> +		while (!(status = get_page_flags(next_folio_vpn, pagemap_file,
> +						 kpageflags_file,
> +						 &page_flags))) {
> +			/* next compound head page or order-0 page */
> +			if ((page_flags & KPF_COMPOUND_HEAD) ||
> +			    !(page_flags & (KPF_COMPOUND_HEAD |
> +			      KPF_COMPOUND_TAIL))) {
> +				if (cur_order < nr_orders) {
> +					orders[cur_order]++;
> +					cur_order = -1;
> +					vpn = next_folio_vpn;
> +				}
> +				break;
> +			}
> +
> +			/* not a head nor a tail in a THP? */
> +			if (!(page_flags & KPF_COMPOUND_TAIL))
> +				return -1;
> +
> +			cur_order++;
> +			next_folio_vpn = vpn + (1 << cur_order);
> +		}
> +
> +		if (status)
> +			return status;
> +	}
> +	if (cur_order > 0 && cur_order < nr_orders)
> +		orders[cur_order]++;
> +	return 0;
> +}
> +
> +int check_folio_orders(uint64_t vpn_start, size_t nr_pages, int pagemap_file,
> +			int kpageflags_file, int orders[], int nr_orders)
> +{
> +	int vpn_orders[nr_orders];

IIRC, we should avoid using VLA (variable length arrays)?

> +	int status;
> +	int i;
> +
> +	memset(vpn_orders, 0, sizeof(int) * nr_orders);
> +	status = gather_folio_orders(vpn_start, nr_pages, pagemap_file,
> +				     kpageflags_file, vpn_orders, nr_orders);
> +	if (status)
> +		return status;
> +
> +	status = 0;
> +	for (i = 0; i < nr_orders; i++)
> +		if (vpn_orders[i] != orders[i]) {
> +			ksft_print_msg("order %d: expected: %d got %d\n", i,
> +				       orders[i], vpn_orders[i]);
> +			status = -1;
> +		}
> +
> +	return status;
> +}
> +
>   /* 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 b55d1809debc..dee9504a6129 100644
> --- a/tools/testing/selftests/mm/vm_util.h
> +++ b/tools/testing/selftests/mm/vm_util.h
> @@ -85,6 +85,8 @@ bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size);
>   int64_t allocate_transhuge(void *ptr, int pagemap_fd);
>   unsigned long default_huge_page_size(void);
>   int detect_hugetlb_page_sizes(size_t sizes[], int max);
> +int check_folio_orders(uint64_t vpn_start, size_t nr_pages, int pagemap_file,
> +			int kpageflags_file, int orders[], int nr_orders);
>   
>   int uffd_register(int uffd, void *addr, uint64_t len,
>   		  bool miss, bool wp, bool minor);


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug.
  2025-08-06  2:20 ` [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug Zi Yan
  2025-08-06 12:42   ` David Hildenbrand
  2025-08-06 16:51   ` Lorenzo Stoakes
@ 2025-08-07  6:50   ` Baolin Wang
  2 siblings, 0 replies; 21+ messages in thread
From: Baolin Wang @ 2025-08-07  6:50 UTC (permalink / raw)
  To: Zi Yan, David Hildenbrand, linux-mm
  Cc: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Nico Pache,
	Ryan Roberts, Dev Jain, Barry Song, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
	linux-kernel, linux-kselftest



On 2025/8/6 10:20, Zi Yan wrote:
> They are useful information for debugging split huge page tests.
> 
> Signed-off-by: Zi Yan <ziy@nvidia.com>

LGTM.
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>

> ---
>   mm/huge_memory.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 2b4ea5a2ce7d..8a11c2d402d4 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -4327,8 +4327,8 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
>   		goto out;
>   	}
>   
> -	pr_debug("Split huge pages in pid: %d, vaddr: [0x%lx - 0x%lx]\n",
> -		 pid, vaddr_start, vaddr_end);
> +	pr_debug("Split huge pages in pid: %d, vaddr: [0x%lx - 0x%lx], new_order: %u, in_folio_offset %ld\n",
> +		 pid, vaddr_start, vaddr_end, new_order, in_folio_offset);
>   
>   	mmap_read_lock(mm);
>   	/*


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-06  2:20 ` [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds Zi Yan
  2025-08-06 12:47   ` David Hildenbrand
@ 2025-08-07  8:45   ` Wei Yang
  2025-08-07 17:04     ` Zi Yan
  2025-08-07  8:55   ` Wei Yang
  2 siblings, 1 reply; 21+ messages in thread
From: Wei Yang @ 2025-08-07  8:45 UTC (permalink / raw)
  To: Zi Yan
  Cc: David Hildenbrand, linux-mm, Andrew Morton, Lorenzo Stoakes,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Shuah Khan, linux-kernel, linux-kselftest

On Tue, Aug 05, 2025 at 10:20:43PM -0400, Zi Yan wrote:
>Current behavior is to move to next PAGE_SIZE and split, but that makes it
>hard to check after-split folio orders. This is a preparation patch to
>allow more precise split_huge_page_test check in an upcoming commit.
>
>split_folio_to_order() part is not changed, since split_pte_mapped_thp test
>relies on its current behavior.
>
>Signed-off-by: Zi Yan <ziy@nvidia.com>
>---
> mm/huge_memory.c | 18 +++++++++++-------
> 1 file changed, 11 insertions(+), 7 deletions(-)
>
>diff --git a/mm/huge_memory.c b/mm/huge_memory.c
>index 8a11c2d402d4..b2ce8ac0c5a9 100644
>--- a/mm/huge_memory.c
>+++ b/mm/huge_memory.c
>@@ -4341,6 +4341,7 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
> 		struct folio *folio;
> 		struct address_space *mapping;
> 		unsigned int target_order = new_order;
>+		long nr_pages;
> 
> 		if (!vma)
> 			break;
>@@ -4358,6 +4359,8 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
> 		if (!is_transparent_hugepage(folio))
> 			goto next;
> 
>+		nr_pages = folio_nr_pages(folio);
>+

Could be folio_large_nr_pages()?

> 		if (!folio_test_anon(folio)) {
> 			mapping = folio->mapping;
> 			target_order = max(new_order,
>@@ -4385,15 +4388,16 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
> 		if (!folio_test_anon(folio) && folio->mapping != mapping)
> 			goto unlock;
> 
>-		if (in_folio_offset < 0 ||
>-		    in_folio_offset >= folio_nr_pages(folio)) {
>+		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
> 			if (!split_folio_to_order(folio, target_order))
> 				split++;
> 		} else {
>-			struct page *split_at = folio_page(folio,
>-							   in_folio_offset);
>-			if (!folio_split(folio, target_order, split_at, NULL))
>+			struct page *split_at =
>+				folio_page(folio, in_folio_offset);
>+			if (!folio_split(folio, target_order, split_at, NULL)) {
> 				split++;
>+				addr += PAGE_SIZE * nr_pages;
>+			}
> 		}
> 
> unlock:
>@@ -4438,8 +4442,8 @@ static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,
> 	if (IS_ERR(candidate))
> 		goto out;
> 
>-	pr_debug("split file-backed THPs in file: %s, page offset: [0x%lx - 0x%lx]\n",
>-		 file_path, off_start, off_end);
>+	pr_debug("split file-backed THPs in file: %s, page offset: [0x%lx - 0x%lx], new_order %u in_folio_offset %ld\n",
>+		 file_path, off_start, off_end, new_order, in_folio_offset);
> 

How about move this part into patch 1?

> 	mapping = candidate->f_mapping;
> 	min_order = mapping_min_folio_order(mapping);
>-- 
>2.47.2
>

-- 
Wei Yang
Help you, Help me

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-06  2:20 ` [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds Zi Yan
  2025-08-06 12:47   ` David Hildenbrand
  2025-08-07  8:45   ` Wei Yang
@ 2025-08-07  8:55   ` Wei Yang
  2025-08-07 17:05     ` Zi Yan
  2 siblings, 1 reply; 21+ messages in thread
From: Wei Yang @ 2025-08-07  8:55 UTC (permalink / raw)
  To: Zi Yan
  Cc: David Hildenbrand, linux-mm, Andrew Morton, Lorenzo Stoakes,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Shuah Khan, linux-kernel, linux-kselftest

On Tue, Aug 05, 2025 at 10:20:43PM -0400, Zi Yan wrote:
[...]
> 
>-		if (in_folio_offset < 0 ||
>-		    in_folio_offset >= folio_nr_pages(folio)) {
>+		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
> 			if (!split_folio_to_order(folio, target_order))
> 				split++;
> 		} else {
>-			struct page *split_at = folio_page(folio,
>-							   in_folio_offset);
>-			if (!folio_split(folio, target_order, split_at, NULL))
>+			struct page *split_at =
>+				folio_page(folio, in_folio_offset);
>+			if (!folio_split(folio, target_order, split_at, NULL)) {
> 				split++;
>+				addr += PAGE_SIZE * nr_pages;
>+			}

Are we sure addr points to the folio start?

-- 
Wei Yang
Help you, Help me

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 3/4] selftests/mm: add check_folio_orders() helper.
  2025-08-07  3:00   ` wang lian
@ 2025-08-07 17:00     ` Zi Yan
  0 siblings, 0 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-07 17:00 UTC (permalink / raw)
  To: wang lian
  Cc: Liam.Howlett, akpm, baohua, baolin.wang, david, dev.jain,
	linux-kernel, linux-kselftest, linux-mm, lorenzo.stoakes, mhocko,
	npache, rppt, ryan.roberts, shuah, surenb, vbabka

On 6 Aug 2025, at 23:00, wang lian wrote:

> Hi Zi,
>
> Thanks for the patch.
>
> I have a nit suggestion to centralize some of the macro definitions
> for better consistency and reusability.
>
> On [Date of patch], Zi Yan wrote:
>> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
>> ...
>> +#define PGMAP_PRESENT		(1UL << 63)
>> +#define KPF_COMPOUND_HEAD	(1UL << 15)
>> +#define KPF_COMPOUND_TAIL	(1UL << 16)
>> +#define KPF_THP			(1UL << 22)
>> +#define PFN_MASK		((1UL<<55)-1)
>
> Currently, these macros and `PGMAP_PRESENT` are defined locally in
> `vm_util.c`. It would be cleaner to move them to the shared header
> `vm_util.h`.
>
> This would also allow us to consistently use `PM_PRESENT` (from the
> header) instead of the local `PGMAP_PRESENT` duplicate. I noticed the
> patch is already moving in this direction, and we can complete this
> cleanup.
>
> How about a change like this?

I did not know about PM_PRESENT. Sure, will move the code like you
did below. Thanks.

>
> --- a/tools/testing/selftests/mm/vm_util.c
> +++ b/tools/testing/selftests/mm/vm_util.c
> @@ -17,17 +17,6 @@
>  #define STATUS_FILE_PATH "/proc/self/status"
>  #define MAX_LINE_LENGTH 500
>
> -#define PGMAP_PRESENT          (1UL << 63)
> -#define KPF_COMPOUND_HEAD      (1UL << 15)
> -#define KPF_COMPOUND_TAIL      (1UL << 16)
> -#define KPF_THP                        (1UL << 22)
> -#define PFN_MASK     ((1UL<<55)-1)
> -
>  unsigned int __page_size;
>  unsigned int __page_shift;
>
> @@ -360,7 +349,7 @@ static int get_page_flags(uint64_t vpn, int pagemap_file, int kpageflags_file,
>  	 * Treat non-present page as a page without any flag, so that
>  	 * gather_folio_orders() just record the current folio order.
>  	 */
> -	if (!(pfn & PGMAP_PRESENT)) {
> +	if (!(pfn & PM_PRESENT)) {
>  		*flags = 0;
>  		return 0;
>  	}
> --- a/tools/testing/selftests/mm/vm_util.h
> +++ b/tools/testing/selftests/mm/vm_util.h
> @@ -17,6 +17,11 @@
>  #define PM_FILE                        BIT_ULL(61)
>  #define PM_SWAP                        BIT_ULL(62)
>  #define PM_PRESENT             BIT_ULL(63)
> +#define KPF_COMPOUND_HEAD      (1UL << 15)
> +#define KPF_COMPOUND_TAIL      (1UL << 16)
> +#define KPF_THP                        (1UL << 22)
> +#define PFN_MASK     ((1UL<<55)-1)
>
>  extern unsigned int __page_size;
>  extern unsigned int __page_shift;
>
>
> Best regards,
> wang lian


--
Best Regards,
Yan, Zi

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 3/4] selftests/mm: add check_folio_orders() helper.
  2025-08-07  6:49   ` Baolin Wang
@ 2025-08-07 17:02     ` Zi Yan
  0 siblings, 0 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-07 17:02 UTC (permalink / raw)
  To: Baolin Wang
  Cc: David Hildenbrand, linux-mm, Andrew Morton, Lorenzo Stoakes,
	Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Shuah Khan, linux-kernel, linux-kselftest

On 7 Aug 2025, at 2:49, Baolin Wang wrote:

> On 2025/8/6 10:20, Zi Yan wrote:
>> The helper gathers an folio order statistics of folios within a virtual
>> address range and checks it against a given order list. It aims to provide
>> a more precise folio order check instead of just checking the existence of
>> PMD folios.
>>
>> Signed-off-by: Zi Yan <ziy@nvidia.com>
>> ---
>>   tools/testing/selftests/mm/vm_util.c | 139 +++++++++++++++++++++++++++
>>   tools/testing/selftests/mm/vm_util.h |   2 +
>>   2 files changed, 141 insertions(+)
>>
>> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
>> index 9dafa7669ef9..373621145b2a 100644
>> --- a/tools/testing/selftests/mm/vm_util.c
>> +++ b/tools/testing/selftests/mm/vm_util.c
>> @@ -17,6 +17,12 @@
>>   #define STATUS_FILE_PATH "/proc/self/status"
>>   #define MAX_LINE_LENGTH 500
>>  +#define PGMAP_PRESENT		(1UL << 63)
>> +#define KPF_COMPOUND_HEAD	(1UL << 15)
>> +#define KPF_COMPOUND_TAIL	(1UL << 16)
>> +#define KPF_THP			(1UL << 22)
>> +#define PFN_MASK     ((1UL<<55)-1)
>> +
>>   unsigned int __page_size;
>>   unsigned int __page_shift;
>>  @@ -338,6 +344,139 @@ int detect_hugetlb_page_sizes(size_t sizes[], int max)
>>   	return count;
>>   }
>>  +static int get_page_flags(uint64_t vpn, int pagemap_file, int kpageflags_file,
>> +			  uint64_t *flags)
>> +{
>> +	uint64_t pfn;
>> +	size_t count;
>> +
>> +	count = pread(pagemap_file, &pfn, sizeof(pfn),
>> +		      vpn * sizeof(pfn));
>> +
>> +	if (count != sizeof(pfn))
>> +		return -1;
>> +
>> +	/*
>> +	 * Treat non-present page as a page without any flag, so that
>> +	 * gather_folio_orders() just record the current folio order.
>> +	 */
>> +	if (!(pfn & PGMAP_PRESENT)) {
>> +		*flags = 0;
>> +		return 0;
>> +	}
>
> It looks like you can reuse the helper pagemap_get_pfn() in this file?

Sure.

>
>> +
>> +	count = pread(kpageflags_file, flags, sizeof(*flags),
>> +		      (pfn & PFN_MASK) * sizeof(*flags));
>> +
>> +	if (count != sizeof(*flags))
>> +		return -1;
>> +
>> +	return 0;
>> +}
>> +
>> +static int gather_folio_orders(uint64_t vpn_start, size_t nr_pages,
>
> In this file, other helper functions use userspace virtual address as parameters, so can we consistently use virtual address for calculations instead of the 'vpn_start'?
>

Sure.

>> +			       int pagemap_file, int kpageflags_file,
>> +			       int orders[], int nr_orders)
>> +{
>> +	uint64_t page_flags = 0;
>> +	int cur_order = -1;
>> +	uint64_t vpn;
>> +
>> +	if (!pagemap_file || !kpageflags_file)
>> +		return -1;
>> +	if (nr_orders <= 0)
>> +		return -1;
>> +
>> +	for (vpn = vpn_start; vpn < vpn_start + nr_pages; ) {
>> +		uint64_t next_folio_vpn;
>> +		int status;
>> +
>> +		if (get_page_flags(vpn, pagemap_file, kpageflags_file, &page_flags))
>> +			return -1;
>> +
>> +		/* all order-0 pages with possible false postive (non folio) */
>> +		if (!(page_flags & (KPF_COMPOUND_HEAD | KPF_COMPOUND_TAIL))) {
>> +			orders[0]++;
>> +			vpn++;
>> +			continue;
>> +		}
>> +
>> +		/* skip non thp compound pages */
>> +		if (!(page_flags & KPF_THP)) {
>> +			vpn++;
>> +			continue;
>> +		}
>> +
>> +		/* vpn points to part of a THP at this point */
>> +		if (page_flags & KPF_COMPOUND_HEAD)
>> +			cur_order = 1;
>> +		else {
>> +			/* not a head nor a tail in a THP? */
>> +			if (!(page_flags & KPF_COMPOUND_TAIL))
>> +				return -1;
>> +			continue;
>> +		}
>> +
>> +		next_folio_vpn = vpn + (1 << cur_order);
>> +
>> +		if (next_folio_vpn >= vpn_start + nr_pages)
>> +			break;
>> +
>> +		while (!(status = get_page_flags(next_folio_vpn, pagemap_file,
>> +						 kpageflags_file,
>> +						 &page_flags))) {
>> +			/* next compound head page or order-0 page */
>> +			if ((page_flags & KPF_COMPOUND_HEAD) ||
>> +			    !(page_flags & (KPF_COMPOUND_HEAD |
>> +			      KPF_COMPOUND_TAIL))) {
>> +				if (cur_order < nr_orders) {
>> +					orders[cur_order]++;
>> +					cur_order = -1;
>> +					vpn = next_folio_vpn;
>> +				}
>> +				break;
>> +			}
>> +
>> +			/* not a head nor a tail in a THP? */
>> +			if (!(page_flags & KPF_COMPOUND_TAIL))
>> +				return -1;
>> +
>> +			cur_order++;
>> +			next_folio_vpn = vpn + (1 << cur_order);
>> +		}
>> +
>> +		if (status)
>> +			return status;
>> +	}
>> +	if (cur_order > 0 && cur_order < nr_orders)
>> +		orders[cur_order]++;
>> +	return 0;
>> +}
>> +
>> +int check_folio_orders(uint64_t vpn_start, size_t nr_pages, int pagemap_file,
>> +			int kpageflags_file, int orders[], int nr_orders)
>> +{
>> +	int vpn_orders[nr_orders];
>
> IIRC, we should avoid using VLA (variable length arrays)?

OK. I can change it to malloc.

Thanks.

>
>> +	int status;
>> +	int i;
>> +
>> +	memset(vpn_orders, 0, sizeof(int) * nr_orders);
>> +	status = gather_folio_orders(vpn_start, nr_pages, pagemap_file,
>> +				     kpageflags_file, vpn_orders, nr_orders);
>> +	if (status)
>> +		return status;
>> +
>> +	status = 0;
>> +	for (i = 0; i < nr_orders; i++)
>> +		if (vpn_orders[i] != orders[i]) {
>> +			ksft_print_msg("order %d: expected: %d got %d\n", i,
>> +				       orders[i], vpn_orders[i]);
>> +			status = -1;
>> +		}
>> +
>> +	return status;
>> +}
>> +
>>   /* 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 b55d1809debc..dee9504a6129 100644
>> --- a/tools/testing/selftests/mm/vm_util.h
>> +++ b/tools/testing/selftests/mm/vm_util.h
>> @@ -85,6 +85,8 @@ bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size);
>>   int64_t allocate_transhuge(void *ptr, int pagemap_fd);
>>   unsigned long default_huge_page_size(void);
>>   int detect_hugetlb_page_sizes(size_t sizes[], int max);
>> +int check_folio_orders(uint64_t vpn_start, size_t nr_pages, int pagemap_file,
>> +			int kpageflags_file, int orders[], int nr_orders);
>>    int uffd_register(int uffd, void *addr, uint64_t len,
>>   		  bool miss, bool wp, bool minor);


--
Best Regards,
Yan, Zi

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-07  8:45   ` Wei Yang
@ 2025-08-07 17:04     ` Zi Yan
  0 siblings, 0 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-07 17:04 UTC (permalink / raw)
  To: Wei Yang
  Cc: David Hildenbrand, linux-mm, Andrew Morton, Lorenzo Stoakes,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Shuah Khan, linux-kernel, linux-kselftest

On 7 Aug 2025, at 4:45, Wei Yang wrote:

> On Tue, Aug 05, 2025 at 10:20:43PM -0400, Zi Yan wrote:
>> Current behavior is to move to next PAGE_SIZE and split, but that makes it
>> hard to check after-split folio orders. This is a preparation patch to
>> allow more precise split_huge_page_test check in an upcoming commit.
>>
>> split_folio_to_order() part is not changed, since split_pte_mapped_thp test
>> relies on its current behavior.
>>
>> Signed-off-by: Zi Yan <ziy@nvidia.com>
>> ---
>> mm/huge_memory.c | 18 +++++++++++-------
>> 1 file changed, 11 insertions(+), 7 deletions(-)
>>
>> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
>> index 8a11c2d402d4..b2ce8ac0c5a9 100644
>> --- a/mm/huge_memory.c
>> +++ b/mm/huge_memory.c
>> @@ -4341,6 +4341,7 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
>> 		struct folio *folio;
>> 		struct address_space *mapping;
>> 		unsigned int target_order = new_order;
>> +		long nr_pages;
>>
>> 		if (!vma)
>> 			break;
>> @@ -4358,6 +4359,8 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
>> 		if (!is_transparent_hugepage(folio))
>> 			goto next;
>>
>> +		nr_pages = folio_nr_pages(folio);
>> +
>
> Could be folio_large_nr_pages()?

Sure.
>
>> 		if (!folio_test_anon(folio)) {
>> 			mapping = folio->mapping;
>> 			target_order = max(new_order,
>> @@ -4385,15 +4388,16 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
>> 		if (!folio_test_anon(folio) && folio->mapping != mapping)
>> 			goto unlock;
>>
>> -		if (in_folio_offset < 0 ||
>> -		    in_folio_offset >= folio_nr_pages(folio)) {
>> +		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
>> 			if (!split_folio_to_order(folio, target_order))
>> 				split++;
>> 		} else {
>> -			struct page *split_at = folio_page(folio,
>> -							   in_folio_offset);
>> -			if (!folio_split(folio, target_order, split_at, NULL))
>> +			struct page *split_at =
>> +				folio_page(folio, in_folio_offset);
>> +			if (!folio_split(folio, target_order, split_at, NULL)) {
>> 				split++;
>> +				addr += PAGE_SIZE * nr_pages;
>> +			}
>> 		}
>>
>> unlock:
>> @@ -4438,8 +4442,8 @@ static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,
>> 	if (IS_ERR(candidate))
>> 		goto out;
>>
>> -	pr_debug("split file-backed THPs in file: %s, page offset: [0x%lx - 0x%lx]\n",
>> -		 file_path, off_start, off_end);
>> +	pr_debug("split file-backed THPs in file: %s, page offset: [0x%lx - 0x%lx], new_order %u in_folio_offset %ld\n",
>> +		 file_path, off_start, off_end, new_order, in_folio_offset);
>>
>
> How about move this part into patch 1?

Sure. I missed it. Thanks.
>
>> 	mapping = candidate->f_mapping;
>> 	min_order = mapping_min_folio_order(mapping);
>> -- 
>> 2.47.2
>>
>
> -- 
> Wei Yang
> Help you, Help me


--
Best Regards,
Yan, Zi

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-07  8:55   ` Wei Yang
@ 2025-08-07 17:05     ` Zi Yan
  2025-08-08  3:15       ` Wei Yang
  0 siblings, 1 reply; 21+ messages in thread
From: Zi Yan @ 2025-08-07 17:05 UTC (permalink / raw)
  To: Wei Yang
  Cc: David Hildenbrand, linux-mm, Andrew Morton, Lorenzo Stoakes,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Shuah Khan, linux-kernel, linux-kselftest

On 7 Aug 2025, at 4:55, Wei Yang wrote:

> On Tue, Aug 05, 2025 at 10:20:43PM -0400, Zi Yan wrote:
> [...]
>>
>> -		if (in_folio_offset < 0 ||
>> -		    in_folio_offset >= folio_nr_pages(folio)) {
>> +		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
>> 			if (!split_folio_to_order(folio, target_order))
>> 				split++;
>> 		} else {
>> -			struct page *split_at = folio_page(folio,
>> -							   in_folio_offset);
>> -			if (!folio_split(folio, target_order, split_at, NULL))
>> +			struct page *split_at =
>> +				folio_page(folio, in_folio_offset);
>> +			if (!folio_split(folio, target_order, split_at, NULL)) {
>> 				split++;
>> +				addr += PAGE_SIZE * nr_pages;
>> +			}
>
> Are we sure addr points to the folio start?

David pointed it out. Will use addr += PAGE_SIZE * (nr_pages - 1).

--
Best Regards,
Yan, Zi

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-07 17:05     ` Zi Yan
@ 2025-08-08  3:15       ` Wei Yang
  2025-08-08 15:24         ` Zi Yan
  0 siblings, 1 reply; 21+ messages in thread
From: Wei Yang @ 2025-08-08  3:15 UTC (permalink / raw)
  To: Zi Yan
  Cc: Wei Yang, David Hildenbrand, linux-mm, Andrew Morton,
	Lorenzo Stoakes, Baolin Wang, Liam R. Howlett, Nico Pache,
	Ryan Roberts, Dev Jain, Barry Song, Vlastimil Babka,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Shuah Khan,
	linux-kernel, linux-kselftest

On Thu, Aug 07, 2025 at 01:05:09PM -0400, Zi Yan wrote:
>On 7 Aug 2025, at 4:55, Wei Yang wrote:
>
>> On Tue, Aug 05, 2025 at 10:20:43PM -0400, Zi Yan wrote:
>> [...]
>>>
>>> -		if (in_folio_offset < 0 ||
>>> -		    in_folio_offset >= folio_nr_pages(folio)) {
>>> +		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
>>> 			if (!split_folio_to_order(folio, target_order))
>>> 				split++;
>>> 		} else {
>>> -			struct page *split_at = folio_page(folio,
>>> -							   in_folio_offset);
>>> -			if (!folio_split(folio, target_order, split_at, NULL))
>>> +			struct page *split_at =
>>> +				folio_page(folio, in_folio_offset);
>>> +			if (!folio_split(folio, target_order, split_at, NULL)) {
>>> 				split++;
>>> +				addr += PAGE_SIZE * nr_pages;
>>> +			}
>>
>> Are we sure addr points to the folio start?
>
>David pointed it out. Will use addr += PAGE_SIZE * (nr_pages - 1).
>

No, let me be more clear. I am talking about the addr in next iteration. I am
talking about the addr in this round.

For an addr in the middle of 2M, we still could get the large folio if my
understanding is correct.  Then (addr + whole folio size) seems wrong.

             addr
	     |
	     v
      +-------------------+
      |                   |
      +-------------------+

Not sure this would be the case.

>--
>Best Regards,
>Yan, Zi

-- 
Wei Yang
Help you, Help me

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-08  3:15       ` Wei Yang
@ 2025-08-08 15:24         ` Zi Yan
  2025-08-08 15:44           ` Zi Yan
  0 siblings, 1 reply; 21+ messages in thread
From: Zi Yan @ 2025-08-08 15:24 UTC (permalink / raw)
  To: Wei Yang
  Cc: David Hildenbrand, linux-mm, Andrew Morton, Lorenzo Stoakes,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Shuah Khan, linux-kernel, linux-kselftest

On 7 Aug 2025, at 23:15, Wei Yang wrote:

> On Thu, Aug 07, 2025 at 01:05:09PM -0400, Zi Yan wrote:
>> On 7 Aug 2025, at 4:55, Wei Yang wrote:
>>
>>> On Tue, Aug 05, 2025 at 10:20:43PM -0400, Zi Yan wrote:
>>> [...]
>>>>
>>>> -		if (in_folio_offset < 0 ||
>>>> -		    in_folio_offset >= folio_nr_pages(folio)) {
>>>> +		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
>>>> 			if (!split_folio_to_order(folio, target_order))
>>>> 				split++;
>>>> 		} else {
>>>> -			struct page *split_at = folio_page(folio,
>>>> -							   in_folio_offset);
>>>> -			if (!folio_split(folio, target_order, split_at, NULL))
>>>> +			struct page *split_at =
>>>> +				folio_page(folio, in_folio_offset);
>>>> +			if (!folio_split(folio, target_order, split_at, NULL)) {
>>>> 				split++;
>>>> +				addr += PAGE_SIZE * nr_pages;
>>>> +			}
>>>
>>> Are we sure addr points to the folio start?
>>
>> David pointed it out. Will use addr += PAGE_SIZE * (nr_pages - 1).
>>
>
> No, let me be more clear. I am talking about the addr in next iteration. I am
> talking about the addr in this round.
>
> For an addr in the middle of 2M, we still could get the large folio if my
> understanding is correct.  Then (addr + whole folio size) seems wrong.
>
>              addr
> 	     |
> 	     v
>       +-------------------+
>       |                   |
>       +-------------------+
>
> Not sure this would be the case.

Got it. addr should be aligned up to PAGE_SIZE * nr_pages to get to the next
folio. Thanks.

--
Best Regards,
Yan, Zi

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds.
  2025-08-08 15:24         ` Zi Yan
@ 2025-08-08 15:44           ` Zi Yan
  0 siblings, 0 replies; 21+ messages in thread
From: Zi Yan @ 2025-08-08 15:44 UTC (permalink / raw)
  To: Wei Yang
  Cc: David Hildenbrand, linux-mm, Andrew Morton, Lorenzo Stoakes,
	Baolin Wang, Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain,
	Barry Song, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
	Michal Hocko, Shuah Khan, linux-kernel, linux-kselftest

On 8 Aug 2025, at 11:24, Zi Yan wrote:

> On 7 Aug 2025, at 23:15, Wei Yang wrote:
>
>> On Thu, Aug 07, 2025 at 01:05:09PM -0400, Zi Yan wrote:
>>> On 7 Aug 2025, at 4:55, Wei Yang wrote:
>>>
>>>> On Tue, Aug 05, 2025 at 10:20:43PM -0400, Zi Yan wrote:
>>>> [...]
>>>>>
>>>>> -		if (in_folio_offset < 0 ||
>>>>> -		    in_folio_offset >= folio_nr_pages(folio)) {
>>>>> +		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
>>>>> 			if (!split_folio_to_order(folio, target_order))
>>>>> 				split++;
>>>>> 		} else {
>>>>> -			struct page *split_at = folio_page(folio,
>>>>> -							   in_folio_offset);
>>>>> -			if (!folio_split(folio, target_order, split_at, NULL))
>>>>> +			struct page *split_at =
>>>>> +				folio_page(folio, in_folio_offset);
>>>>> +			if (!folio_split(folio, target_order, split_at, NULL)) {
>>>>> 				split++;
>>>>> +				addr += PAGE_SIZE * nr_pages;
>>>>> +			}
>>>>
>>>> Are we sure addr points to the folio start?
>>>
>>> David pointed it out. Will use addr += PAGE_SIZE * (nr_pages - 1).
>>>
>>
>> No, let me be more clear. I am talking about the addr in next iteration. I am
>> talking about the addr in this round.
>>
>> For an addr in the middle of 2M, we still could get the large folio if my
>> understanding is correct.  Then (addr + whole folio size) seems wrong.
>>
>>              addr
>> 	     |
>> 	     v
>>       +-------------------+
>>       |                   |
>>       +-------------------+
>>
>> Not sure this would be the case.
>
> Got it. addr should be aligned up to PAGE_SIZE * nr_pages to get to the next
> folio. Thanks.

On a second thought, this new stepping would mess up with PTE-mapped folio split.
I will drop this patch (pr_debug part will be moved to Patch 1) and change
split_huge_page_test.c instead.

--
Best Regards,
Yan, Zi

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2025-08-08 15:44 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-06  2:20 [PATCH 0/4] Better split_huge_page_test result check Zi Yan
2025-08-06  2:20 ` [PATCH 1/4] mm/huge_memory: add new_order and offset to split_huge_pages*() pr_debug Zi Yan
2025-08-06 12:42   ` David Hildenbrand
2025-08-06 16:51   ` Lorenzo Stoakes
2025-08-07  6:50   ` Baolin Wang
2025-08-06  2:20 ` [PATCH 2/4] mm/huge_memory: move to next folio after folio_split() succeeds Zi Yan
2025-08-06 12:47   ` David Hildenbrand
2025-08-06 14:29     ` Zi Yan
2025-08-07  8:45   ` Wei Yang
2025-08-07 17:04     ` Zi Yan
2025-08-07  8:55   ` Wei Yang
2025-08-07 17:05     ` Zi Yan
2025-08-08  3:15       ` Wei Yang
2025-08-08 15:24         ` Zi Yan
2025-08-08 15:44           ` Zi Yan
2025-08-06  2:20 ` [PATCH 3/4] selftests/mm: add check_folio_orders() helper Zi Yan
2025-08-07  3:00   ` wang lian
2025-08-07 17:00     ` [PATCH " Zi Yan
2025-08-07  6:49   ` Baolin Wang
2025-08-07 17:02     ` Zi Yan
2025-08-06  2:20 ` [PATCH 4/4] selftests/mm: check after-split folio orders in split_huge_page_test Zi Yan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).