brintos

brintos / linux-shallow public Read only

0
0
Text · 3.0 KiB · df366a4 Raw
135 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * A test case of using hugepage memory in a user application using the4 * mmap system call with MAP_HUGETLB flag.  Before running this program5 * make sure the administrator has allocated enough default sized huge6 * 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		5523#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 tail73	 * 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}135