1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: LGPL-2.1-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2009 IBM Corporation. 4f08c3bdfSopenharmony_ci * Author: David Gibson 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Kernel has bug in mremap for some architecture. mremap() can cause 11f08c3bdfSopenharmony_ci * crashes on architectures with holes in the address space (like ia64) 12f08c3bdfSopenharmony_ci * and on powerpc with it's distict page size slices. 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * This test perform mremap() with normal and hugepages around powerpc 15f08c3bdfSopenharmony_ci * slice boundary. 16f08c3bdfSopenharmony_ci */ 17f08c3bdfSopenharmony_ci 18f08c3bdfSopenharmony_ci#define _GNU_SOURCE 19f08c3bdfSopenharmony_ci#include "hugetlb.h" 20f08c3bdfSopenharmony_ci 21f08c3bdfSopenharmony_ci#define RANDOM_CONSTANT 0x1234ABCD 22f08c3bdfSopenharmony_ci#define MNTPOINT "hugetlbfs/" 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_cistatic int fd = -1; 25f08c3bdfSopenharmony_cistatic unsigned long slice_boundary; 26f08c3bdfSopenharmony_cistatic unsigned long hpage_size, page_size; 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_cistatic int init_slice_boundary(int fd) 29f08c3bdfSopenharmony_ci{ 30f08c3bdfSopenharmony_ci unsigned long slice_size; 31f08c3bdfSopenharmony_ci void *p, *heap; 32f08c3bdfSopenharmony_ci int i; 33f08c3bdfSopenharmony_ci#if defined(__LP64__) && !defined(__aarch64__) 34f08c3bdfSopenharmony_ci /* powerpc: 1TB slices starting at 1 TB */ 35f08c3bdfSopenharmony_ci slice_boundary = 0x10000000000; 36f08c3bdfSopenharmony_ci slice_size = 0x10000000000; 37f08c3bdfSopenharmony_ci#else 38f08c3bdfSopenharmony_ci /* powerpc: 256MB slices up to 4GB */ 39f08c3bdfSopenharmony_ci slice_boundary = 0x00000000; 40f08c3bdfSopenharmony_ci slice_size = 0x10000000; 41f08c3bdfSopenharmony_ci#endif 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci /* dummy malloc so we know where is heap */ 44f08c3bdfSopenharmony_ci heap = malloc(1); 45f08c3bdfSopenharmony_ci free(heap); 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci /* Avoid underflow on systems with large huge pages. 48f08c3bdfSopenharmony_ci * The additionally plus heap address is to reduce the possibility 49f08c3bdfSopenharmony_ci * of MAP_FIXED stomp over existing mappings. 50f08c3bdfSopenharmony_ci */ 51f08c3bdfSopenharmony_ci while (slice_boundary + slice_size < (unsigned long)heap + 2*hpage_size) 52f08c3bdfSopenharmony_ci slice_boundary += slice_size; 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_ci /* Find 2 neighbour slices with couple huge pages free 55f08c3bdfSopenharmony_ci * around slice boundary. 56f08c3bdfSopenharmony_ci * 16 is the maximum number of slices (low/high) 57f08c3bdfSopenharmony_ci */ 58f08c3bdfSopenharmony_ci for (i = 0; i < 16-1; i++) { 59f08c3bdfSopenharmony_ci slice_boundary += slice_size; 60f08c3bdfSopenharmony_ci p = mmap((void *)(slice_boundary-2*hpage_size), 4*hpage_size, 61f08c3bdfSopenharmony_ci PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0); 62f08c3bdfSopenharmony_ci if (p == MAP_FAILED) { 63f08c3bdfSopenharmony_ci tst_res(TINFO|TERRNO, "can't use slice_boundary: 0x%lx", 64f08c3bdfSopenharmony_ci slice_boundary); 65f08c3bdfSopenharmony_ci } else { 66f08c3bdfSopenharmony_ci SAFE_MUNMAP(p, 4*hpage_size); 67f08c3bdfSopenharmony_ci break; 68f08c3bdfSopenharmony_ci } 69f08c3bdfSopenharmony_ci } 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_ci if (p == MAP_FAILED) { 72f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "couldn't find 2 free neighbour slices"); 73f08c3bdfSopenharmony_ci return -1; 74f08c3bdfSopenharmony_ci } 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci tst_res(TINFO, "using slice_boundary: 0x%lx", slice_boundary); 77f08c3bdfSopenharmony_ci 78f08c3bdfSopenharmony_ci return 0; 79f08c3bdfSopenharmony_ci} 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_cistatic void run_test(void) 82f08c3bdfSopenharmony_ci{ 83f08c3bdfSopenharmony_ci void *p = NULL, *q = NULL, *r; 84f08c3bdfSopenharmony_ci long p_size, q_size; 85f08c3bdfSopenharmony_ci int ret; 86f08c3bdfSopenharmony_ci 87f08c3bdfSopenharmony_ci fd = tst_creat_unlinked(MNTPOINT, 0); 88f08c3bdfSopenharmony_ci ret = init_slice_boundary(fd); 89f08c3bdfSopenharmony_ci if (ret) 90f08c3bdfSopenharmony_ci goto cleanup; 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci /* First, hugepages above, normal below */ 93f08c3bdfSopenharmony_ci tst_res(TINFO, "Testing with hpage above & normal below the slice_boundary"); 94f08c3bdfSopenharmony_ci p_size = hpage_size; 95f08c3bdfSopenharmony_ci p = SAFE_MMAP((void *)(slice_boundary + hpage_size), p_size, 96f08c3bdfSopenharmony_ci PROT_READ | PROT_WRITE, 97f08c3bdfSopenharmony_ci MAP_SHARED | MAP_FIXED, fd, 0); 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_ci ret = do_readback(p, p_size, "huge above"); 100f08c3bdfSopenharmony_ci if (ret) 101f08c3bdfSopenharmony_ci goto cleanup; 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci q_size = page_size; 104f08c3bdfSopenharmony_ci q = SAFE_MMAP((void *)(slice_boundary - page_size), q_size, 105f08c3bdfSopenharmony_ci PROT_READ | PROT_WRITE, 106f08c3bdfSopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci ret = do_readback(q, q_size, "normal below"); 109f08c3bdfSopenharmony_ci if (ret) 110f08c3bdfSopenharmony_ci goto cleanup; 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_ci r = mremap(q, page_size, 2*page_size, 0); 113f08c3bdfSopenharmony_ci if (r == MAP_FAILED) { 114f08c3bdfSopenharmony_ci tst_res(TINFO, "mremap(%p, %lu, %lu, 0) disallowed", 115f08c3bdfSopenharmony_ci q, page_size, 2*page_size); 116f08c3bdfSopenharmony_ci } else { 117f08c3bdfSopenharmony_ci q_size = 2*page_size; 118f08c3bdfSopenharmony_ci if (r != q) { 119f08c3bdfSopenharmony_ci tst_res(TFAIL, "mremap() moved without MREMAP_MAYMOVE!?"); 120f08c3bdfSopenharmony_ci ret = -1; 121f08c3bdfSopenharmony_ci } else 122f08c3bdfSopenharmony_ci ret = do_readback(q, 2*page_size, "normal below expanded"); 123f08c3bdfSopenharmony_ci } 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci SAFE_MUNMAP(p, p_size); 126f08c3bdfSopenharmony_ci SAFE_MUNMAP(q, q_size); 127f08c3bdfSopenharmony_ci if (ret) 128f08c3bdfSopenharmony_ci goto cleanup_fd; 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci /* Next, normal pages above, huge below */ 131f08c3bdfSopenharmony_ci tst_res(TINFO, "Testing with normal above & hpage below the slice_boundary"); 132f08c3bdfSopenharmony_ci p_size = page_size; 133f08c3bdfSopenharmony_ci p = SAFE_MMAP((void *)(slice_boundary + hpage_size), p_size, 134f08c3bdfSopenharmony_ci PROT_READ|PROT_WRITE, 135f08c3bdfSopenharmony_ci MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); 136f08c3bdfSopenharmony_ci 137f08c3bdfSopenharmony_ci ret = do_readback(p, p_size, "normal above"); 138f08c3bdfSopenharmony_ci if (ret) 139f08c3bdfSopenharmony_ci goto cleanup; 140f08c3bdfSopenharmony_ci 141f08c3bdfSopenharmony_ci q_size = hpage_size; 142f08c3bdfSopenharmony_ci q = SAFE_MMAP((void *)(slice_boundary - hpage_size), 143f08c3bdfSopenharmony_ci q_size, PROT_READ | PROT_WRITE, 144f08c3bdfSopenharmony_ci MAP_SHARED | MAP_FIXED, fd, 0); 145f08c3bdfSopenharmony_ci 146f08c3bdfSopenharmony_ci ret = do_readback(q, q_size, "huge below"); 147f08c3bdfSopenharmony_ci if (ret) 148f08c3bdfSopenharmony_ci goto cleanup; 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci r = mremap(q, hpage_size, 2*hpage_size, 0); 151f08c3bdfSopenharmony_ci if (r == MAP_FAILED) { 152f08c3bdfSopenharmony_ci tst_res(TINFO, "mremap(%p, %lu, %lu, 0) disallowed", 153f08c3bdfSopenharmony_ci q, hpage_size, 2*hpage_size); 154f08c3bdfSopenharmony_ci } else { 155f08c3bdfSopenharmony_ci q_size = 2*hpage_size; 156f08c3bdfSopenharmony_ci if (r != q) { 157f08c3bdfSopenharmony_ci tst_res(TFAIL, "mremap() moved without MREMAP_MAYMOVE!?"); 158f08c3bdfSopenharmony_ci ret = -1; 159f08c3bdfSopenharmony_ci } else 160f08c3bdfSopenharmony_ci ret = do_readback(q, 2*hpage_size, "huge below expanded"); 161f08c3bdfSopenharmony_ci } 162f08c3bdfSopenharmony_ci if (ret) 163f08c3bdfSopenharmony_ci goto cleanup; 164f08c3bdfSopenharmony_ci 165f08c3bdfSopenharmony_ci tst_res(TPASS, "Successful"); 166f08c3bdfSopenharmony_ci 167f08c3bdfSopenharmony_cicleanup: 168f08c3bdfSopenharmony_ci if (p) 169f08c3bdfSopenharmony_ci SAFE_MUNMAP(p, p_size); 170f08c3bdfSopenharmony_ci if (q) 171f08c3bdfSopenharmony_ci SAFE_MUNMAP(q, q_size); 172f08c3bdfSopenharmony_cicleanup_fd: 173f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 174f08c3bdfSopenharmony_ci} 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_cistatic void setup(void) 177f08c3bdfSopenharmony_ci{ 178f08c3bdfSopenharmony_ci hpage_size = tst_get_hugepage_size(); 179f08c3bdfSopenharmony_ci page_size = getpagesize(); 180f08c3bdfSopenharmony_ci} 181f08c3bdfSopenharmony_ci 182f08c3bdfSopenharmony_cistatic void cleanup(void) 183f08c3bdfSopenharmony_ci{ 184f08c3bdfSopenharmony_ci if (fd >= 0) 185f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 186f08c3bdfSopenharmony_ci} 187f08c3bdfSopenharmony_ci 188f08c3bdfSopenharmony_cistatic struct tst_test test = { 189f08c3bdfSopenharmony_ci .needs_root = 1, 190f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 191f08c3bdfSopenharmony_ci .needs_hugetlbfs = 1, 192f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 193f08c3bdfSopenharmony_ci .setup = setup, 194f08c3bdfSopenharmony_ci .cleanup = cleanup, 195f08c3bdfSopenharmony_ci .test_all = run_test, 196f08c3bdfSopenharmony_ci .hugepages = {4, TST_NEEDS}, 197f08c3bdfSopenharmony_ci}; 198