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 <[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.
Confusing, we usually add new test after adding new functionality, not the other way around? :) -- Cheers, David

