~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mm/hugepage-mremap.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // 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.  The path to a file in a hugetlbfs filesystem must
  7  * be passed as the last argument to this test.  The amount of memory used
  8  * by this test in MBs can optionally be passed as an argument.  If no memory
  9  * amount is passed, the default amount is 10MB.
 10  *
 11  * To make sure the test triggers pmd sharing and goes through the 'unshare'
 12  * path in the mremap code use 1GB (1024) or more.
 13  */
 14 
 15 #define _GNU_SOURCE
 16 #include <stdlib.h>
 17 #include <stdio.h>
 18 #include <asm-generic/unistd.h>
 19 #include <sys/mman.h>
 20 #include <errno.h>
 21 #include <fcntl.h> /* Definition of O_* constants */
 22 #include <sys/syscall.h> /* Definition of SYS_* constants */
 23 #include <linux/userfaultfd.h>
 24 #include <sys/ioctl.h>
 25 #include <string.h>
 26 #include <stdbool.h>
 27 #include "../kselftest.h"
 28 #include "vm_util.h"
 29 
 30 #define DEFAULT_LENGTH_MB 10UL
 31 #define MB_TO_BYTES(x) (x * 1024 * 1024)
 32 
 33 #define PROTECTION (PROT_READ | PROT_WRITE | PROT_EXEC)
 34 #define FLAGS (MAP_SHARED | MAP_ANONYMOUS)
 35 
 36 static void check_bytes(char *addr)
 37 {
 38         ksft_print_msg("First hex is %x\n", *((unsigned int *)addr));
 39 }
 40 
 41 static void write_bytes(char *addr, size_t len)
 42 {
 43         unsigned long i;
 44 
 45         for (i = 0; i < len; i++)
 46                 *(addr + i) = (char)i;
 47 }
 48 
 49 static int read_bytes(char *addr, size_t len)
 50 {
 51         unsigned long i;
 52 
 53         check_bytes(addr);
 54         for (i = 0; i < len; i++)
 55                 if (*(addr + i) != (char)i) {
 56                         ksft_print_msg("Mismatch at %lu\n", i);
 57                         return 1;
 58                 }
 59         return 0;
 60 }
 61 
 62 static void register_region_with_uffd(char *addr, size_t len)
 63 {
 64         long uffd; /* userfaultfd file descriptor */
 65         struct uffdio_api uffdio_api;
 66 
 67         /* Create and enable userfaultfd object. */
 68 
 69         uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
 70         if (uffd == -1)
 71                 ksft_exit_fail_msg("userfaultfd: %s\n", strerror(errno));
 72 
 73         uffdio_api.api = UFFD_API;
 74         uffdio_api.features = 0;
 75         if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
 76                 ksft_exit_fail_msg("ioctl-UFFDIO_API: %s\n", strerror(errno));
 77 
 78         /* Create a private anonymous mapping. The memory will be
 79          * demand-zero paged--that is, not yet allocated. When we
 80          * actually touch the memory, it will be allocated via
 81          * the userfaultfd.
 82          */
 83 
 84         addr = mmap(NULL, len, PROT_READ | PROT_WRITE,
 85                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 86         if (addr == MAP_FAILED)
 87                 ksft_exit_fail_msg("mmap: %s\n", strerror(errno));
 88 
 89         ksft_print_msg("Address returned by mmap() = %p\n", addr);
 90 
 91         /* Register the memory range of the mapping we just created for
 92          * handling by the userfaultfd object. In mode, we request to track
 93          * missing pages (i.e., pages that have not yet been faulted in).
 94          */
 95         if (uffd_register(uffd, addr, len, true, false, false))
 96                 ksft_exit_fail_msg("ioctl-UFFDIO_REGISTER: %s\n", strerror(errno));
 97 }
 98 
 99 int main(int argc, char *argv[])
100 {
101         size_t length = 0;
102         int ret = 0, fd;
103 
104         ksft_print_header();
105         ksft_set_plan(1);
106 
107         if (argc >= 2 && !strcmp(argv[1], "-h"))
108                 ksft_exit_fail_msg("Usage: %s [length_in_MB]\n", argv[0]);
109 
110         /* Read memory length as the first arg if valid, otherwise fallback to
111          * the default length.
112          */
113         if (argc >= 2)
114                 length = (size_t)atoi(argv[1]);
115         else
116                 length = DEFAULT_LENGTH_MB;
117 
118         length = MB_TO_BYTES(length);
119         fd = memfd_create(argv[0], MFD_HUGETLB);
120         if (fd < 0)
121                 ksft_exit_fail_msg("Open failed: %s\n", strerror(errno));
122 
123         /* mmap to a PUD aligned address to hopefully trigger pmd sharing. */
124         unsigned long suggested_addr = 0x7eaa40000000;
125         void *haddr = mmap((void *)suggested_addr, length, PROTECTION,
126                            MAP_HUGETLB | MAP_SHARED | MAP_POPULATE, fd, 0);
127         ksft_print_msg("Map haddr: Returned address is %p\n", haddr);
128         if (haddr == MAP_FAILED)
129                 ksft_exit_fail_msg("mmap1: %s\n", strerror(errno));
130 
131         /* mmap again to a dummy address to hopefully trigger pmd sharing. */
132         suggested_addr = 0x7daa40000000;
133         void *daddr = mmap((void *)suggested_addr, length, PROTECTION,
134                            MAP_HUGETLB | MAP_SHARED | MAP_POPULATE, fd, 0);
135         ksft_print_msg("Map daddr: Returned address is %p\n", daddr);
136         if (daddr == MAP_FAILED)
137                 ksft_exit_fail_msg("mmap3: %s\n", strerror(errno));
138 
139         suggested_addr = 0x7faa40000000;
140         void *vaddr =
141                 mmap((void *)suggested_addr, length, PROTECTION, FLAGS, -1, 0);
142         ksft_print_msg("Map vaddr: Returned address is %p\n", vaddr);
143         if (vaddr == MAP_FAILED)
144                 ksft_exit_fail_msg("mmap2: %s\n", strerror(errno));
145 
146         register_region_with_uffd(haddr, length);
147 
148         void *addr = mremap(haddr, length, length,
149                             MREMAP_MAYMOVE | MREMAP_FIXED, vaddr);
150         if (addr == MAP_FAILED)
151                 ksft_exit_fail_msg("mremap: %s\n", strerror(errno));
152 
153         ksft_print_msg("Mremap: Returned address is %p\n", addr);
154         check_bytes(addr);
155         write_bytes(addr, length);
156         ret = read_bytes(addr, length);
157 
158         munmap(addr, length);
159 
160         addr = mremap(addr, length, length, 0);
161         if (addr != MAP_FAILED)
162                 ksft_exit_fail_msg("mremap: Expected failure, but call succeeded\n");
163 
164         close(fd);
165 
166         ksft_test_result(!ret, "Read same data\n");
167         ksft_exit(!ret);
168 }
169 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php