0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #define _GNU_SOURCE
0016 #include <stdlib.h>
0017 #include <stdio.h>
0018 #include <unistd.h>
0019 #include <sys/mman.h>
0020 #include <errno.h>
0021 #include <fcntl.h> /* Definition of O_* constants */
0022 #include <sys/syscall.h> /* Definition of SYS_* constants */
0023 #include <linux/userfaultfd.h>
0024 #include <sys/ioctl.h>
0025
0026 #define DEFAULT_LENGTH_MB 10UL
0027 #define MB_TO_BYTES(x) (x * 1024 * 1024)
0028
0029 #define PROTECTION (PROT_READ | PROT_WRITE | PROT_EXEC)
0030 #define FLAGS (MAP_SHARED | MAP_ANONYMOUS)
0031
0032 static void check_bytes(char *addr)
0033 {
0034 printf("First hex is %x\n", *((unsigned int *)addr));
0035 }
0036
0037 static void write_bytes(char *addr, size_t len)
0038 {
0039 unsigned long i;
0040
0041 for (i = 0; i < len; i++)
0042 *(addr + i) = (char)i;
0043 }
0044
0045 static int read_bytes(char *addr, size_t len)
0046 {
0047 unsigned long i;
0048
0049 check_bytes(addr);
0050 for (i = 0; i < len; i++)
0051 if (*(addr + i) != (char)i) {
0052 printf("Mismatch at %lu\n", i);
0053 return 1;
0054 }
0055 return 0;
0056 }
0057
0058 static void register_region_with_uffd(char *addr, size_t len)
0059 {
0060 long uffd;
0061 struct uffdio_api uffdio_api;
0062 struct uffdio_register uffdio_register;
0063
0064
0065
0066 uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
0067 if (uffd == -1) {
0068 perror("userfaultfd");
0069 exit(1);
0070 }
0071
0072 uffdio_api.api = UFFD_API;
0073 uffdio_api.features = 0;
0074 if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1) {
0075 perror("ioctl-UFFDIO_API");
0076 exit(1);
0077 }
0078
0079
0080
0081
0082
0083
0084
0085 addr = mmap(NULL, len, PROT_READ | PROT_WRITE,
0086 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
0087 if (addr == MAP_FAILED) {
0088 perror("mmap");
0089 exit(1);
0090 }
0091
0092 printf("Address returned by mmap() = %p\n", addr);
0093
0094
0095
0096
0097
0098
0099 uffdio_register.range.start = (unsigned long)addr;
0100 uffdio_register.range.len = len;
0101 uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
0102 if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) {
0103 perror("ioctl-UFFDIO_REGISTER");
0104 exit(1);
0105 }
0106 }
0107
0108 int main(int argc, char *argv[])
0109 {
0110 size_t length = 0;
0111
0112 if (argc != 2 && argc != 3) {
0113 printf("Usage: %s [length_in_MB] <hugetlb_file>\n", argv[0]);
0114 exit(1);
0115 }
0116
0117
0118
0119
0120 if (argc == 3)
0121 length = argc > 2 ? (size_t)atoi(argv[1]) : 0UL;
0122
0123 length = length > 0 ? length : DEFAULT_LENGTH_MB;
0124 length = MB_TO_BYTES(length);
0125
0126 int ret = 0;
0127
0128
0129 int fd = open(argv[argc-1], O_CREAT | O_RDWR, 0755);
0130
0131 if (fd < 0) {
0132 perror("Open failed");
0133 exit(1);
0134 }
0135
0136
0137 unsigned long suggested_addr = 0x7eaa40000000;
0138 void *haddr = mmap((void *)suggested_addr, length, PROTECTION,
0139 MAP_HUGETLB | MAP_SHARED | MAP_POPULATE, fd, 0);
0140 printf("Map haddr: Returned address is %p\n", haddr);
0141 if (haddr == MAP_FAILED) {
0142 perror("mmap1");
0143 exit(1);
0144 }
0145
0146
0147 suggested_addr = 0x7daa40000000;
0148 void *daddr = mmap((void *)suggested_addr, length, PROTECTION,
0149 MAP_HUGETLB | MAP_SHARED | MAP_POPULATE, fd, 0);
0150 printf("Map daddr: Returned address is %p\n", daddr);
0151 if (daddr == MAP_FAILED) {
0152 perror("mmap3");
0153 exit(1);
0154 }
0155
0156 suggested_addr = 0x7faa40000000;
0157 void *vaddr =
0158 mmap((void *)suggested_addr, length, PROTECTION, FLAGS, -1, 0);
0159 printf("Map vaddr: Returned address is %p\n", vaddr);
0160 if (vaddr == MAP_FAILED) {
0161 perror("mmap2");
0162 exit(1);
0163 }
0164
0165 register_region_with_uffd(haddr, length);
0166
0167 void *addr = mremap(haddr, length, length,
0168 MREMAP_MAYMOVE | MREMAP_FIXED, vaddr);
0169 if (addr == MAP_FAILED) {
0170 perror("mremap");
0171 exit(1);
0172 }
0173
0174 printf("Mremap: Returned address is %p\n", addr);
0175 check_bytes(addr);
0176 write_bytes(addr, length);
0177 ret = read_bytes(addr, length);
0178
0179 munmap(addr, length);
0180
0181 addr = mremap(addr, length, length, 0);
0182 if (addr != MAP_FAILED) {
0183 printf("mremap: Expected failure, but call succeeded\n");
0184 exit(1);
0185 }
0186
0187 close(fd);
0188 unlink(argv[argc-1]);
0189
0190 return ret;
0191 }