Re: [PATCH v2 3/4] selftests: mm: implement the mTHP-sized hugepage check helpers

Baolin Wang <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.kernel.mm
Message-ID <[email protected]>

On 8/5/26 11:59 PM, Zi Yan wrote:
> On Sat Aug 1, 2026 at 2:26 AM EDT, Baolin Wang wrote:
>> Implement mTHP-sized hugepage checking helpers using gather_folio_orders().
>> Also rename the existing PMD-sized huge page check function to
>> __check_pmd_huge() for clarity.
>>
>> Signed-off-by: Baolin Wang <[email protected]>
>> ---
>>   tools/testing/selftests/mm/vm_util.c | 60 ++++++++++++++++++++++++++--
>>   1 file changed, 56 insertions(+), 4 deletions(-)
>>
>> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
>> index 09e5d5cabe21..1240d783669c 100644
>> --- a/tools/testing/selftests/mm/vm_util.c
>> +++ b/tools/testing/selftests/mm/vm_util.c
>> @@ -15,6 +15,10 @@
>>   #define SMAP_FILE_PATH "/proc/self/smaps"
>>   #define STATUS_FILE_PATH "/proc/self/status"
>>   #define MAX_LINE_LENGTH 500
>> +#define PAGEMAP_PATH "/proc/self/pagemap"
>> +#define KPAGEFLAGS_PATH "/proc/kpageflags"
>> +#define GET_ORDER(nr_pages)    (31 - __builtin_clz(nr_pages))
> 
> This is a fast way of getting log2, but there is no check of the type of
> nr_pages. What prevents one using it on a long variable?
> 
> At least you can convert nr_pages to unsigned int and add a comment.

Good point. Ack.

>> +#define NR_ORDERS 20
> 
> Why 20? mTHP orders can only be in [1, pmd_order - 1] and different arch
> has different pmd_orders. check_large_folios() probably should just cap
> NR_ORDERS at pmd_order.

I followed the NR_ORDERS definition in selftests/mm/hugepage_settings.h, 
and I think this function is not only for mTHP. Other test cases may 
also call it to get the count of large folios beyond PMD order in the 
future.

>>   unsigned int __page_size;
>>   unsigned int __page_shift;
>> @@ -348,7 +352,7 @@ char *__get_smap_entry(void *addr, const char *pattern, char *buf, size_t len)
>>   	return entry;
>>   }
>>   
>> -bool __check_huge(void *addr, char *pattern, int nr_hpages,
>> +static bool __check_pmd_huge(void *addr, char *pattern, int nr_hpages,
>>   		  uint64_t hpage_size)
>>   {
>>   	char buffer[MAX_LINE_LENGTH];
>> @@ -366,19 +370,67 @@ bool __check_huge(void *addr, char *pattern, int nr_hpages,
>>   	return thp == (nr_hpages * (hpage_size >> 10));
>>   }
>>   
>> +static bool check_large_folios(void *addr, unsigned long size, int nr_hpages, uint64_t hpage_size)
>> +{
>> +	int order = 0, pagesize = getpagesize();
>> +	int nr_pages = hpage_size / pagesize;
>> +	int pagemap_fd, kpageflags_fd;
>> +	int orders[NR_ORDERS], status;
> 
> NR_ORDERS is a constant, so you can put orders on stack. I think you can
> rename it to MAX_NR_ORDERS, use 20, 

Sure.

and check pmd_order is not bigger
> than MAX_NR_ORDERS.

I don't think we need this. As I mentioned above, I hope this function 
can also be used in the future to get the number of large folios beyond 
PMD order.

>> +	bool ret = false;
>> +
>> +	if (nr_pages > 0)
>> +		order = GET_ORDER(nr_pages);
> 
> This funciton can fail early if nr_pages is 0.

Ack.

>> +
>> +	if (!order || order >= NR_ORDERS)
>> +		ksft_exit_fail_msg("invalid order\n");
> 
> It should check against pmd_order.

Ditto.

> 
>> +
>> +	memset(orders, 0, sizeof(int) * NR_ORDERS);
>> +	pagemap_fd = open(PAGEMAP_PATH, O_RDONLY);
>> +	if (pagemap_fd == -1)
>> +		ksft_exit_fail_msg("read pagemap fail\n");
>> +
>> +	kpageflags_fd = open(KPAGEFLAGS_PATH, O_RDONLY);
>> +	if (kpageflags_fd == -1) {
>> +		close(pagemap_fd);
>> +		ksft_exit_fail_msg("read kpageflags fail\n");
>> +	}
>> +
>> +	status = gather_folio_orders(addr, size, pagemap_fd,
>> +			kpageflags_fd, orders, NR_ORDERS);
>> +	if (status)
>> +		goto out;
>> +
>> +	if (orders[order] == nr_hpages)
>> +		ret = true;
>> +
>> +out:
>> +	close(pagemap_fd);
>> +	close(kpageflags_fd);
>> +	return ret;
>> +}
>> +
>>   bool check_huge_anon(void *addr, unsigned long size, int nr_hpages, uint64_t hpage_size)
>>   {
>> -	return __check_huge(addr, "AnonHugePages: ", nr_hpages, hpage_size);
>> +	if (hpage_size == read_pmd_pagesize())
> 
> read_pmd_pagesize() can fail and return 0. Either you need a check here
> or add a ksft_exit_fail_msg() in read_pmd_pagesize() to remove the
> burden from all callers.

Ack.

> 
>> +		return __check_pmd_huge(addr, "AnonHugePages: ", nr_hpages, hpage_size);
>> +
>> +	return check_large_folios(addr, size, nr_hpages, hpage_size);
>>   }
>>   
>>   bool check_huge_file(void *addr, unsigned long size, int nr_hpages, uint64_t hpage_size)
>>   {
>> -	return __check_huge(addr, "FilePmdMapped:", nr_hpages, hpage_size);
>> +	if (hpage_size == read_pmd_pagesize())
>> +		return __check_pmd_huge(addr, "FilePmdMapped:", nr_hpages, hpage_size);
>> +
>> +	return check_large_folios(addr, size, nr_hpages, hpage_size);
>>   }
>>   
>>   bool check_huge_shmem(void *addr, unsigned long size, int nr_hpages, uint64_t hpage_size)
>>   {
>> -	return __check_huge(addr, "ShmemPmdMapped:", nr_hpages, hpage_size);
>> +	if (hpage_size == read_pmd_pagesize())
>> +		return __check_pmd_huge(addr, "ShmemPmdMapped:", nr_hpages, hpage_size);
>> +
>> +	return check_large_folios(addr, size, nr_hpages, hpage_size);
>>   }
>>   
>>   int64_t allocate_transhuge(void *ptr, int pagemap_fd)
> 
> All read_pmd_pagesize()s above need to be handled.

Sure. Thanks for taking a look.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.