After mremap(), add a check on content to see whether mremap corrupt data.
Signed-off-by: Wei Yang richard.weiyang@gmail.com
--- v2: add check on content instead of just test backed folio --- tools/testing/selftests/mm/split_huge_page_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f..229b6dcabece 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -423,10 +423,14 @@ static void split_pte_mapped_thp(void)
/* smap does not show THPs after mremap, use kpageflags instead */ thp_size = 0; - for (i = 0; i < pagesize * 4; i++) + for (i = 0; i < pagesize * 4; i++) { + if (pte_mapped[i] != (char)i) + ksft_exit_fail_msg("%ld byte corrupted\n", i); + if (i % pagesize == 0 && is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd)) thp_size++; + }
if (thp_size != 4) ksft_exit_fail_msg("Some THPs are missing during mremap\n");
After mremap(), add a check on content to see whether mremap corrupt data.
LGTM. Reviewed-by: wang lian lianux.mm@gmail.com
Best regards, wang lian
On 31.08.25 04:27, Wei Yang wrote:
Subject: "selftests/mm: verify page content after remapping PMD through PTEs"
After mremap(), add a check on content to see whether mremap corrupt data.
Signed-off-by: Wei Yang richard.weiyang@gmail.com
v2: add check on content instead of just test backed folio
I'm confused, don't we have that exact check later in the function?
Your v1 might have been better, unless I am missing something.
tools/testing/selftests/mm/split_huge_page_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f..229b6dcabece 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -423,10 +423,14 @@ static void split_pte_mapped_thp(void) /* smap does not show THPs after mremap, use kpageflags instead */ thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- if (i % pagesize == 0 && is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd)) thp_size++;
- }
if (thp_size != 4) ksft_exit_fail_msg("Some THPs are missing during mremap\n");
I'm a bit confused with this test in general.
We do a
pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
which I read as a "NOP".
Questions
(a) Will this actually do anything? Also, maybe it does now, but can't the kernel just optimize that out in the future?
(b) Is it even guaranteed that we can access > pagesize afterwards? I mean, we specify MREMAP_MAYMOVE.
I would suggest to just use mprotect/madvise to pte-map a PMD-THP.
This is, of course, independent of this patch.
I'm confused, don't we have that exact check later in the function?
Your v1 might have been better, unless I am missing something.
Hi David,
Perhaps you missed this in the v1 feedback: https://lore.kernel.org/linux-mm/E0C570E7-C4CD-4E41-9590-DDB64757CA2C@nvidia... ?
Best regards, wang lian
On 01.09.25 10:11, wang lian wrote:
I'm confused, don't we have that exact check later in the function?
Your v1 might have been better, unless I am missing something.
Hi David,
Perhaps you missed this in the v1 feedback: https://lore.kernel.org/linux-mm/E0C570E7-C4CD-4E41-9590-DDB64757CA2C@nvidia... ?
We have:
/* smap does not show THPs after mremap, use kpageflags instead */ thp_size = 0; for (i = 0; i < pagesize * 4; i++) { if (pte_mapped[i] != (char)i) ksft_exit_fail_msg("%ld byte corrupted\n", i);
if (i % pagesize == 0 && !is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd)) thp_size++; }
Sure, it's after the split, but if mremap would have corrupted the pages, surely it would still be corrupt after the mremap+split.
On Sep 1, 2025, at 16:16, David Hildenbrand david@redhat.com wrote:
On 01.09.25 10:11, wang lian wrote:
I'm confused, don't we have that exact check later in the function? Your v1 might have been better, unless I am missing something.
Hi David, Perhaps you missed this in the v1 feedback: https://lore.kernel.org/linux-mm/E0C570E7-C4CD-4E41-9590-DDB64757CA2C@nvidia... ?
We have:
/* smap does not show THPs after mremap, use kpageflags instead */ thp_size = 0; for (i = 0; i < pagesize * 4; i++) { if (pte_mapped[i] != (char)i) ksft_exit_fail_msg("%ld byte corrupted\n", i);
if (i % pagesize == 0 && !is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd)) thp_size++;
}
Sure, it's after the split, but if mremap would have corrupted the pages, surely it would still be corrupt after the mremap+split.
Yes, so I think it is correct to add this check in mremap. The check after splitting already exists
-- Cheers
David / dhildenb
Best regards, wang lian
On Mon, Sep 01, 2025 at 09:22:44AM +0200, David Hildenbrand wrote:
On 31.08.25 04:27, Wei Yang wrote:
Subject: "selftests/mm: verify page content after remapping PMD through PTEs"
After mremap(), add a check on content to see whether mremap corrupt data.
Signed-off-by: Wei Yang richard.weiyang@gmail.com
v2: add check on content instead of just test backed folio
I'm confused, don't we have that exact check later in the function?
Your v1 might have been better, unless I am missing something.
Maybe I should insist a little.
tools/testing/selftests/mm/split_huge_page_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f..229b6dcabece 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -423,10 +423,14 @@ static void split_pte_mapped_thp(void) /* smap does not show THPs after mremap, use kpageflags instead */ thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- if (i % pagesize == 0 && is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd)) thp_size++;
- } if (thp_size != 4) ksft_exit_fail_msg("Some THPs are missing during mremap\n");
I'm a bit confused with this test in general.
We do a
pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
which I read as a "NOP".
Questions
(a) Will this actually do anything? Also, maybe it does now, but can't the kernel just optimize that out in the future?
(b) Is it even guaranteed that we can access > pagesize afterwards? I mean, we specify MREMAP_MAYMOVE.
To be honest, I am not fully understand the operations here.
I would suggest to just use mprotect/madvise to pte-map a PMD-THP.
This is, of course, independent of this patch.
-- Cheers
David / dhildenb
On 1 Sep 2025, at 3:22, David Hildenbrand wrote:
On 31.08.25 04:27, Wei Yang wrote:
Subject: "selftests/mm: verify page content after remapping PMD through PTEs"
After mremap(), add a check on content to see whether mremap corrupt data.
Signed-off-by: Wei Yang richard.weiyang@gmail.com
v2: add check on content instead of just test backed folio
I'm confused, don't we have that exact check later in the function?
Your v1 might have been better, unless I am missing something.
tools/testing/selftests/mm/split_huge_page_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f..229b6dcabece 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -423,10 +423,14 @@ static void split_pte_mapped_thp(void) /* smap does not show THPs after mremap, use kpageflags instead */ thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- if (i % pagesize == 0 && is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd)) thp_size++;
- } if (thp_size != 4) ksft_exit_fail_msg("Some THPs are missing during mremap\n");
I'm a bit confused with this test in general.
We do a
pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
which I read as a "NOP".
Questions
(a) Will this actually do anything? Also, maybe it does now, but can't the kernel just optimize that out in the future?
It remaps each subpage of 4 PMD THPs into a contiguous 2MB vaddr range and perform split on that range.
(b) Is it even guaranteed that we can access > pagesize afterwards? I mean, we specify MREMAP_MAYMOVE.
I would suggest to just use mprotect/madvise to pte-map a PMD-THP.
If you want to test that, please add your own test case.
-- Best Regards, Yan, Zi
On 01.09.25 14:56, Zi Yan wrote:
On 1 Sep 2025, at 3:22, David Hildenbrand wrote:
On 31.08.25 04:27, Wei Yang wrote:
Subject: "selftests/mm: verify page content after remapping PMD through PTEs"
After mremap(), add a check on content to see whether mremap corrupt data.
Signed-off-by: Wei Yang richard.weiyang@gmail.com
v2: add check on content instead of just test backed folio
I'm confused, don't we have that exact check later in the function?
Your v1 might have been better, unless I am missing something.
tools/testing/selftests/mm/split_huge_page_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f..229b6dcabece 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -423,10 +423,14 @@ static void split_pte_mapped_thp(void) /* smap does not show THPs after mremap, use kpageflags instead */ thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
if (i % pagesize == 0 && is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd)) thp_size++;
- } if (thp_size != 4) ksft_exit_fail_msg("Some THPs are missing during mremap\n");
I'm a bit confused with this test in general.
We do a
pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
which I read as a "NOP".
Questions
(a) Will this actually do anything? Also, maybe it does now, but can't the kernel just optimize that out in the future?
It remaps each subpage of 4 PMD THPs into a contiguous 2MB vaddr range and perform split on that range.
I'm afraid I am missing the "why".
I would have thought that a "split_pte_mapped_thp" test would want to pte-map THPs to the see if they can be split.
Why is the mremap required? IOW, what exactly is the test trying to test that exceeds "split_pte_mapped_thp" ?
On 1 Sep 2025, at 9:03, David Hildenbrand wrote:
On 01.09.25 14:56, Zi Yan wrote:
On 1 Sep 2025, at 3:22, David Hildenbrand wrote:
On 31.08.25 04:27, Wei Yang wrote:
Subject: "selftests/mm: verify page content after remapping PMD through PTEs"
After mremap(), add a check on content to see whether mremap corrupt data.
Signed-off-by: Wei Yang richard.weiyang@gmail.com
v2: add check on content instead of just test backed folio
I'm confused, don't we have that exact check later in the function?
Your v1 might have been better, unless I am missing something.
tools/testing/selftests/mm/split_huge_page_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f..229b6dcabece 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -423,10 +423,14 @@ static void split_pte_mapped_thp(void) /* smap does not show THPs after mremap, use kpageflags instead */ thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
if (i % pagesize == 0 && is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd)) thp_size++;
- } if (thp_size != 4) ksft_exit_fail_msg("Some THPs are missing during mremap\n");
I'm a bit confused with this test in general.
We do a
pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
which I read as a "NOP".
Questions
(a) Will this actually do anything? Also, maybe it does now, but can't the kernel just optimize that out in the future?
It remaps each subpage of 4 PMD THPs into a contiguous 2MB vaddr range and perform split on that range.
I'm afraid I am missing the "why".
I would have thought that a "split_pte_mapped_thp" test would want to pte-map THPs to the see if they can be split.
Why is the mremap required? IOW, what exactly is the test trying to test that exceeds "split_pte_mapped_thp" ?
IMHO, it is an interesting test case for splitting a THP when only a subpage is mapped into a vaddr range and in a contiguous vaddr each page comes from different THPs. The mprotect test case you are mentioning would still have all subpages mapped by contiguous vaddrs.
But if you think both are just testing PTE-mapped THPs, feel free to replace the existing one with the mprotect test case. In addition, is_backed_by_folio() can be reverted back to its prior version, since it no longer needs to handle the case where subpages from different THPs can be mapped into a vaddr range.
-- Best Regards, Yan, Zi
(a) Will this actually do anything? Also, maybe it does now, but can't the kernel just optimize that out in the future?
It remaps each subpage of 4 PMD THPs into a contiguous 2MB vaddr range and perform split on that range.
I'm afraid I am missing the "why".
I would have thought that a "split_pte_mapped_thp" test would want to pte-map THPs to the see if they can be split.
Why is the mremap required? IOW, what exactly is the test trying to test that exceeds "split_pte_mapped_thp" ?
IMHO, it is an interesting test case for splitting a THP when only a subpage is mapped into a vaddr range and in a contiguous vaddr each page comes from different THPs.
Right. Slightly similar to just MAV_DONTNEED'ing the other PTEs and trying to split the bigger range.
Of course, if you involve more mremap, the RMAP logic of installing migration ptes will get stressed more.
So yes, there are various ways on how to stress the RMAP walk when splitting.
The mprotect test case you are mentioning would still have all subpages mapped by contiguous vaddrs.
Right, it would not stress RMAP as much.
But if you think both are just testing PTE-mapped THPs, feel free to replace the existing one with the mprotect test case. In addition, is_backed_by_folio() can be reverted back to its prior version, since it no longer needs to handle the case where subpages from different THPs can be mapped into a vaddr range.
Oh, the is_backed_by_folio() change is actually really valuable.
I think I was confused by the implementation that works on a single virtual address range with multiple different variables, questioning why we mremap at all.
I tried cleaning up that test myself and ended up with the following (it escalated a bit). If that looks cleaner to you as well, I can submit that as a patch.
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f6..aa0f0502efa06 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -390,67 +390,88 @@ static void split_pmd_thp_to_order(int order)
static void split_pte_mapped_thp(void) { - char *one_page, *pte_mapped, *pte_mapped2; - size_t len = 4 * pmd_pagesize; - uint64_t thp_size; + const size_t nr_thps = 4; + const size_t thp_area_size = nr_thps * pmd_pagesize; + const size_t page_area_size = nr_thps * pagesize; + char *thp_area, *page_area = NULL, *tmp; size_t i;
- one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE, + thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (one_page == MAP_FAILED) - ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno)); + if (thp_area == MAP_FAILED) { + ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno)); + goto out; + }
- madvise(one_page, len, MADV_HUGEPAGE); + madvise(thp_area, thp_area_size, MADV_HUGEPAGE);
- for (i = 0; i < len; i++) - one_page[i] = (char)i; + for (i = 0; i < thp_area_size; i++) + thp_area[i] = (char)i;
- if (!check_huge_anon(one_page, 4, pmd_pagesize)) - ksft_exit_fail_msg("No THP is allocated\n"); + if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) { + ksft_test_result_skip("Not all THPs allocated\n"); + goto out; + }
- /* remap the first pagesize of first THP */ - pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE); - - /* remap the Nth pagesize of Nth THP */ - for (i = 1; i < 4; i++) { - pte_mapped2 = mremap(one_page + pmd_pagesize * i + pagesize * i, - pagesize, pagesize, - MREMAP_MAYMOVE|MREMAP_FIXED, - pte_mapped + pagesize * i); - if (pte_mapped2 == MAP_FAILED) - ksft_exit_fail_msg("mremap failed: %s\n", strerror(errno)); - } - - /* smap does not show THPs after mremap, use kpageflags instead */ - thp_size = 0; - for (i = 0; i < pagesize * 4; i++) - if (i % pagesize == 0 && - is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd)) - thp_size++; - - if (thp_size != 4) - ksft_exit_fail_msg("Some THPs are missing during mremap\n"); - - /* split all remapped THPs */ - write_debugfs(PID_FMT, getpid(), (uint64_t)pte_mapped, - (uint64_t)pte_mapped + pagesize * 4, 0); - - /* smap does not show THPs after mremap, use kpageflags instead */ - thp_size = 0; - for (i = 0; i < pagesize * 4; i++) { - if (pte_mapped[i] != (char)i) - ksft_exit_fail_msg("%ld byte corrupted\n", i); + /* + * To challenge spitting code, we will mremap page[x] of the + * thp[x] into a smaller area, and trigger the split from that + * smaller area. This will end up replacing the PMD mappings in + * the thp_area by PTE mappings first, leaving the THPs unsplit. + */ + page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (page_area == MAP_FAILED) { + ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno)); + goto out; + }
- if (i % pagesize == 0 && - !is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd)) - thp_size++; + for (i = 0; i < nr_thps; i++) { + tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i, + pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED, + page_area + pagesize * i); + if (tmp != MAP_FAILED) + continue; + ksft_test_result_fail("mremap failed: %s\n", strerror(errno)); + goto out; + } + + /* + * Verify that our THPs were not split yet. Note that + * check_huge_anon() cannot be used as it checks for PMD mappings. + */ + for (i = 0; i < nr_thps; i++) { + if (is_backed_by_folio(page_area + i * pagesize, pmd_order, + pagemap_fd, kpageflags_fd)) + continue; + ksft_test_result_fail("THP %zu missing after mremap\n", i); + goto out; }
- if (thp_size) - ksft_exit_fail_msg("Still %ld THPs not split\n", thp_size); + /* Split all THPs through the remapped pages. */ + write_debugfs(PID_FMT, getpid(), (uint64_t)page_area, + (uint64_t)page_area + page_area_size, 0); + + /* Corruption during mremap or split? */ + for (i = 0; i < page_area_size; i++) { + if (page_area[i] == (char)i) + continue; + ksft_test_result_fail("%zu byte corrupted\n", i); + goto out; + } + + /* Split failed? */ + for (i = 0; i < nr_thps; i++) { + if (is_backed_by_folio(&page_area[i], 0, pagemap_fd, kpageflags_fd)) + continue; + ksft_test_result_fail("THP %zu not split\n", i); + }
ksft_test_result_pass("Split PTE-mapped huge pages successful\n"); - munmap(one_page, len); +out: + munmap(thp_area, thp_area_size); + if (page_area) + munmap(page_area, page_area_size); }
static void split_file_backed_thp(int order)
On Mon, Sep 01, 2025 at 09:10:57PM +0200, David Hildenbrand wrote:
(a) Will this actually do anything? Also, maybe it does now, but can't the kernel just optimize that out in the future?
It remaps each subpage of 4 PMD THPs into a contiguous 2MB vaddr range and perform split on that range.
I'm afraid I am missing the "why".
I would have thought that a "split_pte_mapped_thp" test would want to pte-map THPs to the see if they can be split.
Why is the mremap required? IOW, what exactly is the test trying to test that exceeds "split_pte_mapped_thp" ?
IMHO, it is an interesting test case for splitting a THP when only a subpage is mapped into a vaddr range and in a contiguous vaddr each page comes from different THPs.
Right. Slightly similar to just MAV_DONTNEED'ing the other PTEs and trying to split the bigger range.
Of course, if you involve more mremap, the RMAP logic of installing migration ptes will get stressed more.
So yes, there are various ways on how to stress the RMAP walk when splitting.
The mprotect test case you are mentioning would still have all subpages mapped by contiguous vaddrs.
Right, it would not stress RMAP as much.
But if you think both are just testing PTE-mapped THPs, feel free to replace the existing one with the mprotect test case. In addition, is_backed_by_folio() can be reverted back to its prior version, since it no longer needs to handle the case where subpages from different THPs can be mapped into a vaddr range.
Oh, the is_backed_by_folio() change is actually really valuable.
I think I was confused by the implementation that works on a single virtual address range with multiple different variables, questioning why we mremap at all.
I tried cleaning up that test myself and ended up with the following (it escalated a bit). If that looks cleaner to you as well, I can submit that as a patch.
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f6..aa0f0502efa06 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -390,67 +390,88 @@ static void split_pmd_thp_to_order(int order) static void split_pte_mapped_thp(void) {
- char *one_page, *pte_mapped, *pte_mapped2;
- size_t len = 4 * pmd_pagesize;
- uint64_t thp_size;
- const size_t nr_thps = 4;
- const size_t thp_area_size = nr_thps * pmd_pagesize;
- const size_t page_area_size = nr_thps * pagesize;
- char *thp_area, *page_area = NULL, *tmp; size_t i;
- one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE,
- thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (one_page == MAP_FAILED)
ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno));
- if (thp_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
- madvise(one_page, len, MADV_HUGEPAGE);
- madvise(thp_area, thp_area_size, MADV_HUGEPAGE);
- for (i = 0; i < len; i++)
one_page[i] = (char)i;
- for (i = 0; i < thp_area_size; i++)
thp_area[i] = (char)i;
- if (!check_huge_anon(one_page, 4, pmd_pagesize))
ksft_exit_fail_msg("No THP is allocated\n");
- if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) {
ksft_test_result_skip("Not all THPs allocated\n");
goto out;
- }
- /* remap the first pagesize of first THP */
- pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
- /* remap the Nth pagesize of Nth THP */
- for (i = 1; i < 4; i++) {
pte_mapped2 = mremap(one_page + pmd_pagesize * i + pagesize * i,
pagesize, pagesize,
MREMAP_MAYMOVE|MREMAP_FIXED,
pte_mapped + pagesize * i);
if (pte_mapped2 == MAP_FAILED)
ksft_exit_fail_msg("mremap failed: %s\n", strerror(errno));
- }
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
if (i % pagesize == 0 &&
is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd))
thp_size++;
- if (thp_size != 4)
ksft_exit_fail_msg("Some THPs are missing during mremap\n");
- /* split all remapped THPs */
- write_debugfs(PID_FMT, getpid(), (uint64_t)pte_mapped,
(uint64_t)pte_mapped + pagesize * 4, 0);
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
- page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
if (i % pagesize == 0 &&
!is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd))
thp_size++;
- for (i = 0; i < nr_thps; i++) {
tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i,
pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED,
page_area + pagesize * i);
Would this create one hole at the beginning of each 2M range and cause splitting underlining THP?
if (tmp != MAP_FAILED)
continue;
ksft_test_result_fail("mremap failed: %s\n", strerror(errno));
goto out;
- }
- /*
* Verify that our THPs were not split yet. Note that
* check_huge_anon() cannot be used as it checks for PMD mappings.
*/
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(page_area + i * pagesize, pmd_order,
pagemap_fd, kpageflags_fd))
continue;
ksft_test_result_fail("THP %zu missing after mremap\n", i);
}goto out;
- if (thp_size)
ksft_exit_fail_msg("Still %ld THPs not split\n", thp_size);
- /* Split all THPs through the remapped pages. */
- write_debugfs(PID_FMT, getpid(), (uint64_t)page_area,
(uint64_t)page_area + page_area_size, 0);
- /* Corruption during mremap or split? */
- for (i = 0; i < page_area_size; i++) {
if (page_area[i] == (char)i)
continue;
ksft_test_result_fail("%zu byte corrupted\n", i);
goto out;
- }
- /* Split failed? */
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(&page_area[i], 0, pagemap_fd, kpageflags_fd))
continue;
ksft_test_result_fail("THP %zu not split\n", i);
- } ksft_test_result_pass("Split PTE-mapped huge pages successful\n");
- munmap(one_page, len);
+out:
- munmap(thp_area, thp_area_size);
- if (page_area)
munmap(page_area, page_area_size);
} static void split_file_backed_thp(int order) -- 2.50.1
-- Cheers
David / dhildenb
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
- page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
if (i % pagesize == 0 &&
!is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd))
thp_size++;
- for (i = 0; i < nr_thps; i++) {
tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i,
pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED,
page_area + pagesize * i);
Would this create one hole at the beginning of each 2M range and cause splitting underlining THP?
Yes, it will create a hole (this also happens in the old code).
As the comment above it now states: "leaving the THPs unsplit"
There is a check verifying that after this mremap code.
On Tue, Sep 02, 2025 at 09:49:48AM +0200, David Hildenbrand wrote:
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
This confuse me a little. How about move "and trigger the split from that smaller area" to the end? So that I know mremap convert to pte-mapping and leave thp unsplit. Then we do the split.
- page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
if (i % pagesize == 0 &&
!is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd))
thp_size++;
- for (i = 0; i < nr_thps; i++) {
tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i,
pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED,
page_area + pagesize * i);
Would this create one hole at the beginning of each 2M range and cause splitting underlining THP?
Yes, it will create a hole (this also happens in the old code).
As the comment above it now states: "leaving the THPs unsplit"
There is a check verifying that after this mremap code.
Thanks for clarifying. One nit to the comment above.
On 02.09.25 10:13, Wei Yang wrote:
On Tue, Sep 02, 2025 at 09:49:48AM +0200, David Hildenbrand wrote:
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
This confuse me a little. How about move "and trigger the split from that smaller area" to the end? So that I know mremap convert to pte-mapping and leave thp unsplit. Then we do the split.
After spleeping over it, what about the following?
+ /* + * To challenge spitting code, we will mremap a single page of each + * THP (page[i] of thp[i]) in the thp_area into page_area. This will + * replace the PMD mappings in the thp_area by PTE mappings first, + * but leaving the THP unsplit, to then create a page-sized hole in + * the thp_area. + * We will then manually trigger splitting of all THPs through the + * single mremap'ed pages of each THP in the page_area. + */
On Tue, Sep 02, 2025 at 10:23:51AM +0200, David Hildenbrand wrote:
On 02.09.25 10:13, Wei Yang wrote:
On Tue, Sep 02, 2025 at 09:49:48AM +0200, David Hildenbrand wrote:
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
This confuse me a little. How about move "and trigger the split from that smaller area" to the end? So that I know mremap convert to pte-mapping and leave thp unsplit. Then we do the split.
After spleeping over it, what about the following?
/*
* To challenge spitting code, we will mremap a single page of each
* THP (page[i] of thp[i]) in the thp_area into page_area. This will
* replace the PMD mappings in the thp_area by PTE mappings first,
* but leaving the THP unsplit, to then create a page-sized hole in
* the thp_area.
* We will then manually trigger splitting of all THPs through the
* single mremap'ed pages of each THP in the page_area.
*/
Much better, thanks :-)
On Mon, Sep 01, 2025 at 09:10:57PM +0200, David Hildenbrand wrote: [...]
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f6..aa0f0502efa06 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -390,67 +390,88 @@ static void split_pmd_thp_to_order(int order) static void split_pte_mapped_thp(void) {
- char *one_page, *pte_mapped, *pte_mapped2;
- size_t len = 4 * pmd_pagesize;
- uint64_t thp_size;
- const size_t nr_thps = 4;
- const size_t thp_area_size = nr_thps * pmd_pagesize;
- const size_t page_area_size = nr_thps * pagesize;
- char *thp_area, *page_area = NULL, *tmp; size_t i;
- one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE,
- thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (one_page == MAP_FAILED)
ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno));
- if (thp_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
- madvise(one_page, len, MADV_HUGEPAGE);
- madvise(thp_area, thp_area_size, MADV_HUGEPAGE);
- for (i = 0; i < len; i++)
one_page[i] = (char)i;
- for (i = 0; i < thp_area_size; i++)
thp_area[i] = (char)i;
- if (!check_huge_anon(one_page, 4, pmd_pagesize))
ksft_exit_fail_msg("No THP is allocated\n");
- if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) {
ksft_test_result_skip("Not all THPs allocated\n");
Not sure why we skip here?
goto out;
- }
- /* remap the first pagesize of first THP */
- pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
- /* remap the Nth pagesize of Nth THP */
- for (i = 1; i < 4; i++) {
pte_mapped2 = mremap(one_page + pmd_pagesize * i + pagesize * i,
pagesize, pagesize,
MREMAP_MAYMOVE|MREMAP_FIXED,
pte_mapped + pagesize * i);
if (pte_mapped2 == MAP_FAILED)
ksft_exit_fail_msg("mremap failed: %s\n", strerror(errno));
- }
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
if (i % pagesize == 0 &&
is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd))
thp_size++;
- if (thp_size != 4)
ksft_exit_fail_msg("Some THPs are missing during mremap\n");
- /* split all remapped THPs */
- write_debugfs(PID_FMT, getpid(), (uint64_t)pte_mapped,
(uint64_t)pte_mapped + pagesize * 4, 0);
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
- page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
if (i % pagesize == 0 &&
!is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd))
thp_size++;
- for (i = 0; i < nr_thps; i++) {
tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i,
pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED,
page_area + pagesize * i);
if (tmp != MAP_FAILED)
continue;
ksft_test_result_fail("mremap failed: %s\n", strerror(errno));
goto out;
- }
- /*
* Verify that our THPs were not split yet. Note that
* check_huge_anon() cannot be used as it checks for PMD mappings.
*/
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(page_area + i * pagesize, pmd_order,
pagemap_fd, kpageflags_fd))
continue;
ksft_test_result_fail("THP %zu missing after mremap\n", i);
}goto out;
- if (thp_size)
ksft_exit_fail_msg("Still %ld THPs not split\n", thp_size);
- /* Split all THPs through the remapped pages. */
- write_debugfs(PID_FMT, getpid(), (uint64_t)page_area,
(uint64_t)page_area + page_area_size, 0);
- /* Corruption during mremap or split? */
- for (i = 0; i < page_area_size; i++) {
if (page_area[i] == (char)i)
continue;
ksft_test_result_fail("%zu byte corrupted\n", i);
goto out;
- }
- /* Split failed? */
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(&page_area[i], 0, pagemap_fd, kpageflags_fd))
I guess we want to check (page_area + i * pagesize) here?
continue;
ksft_test_result_fail("THP %zu not split\n", i);
- } ksft_test_result_pass("Split PTE-mapped huge pages successful\n");
- munmap(one_page, len);
+out:
- munmap(thp_area, thp_area_size);
- if (page_area)
munmap(page_area, page_area_size);
} static void split_file_backed_thp(int order) -- 2.50.1
-- Cheers
David / dhildenb
On 02.09.25 10:16, Wei Yang wrote:
On Mon, Sep 01, 2025 at 09:10:57PM +0200, David Hildenbrand wrote: [...]
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f6..aa0f0502efa06 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -390,67 +390,88 @@ static void split_pmd_thp_to_order(int order) static void split_pte_mapped_thp(void) {
- char *one_page, *pte_mapped, *pte_mapped2;
- size_t len = 4 * pmd_pagesize;
- uint64_t thp_size;
- const size_t nr_thps = 4;
- const size_t thp_area_size = nr_thps * pmd_pagesize;
- const size_t page_area_size = nr_thps * pagesize;
- char *thp_area, *page_area = NULL, *tmp; size_t i;
- one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE,
- thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (one_page == MAP_FAILED)
ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno));
- if (thp_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
- madvise(one_page, len, MADV_HUGEPAGE);
- madvise(thp_area, thp_area_size, MADV_HUGEPAGE);
- for (i = 0; i < len; i++)
one_page[i] = (char)i;
- for (i = 0; i < thp_area_size; i++)
thp_area[i] = (char)i;
- if (!check_huge_anon(one_page, 4, pmd_pagesize))
ksft_exit_fail_msg("No THP is allocated\n");
- if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) {
ksft_test_result_skip("Not all THPs allocated\n");
Not sure why we skip here?
We usually don't want tests to fail simply because our memory is fragmented.
If I'm going to send this I'll comment on all changes in the patch description.
[...]
- /* Split failed? */
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(&page_area[i], 0, pagemap_fd, kpageflags_fd))
I guess we want to check (page_area + i * pagesize) here?
yes!
On 1 Sep 2025, at 15:10, David Hildenbrand wrote:
(a) Will this actually do anything? Also, maybe it does now, but can't the kernel just optimize that out in the future?
It remaps each subpage of 4 PMD THPs into a contiguous 2MB vaddr range and perform split on that range.
I'm afraid I am missing the "why".
I would have thought that a "split_pte_mapped_thp" test would want to pte-map THPs to the see if they can be split.
Why is the mremap required? IOW, what exactly is the test trying to test that exceeds "split_pte_mapped_thp" ?
IMHO, it is an interesting test case for splitting a THP when only a subpage is mapped into a vaddr range and in a contiguous vaddr each page comes from different THPs.
Right. Slightly similar to just MAV_DONTNEED'ing the other PTEs and trying to split the bigger range.
Of course, if you involve more mremap, the RMAP logic of installing migration ptes will get stressed more.
So yes, there are various ways on how to stress the RMAP walk when splitting.
The mprotect test case you are mentioning would still have all subpages mapped by contiguous vaddrs.
Right, it would not stress RMAP as much.
But if you think both are just testing PTE-mapped THPs, feel free to replace the existing one with the mprotect test case. In addition, is_backed_by_folio() can be reverted back to its prior version, since it no longer needs to handle the case where subpages from different THPs can be mapped into a vaddr range.
Oh, the is_backed_by_folio() change is actually really valuable.
I think I was confused by the implementation that works on a single virtual address range with multiple different variables, questioning why we mremap at all.
I tried cleaning up that test myself and ended up with the following (it escalated a bit). If that looks cleaner to you as well, I can submit that as a patch.
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 10ae65ea032f6..aa0f0502efa06 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -390,67 +390,88 @@ static void split_pmd_thp_to_order(int order) static void split_pte_mapped_thp(void) {
- char *one_page, *pte_mapped, *pte_mapped2;
- size_t len = 4 * pmd_pagesize;
- uint64_t thp_size;
- const size_t nr_thps = 4;
- const size_t thp_area_size = nr_thps * pmd_pagesize;
- const size_t page_area_size = nr_thps * pagesize;
- char *thp_area, *page_area = NULL, *tmp; size_t i;
- one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE,
- thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (one_page == MAP_FAILED)
ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno));
- if (thp_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
thp_area mmap failed and out label will try to munmap MAP_FAILED, which is (void *) -1. munmap will fail with -EINVAL.
- }
- madvise(one_page, len, MADV_HUGEPAGE);
- madvise(thp_area, thp_area_size, MADV_HUGEPAGE);
- for (i = 0; i < len; i++)
one_page[i] = (char)i;
- for (i = 0; i < thp_area_size; i++)
thp_area[i] = (char)i;
- if (!check_huge_anon(one_page, 4, pmd_pagesize))
ksft_exit_fail_msg("No THP is allocated\n");
- if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) {
ksft_test_result_skip("Not all THPs allocated\n");
goto out;
- }
- /* remap the first pagesize of first THP */
- pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
- /* remap the Nth pagesize of Nth THP */
- for (i = 1; i < 4; i++) {
pte_mapped2 = mremap(one_page + pmd_pagesize * i + pagesize * i,
pagesize, pagesize,
MREMAP_MAYMOVE|MREMAP_FIXED,
pte_mapped + pagesize * i);
if (pte_mapped2 == MAP_FAILED)
ksft_exit_fail_msg("mremap failed: %s\n", strerror(errno));
- }
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
if (i % pagesize == 0 &&
is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd))
thp_size++;
- if (thp_size != 4)
ksft_exit_fail_msg("Some THPs are missing during mremap\n");
- /* split all remapped THPs */
- write_debugfs(PID_FMT, getpid(), (uint64_t)pte_mapped,
(uint64_t)pte_mapped + pagesize * 4, 0);
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
- page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
if (i % pagesize == 0 &&
!is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd))
thp_size++;
- for (i = 0; i < nr_thps; i++) {
tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i,
pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED,
page_area + pagesize * i);
if (tmp != MAP_FAILED)
continue;
ksft_test_result_fail("mremap failed: %s\n", strerror(errno));
goto out;
- }
- /*
* Verify that our THPs were not split yet. Note that
* check_huge_anon() cannot be used as it checks for PMD mappings.
*/
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(page_area + i * pagesize, pmd_order,
pagemap_fd, kpageflags_fd))
continue;
ksft_test_result_fail("THP %zu missing after mremap\n", i);
}goto out;
- if (thp_size)
ksft_exit_fail_msg("Still %ld THPs not split\n", thp_size);
- /* Split all THPs through the remapped pages. */
- write_debugfs(PID_FMT, getpid(), (uint64_t)page_area,
(uint64_t)page_area + page_area_size, 0);
- /* Corruption during mremap or split? */
- for (i = 0; i < page_area_size; i++) {
if (page_area[i] == (char)i)
continue;
ksft_test_result_fail("%zu byte corrupted\n", i);
goto out;
- }
- /* Split failed? */
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(&page_area[i], 0, pagemap_fd, kpageflags_fd))
page_area + i * pagesize, like Wei pointed out in another email.
continue;
ksft_test_result_fail("THP %zu not split\n", i);
- } ksft_test_result_pass("Split PTE-mapped huge pages successful\n");
- munmap(one_page, len);
+out:
- munmap(thp_area, thp_area_size);
- if (page_area)
munmap(page_area, page_area_size);
} static void split_file_backed_thp(int order) -- 2.50.1
Otherwise, LGTM. With all the changes in this email and other email, feel free to add Reviewed-by: Zi Yan ziy@nvidia.com when you send it out formally.
Thank you for cleaning this up.
Best Regards, Yan, Zi
[...]
@@ -390,67 +390,88 @@ static void split_pmd_thp_to_order(int order) static void split_pte_mapped_thp(void) {
- char *one_page, *pte_mapped, *pte_mapped2;
- size_t len = 4 * pmd_pagesize;
- uint64_t thp_size;
- const size_t nr_thps = 4;
- const size_t thp_area_size = nr_thps * pmd_pagesize;
- const size_t page_area_size = nr_thps * pagesize;
- char *thp_area, *page_area = NULL, *tmp; size_t i;
- one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE,
- thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (one_page == MAP_FAILED)
ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno));
- if (thp_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
thp_area mmap failed and out label will try to munmap MAP_FAILED, which is (void *) -1. munmap will fail with -EINVAL.
Indeed, should just be a "return;"
- }
- madvise(one_page, len, MADV_HUGEPAGE);
- madvise(thp_area, thp_area_size, MADV_HUGEPAGE);
- for (i = 0; i < len; i++)
one_page[i] = (char)i;
- for (i = 0; i < thp_area_size; i++)
thp_area[i] = (char)i;
- if (!check_huge_anon(one_page, 4, pmd_pagesize))
ksft_exit_fail_msg("No THP is allocated\n");
- if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) {
ksft_test_result_skip("Not all THPs allocated\n");
goto out;
- }
- /* remap the first pagesize of first THP */
- pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
- /* remap the Nth pagesize of Nth THP */
- for (i = 1; i < 4; i++) {
pte_mapped2 = mremap(one_page + pmd_pagesize * i + pagesize * i,
pagesize, pagesize,
MREMAP_MAYMOVE|MREMAP_FIXED,
pte_mapped + pagesize * i);
if (pte_mapped2 == MAP_FAILED)
ksft_exit_fail_msg("mremap failed: %s\n", strerror(errno));
- }
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
if (i % pagesize == 0 &&
is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd))
thp_size++;
- if (thp_size != 4)
ksft_exit_fail_msg("Some THPs are missing during mremap\n");
- /* split all remapped THPs */
- write_debugfs(PID_FMT, getpid(), (uint64_t)pte_mapped,
(uint64_t)pte_mapped + pagesize * 4, 0);
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
- page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
if (i % pagesize == 0 &&
!is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd))
thp_size++;
- for (i = 0; i < nr_thps; i++) {
tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i,
pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED,
page_area + pagesize * i);
if (tmp != MAP_FAILED)
continue;
ksft_test_result_fail("mremap failed: %s\n", strerror(errno));
goto out;
- }
- /*
* Verify that our THPs were not split yet. Note that
* check_huge_anon() cannot be used as it checks for PMD mappings.
*/
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(page_area + i * pagesize, pmd_order,
pagemap_fd, kpageflags_fd))
continue;
ksft_test_result_fail("THP %zu missing after mremap\n", i);
}goto out;
- if (thp_size)
ksft_exit_fail_msg("Still %ld THPs not split\n", thp_size);
- /* Split all THPs through the remapped pages. */
- write_debugfs(PID_FMT, getpid(), (uint64_t)page_area,
(uint64_t)page_area + page_area_size, 0);
- /* Corruption during mremap or split? */
- for (i = 0; i < page_area_size; i++) {
if (page_area[i] == (char)i)
continue;
ksft_test_result_fail("%zu byte corrupted\n", i);
goto out;
- }
- /* Split failed? */
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(&page_area[i], 0, pagemap_fd, kpageflags_fd))
page_area + i * pagesize, like Wei pointed out in another email.
continue;
ksft_test_result_fail("THP %zu not split\n", i);
- } ksft_test_result_pass("Split PTE-mapped huge pages successful\n");
- munmap(one_page, len);
+out:
- munmap(thp_area, thp_area_size);
- if (page_area)
} static void split_file_backed_thp(int order)munmap(page_area, page_area_size);
-- 2.50.1
Otherwise, LGTM. With all the changes in this email and other email, feel free to add Reviewed-by: Zi Yan ziy@nvidia.com when you send it out formally.
Thanks!
I'm currently chasing why I keep getting temporary
Bail out! Some THPs are missing during mremap
Already on the old test. Something doesn't work quite right as it seems.
On 2 Sep 2025, at 11:28, David Hildenbrand wrote:
[...]
@@ -390,67 +390,88 @@ static void split_pmd_thp_to_order(int order) static void split_pte_mapped_thp(void) {
- char *one_page, *pte_mapped, *pte_mapped2;
- size_t len = 4 * pmd_pagesize;
- uint64_t thp_size;
- const size_t nr_thps = 4;
- const size_t thp_area_size = nr_thps * pmd_pagesize;
- const size_t page_area_size = nr_thps * pagesize;
- char *thp_area, *page_area = NULL, *tmp; size_t i;
- one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE,
- thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (one_page == MAP_FAILED)
ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno));
- if (thp_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
thp_area mmap failed and out label will try to munmap MAP_FAILED, which is (void *) -1. munmap will fail with -EINVAL.
Indeed, should just be a "return;"
- }
- madvise(one_page, len, MADV_HUGEPAGE);
- madvise(thp_area, thp_area_size, MADV_HUGEPAGE);
- for (i = 0; i < len; i++)
one_page[i] = (char)i;
- for (i = 0; i < thp_area_size; i++)
thp_area[i] = (char)i;
- if (!check_huge_anon(one_page, 4, pmd_pagesize))
ksft_exit_fail_msg("No THP is allocated\n");
- if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) {
ksft_test_result_skip("Not all THPs allocated\n");
goto out;
- }
- /* remap the first pagesize of first THP */
- pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
- /* remap the Nth pagesize of Nth THP */
- for (i = 1; i < 4; i++) {
pte_mapped2 = mremap(one_page + pmd_pagesize * i + pagesize * i,
pagesize, pagesize,
MREMAP_MAYMOVE|MREMAP_FIXED,
pte_mapped + pagesize * i);
if (pte_mapped2 == MAP_FAILED)
ksft_exit_fail_msg("mremap failed: %s\n", strerror(errno));
- }
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
if (i % pagesize == 0 &&
is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd))
thp_size++;
- if (thp_size != 4)
ksft_exit_fail_msg("Some THPs are missing during mremap\n");
- /* split all remapped THPs */
- write_debugfs(PID_FMT, getpid(), (uint64_t)pte_mapped,
(uint64_t)pte_mapped + pagesize * 4, 0);
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
- page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
if (i % pagesize == 0 &&
!is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd))
thp_size++;
- for (i = 0; i < nr_thps; i++) {
tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i,
pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED,
page_area + pagesize * i);
if (tmp != MAP_FAILED)
continue;
ksft_test_result_fail("mremap failed: %s\n", strerror(errno));
goto out;
- }
- /*
* Verify that our THPs were not split yet. Note that
* check_huge_anon() cannot be used as it checks for PMD mappings.
*/
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(page_area + i * pagesize, pmd_order,
pagemap_fd, kpageflags_fd))
continue;
ksft_test_result_fail("THP %zu missing after mremap\n", i);
}goto out;
- if (thp_size)
ksft_exit_fail_msg("Still %ld THPs not split\n", thp_size);
- /* Split all THPs through the remapped pages. */
- write_debugfs(PID_FMT, getpid(), (uint64_t)page_area,
(uint64_t)page_area + page_area_size, 0);
- /* Corruption during mremap or split? */
- for (i = 0; i < page_area_size; i++) {
if (page_area[i] == (char)i)
continue;
ksft_test_result_fail("%zu byte corrupted\n", i);
goto out;
- }
- /* Split failed? */
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(&page_area[i], 0, pagemap_fd, kpageflags_fd))
page_area + i * pagesize, like Wei pointed out in another email.
continue;
ksft_test_result_fail("THP %zu not split\n", i);
- } ksft_test_result_pass("Split PTE-mapped huge pages successful\n");
- munmap(one_page, len);
+out:
- munmap(thp_area, thp_area_size);
- if (page_area)
} static void split_file_backed_thp(int order)munmap(page_area, page_area_size);
-- 2.50.1
Otherwise, LGTM. With all the changes in this email and other email, feel free to add Reviewed-by: Zi Yan ziy@nvidia.com when you send it out formally.
Thanks!
I'm currently chasing why I keep getting temporary
Bail out! Some THPs are missing during mremap
Already on the old test. Something doesn't work quite right as it seems.
Did you also see “Failed to get folio info”?
If pageflags_get() cannot read kpageflags content, is_backed_by_folio() would not be able to detect a THP.
Best Regards, Yan, Zi
On 02.09.25 17:28, David Hildenbrand wrote:
[...]
@@ -390,67 +390,88 @@ static void split_pmd_thp_to_order(int order) static void split_pte_mapped_thp(void) {
- char *one_page, *pte_mapped, *pte_mapped2;
- size_t len = 4 * pmd_pagesize;
- uint64_t thp_size;
- const size_t nr_thps = 4;
- const size_t thp_area_size = nr_thps * pmd_pagesize;
- const size_t page_area_size = nr_thps * pagesize;
- char *thp_area, *page_area = NULL, *tmp; size_t i;
- one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE,
- thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (one_page == MAP_FAILED)
ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno));
- if (thp_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
thp_area mmap failed and out label will try to munmap MAP_FAILED, which is (void *) -1. munmap will fail with -EINVAL.
Indeed, should just be a "return;"
- }
- madvise(one_page, len, MADV_HUGEPAGE);
- madvise(thp_area, thp_area_size, MADV_HUGEPAGE);
- for (i = 0; i < len; i++)
one_page[i] = (char)i;
- for (i = 0; i < thp_area_size; i++)
thp_area[i] = (char)i;
- if (!check_huge_anon(one_page, 4, pmd_pagesize))
ksft_exit_fail_msg("No THP is allocated\n");
- if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) {
ksft_test_result_skip("Not all THPs allocated\n");
goto out;
- }
- /* remap the first pagesize of first THP */
- pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
- /* remap the Nth pagesize of Nth THP */
- for (i = 1; i < 4; i++) {
pte_mapped2 = mremap(one_page + pmd_pagesize * i + pagesize * i,
pagesize, pagesize,
MREMAP_MAYMOVE|MREMAP_FIXED,
pte_mapped + pagesize * i);
if (pte_mapped2 == MAP_FAILED)
ksft_exit_fail_msg("mremap failed: %s\n", strerror(errno));
- }
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
if (i % pagesize == 0 &&
is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd))
thp_size++;
- if (thp_size != 4)
ksft_exit_fail_msg("Some THPs are missing during mremap\n");
- /* split all remapped THPs */
- write_debugfs(PID_FMT, getpid(), (uint64_t)pte_mapped,
(uint64_t)pte_mapped + pagesize * 4, 0);
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
- page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
if (i % pagesize == 0 &&
!is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd))
thp_size++;
- for (i = 0; i < nr_thps; i++) {
tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i,
pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED,
page_area + pagesize * i);
if (tmp != MAP_FAILED)
continue;
ksft_test_result_fail("mremap failed: %s\n", strerror(errno));
goto out;
- }
- /*
* Verify that our THPs were not split yet. Note that
* check_huge_anon() cannot be used as it checks for PMD mappings.
*/
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(page_area + i * pagesize, pmd_order,
pagemap_fd, kpageflags_fd))
continue;
ksft_test_result_fail("THP %zu missing after mremap\n", i);
}goto out;
- if (thp_size)
ksft_exit_fail_msg("Still %ld THPs not split\n", thp_size);
- /* Split all THPs through the remapped pages. */
- write_debugfs(PID_FMT, getpid(), (uint64_t)page_area,
(uint64_t)page_area + page_area_size, 0);
- /* Corruption during mremap or split? */
- for (i = 0; i < page_area_size; i++) {
if (page_area[i] == (char)i)
continue;
ksft_test_result_fail("%zu byte corrupted\n", i);
goto out;
- }
- /* Split failed? */
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(&page_area[i], 0, pagemap_fd, kpageflags_fd))
page_area + i * pagesize, like Wei pointed out in another email.
continue;
ksft_test_result_fail("THP %zu not split\n", i);
- } ksft_test_result_pass("Split PTE-mapped huge pages successful\n");
- munmap(one_page, len);
+out:
- munmap(thp_area, thp_area_size);
- if (page_area)
} static void split_file_backed_thp(int order)munmap(page_area, page_area_size);
-- 2.50.1
Otherwise, LGTM. With all the changes in this email and other email, feel free to add Reviewed-by: Zi Yan ziy@nvidia.com when you send it out formally.
Thanks!
I'm currently chasing why I keep getting temporary
Bail out! Some THPs are missing during mremap
Already on the old test. Something doesn't work quite right as it seems.
Ah, I think I know why:
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index c94fd64066ef6..4051a5c98a97c 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -95,7 +95,7 @@ static bool is_backed_by_folio(char *vaddr, int order, int pagemap_fd, return true;
/* this folio is bigger than the given order */ - if (pfn_flags & (KPF_THP | KPF_COMPOUND_TAIL)) + if (pfn_flags & (KPF_THP | KPF_COMPOUND_TAIL) == KPF_THP | KPF_COMPOUND_TAIL) return false;
return true;
Let me test with that.
On 2 Sep 2025, at 11:40, David Hildenbrand wrote:
On 02.09.25 17:28, David Hildenbrand wrote:
[...]
@@ -390,67 +390,88 @@ static void split_pmd_thp_to_order(int order) static void split_pte_mapped_thp(void) {
- char *one_page, *pte_mapped, *pte_mapped2;
- size_t len = 4 * pmd_pagesize;
- uint64_t thp_size;
- const size_t nr_thps = 4;
- const size_t thp_area_size = nr_thps * pmd_pagesize;
- const size_t page_area_size = nr_thps * pagesize;
- char *thp_area, *page_area = NULL, *tmp; size_t i;
- one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE,
- thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (one_page == MAP_FAILED)
ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno));
- if (thp_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
thp_area mmap failed and out label will try to munmap MAP_FAILED, which is (void *) -1. munmap will fail with -EINVAL.
Indeed, should just be a "return;"
- }
- madvise(one_page, len, MADV_HUGEPAGE);
- madvise(thp_area, thp_area_size, MADV_HUGEPAGE);
- for (i = 0; i < len; i++)
one_page[i] = (char)i;
- for (i = 0; i < thp_area_size; i++)
thp_area[i] = (char)i;
- if (!check_huge_anon(one_page, 4, pmd_pagesize))
ksft_exit_fail_msg("No THP is allocated\n");
- if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) {
ksft_test_result_skip("Not all THPs allocated\n");
goto out;
- }
- /* remap the first pagesize of first THP */
- pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE);
- /* remap the Nth pagesize of Nth THP */
- for (i = 1; i < 4; i++) {
pte_mapped2 = mremap(one_page + pmd_pagesize * i + pagesize * i,
pagesize, pagesize,
MREMAP_MAYMOVE|MREMAP_FIXED,
pte_mapped + pagesize * i);
if (pte_mapped2 == MAP_FAILED)
ksft_exit_fail_msg("mremap failed: %s\n", strerror(errno));
- }
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++)
if (i % pagesize == 0 &&
is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd))
thp_size++;
- if (thp_size != 4)
ksft_exit_fail_msg("Some THPs are missing during mremap\n");
- /* split all remapped THPs */
- write_debugfs(PID_FMT, getpid(), (uint64_t)pte_mapped,
(uint64_t)pte_mapped + pagesize * 4, 0);
- /* smap does not show THPs after mremap, use kpageflags instead */
- thp_size = 0;
- for (i = 0; i < pagesize * 4; i++) {
if (pte_mapped[i] != (char)i)
ksft_exit_fail_msg("%ld byte corrupted\n", i);
- /*
* To challenge spitting code, we will mremap page[x] of the
* thp[x] into a smaller area, and trigger the split from that
* smaller area. This will end up replacing the PMD mappings in
* the thp_area by PTE mappings first, leaving the THPs unsplit.
*/
- page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (page_area == MAP_FAILED) {
ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno));
goto out;
- }
if (i % pagesize == 0 &&
!is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd))
thp_size++;
- for (i = 0; i < nr_thps; i++) {
tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i,
pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED,
page_area + pagesize * i);
if (tmp != MAP_FAILED)
continue;
ksft_test_result_fail("mremap failed: %s\n", strerror(errno));
goto out;
- }
- /*
* Verify that our THPs were not split yet. Note that
* check_huge_anon() cannot be used as it checks for PMD mappings.
*/
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(page_area + i * pagesize, pmd_order,
pagemap_fd, kpageflags_fd))
continue;
ksft_test_result_fail("THP %zu missing after mremap\n", i);
}goto out;
- if (thp_size)
ksft_exit_fail_msg("Still %ld THPs not split\n", thp_size);
- /* Split all THPs through the remapped pages. */
- write_debugfs(PID_FMT, getpid(), (uint64_t)page_area,
(uint64_t)page_area + page_area_size, 0);
- /* Corruption during mremap or split? */
- for (i = 0; i < page_area_size; i++) {
if (page_area[i] == (char)i)
continue;
ksft_test_result_fail("%zu byte corrupted\n", i);
goto out;
- }
- /* Split failed? */
- for (i = 0; i < nr_thps; i++) {
if (is_backed_by_folio(&page_area[i], 0, pagemap_fd, kpageflags_fd))
page_area + i * pagesize, like Wei pointed out in another email.
continue;
ksft_test_result_fail("THP %zu not split\n", i);
- } ksft_test_result_pass("Split PTE-mapped huge pages successful\n");
- munmap(one_page, len);
+out:
- munmap(thp_area, thp_area_size);
- if (page_area)
} static void split_file_backed_thp(int order)munmap(page_area, page_area_size);
-- 2.50.1
Otherwise, LGTM. With all the changes in this email and other email, feel free to add Reviewed-by: Zi Yan ziy@nvidia.com when you send it out formally.
Thanks!
I'm currently chasing why I keep getting temporary
Bail out! Some THPs are missing during mremap
Already on the old test. Something doesn't work quite right as it seems.
Ah, I think I know why:
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index c94fd64066ef6..4051a5c98a97c 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -95,7 +95,7 @@ static bool is_backed_by_folio(char *vaddr, int order, int pagemap_fd, return true; /* this folio is bigger than the given order */
if (pfn_flags & (KPF_THP | KPF_COMPOUND_TAIL))
if (pfn_flags & (KPF_THP | KPF_COMPOUND_TAIL) == KPF_THP | KPF_COMPOUND_TAIL) return false; return true;
Let me test with that.
Oh, so if next page is a THP head, this will report a false negative result.
Best Regards, Yan, Zi
linux-kselftest-mirror@lists.linaro.org