1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci 3f08c3bdfSopenharmony_ci/* 4f08c3bdfSopenharmony_ci * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 5f08c3bdfSopenharmony_ci * Email: code@zilogic.com 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci 8f08c3bdfSopenharmony_ci/* 9f08c3bdfSopenharmony_ci * Test: Validating memfd_create() with MFD_HUGETLB flag. 10f08c3bdfSopenharmony_ci * 11f08c3bdfSopenharmony_ci * Test case 1: --WRITE CALL IN HUGEPAGES TEST-- 12f08c3bdfSopenharmony_ci * Huge pages are write protected. Any writes to 13f08c3bdfSopenharmony_ci * the file should return EINVAL error. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * Test case 2: --PAGE SIZE OF CREATED FILE TEST-- 16f08c3bdfSopenharmony_ci * Default huge page sized pages are created with 17f08c3bdfSopenharmony_ci * MFD_HUGETLB flag. Any attempt to unmap memory-mapped 18f08c3bdfSopenharmony_ci * huge pages with an unmapping length less than 19f08c3bdfSopenharmony_ci * huge page size should return EINVAL error. 20f08c3bdfSopenharmony_ci * 21f08c3bdfSopenharmony_ci * Test case 3: --HUGEPAGE ALLOCATION LIMIT TEST-- 22f08c3bdfSopenharmony_ci * Number of huge pages currently available to use should be 23f08c3bdfSopenharmony_ci * atmost total number of allowed huge pages. Memory-mapping 24f08c3bdfSopenharmony_ci * more than allowed huge pages should return ENOMEM error. 25f08c3bdfSopenharmony_ci */ 26f08c3bdfSopenharmony_ci 27f08c3bdfSopenharmony_ci#define _GNU_SOURCE 28f08c3bdfSopenharmony_ci 29f08c3bdfSopenharmony_ci#include "tst_test.h" 30f08c3bdfSopenharmony_ci#include "memfd_create_common.h" 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_ci#include <stdio.h> 33f08c3bdfSopenharmony_ci#include <errno.h> 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_cistatic void *check_huge_mmapable(int fd, unsigned long size) 36f08c3bdfSopenharmony_ci{ 37f08c3bdfSopenharmony_ci void *mem; 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_ci mem = SAFE_MMAP(NULL, size, PROT_WRITE, MAP_PRIVATE, fd, 0); 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_ci memset((char *)mem, 0, 1); 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci tst_res(TINFO, 44f08c3bdfSopenharmony_ci "mmap(%p, %lu, %d, %d, %d, %d) succeeded", 45f08c3bdfSopenharmony_ci NULL, size, PROT_WRITE, MAP_PRIVATE, fd, 0); 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci return mem; 48f08c3bdfSopenharmony_ci} 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_cistatic void test_write_protect(int fd) 51f08c3bdfSopenharmony_ci{ 52f08c3bdfSopenharmony_ci ssize_t ret; 53f08c3bdfSopenharmony_ci char test_str[] = "LTP"; 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_ci ret = write(fd, test_str, strlen(test_str)); 56f08c3bdfSopenharmony_ci if (ret < 0) { 57f08c3bdfSopenharmony_ci if (errno != EINVAL) { 58f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, 59f08c3bdfSopenharmony_ci "write(%d, \"%s\", %zu) didn't fail as expected\n", 60f08c3bdfSopenharmony_ci fd, test_str, strlen(test_str)); 61f08c3bdfSopenharmony_ci return; 62f08c3bdfSopenharmony_ci } 63f08c3bdfSopenharmony_ci } else { 64f08c3bdfSopenharmony_ci tst_res(TFAIL, 65f08c3bdfSopenharmony_ci "write(%d, \"%s\", %zu) succeeded unexpectedly\n", 66f08c3bdfSopenharmony_ci fd, test_str, strlen(test_str)); 67f08c3bdfSopenharmony_ci return; 68f08c3bdfSopenharmony_ci } 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci tst_res(TPASS, 71f08c3bdfSopenharmony_ci "write(%d, \"%s\", %zu) failed as expected\n", 72f08c3bdfSopenharmony_ci fd, test_str, strlen(test_str)); 73f08c3bdfSopenharmony_ci} 74f08c3bdfSopenharmony_ci 75f08c3bdfSopenharmony_cistatic void test_def_pagesize(int fd) 76f08c3bdfSopenharmony_ci{ 77f08c3bdfSopenharmony_ci unsigned int i; 78f08c3bdfSopenharmony_ci int unmap_size; 79f08c3bdfSopenharmony_ci int ret; 80f08c3bdfSopenharmony_ci long hps; 81f08c3bdfSopenharmony_ci void *mem; 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci hps = SAFE_READ_MEMINFO("Hugepagesize:"); 84f08c3bdfSopenharmony_ci hps = hps << 10; 85f08c3bdfSopenharmony_ci unmap_size = hps / 4; 86f08c3bdfSopenharmony_ci mem = check_huge_mmapable(fd, hps); 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci for (i = unmap_size; i < hps; i += unmap_size) { 89f08c3bdfSopenharmony_ci ret = munmap(mem, i); 90f08c3bdfSopenharmony_ci if (ret == -1) { 91f08c3bdfSopenharmony_ci if (errno == EINVAL) { 92f08c3bdfSopenharmony_ci tst_res(TINFO, 93f08c3bdfSopenharmony_ci "munmap(%p, %dkB) failed as expected", 94f08c3bdfSopenharmony_ci mem, i/1024); 95f08c3bdfSopenharmony_ci } else { 96f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, 97f08c3bdfSopenharmony_ci "munmap(%p, %dkB) failed unexpectedly", 98f08c3bdfSopenharmony_ci mem, i/1024); 99f08c3bdfSopenharmony_ci return; 100f08c3bdfSopenharmony_ci } 101f08c3bdfSopenharmony_ci } else { 102f08c3bdfSopenharmony_ci tst_res(TFAIL, 103f08c3bdfSopenharmony_ci "munmap(%p, %dkB) suceeded unexpectedly\n", 104f08c3bdfSopenharmony_ci mem, i/1024); 105f08c3bdfSopenharmony_ci return; 106f08c3bdfSopenharmony_ci } 107f08c3bdfSopenharmony_ci } 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci SAFE_MUNMAP(mem, hps); 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci tst_res(TPASS, 112f08c3bdfSopenharmony_ci "munmap() fails for page sizes less than %ldkB\n", hps/1024); 113f08c3bdfSopenharmony_ci} 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_cistatic void test_max_hugepages(int fd) 116f08c3bdfSopenharmony_ci{ 117f08c3bdfSopenharmony_ci int new_fd; 118f08c3bdfSopenharmony_ci long hps; 119f08c3bdfSopenharmony_ci long free_pages; 120f08c3bdfSopenharmony_ci void *mem; 121f08c3bdfSopenharmony_ci void *new_mem; 122f08c3bdfSopenharmony_ci 123f08c3bdfSopenharmony_ci free_pages = SAFE_READ_MEMINFO("HugePages_Free:"); 124f08c3bdfSopenharmony_ci hps = SAFE_READ_MEMINFO("Hugepagesize:"); 125f08c3bdfSopenharmony_ci hps = hps << 10; 126f08c3bdfSopenharmony_ci mem = check_huge_mmapable(fd, free_pages * hps); 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci new_fd = sys_memfd_create("new_file", MFD_HUGETLB); 129f08c3bdfSopenharmony_ci if (new_fd < 0) 130f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, "memfd_create() failed"); 131f08c3bdfSopenharmony_ci tst_res(TINFO, "memfd_create() succeeded"); 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci new_mem = mmap(NULL, hps, 0, MAP_PRIVATE, new_fd, 0); 134f08c3bdfSopenharmony_ci if (new_mem == MAP_FAILED) { 135f08c3bdfSopenharmony_ci if (errno == ENOMEM) 136f08c3bdfSopenharmony_ci tst_res(TPASS, 137f08c3bdfSopenharmony_ci "mmap(%p, %lu, %d, %d, %d, %d) failed as expected", 138f08c3bdfSopenharmony_ci NULL, hps, 0, MAP_PRIVATE, new_fd, 0); 139f08c3bdfSopenharmony_ci else 140f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, 141f08c3bdfSopenharmony_ci "mmap(%p, %lu, %d, %d, %d, %d) failed unexpectedly", 142f08c3bdfSopenharmony_ci NULL, hps, 0, MAP_PRIVATE, new_fd, 0); 143f08c3bdfSopenharmony_ci } else { 144f08c3bdfSopenharmony_ci tst_res(TFAIL, 145f08c3bdfSopenharmony_ci "mmap(%p, %lu, %d, %d, %d, %d) succeeded", 146f08c3bdfSopenharmony_ci NULL, hps, 0, MAP_PRIVATE, new_fd, 0); 147f08c3bdfSopenharmony_ci SAFE_MUNMAP(new_mem, hps); 148f08c3bdfSopenharmony_ci } 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci SAFE_CLOSE(new_fd); 151f08c3bdfSopenharmony_ci 152f08c3bdfSopenharmony_ci SAFE_MUNMAP(mem, free_pages * hps); 153f08c3bdfSopenharmony_ci} 154f08c3bdfSopenharmony_ci 155f08c3bdfSopenharmony_cistatic const struct tcase { 156f08c3bdfSopenharmony_ci void (*func)(int fd); 157f08c3bdfSopenharmony_ci const char *desc; 158f08c3bdfSopenharmony_ci} tcases[] = { 159f08c3bdfSopenharmony_ci {&test_write_protect, "--TESTING WRITE CALL IN HUGEPAGES--"}, 160f08c3bdfSopenharmony_ci {&test_def_pagesize, "--TESTING PAGE SIZE OF CREATED FILE--"}, 161f08c3bdfSopenharmony_ci {&test_max_hugepages, "--TESTING HUGEPAGE ALLOCATION LIMIT--"}, 162f08c3bdfSopenharmony_ci}; 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_cistatic void memfd_huge_controller(unsigned int n) 165f08c3bdfSopenharmony_ci{ 166f08c3bdfSopenharmony_ci int fd; 167f08c3bdfSopenharmony_ci const struct tcase *tc; 168f08c3bdfSopenharmony_ci 169f08c3bdfSopenharmony_ci tc = &tcases[n]; 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_ci tst_res(TINFO, "%s", tc->desc); 172f08c3bdfSopenharmony_ci 173f08c3bdfSopenharmony_ci fd = sys_memfd_create("test_file", MFD_HUGETLB); 174f08c3bdfSopenharmony_ci if (fd < 0) 175f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, "memfd_create() failed"); 176f08c3bdfSopenharmony_ci tst_res(TINFO, "memfd_create() succeeded"); 177f08c3bdfSopenharmony_ci 178f08c3bdfSopenharmony_ci tc->func(fd); 179f08c3bdfSopenharmony_ci 180f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 181f08c3bdfSopenharmony_ci} 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_cistatic struct tst_test test = { 184f08c3bdfSopenharmony_ci .test = memfd_huge_controller, 185f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 186f08c3bdfSopenharmony_ci .needs_root = 1, 187f08c3bdfSopenharmony_ci .min_kver = "4.14", 188f08c3bdfSopenharmony_ci .hugepages = {1, TST_NEEDS}, 189f08c3bdfSopenharmony_ci}; 190