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 <[email protected]> >> --- >> 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 __shmem_ops = { >> .name = "shmem", >> }; >> +static bool is_tmpfs(struct mem_ops *ops) >> +{ >> + return (ops == &__read_only_file_ops || >> + ops == &__read_write_file_ops) && >> + finfo.type == VMA_SHMEM; >> +} >> + >> +static bool is_anon(struct mem_ops *ops) >> +{ >> + return ops == &__anon_ops; >> +} >> + >> static void __madvise_collapse(const char *msg, char *p, int nr_hpages, >> struct mem_ops *ops, bool expect) >> { >> @@ -512,6 +559,10 @@ static void __madvise_collapse(const char *msg, char >> *p, int nr_hpages, >> printf("%s...", msg); >> + /* read&write file collapse always fail */ > > Just to confirm, you are adding the write part here so that before commit 13 > & 14, the behavior is that it will fail. Whereas after with patch 13/14, we > expect this behavior to be supported correct? Yes.
> > Thanks for working on this :) > > I plan on testing the selftests changes at some point this week (if I find > some downtime during LSFMM), and finishing my review here. > Thanks. Best Regards, Yan, Zi

