Re: [PATCH v5 11/14] selftests/mm: remove READ_ONLY_THP_FOR_FS in khugepaged

2026-05-18 Thread Zi Yan
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

2026-05-16 Thread Zi Yan
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

2026-05-08 Thread David Hildenbrand (Arm)
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

2026-05-08 Thread David Hildenbrand (Arm)
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

2026-05-08 Thread David Hildenbrand (Arm)
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

2026-05-07 Thread Zi Yan
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

2026-05-07 Thread Zi Yan
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

2026-05-06 Thread Nico Pache
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

2026-05-06 Thread Zi Yan
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

2026-05-06 Thread Zi Yan
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

2026-05-04 Thread Nico Pache




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

2026-05-03 Thread Nico Pache




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

2026-04-30 Thread Zi Yan
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

2026-04-30 Thread Zi Yan
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",
>