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