1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: LGPL-2.1-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2015 Oracle Corporation 4f08c3bdfSopenharmony_ci * Author: Mike Kravetz 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * It tests alignment of fallocate arguments. fallocate will take non-huge 11f08c3bdfSopenharmony_ci * page aligned offsets and addresses. However, operations are only 12f08c3bdfSopenharmony_ci * performed on huge pages. This is different that than fallocate 13f08c3bdfSopenharmony_ci * behavior in "normal" filesystems. 14f08c3bdfSopenharmony_ci */ 15f08c3bdfSopenharmony_ci 16f08c3bdfSopenharmony_ci#define _GNU_SOURCE 17f08c3bdfSopenharmony_ci#include <stdio.h> 18f08c3bdfSopenharmony_ci#include <sys/mount.h> 19f08c3bdfSopenharmony_ci#include <limits.h> 20f08c3bdfSopenharmony_ci#include <sys/param.h> 21f08c3bdfSopenharmony_ci#include <sys/types.h> 22f08c3bdfSopenharmony_ci 23f08c3bdfSopenharmony_ci#include "hugetlb.h" 24f08c3bdfSopenharmony_ci#include "lapi/fallocate.h" 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#define MNTPOINT "hugetlbfs/" 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_cistatic int fd = -1; 29f08c3bdfSopenharmony_cistatic long hpage_size; 30f08c3bdfSopenharmony_ci 31f08c3bdfSopenharmony_cistatic void run_test(void) 32f08c3bdfSopenharmony_ci{ 33f08c3bdfSopenharmony_ci int err; 34f08c3bdfSopenharmony_ci unsigned long free_initial, free_after, free_after_delete; 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_ci fd = tst_creat_unlinked(MNTPOINT, 0); 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_ci free_initial = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); 39f08c3bdfSopenharmony_ci 40f08c3bdfSopenharmony_ci /* 41f08c3bdfSopenharmony_ci * First preallocate file with just 1 byte. Allocation sizes 42f08c3bdfSopenharmony_ci * are rounded up, so we should get an entire huge page. 43f08c3bdfSopenharmony_ci */ 44f08c3bdfSopenharmony_ci err = fallocate(fd, 0, 0, 1); 45f08c3bdfSopenharmony_ci if (err) { 46f08c3bdfSopenharmony_ci if (errno == EOPNOTSUPP) 47f08c3bdfSopenharmony_ci tst_brk(TCONF, "Operation Not Supported"); 48f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "fallocate()"); 49f08c3bdfSopenharmony_ci goto cleanup; 50f08c3bdfSopenharmony_ci } 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_ci free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); 53f08c3bdfSopenharmony_ci if (free_initial - free_after != 1) { 54f08c3bdfSopenharmony_ci tst_res(TFAIL, "fallocate 1 byte did not preallocate entire huge page"); 55f08c3bdfSopenharmony_ci goto cleanup; 56f08c3bdfSopenharmony_ci } 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci /* 59f08c3bdfSopenharmony_ci * Now punch a hole with just 1 byte. On hole punch, sizes are 60f08c3bdfSopenharmony_ci * rounded down. So, this operation should not create a hole. 61f08c3bdfSopenharmony_ci */ 62f08c3bdfSopenharmony_ci err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 63f08c3bdfSopenharmony_ci 0, 1); 64f08c3bdfSopenharmony_ci if (err) { 65f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "fallocate(FALLOC_FL_PUNCH_HOLE)"); 66f08c3bdfSopenharmony_ci goto cleanup; 67f08c3bdfSopenharmony_ci } 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_ci free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); 70f08c3bdfSopenharmony_ci if (free_after == free_initial) { 71f08c3bdfSopenharmony_ci tst_res(TFAIL, "fallocate hole punch 1 byte free'ed a huge page"); 72f08c3bdfSopenharmony_ci goto cleanup; 73f08c3bdfSopenharmony_ci } 74f08c3bdfSopenharmony_ci 75f08c3bdfSopenharmony_ci /* 76f08c3bdfSopenharmony_ci * Now punch a hole with of 2 * hpage_size - 1 byte. This size 77f08c3bdfSopenharmony_ci * should be rounded down to a single huge page and the hole created. 78f08c3bdfSopenharmony_ci */ 79f08c3bdfSopenharmony_ci err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 80f08c3bdfSopenharmony_ci 0, (2 * hpage_size) - 1); 81f08c3bdfSopenharmony_ci if (err) { 82f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "fallocate(FALLOC_FL_PUNCH_HOLE)"); 83f08c3bdfSopenharmony_ci goto cleanup; 84f08c3bdfSopenharmony_ci } 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); 87f08c3bdfSopenharmony_ci if (free_after != free_initial) { 88f08c3bdfSopenharmony_ci tst_res(TFAIL, "fallocate hole punch 2 * hpage_size - 1 byte did not" 89f08c3bdfSopenharmony_ci " free huge page"); 90f08c3bdfSopenharmony_ci goto cleanup; 91f08c3bdfSopenharmony_ci } 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci /* 94f08c3bdfSopenharmony_ci * Perform a preallocate operation with offset 1 and size of 95f08c3bdfSopenharmony_ci * hpage_size. The offset should be rounded down and the 96f08c3bdfSopenharmony_ci * size rounded up to preallocate two huge pages. 97f08c3bdfSopenharmony_ci */ 98f08c3bdfSopenharmony_ci err = fallocate(fd, 0, 1, hpage_size); 99f08c3bdfSopenharmony_ci if (err) { 100f08c3bdfSopenharmony_ci tst_res(TFAIL, "fallocate()"); 101f08c3bdfSopenharmony_ci goto cleanup; 102f08c3bdfSopenharmony_ci } 103f08c3bdfSopenharmony_ci 104f08c3bdfSopenharmony_ci free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); 105f08c3bdfSopenharmony_ci if (free_initial - free_after != 2) { 106f08c3bdfSopenharmony_ci tst_res(TFAIL, "fallocate 1 byte offset, huge page size did not" 107f08c3bdfSopenharmony_ci " preallocate two huge pages"); 108f08c3bdfSopenharmony_ci goto cleanup; 109f08c3bdfSopenharmony_ci } 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci /* 112f08c3bdfSopenharmony_ci * The hole punch code will only delete 'whole' huge pags that are 113f08c3bdfSopenharmony_ci * in the specified range. The offset is rounded up, and (offset 114f08c3bdfSopenharmony_ci * + size) is rounded down to determine the huge pages to be deleted. 115f08c3bdfSopenharmony_ci * In this case, after rounding the range is (hpage_size, hpage_size). 116f08c3bdfSopenharmony_ci * So, no pages should be deleted. 117f08c3bdfSopenharmony_ci */ 118f08c3bdfSopenharmony_ci err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 119f08c3bdfSopenharmony_ci 1, hpage_size); 120f08c3bdfSopenharmony_ci if (err) { 121f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "fallocate(FALLOC_FL_PUNCH_HOLE)"); 122f08c3bdfSopenharmony_ci goto cleanup; 123f08c3bdfSopenharmony_ci } 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); 126f08c3bdfSopenharmony_ci if (free_initial - free_after != 2) { 127f08c3bdfSopenharmony_ci tst_res(TFAIL, "fallocate hole punch 1 byte offset, huge page size" 128f08c3bdfSopenharmony_ci " incorrectly deleted a huge page"); 129f08c3bdfSopenharmony_ci goto cleanup; 130f08c3bdfSopenharmony_ci } 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_ci /* 133f08c3bdfSopenharmony_ci * To delete both huge pages, the range passed to hole punch must 134f08c3bdfSopenharmony_ci * overlap the allocated pages 135f08c3bdfSopenharmony_ci */ 136f08c3bdfSopenharmony_ci err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 137f08c3bdfSopenharmony_ci 0, 2 * hpage_size); 138f08c3bdfSopenharmony_ci if (err) { 139f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "fallocate(FALLOC_FL_PUNCH_HOLE)"); 140f08c3bdfSopenharmony_ci goto cleanup; 141f08c3bdfSopenharmony_ci } 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_ci free_after_delete = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); 144f08c3bdfSopenharmony_ci TST_EXP_EQ_LU(free_after_delete, free_initial); 145f08c3bdfSopenharmony_cicleanup: 146f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 147f08c3bdfSopenharmony_ci} 148f08c3bdfSopenharmony_ci 149f08c3bdfSopenharmony_cistatic void setup(void) 150f08c3bdfSopenharmony_ci{ 151f08c3bdfSopenharmony_ci hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; 152f08c3bdfSopenharmony_ci} 153f08c3bdfSopenharmony_ci 154f08c3bdfSopenharmony_cistatic void cleanup(void) 155f08c3bdfSopenharmony_ci{ 156f08c3bdfSopenharmony_ci if (fd > 0) 157f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 158f08c3bdfSopenharmony_ci} 159f08c3bdfSopenharmony_ci 160f08c3bdfSopenharmony_cistatic struct tst_test test = { 161f08c3bdfSopenharmony_ci .needs_root = 1, 162f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 163f08c3bdfSopenharmony_ci .needs_hugetlbfs = 1, 164f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 165f08c3bdfSopenharmony_ci .setup = setup, 166f08c3bdfSopenharmony_ci .cleanup = cleanup, 167f08c3bdfSopenharmony_ci .test_all = run_test, 168f08c3bdfSopenharmony_ci .hugepages = {2, TST_NEEDS}, 169f08c3bdfSopenharmony_ci}; 170