1a93cbee5SMike Rapoport (Microsoft) // SPDX-License-Identifier: GPL-2.0 2a93cbee5SMike Rapoport (Microsoft) /* 3a93cbee5SMike Rapoport (Microsoft) * hugetlb-mmap: 4a93cbee5SMike Rapoport (Microsoft) * 5a93cbee5SMike Rapoport (Microsoft) * Example of using huge page memory in a user application using the mmap 6a93cbee5SMike Rapoport (Microsoft) * system call. Before running this application, make sure that the 7a93cbee5SMike Rapoport (Microsoft) * administrator has mounted the hugetlbfs filesystem (on some directory 8a93cbee5SMike Rapoport (Microsoft) * like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this 9a93cbee5SMike Rapoport (Microsoft) * example, the app is requesting memory of size 256MB that is backed by 10a93cbee5SMike Rapoport (Microsoft) * huge pages. 11a93cbee5SMike Rapoport (Microsoft) */ 12a93cbee5SMike Rapoport (Microsoft) #define _GNU_SOURCE 13a93cbee5SMike Rapoport (Microsoft) #include <stdlib.h> 14a93cbee5SMike Rapoport (Microsoft) #include <stdio.h> 15a93cbee5SMike Rapoport (Microsoft) #include <unistd.h> 16a93cbee5SMike Rapoport (Microsoft) #include <sys/mman.h> 17a93cbee5SMike Rapoport (Microsoft) #include <fcntl.h> 18a93cbee5SMike Rapoport (Microsoft) #include <linux/memfd.h> 19a93cbee5SMike Rapoport (Microsoft) #include "vm_util.h" 20a93cbee5SMike Rapoport (Microsoft) #include "kselftest.h" 211bdc1698SMike Rapoport (Microsoft) #include "hugepage_settings.h" 22a93cbee5SMike Rapoport (Microsoft) 23a93cbee5SMike Rapoport (Microsoft) #define LENGTH (256UL*1024*1024) 24a93cbee5SMike Rapoport (Microsoft) #define PROTECTION (PROT_READ | PROT_WRITE) 25a93cbee5SMike Rapoport (Microsoft) 26a93cbee5SMike Rapoport (Microsoft) static void check_bytes(char *addr) 27a93cbee5SMike Rapoport (Microsoft) { 28a93cbee5SMike Rapoport (Microsoft) ksft_print_msg("First hex is %x\n", *((unsigned int *)addr)); 29a93cbee5SMike Rapoport (Microsoft) } 30a93cbee5SMike Rapoport (Microsoft) 31a93cbee5SMike Rapoport (Microsoft) static void write_bytes(char *addr, size_t length) 32a93cbee5SMike Rapoport (Microsoft) { 33a93cbee5SMike Rapoport (Microsoft) unsigned long i; 34a93cbee5SMike Rapoport (Microsoft) 35a93cbee5SMike Rapoport (Microsoft) for (i = 0; i < length; i++) 36a93cbee5SMike Rapoport (Microsoft) *(addr + i) = (char)i; 37a93cbee5SMike Rapoport (Microsoft) } 38a93cbee5SMike Rapoport (Microsoft) 39a93cbee5SMike Rapoport (Microsoft) static bool verify_bytes(char *addr, size_t length) 40a93cbee5SMike Rapoport (Microsoft) { 41a93cbee5SMike Rapoport (Microsoft) unsigned long i; 42a93cbee5SMike Rapoport (Microsoft) 43a93cbee5SMike Rapoport (Microsoft) check_bytes(addr); 44a93cbee5SMike Rapoport (Microsoft) for (i = 0; i < length; i++) 45a93cbee5SMike Rapoport (Microsoft) if (*(addr + i) != (char)i) { 46a93cbee5SMike Rapoport (Microsoft) ksft_print_msg("Error: Mismatch at %lu(%p)\n", i, addr); 47a93cbee5SMike Rapoport (Microsoft) return false; 48a93cbee5SMike Rapoport (Microsoft) } 49a93cbee5SMike Rapoport (Microsoft) 50a93cbee5SMike Rapoport (Microsoft) return true; 51a93cbee5SMike Rapoport (Microsoft) } 52a93cbee5SMike Rapoport (Microsoft) 53a93cbee5SMike Rapoport (Microsoft) static void test_mmap(size_t length, int mmap_flags, int fd, 54a93cbee5SMike Rapoport (Microsoft) const char *test_name) 55a93cbee5SMike Rapoport (Microsoft) { 56a93cbee5SMike Rapoport (Microsoft) bool passed = true; 57a93cbee5SMike Rapoport (Microsoft) void *addr; 58a93cbee5SMike Rapoport (Microsoft) 59a93cbee5SMike Rapoport (Microsoft) addr = mmap(NULL, length, PROTECTION, mmap_flags, fd, 0); 60a93cbee5SMike Rapoport (Microsoft) if (addr == MAP_FAILED) 61a93cbee5SMike Rapoport (Microsoft) ksft_exit_fail_perror("mmap"); 62a93cbee5SMike Rapoport (Microsoft) 63a93cbee5SMike Rapoport (Microsoft) ksft_print_msg("Returned address is %p\n", addr); 64a93cbee5SMike Rapoport (Microsoft) check_bytes(addr); 65a93cbee5SMike Rapoport (Microsoft) write_bytes(addr, length); 66a93cbee5SMike Rapoport (Microsoft) if (!verify_bytes(addr, length)) 67a93cbee5SMike Rapoport (Microsoft) passed = false; 68a93cbee5SMike Rapoport (Microsoft) 69a93cbee5SMike Rapoport (Microsoft) /* munmap() length of MAP_HUGETLB memory must be hugepage aligned */ 70a93cbee5SMike Rapoport (Microsoft) if (munmap(addr, length)) 71a93cbee5SMike Rapoport (Microsoft) ksft_exit_fail_perror("munmap"); 72a93cbee5SMike Rapoport (Microsoft) 73a93cbee5SMike Rapoport (Microsoft) ksft_test_result(passed, "%s\n", test_name); 74a93cbee5SMike Rapoport (Microsoft) } 75a93cbee5SMike Rapoport (Microsoft) 76a93cbee5SMike Rapoport (Microsoft) static void test_anon_mmap(size_t length, int shift) 77a93cbee5SMike Rapoport (Microsoft) { 78a93cbee5SMike Rapoport (Microsoft) const char *test_name = "hugetlb anonymous mmap"; 79a93cbee5SMike Rapoport (Microsoft) int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB; 80a93cbee5SMike Rapoport (Microsoft) 81a93cbee5SMike Rapoport (Microsoft) if (shift) 82a93cbee5SMike Rapoport (Microsoft) mmap_flags |= (shift & MAP_HUGE_MASK) << MAP_HUGE_SHIFT; 83a93cbee5SMike Rapoport (Microsoft) 84a93cbee5SMike Rapoport (Microsoft) test_mmap(length, mmap_flags, -1, test_name); 85a93cbee5SMike Rapoport (Microsoft) } 86a93cbee5SMike Rapoport (Microsoft) 87a93cbee5SMike Rapoport (Microsoft) static void test_file_mmap(size_t length, int shift) 88a93cbee5SMike Rapoport (Microsoft) { 89a93cbee5SMike Rapoport (Microsoft) const char *test_name = "hugetlb file mmap"; 90a93cbee5SMike Rapoport (Microsoft) int mfd_flags = MFD_HUGETLB; 91a93cbee5SMike Rapoport (Microsoft) int fd; 92a93cbee5SMike Rapoport (Microsoft) 93a93cbee5SMike Rapoport (Microsoft) if (shift) 94a93cbee5SMike Rapoport (Microsoft) mfd_flags |= (shift & MFD_HUGE_MASK) << MFD_HUGE_SHIFT; 95a93cbee5SMike Rapoport (Microsoft) 96a93cbee5SMike Rapoport (Microsoft) fd = memfd_create("hugetlb-mmap", mfd_flags); 97a93cbee5SMike Rapoport (Microsoft) if (fd < 0) 98a93cbee5SMike Rapoport (Microsoft) ksft_exit_fail_perror("memfd_create"); 99a93cbee5SMike Rapoport (Microsoft) 100a93cbee5SMike Rapoport (Microsoft) test_mmap(length, MAP_SHARED, fd, test_name); 101a93cbee5SMike Rapoport (Microsoft) close(fd); 102a93cbee5SMike Rapoport (Microsoft) } 103a93cbee5SMike Rapoport (Microsoft) 104a93cbee5SMike Rapoport (Microsoft) int main(int argc, char **argv) 105a93cbee5SMike Rapoport (Microsoft) { 106a93cbee5SMike Rapoport (Microsoft) size_t hugepage_size; 107a93cbee5SMike Rapoport (Microsoft) size_t length = LENGTH; 108*ae571cd6SMike Rapoport (Microsoft) int shift = 0, nr; 109a93cbee5SMike Rapoport (Microsoft) 110a93cbee5SMike Rapoport (Microsoft) ksft_print_header(); 111a93cbee5SMike Rapoport (Microsoft) 112a93cbee5SMike Rapoport (Microsoft) if (argc > 1) 113a93cbee5SMike Rapoport (Microsoft) length = atol(argv[1]) << 20; 114a93cbee5SMike Rapoport (Microsoft) if (argc > 2) 115a93cbee5SMike Rapoport (Microsoft) shift = atoi(argv[2]); 116a93cbee5SMike Rapoport (Microsoft) 117*ae571cd6SMike Rapoport (Microsoft) hugetlb_save_settings(); 118a93cbee5SMike Rapoport (Microsoft) if (shift) { 119a93cbee5SMike Rapoport (Microsoft) hugepage_size = (1UL << shift); 120a93cbee5SMike Rapoport (Microsoft) ksft_print_msg("%lu kB hugepages\n", 1UL << (shift - 10)); 121a93cbee5SMike Rapoport (Microsoft) } else { 122a93cbee5SMike Rapoport (Microsoft) hugepage_size = default_huge_page_size(); 123*ae571cd6SMike Rapoport (Microsoft) if (!hugepage_size) 124*ae571cd6SMike Rapoport (Microsoft) ksft_exit_skip("Could not detect default hugetlb page size."); 125a93cbee5SMike Rapoport (Microsoft) ksft_print_msg("Default size hugepages (%lu kB)\n", hugepage_size >> 10); 126a93cbee5SMike Rapoport (Microsoft) } 127a93cbee5SMike Rapoport (Microsoft) 128a93cbee5SMike Rapoport (Microsoft) /* munmap will fail if the length is not page aligned */ 129*ae571cd6SMike Rapoport (Microsoft) length = (length + hugepage_size - 1) & ~(hugepage_size - 1); 130*ae571cd6SMike Rapoport (Microsoft) nr = length / hugepage_size; 131a93cbee5SMike Rapoport (Microsoft) 132*ae571cd6SMike Rapoport (Microsoft) hugetlb_set_nr_pages(hugepage_size, nr); 133*ae571cd6SMike Rapoport (Microsoft) if (hugetlb_free_pages(hugepage_size) < nr) 134*ae571cd6SMike Rapoport (Microsoft) ksft_exit_skip("Not enough %lu Kb pages\n", hugepage_size >> 10); 135*ae571cd6SMike Rapoport (Microsoft) 136*ae571cd6SMike Rapoport (Microsoft) ksft_set_plan(2); 137a93cbee5SMike Rapoport (Microsoft) ksft_print_msg("Mapping %lu Mbytes\n", (unsigned long)length >> 20); 138a93cbee5SMike Rapoport (Microsoft) 139a93cbee5SMike Rapoport (Microsoft) test_anon_mmap(length, shift); 140a93cbee5SMike Rapoport (Microsoft) test_file_mmap(length, shift); 141a93cbee5SMike Rapoport (Microsoft) 142a93cbee5SMike Rapoport (Microsoft) ksft_finished(); 143a93cbee5SMike Rapoport (Microsoft) } 144