blob: 257df94697a52a8c02ea7a706ae14602b17dee08 [file] [log] [blame]
Mina Almasry12b61322021-11-05 13:41:43 -07001// SPDX-License-Identifier: GPL-2.0
2/*
3 * hugepage-mremap:
4 *
5 * Example of remapping huge page memory in a user application using the
6 * mremap system call. Code assumes a hugetlbfs filesystem is mounted
7 * at './huge'. The code will use 10MB worth of huge pages.
8 */
9
10#define _GNU_SOURCE
11#include <stdlib.h>
12#include <stdio.h>
13#include <unistd.h>
14#include <sys/mman.h>
15#include <errno.h>
16#include <fcntl.h> /* Definition of O_* constants */
17#include <sys/syscall.h> /* Definition of SYS_* constants */
Mina Almasry12b61322021-11-05 13:41:43 -070018#include <linux/userfaultfd.h>
19#include <sys/ioctl.h>
20
21#define LENGTH (1UL * 1024 * 1024 * 1024)
22
23#define PROTECTION (PROT_READ | PROT_WRITE | PROT_EXEC)
24#define FLAGS (MAP_SHARED | MAP_ANONYMOUS)
25
26static void check_bytes(char *addr)
27{
28 printf("First hex is %x\n", *((unsigned int *)addr));
29}
30
31static void write_bytes(char *addr)
32{
33 unsigned long i;
34
35 for (i = 0; i < LENGTH; i++)
36 *(addr + i) = (char)i;
37}
38
39static int read_bytes(char *addr)
40{
41 unsigned long i;
42
43 check_bytes(addr);
44 for (i = 0; i < LENGTH; i++)
45 if (*(addr + i) != (char)i) {
46 printf("Mismatch at %lu\n", i);
47 return 1;
48 }
49 return 0;
50}
51
52static void register_region_with_uffd(char *addr, size_t len)
53{
54 long uffd; /* userfaultfd file descriptor */
55 struct uffdio_api uffdio_api;
56 struct uffdio_register uffdio_register;
57
58 /* Create and enable userfaultfd object. */
59
60 uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
61 if (uffd == -1) {
62 perror("userfaultfd");
63 exit(1);
64 }
65
66 uffdio_api.api = UFFD_API;
67 uffdio_api.features = 0;
68 if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1) {
69 perror("ioctl-UFFDIO_API");
70 exit(1);
71 }
72
73 /* Create a private anonymous mapping. The memory will be
74 * demand-zero paged--that is, not yet allocated. When we
75 * actually touch the memory, it will be allocated via
76 * the userfaultfd.
77 */
78
79 addr = mmap(NULL, len, PROT_READ | PROT_WRITE,
80 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
81 if (addr == MAP_FAILED) {
82 perror("mmap");
83 exit(1);
84 }
85
86 printf("Address returned by mmap() = %p\n", addr);
87
88 /* Register the memory range of the mapping we just created for
89 * handling by the userfaultfd object. In mode, we request to track
90 * missing pages (i.e., pages that have not yet been faulted in).
91 */
92
93 uffdio_register.range.start = (unsigned long)addr;
94 uffdio_register.range.len = len;
95 uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
96 if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) {
97 perror("ioctl-UFFDIO_REGISTER");
98 exit(1);
99 }
100}
101
102int main(void)
103{
104 int ret = 0;
105
106 int fd = open("/huge/test", O_CREAT | O_RDWR, 0755);
107
108 if (fd < 0) {
109 perror("Open failed");
110 exit(1);
111 }
112
113 /* mmap to a PUD aligned address to hopefully trigger pmd sharing. */
114 unsigned long suggested_addr = 0x7eaa40000000;
115 void *haddr = mmap((void *)suggested_addr, LENGTH, PROTECTION,
116 MAP_HUGETLB | MAP_SHARED | MAP_POPULATE, fd, 0);
117 printf("Map haddr: Returned address is %p\n", haddr);
118 if (haddr == MAP_FAILED) {
119 perror("mmap1");
120 exit(1);
121 }
122
123 /* mmap again to a dummy address to hopefully trigger pmd sharing. */
124 suggested_addr = 0x7daa40000000;
125 void *daddr = mmap((void *)suggested_addr, LENGTH, PROTECTION,
126 MAP_HUGETLB | MAP_SHARED | MAP_POPULATE, fd, 0);
127 printf("Map daddr: Returned address is %p\n", daddr);
128 if (daddr == MAP_FAILED) {
129 perror("mmap3");
130 exit(1);
131 }
132
133 suggested_addr = 0x7faa40000000;
134 void *vaddr =
135 mmap((void *)suggested_addr, LENGTH, PROTECTION, FLAGS, -1, 0);
136 printf("Map vaddr: Returned address is %p\n", vaddr);
137 if (vaddr == MAP_FAILED) {
138 perror("mmap2");
139 exit(1);
140 }
141
142 register_region_with_uffd(haddr, LENGTH);
143
144 void *addr = mremap(haddr, LENGTH, LENGTH,
145 MREMAP_MAYMOVE | MREMAP_FIXED, vaddr);
146 if (addr == MAP_FAILED) {
147 perror("mremap");
148 exit(1);
149 }
150
151 printf("Mremap: Returned address is %p\n", addr);
152 check_bytes(addr);
153 write_bytes(addr);
154 ret = read_bytes(addr);
155
156 munmap(addr, LENGTH);
157
158 return ret;
159}