Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 9 May 2026, at 3:51, David Hildenbrand (Arm) wrote:
> On 5/6/26 15:11, Zi Yan wrote:
>> On 4 May 2026, at 12:23, Nico Pache wrote:
>>
>>> On 4/29/26 9:35 AM, Zi Yan wrote:
Change the requirement to a file system with large folio support and the
supported order needs to include PMD_ORDER.
Also add tests of opening a file with read write permission and populating
folios with writes. Reuse the XFS image from split_huge_page_test.
Signed-off-by: Zi Yan
---
tools/testing/selftests/mm/khugepaged.c | 131 +++---
tools/testing/selftests/mm/run_vmtests.sh | 12 +-
2 files changed, 102 insertions(+), 41 deletions(-)
diff --git a/tools/testing/selftests/mm/khugepaged.c
b/tools/testing/selftests/mm/khugepaged.c
index a6bb9d50363d2..80b913185c643 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -49,7 +49,8 @@ struct mem_ops {
const char *name;
};
-static struct mem_ops *file_ops;
+static struct mem_ops *read_only_file_ops;
+static struct mem_ops *read_write_file_ops;
static struct mem_ops *anon_ops;
static struct mem_ops *shmem_ops;
@@ -112,7 +113,8 @@ static void restore_settings(int sig)
static void save_settings(void)
{
printf("Save THP and khugepaged settings...");
- if (file_ops && finfo.type == VMA_FILE)
+ if ((read_only_file_ops || read_write_file_ops) &&
+ finfo.type == VMA_FILE)
thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path);
thp_save_settings();
@@ -364,11 +366,14 @@ static bool anon_check_huge(void *addr, int
nr_hpages)
return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
}
-static void *file_setup_area(int nr_hpages)
+static void *file_setup_area_common(int nr_hpages, bool read_only)
{
int fd;
void *p;
unsigned long size;
+ int open_opt = read_only ? O_RDONLY : O_RDWR;
+ int mmap_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE);
+ int mmap_opt = read_only ? MAP_PRIVATE : MAP_SHARED;
unlink(finfo.path); /* Cleanup from previous failed tests */
printf("Creating %s for collapse%s...", finfo.path,
@@ -399,14 +404,15 @@ static void *file_setup_area(int nr_hpages)
munmap(p, size);
success("OK");
- printf("Opening %s read only for collapse...", finfo.path);
- finfo.fd = open(finfo.path, O_RDONLY, 777);
+ printf("Opening %s %s for collapse...", finfo.path,
+ read_only ? "read only" : "read-write");
+ finfo.fd = open(finfo.path, open_opt, 777);
if (finfo.fd < 0) {
perror("open()");
exit(EXIT_FAILURE);
}
- p = mmap(BASE_ADDR, size, PROT_READ,
- MAP_PRIVATE, finfo.fd, 0);
+ p = mmap(BASE_ADDR, size, mmap_prot,
+ mmap_opt, finfo.fd, 0);
if (p == MAP_FAILED || p != BASE_ADDR) {
perror("mmap()");
exit(EXIT_FAILURE);
@@ -418,6 +424,16 @@ static void *file_setup_area(int nr_hpages)
return p;
}
+static void *file_setup_read_only_area(int nr_hpages)
+{
+ return file_setup_area_common(nr_hpages, /* read_only= */ true);
+}
+
+static void *file_setup_read_write_area(int nr_hpages)
+{
+ return file_setup_area_common(nr_hpages, /* read_only= */ false);
+}
+
static void file_cleanup_area(void *p, unsigned long size)
{
munmap(p, size);
@@ -425,14 +441,25 @@ static void file_cleanup_area(void *p, unsigned long
size)
unlink(finfo.path);
}
-static void file_fault(void *p, unsigned long start, unsigned long end)
+static void file_fault_common(void *p, unsigned long start, unsigned long
end,
+ int madv_ops)
{
- if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
+ if (madvise(((char *)p) + start, end - start, madv_ops)) {
perror("madvise(MADV_POPULATE_READ");
exit(EXIT_FAILURE);
}
}
+static void file_fault_read(void *p, unsigned long start, unsigned long
end)
+{
+ file_fault_common(p, start, end, MADV_POPULATE_READ);
+}
+
+static void file_fault_write(void *p, unsigned long start, unsigned long
end)
+{
+ file_fault_common(p, start, end, MADV_POPULATE_WRITE);
+}
+
static bool file_check_huge(void *addr, int nr_hpages)
{
switch (finfo.type) {
@@ -488,10 +515,18 @@ static struct mem_ops __anon_ops = {
.name = "anon",
};
-static struct mem_ops __file_ops = {
- .setup_area = &file_setup_area,
+static struct mem_ops __read_only_file_ops = {
+ .setup_area = &file_setup_read_only_area,
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 9 May 2026, at 4:06, David Hildenbrand (Arm) wrote:
> On 4/29/26 17:35, Zi Yan wrote:
>> Change the requirement to a file system with large folio support and the
>> supported order needs to include PMD_ORDER.
>>
>> Also add tests of opening a file with read write permission and populating
>> folios with writes. Reuse the XFS image from split_huge_page_test.
>>
>> Signed-off-by: Zi Yan
>> ---
>> tools/testing/selftests/mm/khugepaged.c | 131 +++---
>> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
>> 2 files changed, 102 insertions(+), 41 deletions(-)
>>
>> diff --git a/tools/testing/selftests/mm/khugepaged.c
>> b/tools/testing/selftests/mm/khugepaged.c
>> index a6bb9d50363d2..80b913185c643 100644
>> --- a/tools/testing/selftests/mm/khugepaged.c
>> +++ b/tools/testing/selftests/mm/khugepaged.c
>> @@ -49,7 +49,8 @@ struct mem_ops {
>> const char *name;
>> };
>>
>> -static struct mem_ops *file_ops;
>> +static struct mem_ops *read_only_file_ops;
>> +static struct mem_ops *read_write_file_ops;
>> static struct mem_ops *anon_ops;
>> static struct mem_ops *shmem_ops;
>>
>> @@ -112,7 +113,8 @@ static void restore_settings(int sig)
>> static void save_settings(void)
>> {
>> printf("Save THP and khugepaged settings...");
>> -if (file_ops && finfo.type == VMA_FILE)
>> +if ((read_only_file_ops || read_write_file_ops) &&
>> +finfo.type == VMA_FILE)
>> thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path);
>> thp_save_settings();
>>
>> @@ -364,11 +366,14 @@ static bool anon_check_huge(void *addr, int nr_hpages)
>> return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
>> }
>>
>> -static void *file_setup_area(int nr_hpages)
>> +static void *file_setup_area_common(int nr_hpages, bool read_only)
>> {
>> int fd;
>> void *p;
>> unsigned long size;
>> +int open_opt = read_only ? O_RDONLY : O_RDWR;
>> +int mmap_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE);
>> +int mmap_opt = read_only ? MAP_PRIVATE : MAP_SHARED;
>
> Can all be const and read better at the very top of the list.
>
> Why do we go from private->shared depending on "read_only" parameter? I'd
> assume
> we'd want to test MAP_SHARED for both (read-only + read-write)?
The original code used MAP_PRIVATE, but I agree that MAP_SHARED works.
Will change it.
>
>
>>
>> unlink(finfo.path); /* Cleanup from previous failed tests */
>> printf("Creating %s for collapse%s...", finfo.path,
>> @@ -399,14 +404,15 @@ static void *file_setup_area(int nr_hpages)
>> munmap(p, size);
>> success("OK");
>>
>> -printf("Opening %s read only for collapse...", finfo.path);
>> -finfo.fd = open(finfo.path, O_RDONLY, 777);
>> +printf("Opening %s %s for collapse...", finfo.path,
>> + read_only ? "read only" : "read-write");
>
> "read-only" ?
>
>> +finfo.fd = open(finfo.path, open_opt, 777);
>> if (finfo.fd < 0) {
>> perror("open()");
>> exit(EXIT_FAILURE);
>> }
>> -p = mmap(BASE_ADDR, size, PROT_READ,
>> - MAP_PRIVATE, finfo.fd, 0);
>> +p = mmap(BASE_ADDR, size, mmap_prot,
>> + mmap_opt, finfo.fd, 0);
>
> While at it, can fit that into a single line.
>
>> if (p == MAP_FAILED || p != BASE_ADDR) {
>> perror("mmap()");
>> exit(EXIT_FAILURE);
>> @@ -418,6 +424,16 @@ static void *file_setup_area(int nr_hpages)
>> return p;
>> }
>>
>> +static void *file_setup_read_only_area(int nr_hpages)
>> +{
>> +return file_setup_area_common(nr_hpages, /* read_only= */ true);
>> +}
>> +
>> +static void *file_setup_read_write_area(int nr_hpages)
>> +{
>> +return file_setup_area_common(nr_hpages, /* read_only= */ false);
>> +}
>> +
>> static void file_cleanup_area(void *p, unsigned long size)
>> {
>> munmap(p, size);
>> @@ -425,14 +441,25 @@ static void file_cleanup_area(void *p, unsigned long
>> size)
>> unlink(finfo.path);
>> }
>>
>> -static void file_fault(void *p, unsigned long start, unsigned long end)
>> +static void file_fault_common(void *p, unsigned long start, unsigned long
>> end,
>> +int madv_ops)
>> {
>> -if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
>> +if (madvise(((char *)p) + start, end - start, madv_ops)) {
>> perror("madvise(MADV_POPULATE_READ");
>> exit(EXIT_FAILURE);
>> }
>> }
>>
>> +static void file_fault_read(void *p, unsigned long start, unsigned long end)
>> +{
>> +file_fault_common(p, start, end, MADV_POPULATE_READ);
>
> Do we really want file_fault_common()? I'd say, just inline it. In particular
> avoids checking the madv_ops to figure out the error message ...
>
>> +}
>> +
>> +static void file_fault_write(void *p, unsigned long start, unsigned long
>> end)
>> +{
>> +file_fault_common(p, start, end, MADV_POPULATE_WRITE);
>> +}
>> +
>> static bool file_check_huge(void *addr, int nr_hpages)
>> {
>> swi
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 4/29/26 17:35, Zi Yan wrote:
> Change the requirement to a file system with large folio support and the
> supported order needs to include PMD_ORDER.
>
> Also add tests of opening a file with read write permission and populating
> folios with writes. Reuse the XFS image from split_huge_page_test.
>
> Signed-off-by: Zi Yan
> ---
> tools/testing/selftests/mm/khugepaged.c | 131 +++---
> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
> 2 files changed, 102 insertions(+), 41 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/khugepaged.c
> b/tools/testing/selftests/mm/khugepaged.c
> index a6bb9d50363d2..80b913185c643 100644
> --- a/tools/testing/selftests/mm/khugepaged.c
> +++ b/tools/testing/selftests/mm/khugepaged.c
> @@ -49,7 +49,8 @@ struct mem_ops {
> const char *name;
> };
>
> -static struct mem_ops *file_ops;
> +static struct mem_ops *read_only_file_ops;
> +static struct mem_ops *read_write_file_ops;
> static struct mem_ops *anon_ops;
> static struct mem_ops *shmem_ops;
>
> @@ -112,7 +113,8 @@ static void restore_settings(int sig)
> static void save_settings(void)
> {
> printf("Save THP and khugepaged settings...");
> - if (file_ops && finfo.type == VMA_FILE)
> + if ((read_only_file_ops || read_write_file_ops) &&
> + finfo.type == VMA_FILE)
> thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path);
> thp_save_settings();
>
> @@ -364,11 +366,14 @@ static bool anon_check_huge(void *addr, int nr_hpages)
> return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
> }
>
> -static void *file_setup_area(int nr_hpages)
> +static void *file_setup_area_common(int nr_hpages, bool read_only)
> {
> int fd;
> void *p;
> unsigned long size;
> + int open_opt = read_only ? O_RDONLY : O_RDWR;
> + int mmap_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE);
> + int mmap_opt = read_only ? MAP_PRIVATE : MAP_SHARED;
Can all be const and read better at the very top of the list.
Why do we go from private->shared depending on "read_only" parameter? I'd assume
we'd want to test MAP_SHARED for both (read-only + read-write)?
>
> unlink(finfo.path); /* Cleanup from previous failed tests */
> printf("Creating %s for collapse%s...", finfo.path,
> @@ -399,14 +404,15 @@ static void *file_setup_area(int nr_hpages)
> munmap(p, size);
> success("OK");
>
> - printf("Opening %s read only for collapse...", finfo.path);
> - finfo.fd = open(finfo.path, O_RDONLY, 777);
> + printf("Opening %s %s for collapse...", finfo.path,
> +read_only ? "read only" : "read-write");
"read-only" ?
> + finfo.fd = open(finfo.path, open_opt, 777);
> if (finfo.fd < 0) {
> perror("open()");
> exit(EXIT_FAILURE);
> }
> - p = mmap(BASE_ADDR, size, PROT_READ,
> - MAP_PRIVATE, finfo.fd, 0);
> + p = mmap(BASE_ADDR, size, mmap_prot,
> + mmap_opt, finfo.fd, 0);
While at it, can fit that into a single line.
> if (p == MAP_FAILED || p != BASE_ADDR) {
> perror("mmap()");
> exit(EXIT_FAILURE);
> @@ -418,6 +424,16 @@ static void *file_setup_area(int nr_hpages)
> return p;
> }
>
> +static void *file_setup_read_only_area(int nr_hpages)
> +{
> + return file_setup_area_common(nr_hpages, /* read_only= */ true);
> +}
> +
> +static void *file_setup_read_write_area(int nr_hpages)
> +{
> + return file_setup_area_common(nr_hpages, /* read_only= */ false);
> +}
> +
> static void file_cleanup_area(void *p, unsigned long size)
> {
> munmap(p, size);
> @@ -425,14 +441,25 @@ static void file_cleanup_area(void *p, unsigned long
> size)
> unlink(finfo.path);
> }
>
> -static void file_fault(void *p, unsigned long start, unsigned long end)
> +static void file_fault_common(void *p, unsigned long start, unsigned long
> end,
> + int madv_ops)
> {
> - if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
> + if (madvise(((char *)p) + start, end - start, madv_ops)) {
> perror("madvise(MADV_POPULATE_READ");
> exit(EXIT_FAILURE);
> }
> }
>
> +static void file_fault_read(void *p, unsigned long start, unsigned long end)
> +{
> + file_fault_common(p, start, end, MADV_POPULATE_READ);
Do we really want file_fault_common()? I'd say, just inline it. In particular
avoids checking the madv_ops to figure out the error message ...
> +}
> +
> +static void file_fault_write(void *p, unsigned long start, unsigned long end)
> +{
> + file_fault_common(p, start, end, MADV_POPULATE_WRITE);
> +}
> +
> static bool file_check_huge(void *addr, int nr_hpages)
> {
> switch (finfo.type) {
> @@ -488,10 +515,18 @@ static struct mem_ops __anon_ops = {
> .name = "anon",
> };
[...]
> };
>
> +static bool is_tmpfs(struct mem_ops *ops)
> +{
> + return (ops == &__read_only_file_ops ||
> +
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 5/6/26 15:11, Zi Yan wrote:
> On 4 May 2026, at 12:23, Nico Pache wrote:
>
>> On 4/29/26 9:35 AM, Zi Yan wrote:
>>> Change the requirement to a file system with large folio support and the
>>> supported order needs to include PMD_ORDER.
>>>
>>> Also add tests of opening a file with read write permission and populating
>>> folios with writes. Reuse the XFS image from split_huge_page_test.
>>>
>>> Signed-off-by: Zi Yan
>>> ---
>>> tools/testing/selftests/mm/khugepaged.c | 131 +++---
>>> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
>>> 2 files changed, 102 insertions(+), 41 deletions(-)
>>>
>>> diff --git a/tools/testing/selftests/mm/khugepaged.c
>>> b/tools/testing/selftests/mm/khugepaged.c
>>> index a6bb9d50363d2..80b913185c643 100644
>>> --- a/tools/testing/selftests/mm/khugepaged.c
>>> +++ b/tools/testing/selftests/mm/khugepaged.c
>>> @@ -49,7 +49,8 @@ struct mem_ops {
>>> const char *name;
>>> };
>>> -static struct mem_ops *file_ops;
>>> +static struct mem_ops *read_only_file_ops;
>>> +static struct mem_ops *read_write_file_ops;
>>> static struct mem_ops *anon_ops;
>>> static struct mem_ops *shmem_ops;
>>> @@ -112,7 +113,8 @@ static void restore_settings(int sig)
>>> static void save_settings(void)
>>> {
>>> printf("Save THP and khugepaged settings...");
>>> - if (file_ops && finfo.type == VMA_FILE)
>>> + if ((read_only_file_ops || read_write_file_ops) &&
>>> + finfo.type == VMA_FILE)
>>> thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path);
>>> thp_save_settings();
>>> @@ -364,11 +366,14 @@ static bool anon_check_huge(void *addr, int
>>> nr_hpages)
>>> return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
>>> }
>>> -static void *file_setup_area(int nr_hpages)
>>> +static void *file_setup_area_common(int nr_hpages, bool read_only)
>>> {
>>> int fd;
>>> void *p;
>>> unsigned long size;
>>> + int open_opt = read_only ? O_RDONLY : O_RDWR;
>>> + int mmap_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE);
>>> + int mmap_opt = read_only ? MAP_PRIVATE : MAP_SHARED;
>>> unlink(finfo.path); /* Cleanup from previous failed tests */
>>> printf("Creating %s for collapse%s...", finfo.path,
>>> @@ -399,14 +404,15 @@ static void *file_setup_area(int nr_hpages)
>>> munmap(p, size);
>>> success("OK");
>>> - printf("Opening %s read only for collapse...", finfo.path);
>>> - finfo.fd = open(finfo.path, O_RDONLY, 777);
>>> + printf("Opening %s %s for collapse...", finfo.path,
>>> + read_only ? "read only" : "read-write");
>>> + finfo.fd = open(finfo.path, open_opt, 777);
>>> if (finfo.fd < 0) {
>>> perror("open()");
>>> exit(EXIT_FAILURE);
>>> }
>>> - p = mmap(BASE_ADDR, size, PROT_READ,
>>> -MAP_PRIVATE, finfo.fd, 0);
>>> + p = mmap(BASE_ADDR, size, mmap_prot,
>>> +mmap_opt, finfo.fd, 0);
>>> if (p == MAP_FAILED || p != BASE_ADDR) {
>>> perror("mmap()");
>>> exit(EXIT_FAILURE);
>>> @@ -418,6 +424,16 @@ static void *file_setup_area(int nr_hpages)
>>> return p;
>>> }
>>> +static void *file_setup_read_only_area(int nr_hpages)
>>> +{
>>> + return file_setup_area_common(nr_hpages, /* read_only= */ true);
>>> +}
>>> +
>>> +static void *file_setup_read_write_area(int nr_hpages)
>>> +{
>>> + return file_setup_area_common(nr_hpages, /* read_only= */ false);
>>> +}
>>> +
>>> static void file_cleanup_area(void *p, unsigned long size)
>>> {
>>> munmap(p, size);
>>> @@ -425,14 +441,25 @@ static void file_cleanup_area(void *p, unsigned long
>>> size)
>>> unlink(finfo.path);
>>> }
>>> -static void file_fault(void *p, unsigned long start, unsigned long end)
>>> +static void file_fault_common(void *p, unsigned long start, unsigned long
>>> end,
>>> + int madv_ops)
>>> {
>>> - if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
>>> + if (madvise(((char *)p) + start, end - start, madv_ops)) {
>>> perror("madvise(MADV_POPULATE_READ");
>>> exit(EXIT_FAILURE);
>>> }
>>> }
>>> +static void file_fault_read(void *p, unsigned long start, unsigned long
>>> end)
>>> +{
>>> + file_fault_common(p, start, end, MADV_POPULATE_READ);
>>> +}
>>> +
>>> +static void file_fault_write(void *p, unsigned long start, unsigned long
>>> end)
>>> +{
>>> + file_fault_common(p, start, end, MADV_POPULATE_WRITE);
>>> +}
>>> +
>>> static bool file_check_huge(void *addr, int nr_hpages)
>>> {
>>> switch (finfo.type) {
>>> @@ -488,10 +515,18 @@ static struct mem_ops __anon_ops = {
>>> .name = "anon",
>>> };
>>> -static struct mem_ops __file_ops = {
>>> - .setup_area = &file_setup_area,
>>> +static struct mem_ops __read_only_file_ops = {
>>> + .setup_area = &file_setup_read_only_area,
>>> .cleanup_area = &file_cleanup_area,
>>> - .fault = &file_fault,
>>> + .fault = &file_fault_read,
>>> + .check_huge = &file_c
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 4/30/26 17:27, Zi Yan wrote:
> On 30 Apr 2026, at 11:16, Zi Yan wrote:
>
>> On 29 Apr 2026, at 11:35, Zi Yan wrote:
>>
>>> Change the requirement to a file system with large folio support and the
>>> supported order needs to include PMD_ORDER.
>>>
>>> Also add tests of opening a file with read write permission and populating
>>> folios with writes. Reuse the XFS image from split_huge_page_test.
>>>
>>> Signed-off-by: Zi Yan
>>> ---
>>> tools/testing/selftests/mm/khugepaged.c | 131 +++---
>>> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
>>> 2 files changed, 102 insertions(+), 41 deletions(-)
>>>
>
>
>
>>> -static void file_fault(void *p, unsigned long start, unsigned long end)
>>> +static void file_fault_common(void *p, unsigned long start, unsigned long
>>> end,
>>> + int madv_ops)
>>> {
>>> - if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
>>> + if (madvise(((char *)p) + start, end - start, madv_ops)) {
>>> perror("madvise(MADV_POPULATE_READ");
>>
>> Sashiko:
>> Since madv_ops can now be either MADV_POPULATE_READ or MADV_POPULATE_WRITE,
>> will this hardcoded error message be misleading if the write fault path
>> fails?
>>
>> Answer:
>> Will send a fixup.
>
>
> This is the fixup:
> From 76e301cf5198f33d07492e224ec627b94902b4b6 Mon Sep 17 00:00:00 2001
> From: Zi Yan
> Date: Thu, 30 Apr 2026 11:22:30 -0400
> Subject: [PATCH] selftests/mm: khugepaged perror fixup.
>
> Signed-off-by: Zi Yan
> ---
> tools/testing/selftests/mm/khugepaged.c | 5 -
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/mm/khugepaged.c
> b/tools/testing/selftests/mm/khugepaged.c
> index 80b913185c643..97b8fcc490c76 100644
> --- a/tools/testing/selftests/mm/khugepaged.c
> +++ b/tools/testing/selftests/mm/khugepaged.c
> @@ -445,7 +445,10 @@ static void file_fault_common(void *p, unsigned long
> start, unsigned long end,
> int madv_ops)
> {
> if (madvise(((char *)p) + start, end - start, madv_ops)) {
> - perror("madvise(MADV_POPULATE_READ");
> + if (madv_ops == MADV_POPULATE_READ)
> + perror("madvise(MADV_POPULATE_READ");
> + else if (madv_ops == MADV_POPULATE_WRITE)
> + perror("madvise(MADV_POPULATE_WRITE");
Alternatively, just "madvise()". It's unexpected to fail in any case and would
have to be debugged ...
--
Cheers,
David
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 29 Apr 2026, at 23:35, Zi Yan wrote:
> Change the requirement to a file system with large folio support and the
> supported order needs to include PMD_ORDER.
>
> Also add tests of opening a file with read write permission and populating
> folios with writes. Reuse the XFS image from split_huge_page_test.
>
> Signed-off-by: Zi Yan
> ---
> tools/testing/selftests/mm/khugepaged.c | 131 +++---
> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
> 2 files changed, 102 insertions(+), 41 deletions(-)
>
Hi Andrew,
Here is the second fixup to this patch. It addresses an issue that
[SKIP] is always printed, if XFS is not present, even if khugepaged
never runs, discovered by Nico. Thanks.
From eb9a5c25434e3882423f621dc46281156eac843a Mon Sep 17 00:00:00 2001
From: Zi Yan
Date: Thu, 7 May 2026 03:17:51 -0400
Subject: [PATCH] fix run_vmtests.sh to only print SKIP when khugepaged is
selected
Signed-off-by: Zi Yan
---
tools/testing/selftests/mm/run_vmtests.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/run_vmtests.sh
b/tools/testing/selftests/mm/run_vmtests.sh
index 854c5c3e3a6ae..b73921b2cac02 100755
--- a/tools/testing/selftests/mm/run_vmtests.sh
+++ b/tools/testing/selftests/mm/run_vmtests.sh
@@ -508,7 +508,7 @@ fi
if [ -n "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
CATEGORY="thp" run_test ./khugepaged all:file ${SPLIT_HUGE_PAGE_TEST_XFS_PATH}
-else
+elif test_selected thp; then
count_total=$(( count_total + 1 ))
count_skip=$(( count_skip + 1 ))
echo "[SKIP] ./khugepaged all:file" | tap_prefix
--
2.53.0
Best Regards,
Yan, Zi
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 7 May 2026, at 14:35, Nico Pache wrote:
> On Wed, May 6, 2026 at 7:15 AM Zi Yan wrote:
>>
>> On 4 May 2026, at 18:11, Nico Pache wrote:
>>
>>> On 4/29/26 9:35 AM, Zi Yan wrote:
Change the requirement to a file system with large folio support and the
supported order needs to include PMD_ORDER.
Also add tests of opening a file with read write permission and populating
folios with writes. Reuse the XFS image from split_huge_page_test.
Signed-off-by: Zi Yan
---
tools/testing/selftests/mm/khugepaged.c | 131 +++---
tools/testing/selftests/mm/run_vmtests.sh | 12 +-
2 files changed, 102 insertions(+), 41 deletions(-)
>>
>>
>>
diff --git a/tools/testing/selftests/mm/run_vmtests.sh
b/tools/testing/selftests/mm/run_vmtests.sh
index 3b61677fe9840..854c5c3e3a6ae 100755
--- a/tools/testing/selftests/mm/run_vmtests.sh
+++ b/tools/testing/selftests/mm/run_vmtests.sh
@@ -490,8 +490,6 @@ CATEGORY="thp" run_test ./khugepaged all:shmem
CATEGORY="thp" run_test ./khugepaged -s 4 all:shmem
-CATEGORY="thp" run_test ./transhuge-stress -d 20
-
# Try to create XFS if not provided
if [ -z "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
if [ "${HAVE_HUGEPAGES}" = "1" ]; then
@@ -508,6 +506,14 @@ if [ -z "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
fi
fi
+if [ -n "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
+CATEGORY="thp" run_test ./khugepaged all:file
${SPLIT_HUGE_PAGE_TEST_XFS_PATH}
+else
+count_total=$(( count_total + 1 ))
+count_skip=$(( count_skip + 1 ))
+echo "[SKIP] ./khugepaged all:file" | tap_prefix
>>>
>>> This leads selftest runs to always litter the output with SKIP when running
>>> this with the wrapper
>>>
>>> make -C tools/testing/selftests TARGETS=mm run_tests
>>
>> Yes, this is intended to let people know one case is not tested and skipped
>> if XFS cannot be created.
>
> Yes but it prints after each test case run, not just the khugepaged runs
You are right. Let me send a fixup. Thank you.
Best Regards,
Yan, Zi
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On Wed, May 6, 2026 at 7:15 AM Zi Yan wrote:
>
> On 4 May 2026, at 18:11, Nico Pache wrote:
>
> > On 4/29/26 9:35 AM, Zi Yan wrote:
> >> Change the requirement to a file system with large folio support and the
> >> supported order needs to include PMD_ORDER.
> >>
> >> Also add tests of opening a file with read write permission and populating
> >> folios with writes. Reuse the XFS image from split_huge_page_test.
> >>
> >> Signed-off-by: Zi Yan
> >> ---
> >> tools/testing/selftests/mm/khugepaged.c | 131 +++---
> >> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
> >> 2 files changed, 102 insertions(+), 41 deletions(-)
> >>
>
>
>
> >> diff --git a/tools/testing/selftests/mm/run_vmtests.sh
> >> b/tools/testing/selftests/mm/run_vmtests.sh
> >> index 3b61677fe9840..854c5c3e3a6ae 100755
> >> --- a/tools/testing/selftests/mm/run_vmtests.sh
> >> +++ b/tools/testing/selftests/mm/run_vmtests.sh
> >> @@ -490,8 +490,6 @@ CATEGORY="thp" run_test ./khugepaged all:shmem
> >>CATEGORY="thp" run_test ./khugepaged -s 4 all:shmem
> >> -CATEGORY="thp" run_test ./transhuge-stress -d 20
> >> -
> >> # Try to create XFS if not provided
> >> if [ -z "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
> >> if [ "${HAVE_HUGEPAGES}" = "1" ]; then
> >> @@ -508,6 +506,14 @@ if [ -z "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
> >> fi
> >> fi
> >> +if [ -n "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
> >> +CATEGORY="thp" run_test ./khugepaged all:file
> >> ${SPLIT_HUGE_PAGE_TEST_XFS_PATH}
> >> +else
> >> +count_total=$(( count_total + 1 ))
> >> +count_skip=$(( count_skip + 1 ))
> >> +echo "[SKIP] ./khugepaged all:file" | tap_prefix
> >
> > This leads selftest runs to always litter the output with SKIP when running
> > this with the wrapper
> >
> > make -C tools/testing/selftests TARGETS=mm run_tests
>
> Yes, this is intended to let people know one case is not tested and skipped
> if XFS cannot be created.
Yes but it prints after each test case run, not just the khugepaged runs
>
> >
> >> +fi
> >> +
> >> CATEGORY="thp" run_test ./split_huge_page_test
> >> ${SPLIT_HUGE_PAGE_TEST_XFS_PATH}
> >>if [ -n "${MOUNTED_XFS}" ]; then
> >> @@ -516,6 +522,8 @@ if [ -n "${MOUNTED_XFS}" ]; then
> >> rm -f ${XFS_IMG}
> >> fi
> >> +CATEGORY="thp" run_test ./transhuge-stress -d 20
> >> +
> >> CATEGORY="thp" run_test ./folio_split_race_test
> >>CATEGORY="migration" run_test ./migration
>
>
> Best Regards,
> Yan, Zi
>
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 4 May 2026, at 18:11, Nico Pache wrote:
> On 4/29/26 9:35 AM, Zi Yan wrote:
>> Change the requirement to a file system with large folio support and the
>> supported order needs to include PMD_ORDER.
>>
>> Also add tests of opening a file with read write permission and populating
>> folios with writes. Reuse the XFS image from split_huge_page_test.
>>
>> Signed-off-by: Zi Yan
>> ---
>> tools/testing/selftests/mm/khugepaged.c | 131 +++---
>> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
>> 2 files changed, 102 insertions(+), 41 deletions(-)
>>
>> diff --git a/tools/testing/selftests/mm/run_vmtests.sh
>> b/tools/testing/selftests/mm/run_vmtests.sh
>> index 3b61677fe9840..854c5c3e3a6ae 100755
>> --- a/tools/testing/selftests/mm/run_vmtests.sh
>> +++ b/tools/testing/selftests/mm/run_vmtests.sh
>> @@ -490,8 +490,6 @@ CATEGORY="thp" run_test ./khugepaged all:shmem
>>CATEGORY="thp" run_test ./khugepaged -s 4 all:shmem
>> -CATEGORY="thp" run_test ./transhuge-stress -d 20
>> -
>> # Try to create XFS if not provided
>> if [ -z "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
>> if [ "${HAVE_HUGEPAGES}" = "1" ]; then
>> @@ -508,6 +506,14 @@ if [ -z "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
>> fi
>> fi
>> +if [ -n "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
>> +CATEGORY="thp" run_test ./khugepaged all:file
>> ${SPLIT_HUGE_PAGE_TEST_XFS_PATH}
>> +else
>> +count_total=$(( count_total + 1 ))
>> +count_skip=$(( count_skip + 1 ))
>> +echo "[SKIP] ./khugepaged all:file" | tap_prefix
>
> This leads selftest runs to always litter the output with SKIP when running
> this with the wrapper
>
> make -C tools/testing/selftests TARGETS=mm run_tests
Yes, this is intended to let people know one case is not tested and skipped if
XFS cannot be created.
>
>> +fi
>> +
>> CATEGORY="thp" run_test ./split_huge_page_test
>> ${SPLIT_HUGE_PAGE_TEST_XFS_PATH}
>>if [ -n "${MOUNTED_XFS}" ]; then
>> @@ -516,6 +522,8 @@ if [ -n "${MOUNTED_XFS}" ]; then
>> rm -f ${XFS_IMG}
>> fi
>> +CATEGORY="thp" run_test ./transhuge-stress -d 20
>> +
>> CATEGORY="thp" run_test ./folio_split_race_test
>>CATEGORY="migration" run_test ./migration
Best Regards,
Yan, Zi
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 4 May 2026, at 12:23, Nico Pache wrote:
> On 4/29/26 9:35 AM, Zi Yan wrote:
>> Change the requirement to a file system with large folio support and the
>> supported order needs to include PMD_ORDER.
>>
>> Also add tests of opening a file with read write permission and populating
>> folios with writes. Reuse the XFS image from split_huge_page_test.
>>
>> Signed-off-by: Zi Yan
>> ---
>> tools/testing/selftests/mm/khugepaged.c | 131 +++---
>> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
>> 2 files changed, 102 insertions(+), 41 deletions(-)
>>
>> diff --git a/tools/testing/selftests/mm/khugepaged.c
>> b/tools/testing/selftests/mm/khugepaged.c
>> index a6bb9d50363d2..80b913185c643 100644
>> --- a/tools/testing/selftests/mm/khugepaged.c
>> +++ b/tools/testing/selftests/mm/khugepaged.c
>> @@ -49,7 +49,8 @@ struct mem_ops {
>> const char *name;
>> };
>> -static struct mem_ops *file_ops;
>> +static struct mem_ops *read_only_file_ops;
>> +static struct mem_ops *read_write_file_ops;
>> static struct mem_ops *anon_ops;
>> static struct mem_ops *shmem_ops;
>> @@ -112,7 +113,8 @@ static void restore_settings(int sig)
>> static void save_settings(void)
>> {
>> printf("Save THP and khugepaged settings...");
>> -if (file_ops && finfo.type == VMA_FILE)
>> +if ((read_only_file_ops || read_write_file_ops) &&
>> +finfo.type == VMA_FILE)
>> thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path);
>> thp_save_settings();
>> @@ -364,11 +366,14 @@ static bool anon_check_huge(void *addr, int nr_hpages)
>> return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
>> }
>> -static void *file_setup_area(int nr_hpages)
>> +static void *file_setup_area_common(int nr_hpages, bool read_only)
>> {
>> int fd;
>> void *p;
>> unsigned long size;
>> +int open_opt = read_only ? O_RDONLY : O_RDWR;
>> +int mmap_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE);
>> +int mmap_opt = read_only ? MAP_PRIVATE : MAP_SHARED;
>> unlink(finfo.path); /* Cleanup from previous failed tests */
>> printf("Creating %s for collapse%s...", finfo.path,
>> @@ -399,14 +404,15 @@ static void *file_setup_area(int nr_hpages)
>> munmap(p, size);
>> success("OK");
>> - printf("Opening %s read only for collapse...", finfo.path);
>> -finfo.fd = open(finfo.path, O_RDONLY, 777);
>> +printf("Opening %s %s for collapse...", finfo.path,
>> + read_only ? "read only" : "read-write");
>> +finfo.fd = open(finfo.path, open_opt, 777);
>> if (finfo.fd < 0) {
>> perror("open()");
>> exit(EXIT_FAILURE);
>> }
>> -p = mmap(BASE_ADDR, size, PROT_READ,
>> - MAP_PRIVATE, finfo.fd, 0);
>> +p = mmap(BASE_ADDR, size, mmap_prot,
>> + mmap_opt, finfo.fd, 0);
>> if (p == MAP_FAILED || p != BASE_ADDR) {
>> perror("mmap()");
>> exit(EXIT_FAILURE);
>> @@ -418,6 +424,16 @@ static void *file_setup_area(int nr_hpages)
>> return p;
>> }
>> +static void *file_setup_read_only_area(int nr_hpages)
>> +{
>> +return file_setup_area_common(nr_hpages, /* read_only= */ true);
>> +}
>> +
>> +static void *file_setup_read_write_area(int nr_hpages)
>> +{
>> +return file_setup_area_common(nr_hpages, /* read_only= */ false);
>> +}
>> +
>> static void file_cleanup_area(void *p, unsigned long size)
>> {
>> munmap(p, size);
>> @@ -425,14 +441,25 @@ static void file_cleanup_area(void *p, unsigned long
>> size)
>> unlink(finfo.path);
>> }
>> -static void file_fault(void *p, unsigned long start, unsigned long end)
>> +static void file_fault_common(void *p, unsigned long start, unsigned long
>> end,
>> +int madv_ops)
>> {
>> -if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
>> +if (madvise(((char *)p) + start, end - start, madv_ops)) {
>> perror("madvise(MADV_POPULATE_READ");
>> exit(EXIT_FAILURE);
>> }
>> }
>> +static void file_fault_read(void *p, unsigned long start, unsigned long
>> end)
>> +{
>> +file_fault_common(p, start, end, MADV_POPULATE_READ);
>> +}
>> +
>> +static void file_fault_write(void *p, unsigned long start, unsigned long
>> end)
>> +{
>> +file_fault_common(p, start, end, MADV_POPULATE_WRITE);
>> +}
>> +
>> static bool file_check_huge(void *addr, int nr_hpages)
>> {
>> switch (finfo.type) {
>> @@ -488,10 +515,18 @@ static struct mem_ops __anon_ops = {
>> .name = "anon",
>> };
>> -static struct mem_ops __file_ops = {
>> -.setup_area = &file_setup_area,
>> +static struct mem_ops __read_only_file_ops = {
>> +.setup_area = &file_setup_read_only_area,
>> .cleanup_area = &file_cleanup_area,
>> -.fault = &file_fault,
>> +.fault = &file_fault_read,
>> +.check_huge = &file_check_huge,
>> +.name = "file",
>> +};
>> +
>> +static struct mem_ops __read_write_file_ops = {
>> +.se
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 4/29/26 9:35 AM, Zi Yan wrote:
Change the requirement to a file system with large folio support and the
supported order needs to include PMD_ORDER.
Also add tests of opening a file with read write permission and populating
folios with writes. Reuse the XFS image from split_huge_page_test.
Signed-off-by: Zi Yan
---
tools/testing/selftests/mm/khugepaged.c | 131 +++---
tools/testing/selftests/mm/run_vmtests.sh | 12 +-
2 files changed, 102 insertions(+), 41 deletions(-)
diff --git a/tools/testing/selftests/mm/khugepaged.c
b/tools/testing/selftests/mm/khugepaged.c
index a6bb9d50363d2..80b913185c643 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -49,7 +49,8 @@ struct mem_ops {
const char *name;
};
-static struct mem_ops *file_ops;
+static struct mem_ops *read_only_file_ops;
+static struct mem_ops *read_write_file_ops;
static struct mem_ops *anon_ops;
static struct mem_ops *shmem_ops;
@@ -112,7 +113,8 @@ static void restore_settings(int sig)
static void save_settings(void)
{
printf("Save THP and khugepaged settings...");
- if (file_ops && finfo.type == VMA_FILE)
+ if ((read_only_file_ops || read_write_file_ops) &&
+ finfo.type == VMA_FILE)
thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path);
thp_save_settings();
@@ -364,11 +366,14 @@ static bool anon_check_huge(void *addr, int nr_hpages)
return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
}
-static void *file_setup_area(int nr_hpages)
+static void *file_setup_area_common(int nr_hpages, bool read_only)
{
int fd;
void *p;
unsigned long size;
+ int open_opt = read_only ? O_RDONLY : O_RDWR;
+ int mmap_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE);
+ int mmap_opt = read_only ? MAP_PRIVATE : MAP_SHARED;
unlink(finfo.path); /* Cleanup from previous failed tests */
printf("Creating %s for collapse%s...", finfo.path,
@@ -399,14 +404,15 @@ static void *file_setup_area(int nr_hpages)
munmap(p, size);
success("OK");
- printf("Opening %s read only for collapse...", finfo.path);
- finfo.fd = open(finfo.path, O_RDONLY, 777);
+ printf("Opening %s %s for collapse...", finfo.path,
+ read_only ? "read only" : "read-write");
+ finfo.fd = open(finfo.path, open_opt, 777);
if (finfo.fd < 0) {
perror("open()");
exit(EXIT_FAILURE);
}
- p = mmap(BASE_ADDR, size, PROT_READ,
-MAP_PRIVATE, finfo.fd, 0);
+ p = mmap(BASE_ADDR, size, mmap_prot,
+mmap_opt, finfo.fd, 0);
if (p == MAP_FAILED || p != BASE_ADDR) {
perror("mmap()");
exit(EXIT_FAILURE);
@@ -418,6 +424,16 @@ static void *file_setup_area(int nr_hpages)
return p;
}
+static void *file_setup_read_only_area(int nr_hpages)
+{
+ return file_setup_area_common(nr_hpages, /* read_only= */ true);
+}
+
+static void *file_setup_read_write_area(int nr_hpages)
+{
+ return file_setup_area_common(nr_hpages, /* read_only= */ false);
+}
+
static void file_cleanup_area(void *p, unsigned long size)
{
munmap(p, size);
@@ -425,14 +441,25 @@ static void file_cleanup_area(void *p, unsigned long size)
unlink(finfo.path);
}
-static void file_fault(void *p, unsigned long start, unsigned long end)
+static void file_fault_common(void *p, unsigned long start, unsigned long end,
+ int madv_ops)
{
- if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
+ if (madvise(((char *)p) + start, end - start, madv_ops)) {
perror("madvise(MADV_POPULATE_READ");
exit(EXIT_FAILURE);
}
}
+static void file_fault_read(void *p, unsigned long start, unsigned long end)
+{
+ file_fault_common(p, start, end, MADV_POPULATE_READ);
+}
+
+static void file_fault_write(void *p, unsigned long start, unsigned long end)
+{
+ file_fault_common(p, start, end, MADV_POPULATE_WRITE);
+}
+
static bool file_check_huge(void *addr, int nr_hpages)
{
switch (finfo.type) {
@@ -488,10 +515,18 @@ static struct mem_ops __anon_ops = {
.name = "anon",
};
-static struct mem_ops __file_ops = {
- .setup_area = &file_setup_area,
+static struct mem_ops __read_only_file_ops = {
+ .setup_area = &file_setup_read_only_area,
.cleanup_area = &file_cleanup_area,
- .fault = &file_fault,
+ .fault = &file_fault_read,
+ .check_huge = &file_check_huge,
+ .name = "file",
+};
+
+static struct mem_ops __read_write_file_ops = {
+ .setup_area = &file_setup_read_write_area,
+ .cleanup_area = &file_cleanup_area,
+ .fault = &file_fault_write,
.check_huge = &file_check_huge,
.name = "file",
};
@@ -504,6 +539,18 @@ static struct mem_ops __shm
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 4/29/26 9:35 AM, Zi Yan wrote:
Change the requirement to a file system with large folio support and the
supported order needs to include PMD_ORDER.
Also add tests of opening a file with read write permission and populating
folios with writes. Reuse the XFS image from split_huge_page_test.
Signed-off-by: Zi Yan
---
tools/testing/selftests/mm/khugepaged.c | 131 +++---
tools/testing/selftests/mm/run_vmtests.sh | 12 +-
2 files changed, 102 insertions(+), 41 deletions(-)
diff --git a/tools/testing/selftests/mm/khugepaged.c
b/tools/testing/selftests/mm/khugepaged.c
index a6bb9d50363d2..80b913185c643 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -49,7 +49,8 @@ struct mem_ops {
const char *name;
};
-static struct mem_ops *file_ops;
+static struct mem_ops *read_only_file_ops;
+static struct mem_ops *read_write_file_ops;
static struct mem_ops *anon_ops;
static struct mem_ops *shmem_ops;
@@ -112,7 +113,8 @@ static void restore_settings(int sig)
static void save_settings(void)
{
printf("Save THP and khugepaged settings...");
- if (file_ops && finfo.type == VMA_FILE)
+ if ((read_only_file_ops || read_write_file_ops) &&
+ finfo.type == VMA_FILE)
thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path);
thp_save_settings();
@@ -364,11 +366,14 @@ static bool anon_check_huge(void *addr, int nr_hpages)
return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
}
-static void *file_setup_area(int nr_hpages)
+static void *file_setup_area_common(int nr_hpages, bool read_only)
{
int fd;
void *p;
unsigned long size;
+ int open_opt = read_only ? O_RDONLY : O_RDWR;
+ int mmap_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE);
+ int mmap_opt = read_only ? MAP_PRIVATE : MAP_SHARED;
unlink(finfo.path); /* Cleanup from previous failed tests */
printf("Creating %s for collapse%s...", finfo.path,
@@ -399,14 +404,15 @@ static void *file_setup_area(int nr_hpages)
munmap(p, size);
success("OK");
- printf("Opening %s read only for collapse...", finfo.path);
- finfo.fd = open(finfo.path, O_RDONLY, 777);
+ printf("Opening %s %s for collapse...", finfo.path,
+ read_only ? "read only" : "read-write");
+ finfo.fd = open(finfo.path, open_opt, 777);
if (finfo.fd < 0) {
perror("open()");
exit(EXIT_FAILURE);
}
- p = mmap(BASE_ADDR, size, PROT_READ,
-MAP_PRIVATE, finfo.fd, 0);
+ p = mmap(BASE_ADDR, size, mmap_prot,
+mmap_opt, finfo.fd, 0);
if (p == MAP_FAILED || p != BASE_ADDR) {
perror("mmap()");
exit(EXIT_FAILURE);
@@ -418,6 +424,16 @@ static void *file_setup_area(int nr_hpages)
return p;
}
+static void *file_setup_read_only_area(int nr_hpages)
+{
+ return file_setup_area_common(nr_hpages, /* read_only= */ true);
+}
+
+static void *file_setup_read_write_area(int nr_hpages)
+{
+ return file_setup_area_common(nr_hpages, /* read_only= */ false);
+}
+
static void file_cleanup_area(void *p, unsigned long size)
{
munmap(p, size);
@@ -425,14 +441,25 @@ static void file_cleanup_area(void *p, unsigned long size)
unlink(finfo.path);
}
-static void file_fault(void *p, unsigned long start, unsigned long end)
+static void file_fault_common(void *p, unsigned long start, unsigned long end,
+ int madv_ops)
{
- if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
+ if (madvise(((char *)p) + start, end - start, madv_ops)) {
perror("madvise(MADV_POPULATE_READ");
exit(EXIT_FAILURE);
}
}
+static void file_fault_read(void *p, unsigned long start, unsigned long end)
+{
+ file_fault_common(p, start, end, MADV_POPULATE_READ);
+}
+
+static void file_fault_write(void *p, unsigned long start, unsigned long end)
+{
+ file_fault_common(p, start, end, MADV_POPULATE_WRITE);
+}
+
static bool file_check_huge(void *addr, int nr_hpages)
{
switch (finfo.type) {
@@ -488,10 +515,18 @@ static struct mem_ops __anon_ops = {
.name = "anon",
};
-static struct mem_ops __file_ops = {
- .setup_area = &file_setup_area,
+static struct mem_ops __read_only_file_ops = {
+ .setup_area = &file_setup_read_only_area,
.cleanup_area = &file_cleanup_area,
- .fault = &file_fault,
+ .fault = &file_fault_read,
+ .check_huge = &file_check_huge,
+ .name = "file",
+};
+
+static struct mem_ops __read_write_file_ops = {
+ .setup_area = &file_setup_read_write_area,
+ .cleanup_area = &file_cleanup_area,
+ .fault = &file_fault_write,
.check_huge = &file_check_huge,
.name = "file",
};
@@ -504,6 +539,18 @@ static struct mem_ops __shm
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 30 Apr 2026, at 11:16, Zi Yan wrote:
> On 29 Apr 2026, at 11:35, Zi Yan wrote:
>
>> Change the requirement to a file system with large folio support and the
>> supported order needs to include PMD_ORDER.
>>
>> Also add tests of opening a file with read write permission and populating
>> folios with writes. Reuse the XFS image from split_huge_page_test.
>>
>> Signed-off-by: Zi Yan
>> ---
>> tools/testing/selftests/mm/khugepaged.c | 131 +++---
>> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
>> 2 files changed, 102 insertions(+), 41 deletions(-)
>>
>> -static void file_fault(void *p, unsigned long start, unsigned long end)
>> +static void file_fault_common(void *p, unsigned long start, unsigned long
>> end,
>> +int madv_ops)
>> {
>> -if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
>> +if (madvise(((char *)p) + start, end - start, madv_ops)) {
>> perror("madvise(MADV_POPULATE_READ");
>
> Sashiko:
> Since madv_ops can now be either MADV_POPULATE_READ or MADV_POPULATE_WRITE,
> will this hardcoded error message be misleading if the write fault path
> fails?
>
> Answer:
> Will send a fixup.
This is the fixup:
From 76e301cf5198f33d07492e224ec627b94902b4b6 Mon Sep 17 00:00:00 2001
From: Zi Yan
Date: Thu, 30 Apr 2026 11:22:30 -0400
Subject: [PATCH] selftests/mm: khugepaged perror fixup.
Signed-off-by: Zi Yan
---
tools/testing/selftests/mm/khugepaged.c | 5 -
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/khugepaged.c
b/tools/testing/selftests/mm/khugepaged.c
index 80b913185c643..97b8fcc490c76 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -445,7 +445,10 @@ static void file_fault_common(void *p, unsigned long
start, unsigned long end,
int madv_ops)
{
if (madvise(((char *)p) + start, end - start, madv_ops)) {
- perror("madvise(MADV_POPULATE_READ");
+ if (madv_ops == MADV_POPULATE_READ)
+ perror("madvise(MADV_POPULATE_READ");
+ else if (madv_ops == MADV_POPULATE_WRITE)
+ perror("madvise(MADV_POPULATE_WRITE");
exit(EXIT_FAILURE);
}
}
--
2.53.0
Best Regards,
Yan, Zi
Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged
On 29 Apr 2026, at 11:35, Zi Yan wrote:
> Change the requirement to a file system with large folio support and the
> supported order needs to include PMD_ORDER.
>
> Also add tests of opening a file with read write permission and populating
> folios with writes. Reuse the XFS image from split_huge_page_test.
>
> Signed-off-by: Zi Yan
> ---
> tools/testing/selftests/mm/khugepaged.c | 131 +++---
> tools/testing/selftests/mm/run_vmtests.sh | 12 +-
> 2 files changed, 102 insertions(+), 41 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/khugepaged.c
> b/tools/testing/selftests/mm/khugepaged.c
> index a6bb9d50363d2..80b913185c643 100644
> --- a/tools/testing/selftests/mm/khugepaged.c
> +++ b/tools/testing/selftests/mm/khugepaged.c
> @@ -49,7 +49,8 @@ struct mem_ops {
> const char *name;
> };
>
> -static struct mem_ops *file_ops;
> +static struct mem_ops *read_only_file_ops;
> +static struct mem_ops *read_write_file_ops;
> static struct mem_ops *anon_ops;
> static struct mem_ops *shmem_ops;
>
> @@ -112,7 +113,8 @@ static void restore_settings(int sig)
> static void save_settings(void)
> {
> printf("Save THP and khugepaged settings...");
> - if (file_ops && finfo.type == VMA_FILE)
> + if ((read_only_file_ops || read_write_file_ops) &&
> + finfo.type == VMA_FILE)
> thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path);
> thp_save_settings();
>
> @@ -364,11 +366,14 @@ static bool anon_check_huge(void *addr, int nr_hpages)
> return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
> }
>
> -static void *file_setup_area(int nr_hpages)
> +static void *file_setup_area_common(int nr_hpages, bool read_only)
> {
> int fd;
> void *p;
> unsigned long size;
> + int open_opt = read_only ? O_RDONLY : O_RDWR;
> + int mmap_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE);
> + int mmap_opt = read_only ? MAP_PRIVATE : MAP_SHARED;
>
> unlink(finfo.path); /* Cleanup from previous failed tests */
> printf("Creating %s for collapse%s...", finfo.path,
> @@ -399,14 +404,15 @@ static void *file_setup_area(int nr_hpages)
> munmap(p, size);
> success("OK");
>
> - printf("Opening %s read only for collapse...", finfo.path);
> - finfo.fd = open(finfo.path, O_RDONLY, 777);
> + printf("Opening %s %s for collapse...", finfo.path,
> +read_only ? "read only" : "read-write");
> + finfo.fd = open(finfo.path, open_opt, 777);
> if (finfo.fd < 0) {
> perror("open()");
> exit(EXIT_FAILURE);
> }
> - p = mmap(BASE_ADDR, size, PROT_READ,
> - MAP_PRIVATE, finfo.fd, 0);
> + p = mmap(BASE_ADDR, size, mmap_prot,
> + mmap_opt, finfo.fd, 0);
> if (p == MAP_FAILED || p != BASE_ADDR) {
> perror("mmap()");
> exit(EXIT_FAILURE);
> @@ -418,6 +424,16 @@ static void *file_setup_area(int nr_hpages)
> return p;
> }
>
> +static void *file_setup_read_only_area(int nr_hpages)
> +{
> + return file_setup_area_common(nr_hpages, /* read_only= */ true);
> +}
> +
> +static void *file_setup_read_write_area(int nr_hpages)
> +{
> + return file_setup_area_common(nr_hpages, /* read_only= */ false);
> +}
> +
> static void file_cleanup_area(void *p, unsigned long size)
> {
> munmap(p, size);
> @@ -425,14 +441,25 @@ static void file_cleanup_area(void *p, unsigned long
> size)
> unlink(finfo.path);
> }
>
> -static void file_fault(void *p, unsigned long start, unsigned long end)
> +static void file_fault_common(void *p, unsigned long start, unsigned long
> end,
> + int madv_ops)
> {
> - if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) {
> + if (madvise(((char *)p) + start, end - start, madv_ops)) {
> perror("madvise(MADV_POPULATE_READ");
Sashiko:
Since madv_ops can now be either MADV_POPULATE_READ or MADV_POPULATE_WRITE,
will this hardcoded error message be misleading if the write fault path
fails?
Answer:
Will send a fixup.
> exit(EXIT_FAILURE);
> }
> }
>
> +static void file_fault_read(void *p, unsigned long start, unsigned long end)
> +{
> + file_fault_common(p, start, end, MADV_POPULATE_READ);
> +}
> +
> +static void file_fault_write(void *p, unsigned long start, unsigned long end)
> +{
> + file_fault_common(p, start, end, MADV_POPULATE_WRITE);
> +}
> +
> static bool file_check_huge(void *addr, int nr_hpages)
> {
> switch (finfo.type) {
> @@ -488,10 +515,18 @@ static struct mem_ops __anon_ops = {
> .name = "anon",
> };
>
> -static struct mem_ops __file_ops = {
> - .setup_area = &file_setup_area,
> +static struct mem_ops __read_only_file_ops = {
> + .setup_area = &file_setup_read_only_area,
> .cleanup_area = &file_cleanup_area,
> - .fault = &file_fault,
> + .fault = &file_fault_read,
> + .check_huge = &file_check_huge,
> + .name = "file",
>

