File Index
Files and directories
Sign in
FILE

hugepage-vmemmap.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/mm/hugepage-vmemmap.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * A test case of using hugepage memory in a user application using the
  4 * mmap system call with MAP_HUGETLB flag.  Before running this program
  5 * make sure the administrator has allocated enough default sized huge
  6 * pages to cover the 2 MB allocation.
  7 */
  8#include <stdlib.h>
  9#include <stdio.h>
 10#include <unistd.h>
 11#include <sys/mman.h>
 12#include <fcntl.h>
 13#include "vm_util.h"
 14
 15#define PAGE_COMPOUND_HEAD	(1UL << 15)
 16#define PAGE_COMPOUND_TAIL	(1UL << 16)
 17#define PAGE_HUGE		(1UL << 17)
 18
 19#define HEAD_PAGE_FLAGS		(PAGE_COMPOUND_HEAD | PAGE_HUGE)
 20#define TAIL_PAGE_FLAGS		(PAGE_COMPOUND_TAIL | PAGE_HUGE)
 21
 22#define PM_PFRAME_BITS		55
 23#define PM_PFRAME_MASK		~((1UL << PM_PFRAME_BITS) - 1)
 24
 25static size_t pagesize;
 26static size_t maplength;
 27
 28static void write_bytes(char *addr, size_t length)
 29{
 30	unsigned long i;
 31
 32	for (i = 0; i < length; i++)
 33		*(addr + i) = (char)i;
 34}
 35
 36static unsigned long virt_to_pfn(void *addr)
 37{
 38	int fd;
 39	unsigned long pagemap;
 40
 41	fd = open("/proc/self/pagemap", O_RDONLY);
 42	if (fd < 0)
 43		return -1UL;
 44
 45	lseek(fd, (unsigned long)addr / pagesize * sizeof(pagemap), SEEK_SET);
 46	read(fd, &pagemap, sizeof(pagemap));
 47	close(fd);
 48
 49	return pagemap & ~PM_PFRAME_MASK;
 50}
 51
 52static int check_page_flags(unsigned long pfn)
 53{
 54	int fd, i;
 55	unsigned long pageflags;
 56
 57	fd = open("/proc/kpageflags", O_RDONLY);
 58	if (fd < 0)
 59		return -1;
 60
 61	lseek(fd, pfn * sizeof(pageflags), SEEK_SET);
 62
 63	read(fd, &pageflags, sizeof(pageflags));
 64	if ((pageflags & HEAD_PAGE_FLAGS) != HEAD_PAGE_FLAGS) {
 65		close(fd);
 66		printf("Head page flags (%lx) is invalid\n", pageflags);
 67		return -1;
 68	}
 69
 70	/*
 71	 * pages other than the first page must be tail and shouldn't be head;
 72	 * this also verifies kernel has correctly set the fake page_head to tail
 73	 * while hugetlb_free_vmemmap is enabled.
 74	 */
 75	for (i = 1; i < maplength / pagesize; i++) {
 76		read(fd, &pageflags, sizeof(pageflags));
 77		if ((pageflags & TAIL_PAGE_FLAGS) != TAIL_PAGE_FLAGS ||
 78		    (pageflags & HEAD_PAGE_FLAGS) == HEAD_PAGE_FLAGS) {
 79			close(fd);
 80			printf("Tail page flags (%lx) is invalid\n", pageflags);
 81			return -1;
 82		}
 83	}
 84
 85	close(fd);
 86
 87	return 0;
 88}
 89
 90int main(int argc, char **argv)
 91{
 92	void *addr;
 93	unsigned long pfn;
 94
 95	pagesize  = psize();
 96	maplength = default_huge_page_size();
 97	if (!maplength) {
 98		printf("Unable to determine huge page size\n");
 99		exit(1);
100	}
101
102	addr = mmap(NULL, maplength, PROT_READ | PROT_WRITE,
103			MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
104	if (addr == MAP_FAILED) {
105		perror("mmap");
106		exit(1);
107	}
108
109	/* Trigger allocation of HugeTLB page. */
110	write_bytes(addr, maplength);
111
112	pfn = virt_to_pfn(addr);
113	if (pfn == -1UL) {
114		munmap(addr, maplength);
115		perror("virt_to_pfn");
116		exit(1);
117	}
118
119	printf("Returned address is %p whose pfn is %lx\n", addr, pfn);
120
121	if (check_page_flags(pfn) < 0) {
122		munmap(addr, maplength);
123		perror("check_page_flags");
124		exit(1);
125	}
126
127	/* munmap() length of MAP_HUGETLB memory must be hugepage aligned */
128	if (munmap(addr, maplength)) {
129		perror("munmap");
130		exit(1);
131	}
132
133	return 0;
134}
~/ Read-only file preview.