1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. 4f08c3bdfSopenharmony_ci * Author: Alexey Kodanev <alexey.kodanev@oracle.com> 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Test allocates a file with specified size then tests the following modes: 7f08c3bdfSopenharmony_ci * FALLOC_FL_PUNCH_HOLE, FALLOC_FL_ZERO_RANGE and FALLOC_FL_COLLAPSE_RANGE. 8f08c3bdfSopenharmony_ci */ 9f08c3bdfSopenharmony_ci 10f08c3bdfSopenharmony_ci#define _GNU_SOURCE 11f08c3bdfSopenharmony_ci 12f08c3bdfSopenharmony_ci#include <stdio.h> 13f08c3bdfSopenharmony_ci#include <stdlib.h> 14f08c3bdfSopenharmony_ci#include <errno.h> 15f08c3bdfSopenharmony_ci#include <sys/stat.h> 16f08c3bdfSopenharmony_ci#include <fcntl.h> 17f08c3bdfSopenharmony_ci#include <unistd.h> 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci#include "tst_test.h" 20f08c3bdfSopenharmony_ci#include "lapi/fallocate.h" 21f08c3bdfSopenharmony_ci 22f08c3bdfSopenharmony_cistatic int fd; 23f08c3bdfSopenharmony_cistatic size_t block_size; 24f08c3bdfSopenharmony_cistatic size_t buf_size; 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#define MNTPOINT "fallocate" 27f08c3bdfSopenharmony_ci#define FNAME MNTPOINT "/fallocate.txt" 28f08c3bdfSopenharmony_ci#define NUM_OF_BLOCKS 3 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_cistatic char *verbose; 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_cistatic void get_blocksize(void) 33f08c3bdfSopenharmony_ci{ 34f08c3bdfSopenharmony_ci struct stat file_stat; 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_ci SAFE_FSTAT(fd, &file_stat); 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_ci block_size = file_stat.st_blksize; 39f08c3bdfSopenharmony_ci buf_size = NUM_OF_BLOCKS * block_size; 40f08c3bdfSopenharmony_ci} 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_cistatic size_t get_allocsize(void) 43f08c3bdfSopenharmony_ci{ 44f08c3bdfSopenharmony_ci struct stat file_stat; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci fsync(fd); 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_ci SAFE_FSTAT(fd, &file_stat); 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_ci return file_stat.st_blocks * 512; 51f08c3bdfSopenharmony_ci} 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_cistatic void fill_tst_buf(char buf[]) 54f08c3bdfSopenharmony_ci{ 55f08c3bdfSopenharmony_ci /* fill the buffer with a, b, c, ... letters on each block */ 56f08c3bdfSopenharmony_ci int i; 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci for (i = 0; i < NUM_OF_BLOCKS; ++i) 59f08c3bdfSopenharmony_ci memset(buf + i * block_size, 'a' + i, block_size); 60f08c3bdfSopenharmony_ci} 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_cistatic void check_file_data(const char exp_buf[], size_t size) 63f08c3bdfSopenharmony_ci{ 64f08c3bdfSopenharmony_ci char rbuf[size]; 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci tst_res(TINFO, "reading the file, compare with expected buffer"); 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci SAFE_LSEEK(fd, 0, SEEK_SET); 69f08c3bdfSopenharmony_ci SAFE_READ(1, fd, rbuf, size); 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_ci if (memcmp(exp_buf, rbuf, size)) { 72f08c3bdfSopenharmony_ci if (verbose) { 73f08c3bdfSopenharmony_ci tst_res_hexd(TINFO, exp_buf, size, "expected:"); 74f08c3bdfSopenharmony_ci tst_res_hexd(TINFO, rbuf, size, "but read:"); 75f08c3bdfSopenharmony_ci } 76f08c3bdfSopenharmony_ci tst_brk(TFAIL, "not expected file data"); 77f08c3bdfSopenharmony_ci } 78f08c3bdfSopenharmony_ci} 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_cistatic void test01(void) 81f08c3bdfSopenharmony_ci{ 82f08c3bdfSopenharmony_ci tst_res(TINFO, "allocate '%zu' bytes", buf_size); 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci if (fallocate(fd, 0, 0, buf_size) == -1) { 85f08c3bdfSopenharmony_ci if (errno == ENOSYS || errno == EOPNOTSUPP) 86f08c3bdfSopenharmony_ci tst_brk(TCONF, "fallocate() not supported"); 87f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, "fallocate() failed"); 88f08c3bdfSopenharmony_ci } 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci char buf[buf_size]; 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci fill_tst_buf(buf); 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, buf_size); 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci tst_res(TPASS, "test-case succeeded"); 97f08c3bdfSopenharmony_ci} 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_cistatic void test02(void) 100f08c3bdfSopenharmony_ci{ 101f08c3bdfSopenharmony_ci size_t alloc_size0 = get_allocsize(); 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci tst_res(TINFO, "read allocated file size '%zu'", alloc_size0); 104f08c3bdfSopenharmony_ci tst_res(TINFO, "make a hole with FALLOC_FL_PUNCH_HOLE"); 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 107f08c3bdfSopenharmony_ci block_size, block_size) == -1) { 108f08c3bdfSopenharmony_ci if (errno == EOPNOTSUPP) { 109f08c3bdfSopenharmony_ci tst_brk(TCONF, 110f08c3bdfSopenharmony_ci "FALLOC_FL_PUNCH_HOLE not supported"); 111f08c3bdfSopenharmony_ci } 112f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, "fallocate() failed"); 113f08c3bdfSopenharmony_ci } 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci tst_res(TINFO, "check that file has a hole with lseek(,,SEEK_HOLE)"); 116f08c3bdfSopenharmony_ci off_t ret = lseek(fd, 0, SEEK_HOLE); 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_ci if (ret != (ssize_t)block_size) { 119f08c3bdfSopenharmony_ci /* exclude error when kernel doesn't have SEEK_HOLE support */ 120f08c3bdfSopenharmony_ci if (errno != EINVAL) { 121f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, 122f08c3bdfSopenharmony_ci "fallocate() or lseek() failed"); 123f08c3bdfSopenharmony_ci } 124f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, 125f08c3bdfSopenharmony_ci "lseek() doesn't support SEEK_HOLE"); 126f08c3bdfSopenharmony_ci } else { 127f08c3bdfSopenharmony_ci tst_res(TINFO, "found a hole at '%ld' offset", ret); 128f08c3bdfSopenharmony_ci } 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci size_t alloc_size1 = get_allocsize(); 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_ci tst_res(TINFO, "allocated file size before '%zu' and after '%zu'", 133f08c3bdfSopenharmony_ci alloc_size0, alloc_size1); 134f08c3bdfSopenharmony_ci if ((alloc_size0 - block_size) != alloc_size1) 135f08c3bdfSopenharmony_ci tst_brk(TFAIL, "not expected allocated size"); 136f08c3bdfSopenharmony_ci 137f08c3bdfSopenharmony_ci char exp_buf[buf_size]; 138f08c3bdfSopenharmony_ci 139f08c3bdfSopenharmony_ci fill_tst_buf(exp_buf); 140f08c3bdfSopenharmony_ci memset(exp_buf + block_size, 0, block_size); 141f08c3bdfSopenharmony_ci 142f08c3bdfSopenharmony_ci check_file_data(exp_buf, buf_size); 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci tst_res(TPASS, "test-case succeeded"); 145f08c3bdfSopenharmony_ci} 146f08c3bdfSopenharmony_ci 147f08c3bdfSopenharmony_cistatic void test03(void) 148f08c3bdfSopenharmony_ci{ 149f08c3bdfSopenharmony_ci tst_res(TINFO, "zeroing file space with FALLOC_FL_ZERO_RANGE"); 150f08c3bdfSopenharmony_ci 151f08c3bdfSopenharmony_ci if (tst_kvercmp(3, 15, 0) < 0) { 152f08c3bdfSopenharmony_ci tst_brk(TCONF, 153f08c3bdfSopenharmony_ci "FALLOC_FL_ZERO_RANGE needs Linux 3.15 or newer"); 154f08c3bdfSopenharmony_ci } 155f08c3bdfSopenharmony_ci 156f08c3bdfSopenharmony_ci size_t alloc_size0 = get_allocsize(); 157f08c3bdfSopenharmony_ci 158f08c3bdfSopenharmony_ci tst_res(TINFO, "read current allocated file size '%zu'", alloc_size0); 159f08c3bdfSopenharmony_ci 160f08c3bdfSopenharmony_ci if (fallocate(fd, FALLOC_FL_ZERO_RANGE, block_size - 1, 161f08c3bdfSopenharmony_ci block_size + 2) == -1) { 162f08c3bdfSopenharmony_ci if (errno == EOPNOTSUPP) { 163f08c3bdfSopenharmony_ci tst_brk(TCONF, 164f08c3bdfSopenharmony_ci "FALLOC_FL_ZERO_RANGE not supported"); 165f08c3bdfSopenharmony_ci } 166f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, "fallocate failed"); 167f08c3bdfSopenharmony_ci } 168f08c3bdfSopenharmony_ci 169f08c3bdfSopenharmony_ci /* The file hole in the specified range must be allocated and 170f08c3bdfSopenharmony_ci * filled with zeros. Check it. 171f08c3bdfSopenharmony_ci */ 172f08c3bdfSopenharmony_ci size_t alloc_size1 = get_allocsize(); 173f08c3bdfSopenharmony_ci 174f08c3bdfSopenharmony_ci tst_res(TINFO, "allocated file size before '%zu' and after '%zu'", 175f08c3bdfSopenharmony_ci alloc_size0, alloc_size1); 176f08c3bdfSopenharmony_ci if ((alloc_size0 + block_size) != alloc_size1) 177f08c3bdfSopenharmony_ci tst_brk(TFAIL, "not expected allocated size"); 178f08c3bdfSopenharmony_ci 179f08c3bdfSopenharmony_ci char exp_buf[buf_size]; 180f08c3bdfSopenharmony_ci 181f08c3bdfSopenharmony_ci fill_tst_buf(exp_buf); 182f08c3bdfSopenharmony_ci memset(exp_buf + block_size - 1, 0, block_size + 2); 183f08c3bdfSopenharmony_ci 184f08c3bdfSopenharmony_ci check_file_data(exp_buf, buf_size); 185f08c3bdfSopenharmony_ci 186f08c3bdfSopenharmony_ci tst_res(TPASS, "test-case succeeded"); 187f08c3bdfSopenharmony_ci} 188f08c3bdfSopenharmony_ci 189f08c3bdfSopenharmony_cistatic void test04(void) 190f08c3bdfSopenharmony_ci{ 191f08c3bdfSopenharmony_ci tst_res(TINFO, "collapsing file space with FALLOC_FL_COLLAPSE_RANGE"); 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_ci size_t alloc_size0 = get_allocsize(); 194f08c3bdfSopenharmony_ci 195f08c3bdfSopenharmony_ci tst_res(TINFO, "read current allocated file size '%zu'", alloc_size0); 196f08c3bdfSopenharmony_ci 197f08c3bdfSopenharmony_ci if (fallocate(fd, FALLOC_FL_COLLAPSE_RANGE, block_size, 198f08c3bdfSopenharmony_ci block_size) == -1) { 199f08c3bdfSopenharmony_ci if (errno == EOPNOTSUPP) { 200f08c3bdfSopenharmony_ci tst_brk(TCONF, 201f08c3bdfSopenharmony_ci "FALLOC_FL_COLLAPSE_RANGE not supported"); 202f08c3bdfSopenharmony_ci } 203f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, "fallocate failed"); 204f08c3bdfSopenharmony_ci } 205f08c3bdfSopenharmony_ci 206f08c3bdfSopenharmony_ci size_t alloc_size1 = get_allocsize(); 207f08c3bdfSopenharmony_ci 208f08c3bdfSopenharmony_ci tst_res(TINFO, "allocated file size before '%zu' and after '%zu'", 209f08c3bdfSopenharmony_ci alloc_size0, alloc_size1); 210f08c3bdfSopenharmony_ci if ((alloc_size0 - block_size) != alloc_size1) 211f08c3bdfSopenharmony_ci tst_brk(TFAIL, "not expected allocated size"); 212f08c3bdfSopenharmony_ci 213f08c3bdfSopenharmony_ci size_t size = buf_size - block_size; 214f08c3bdfSopenharmony_ci char tmp_buf[buf_size]; 215f08c3bdfSopenharmony_ci char exp_buf[size]; 216f08c3bdfSopenharmony_ci 217f08c3bdfSopenharmony_ci fill_tst_buf(tmp_buf); 218f08c3bdfSopenharmony_ci 219f08c3bdfSopenharmony_ci memcpy(exp_buf, tmp_buf, block_size); 220f08c3bdfSopenharmony_ci memcpy(exp_buf + block_size, tmp_buf + 2 * block_size, 221f08c3bdfSopenharmony_ci buf_size - block_size * 2); 222f08c3bdfSopenharmony_ci 223f08c3bdfSopenharmony_ci exp_buf[block_size - 1] = exp_buf[block_size] = '\0'; 224f08c3bdfSopenharmony_ci check_file_data(exp_buf, size); 225f08c3bdfSopenharmony_ci 226f08c3bdfSopenharmony_ci tst_res(TPASS, "test-case succeeded"); 227f08c3bdfSopenharmony_ci} 228f08c3bdfSopenharmony_ci 229f08c3bdfSopenharmony_cistatic void test05(void) 230f08c3bdfSopenharmony_ci{ 231f08c3bdfSopenharmony_ci tst_res(TINFO, "inserting space with FALLOC_FL_INSERT_RANGE"); 232f08c3bdfSopenharmony_ci 233f08c3bdfSopenharmony_ci size_t alloc_size0 = get_allocsize(); 234f08c3bdfSopenharmony_ci 235f08c3bdfSopenharmony_ci tst_res(TINFO, "read current allocated file size '%zu'", alloc_size0); 236f08c3bdfSopenharmony_ci 237f08c3bdfSopenharmony_ci if (fallocate(fd, FALLOC_FL_INSERT_RANGE, block_size, 238f08c3bdfSopenharmony_ci block_size) == -1) { 239f08c3bdfSopenharmony_ci if (errno == EOPNOTSUPP) { 240f08c3bdfSopenharmony_ci tst_brk(TCONF, 241f08c3bdfSopenharmony_ci "FALLOC_FL_INSERT_RANGE not supported"); 242f08c3bdfSopenharmony_ci } 243f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, "fallocate failed"); 244f08c3bdfSopenharmony_ci } 245f08c3bdfSopenharmony_ci 246f08c3bdfSopenharmony_ci /* allocate space and ensure that it filled with zeroes */ 247f08c3bdfSopenharmony_ci if (fallocate(fd, FALLOC_FL_ZERO_RANGE, block_size, block_size) == -1) 248f08c3bdfSopenharmony_ci tst_brk(TFAIL | TERRNO, "fallocate failed"); 249f08c3bdfSopenharmony_ci 250f08c3bdfSopenharmony_ci size_t alloc_size1 = get_allocsize(); 251f08c3bdfSopenharmony_ci 252f08c3bdfSopenharmony_ci tst_res(TINFO, "allocated file size before '%zu' and after '%zu'", 253f08c3bdfSopenharmony_ci alloc_size0, alloc_size1); 254f08c3bdfSopenharmony_ci if ((alloc_size0 + block_size) != alloc_size1) 255f08c3bdfSopenharmony_ci tst_brk(TFAIL, "not expected allocated size"); 256f08c3bdfSopenharmony_ci 257f08c3bdfSopenharmony_ci char exp_buf[buf_size]; 258f08c3bdfSopenharmony_ci 259f08c3bdfSopenharmony_ci fill_tst_buf(exp_buf); 260f08c3bdfSopenharmony_ci memset(exp_buf + block_size - 1, 0, block_size + 2); 261f08c3bdfSopenharmony_ci 262f08c3bdfSopenharmony_ci check_file_data(exp_buf, buf_size); 263f08c3bdfSopenharmony_ci 264f08c3bdfSopenharmony_ci tst_res(TPASS, "test-case succeeded"); 265f08c3bdfSopenharmony_ci} 266f08c3bdfSopenharmony_ci 267f08c3bdfSopenharmony_cistatic void (*tcases[])(void) = { 268f08c3bdfSopenharmony_ci test01, test02, test03, test04, test05 269f08c3bdfSopenharmony_ci}; 270f08c3bdfSopenharmony_ci 271f08c3bdfSopenharmony_cistatic void run(unsigned int i) 272f08c3bdfSopenharmony_ci{ 273f08c3bdfSopenharmony_ci tcases[i](); 274f08c3bdfSopenharmony_ci} 275f08c3bdfSopenharmony_ci 276f08c3bdfSopenharmony_cistatic void setup(void) 277f08c3bdfSopenharmony_ci{ 278f08c3bdfSopenharmony_ci fd = SAFE_OPEN(FNAME, O_RDWR | O_CREAT, 0700); 279f08c3bdfSopenharmony_ci 280f08c3bdfSopenharmony_ci get_blocksize(); 281f08c3bdfSopenharmony_ci} 282f08c3bdfSopenharmony_ci 283f08c3bdfSopenharmony_cistatic void cleanup(void) 284f08c3bdfSopenharmony_ci{ 285f08c3bdfSopenharmony_ci if (fd > 0) 286f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 287f08c3bdfSopenharmony_ci} 288f08c3bdfSopenharmony_ci 289f08c3bdfSopenharmony_cistatic struct tst_test test = { 290f08c3bdfSopenharmony_ci .options = (struct tst_option[]) { 291f08c3bdfSopenharmony_ci {"v", &verbose, "Turns on verbose mode"}, 292f08c3bdfSopenharmony_ci {} 293f08c3bdfSopenharmony_ci }, 294f08c3bdfSopenharmony_ci .cleanup = cleanup, 295f08c3bdfSopenharmony_ci .setup = setup, 296f08c3bdfSopenharmony_ci .test = run, 297f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 298f08c3bdfSopenharmony_ci .mount_device = 1, 299f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 300f08c3bdfSopenharmony_ci .all_filesystems = 1, 301f08c3bdfSopenharmony_ci .needs_root = 1, 302f08c3bdfSopenharmony_ci}; 303