1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2012 Linux Test Project, Inc. 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci 6f08c3bdfSopenharmony_ci/* 7f08c3bdfSopenharmony_ci * functional test for readahead() syscall 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * This test is measuring effects of readahead syscall. 10f08c3bdfSopenharmony_ci * It mmaps/reads a test file with and without prior call to readahead. 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * The overlay part of the test is regression for: 13f08c3bdfSopenharmony_ci * b833a3660394 14f08c3bdfSopenharmony_ci * ("ovl: add ovl_fadvise()") 15f08c3bdfSopenharmony_ci * Introduced by: 16f08c3bdfSopenharmony_ci * 5b910bd615ba 17f08c3bdfSopenharmony_ci * ("ovl: fix GPF in swapfile_activate of file from overlayfs over xfs") 18f08c3bdfSopenharmony_ci */ 19f08c3bdfSopenharmony_ci#define _GNU_SOURCE 20f08c3bdfSopenharmony_ci#include <sys/types.h> 21f08c3bdfSopenharmony_ci#include <sys/syscall.h> 22f08c3bdfSopenharmony_ci#include <sys/mman.h> 23f08c3bdfSopenharmony_ci#include <sys/mount.h> 24f08c3bdfSopenharmony_ci#include <sys/stat.h> 25f08c3bdfSopenharmony_ci#include <sys/types.h> 26f08c3bdfSopenharmony_ci#include <errno.h> 27f08c3bdfSopenharmony_ci#include <stdio.h> 28f08c3bdfSopenharmony_ci#include <stdlib.h> 29f08c3bdfSopenharmony_ci#include <stdint.h> 30f08c3bdfSopenharmony_ci#include <unistd.h> 31f08c3bdfSopenharmony_ci#include <fcntl.h> 32f08c3bdfSopenharmony_ci#include "config.h" 33f08c3bdfSopenharmony_ci#include "tst_test.h" 34f08c3bdfSopenharmony_ci#include "tst_timer.h" 35f08c3bdfSopenharmony_ci#include "lapi/syscalls.h" 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_cistatic char testfile[PATH_MAX] = "testfile"; 38f08c3bdfSopenharmony_ci#define DROP_CACHES_FNAME "/proc/sys/vm/drop_caches" 39f08c3bdfSopenharmony_ci#define MEMINFO_FNAME "/proc/meminfo" 40f08c3bdfSopenharmony_ci#define PROC_IO_FNAME "/proc/self/io" 41f08c3bdfSopenharmony_ci#define DEFAULT_FILESIZE (64 * 1024 * 1024) 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_cistatic size_t testfile_size = DEFAULT_FILESIZE; 44f08c3bdfSopenharmony_cistatic char *opt_fsizestr; 45f08c3bdfSopenharmony_cistatic int pagesize; 46f08c3bdfSopenharmony_cistatic unsigned long cached_max; 47f08c3bdfSopenharmony_cistatic int ovl_mounted; 48f08c3bdfSopenharmony_cistatic int readahead_length = 4096; 49f08c3bdfSopenharmony_cistatic char sys_bdi_ra_path[PATH_MAX]; 50f08c3bdfSopenharmony_cistatic int orig_bdi_limit; 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_cistatic const char mntpoint[] = OVL_BASE_MNTPOINT; 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_cistatic int libc_readahead(int fd, off_t offset, size_t len) 55f08c3bdfSopenharmony_ci{ 56f08c3bdfSopenharmony_ci return readahead(fd, offset, len); 57f08c3bdfSopenharmony_ci} 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_cistatic int fadvise_willneed(int fd, off_t offset, size_t len) 60f08c3bdfSopenharmony_ci{ 61f08c3bdfSopenharmony_ci /* Should have the same effect as readahead() syscall */ 62f08c3bdfSopenharmony_ci errno = posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED); 63f08c3bdfSopenharmony_ci /* posix_fadvise returns error number (not in errno) */ 64f08c3bdfSopenharmony_ci return errno ? -1 : 0; 65f08c3bdfSopenharmony_ci} 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_cistatic struct tcase { 68f08c3bdfSopenharmony_ci const char *tname; 69f08c3bdfSopenharmony_ci int use_overlay; 70f08c3bdfSopenharmony_ci int use_fadvise; 71f08c3bdfSopenharmony_ci /* Use either readahead() syscall or POSIX_FADV_WILLNEED */ 72f08c3bdfSopenharmony_ci int (*readahead)(int fd, off_t offset, size_t len); 73f08c3bdfSopenharmony_ci} tcases[] = { 74f08c3bdfSopenharmony_ci { "readahead on file", 0, 0, libc_readahead }, 75f08c3bdfSopenharmony_ci { "readahead on overlayfs file", 1, 0, libc_readahead }, 76f08c3bdfSopenharmony_ci { "POSIX_FADV_WILLNEED on file", 0, 1, fadvise_willneed }, 77f08c3bdfSopenharmony_ci { "POSIX_FADV_WILLNEED on overlayfs file", 1, 1, fadvise_willneed }, 78f08c3bdfSopenharmony_ci}; 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_cistatic int readahead_supported = 1; 81f08c3bdfSopenharmony_cistatic int fadvise_supported = 1; 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_cistatic int has_file(const char *fname, int required) 84f08c3bdfSopenharmony_ci{ 85f08c3bdfSopenharmony_ci struct stat buf; 86f08c3bdfSopenharmony_ci 87f08c3bdfSopenharmony_ci if (stat(fname, &buf) == -1) { 88f08c3bdfSopenharmony_ci if (errno != ENOENT) 89f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "stat %s", fname); 90f08c3bdfSopenharmony_ci if (required) 91f08c3bdfSopenharmony_ci tst_brk(TCONF, "%s not available", fname); 92f08c3bdfSopenharmony_ci return 0; 93f08c3bdfSopenharmony_ci } 94f08c3bdfSopenharmony_ci return 1; 95f08c3bdfSopenharmony_ci} 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_cistatic void drop_caches(void) 98f08c3bdfSopenharmony_ci{ 99f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(DROP_CACHES_FNAME, "1"); 100f08c3bdfSopenharmony_ci} 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_cistatic unsigned long get_bytes_read(void) 103f08c3bdfSopenharmony_ci{ 104f08c3bdfSopenharmony_ci unsigned long ret; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci SAFE_FILE_LINES_SCANF(PROC_IO_FNAME, "read_bytes: %lu", &ret); 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci return ret; 109f08c3bdfSopenharmony_ci} 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_cistatic unsigned long get_cached_size(void) 112f08c3bdfSopenharmony_ci{ 113f08c3bdfSopenharmony_ci unsigned long ret; 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci SAFE_FILE_LINES_SCANF(MEMINFO_FNAME, "Cached: %lu", &ret); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci return ret; 118f08c3bdfSopenharmony_ci} 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_cistatic void create_testfile(int use_overlay) 121f08c3bdfSopenharmony_ci{ 122f08c3bdfSopenharmony_ci int fd; 123f08c3bdfSopenharmony_ci char *tmp; 124f08c3bdfSopenharmony_ci size_t i; 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci sprintf(testfile, "%s/testfile", 127f08c3bdfSopenharmony_ci use_overlay ? OVL_MNT : OVL_BASE_MNTPOINT); 128f08c3bdfSopenharmony_ci tst_res(TINFO, "creating test file of size: %zu", testfile_size); 129f08c3bdfSopenharmony_ci tmp = SAFE_MALLOC(pagesize); 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci /* round to page size */ 132f08c3bdfSopenharmony_ci testfile_size = testfile_size & ~((long)pagesize - 1); 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_ci fd = SAFE_CREAT(testfile, 0644); 135f08c3bdfSopenharmony_ci for (i = 0; i < testfile_size; i += pagesize) 136f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, fd, tmp, pagesize); 137f08c3bdfSopenharmony_ci SAFE_FSYNC(fd); 138f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 139f08c3bdfSopenharmony_ci free(tmp); 140f08c3bdfSopenharmony_ci} 141f08c3bdfSopenharmony_ci 142f08c3bdfSopenharmony_ci/* read_testfile - mmap testfile and read every page. 143f08c3bdfSopenharmony_ci * This functions measures how many I/O and time it takes to fully 144f08c3bdfSopenharmony_ci * read contents of test file. 145f08c3bdfSopenharmony_ci * 146f08c3bdfSopenharmony_ci * @do_readahead: call readahead prior to reading file content? 147f08c3bdfSopenharmony_ci * @fname: name of file to test 148f08c3bdfSopenharmony_ci * @fsize: how many bytes to read/mmap 149f08c3bdfSopenharmony_ci * @read_bytes: returns difference of bytes read, parsed from /proc/<pid>/io 150f08c3bdfSopenharmony_ci * @usec: returns how many microsecond it took to go over fsize bytes 151f08c3bdfSopenharmony_ci * @cached: returns cached kB from /proc/meminfo 152f08c3bdfSopenharmony_ci */ 153f08c3bdfSopenharmony_cistatic int read_testfile(struct tcase *tc, int do_readahead, 154f08c3bdfSopenharmony_ci const char *fname, size_t fsize, 155f08c3bdfSopenharmony_ci unsigned long *read_bytes, long long *usec, 156f08c3bdfSopenharmony_ci unsigned long *cached) 157f08c3bdfSopenharmony_ci{ 158f08c3bdfSopenharmony_ci int fd; 159f08c3bdfSopenharmony_ci size_t i = 0; 160f08c3bdfSopenharmony_ci long read_bytes_start; 161f08c3bdfSopenharmony_ci unsigned char *p, tmp; 162f08c3bdfSopenharmony_ci off_t offset = 0; 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_ci fd = SAFE_OPEN(fname, O_RDONLY); 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_ci if (do_readahead) { 167f08c3bdfSopenharmony_ci do { 168f08c3bdfSopenharmony_ci TEST(tc->readahead(fd, offset, fsize - offset)); 169f08c3bdfSopenharmony_ci if (TST_RET != 0) { 170f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 171f08c3bdfSopenharmony_ci return TST_ERR; 172f08c3bdfSopenharmony_ci } 173f08c3bdfSopenharmony_ci 174f08c3bdfSopenharmony_ci i++; 175f08c3bdfSopenharmony_ci offset += readahead_length; 176f08c3bdfSopenharmony_ci } while ((size_t)offset < fsize); 177f08c3bdfSopenharmony_ci tst_res(TINFO, "readahead calls made: %zu", i); 178f08c3bdfSopenharmony_ci *cached = get_cached_size(); 179f08c3bdfSopenharmony_ci 180f08c3bdfSopenharmony_ci /* offset of file shouldn't change after readahead */ 181f08c3bdfSopenharmony_ci offset = SAFE_LSEEK(fd, 0, SEEK_CUR); 182f08c3bdfSopenharmony_ci if (offset == 0) 183f08c3bdfSopenharmony_ci tst_res(TPASS, "offset is still at 0 as expected"); 184f08c3bdfSopenharmony_ci else 185f08c3bdfSopenharmony_ci tst_res(TFAIL, "offset has changed to: %lu", offset); 186f08c3bdfSopenharmony_ci } 187f08c3bdfSopenharmony_ci 188f08c3bdfSopenharmony_ci tst_timer_start(CLOCK_MONOTONIC); 189f08c3bdfSopenharmony_ci read_bytes_start = get_bytes_read(); 190f08c3bdfSopenharmony_ci 191f08c3bdfSopenharmony_ci p = SAFE_MMAP(NULL, fsize, PROT_READ, MAP_SHARED | MAP_POPULATE, fd, 0); 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_ci /* for old kernels, where MAP_POPULATE doesn't work, touch each page */ 194f08c3bdfSopenharmony_ci tmp = 0; 195f08c3bdfSopenharmony_ci for (i = 0; i < fsize; i += pagesize) 196f08c3bdfSopenharmony_ci tmp = tmp ^ p[i]; 197f08c3bdfSopenharmony_ci /* prevent gcc from optimizing out loop above */ 198f08c3bdfSopenharmony_ci if (tmp != 0) 199f08c3bdfSopenharmony_ci tst_brk(TBROK, "This line should not be reached"); 200f08c3bdfSopenharmony_ci 201f08c3bdfSopenharmony_ci if (!do_readahead) 202f08c3bdfSopenharmony_ci *cached = get_cached_size(); 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_ci SAFE_MUNMAP(p, fsize); 205f08c3bdfSopenharmony_ci 206f08c3bdfSopenharmony_ci *read_bytes = get_bytes_read() - read_bytes_start; 207f08c3bdfSopenharmony_ci 208f08c3bdfSopenharmony_ci tst_timer_stop(); 209f08c3bdfSopenharmony_ci *usec = tst_timer_elapsed_us(); 210f08c3bdfSopenharmony_ci 211f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 212f08c3bdfSopenharmony_ci return 0; 213f08c3bdfSopenharmony_ci} 214f08c3bdfSopenharmony_ci 215f08c3bdfSopenharmony_cistatic void test_readahead(unsigned int n) 216f08c3bdfSopenharmony_ci{ 217f08c3bdfSopenharmony_ci unsigned long read_bytes, read_bytes_ra; 218f08c3bdfSopenharmony_ci long long usec, usec_ra; 219f08c3bdfSopenharmony_ci unsigned long cached_high, cached_low, cached, cached_ra; 220f08c3bdfSopenharmony_ci int ret; 221f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 222f08c3bdfSopenharmony_ci 223f08c3bdfSopenharmony_ci tst_res(TINFO, "Test #%d: %s", n, tc->tname); 224f08c3bdfSopenharmony_ci 225f08c3bdfSopenharmony_ci if (tc->use_overlay && !ovl_mounted) { 226f08c3bdfSopenharmony_ci tst_res(TCONF, "overlayfs is not configured in this kernel"); 227f08c3bdfSopenharmony_ci return; 228f08c3bdfSopenharmony_ci } 229f08c3bdfSopenharmony_ci 230f08c3bdfSopenharmony_ci create_testfile(tc->use_overlay); 231f08c3bdfSopenharmony_ci 232f08c3bdfSopenharmony_ci /* find out how much can cache hold if we read whole file */ 233f08c3bdfSopenharmony_ci read_testfile(tc, 0, testfile, testfile_size, &read_bytes, &usec, 234f08c3bdfSopenharmony_ci &cached); 235f08c3bdfSopenharmony_ci cached_high = get_cached_size(); 236f08c3bdfSopenharmony_ci sync(); 237f08c3bdfSopenharmony_ci drop_caches(); 238f08c3bdfSopenharmony_ci cached_low = get_cached_size(); 239f08c3bdfSopenharmony_ci cached_max = MAX(cached_max, cached_high - cached_low); 240f08c3bdfSopenharmony_ci 241f08c3bdfSopenharmony_ci tst_res(TINFO, "read_testfile(0)"); 242f08c3bdfSopenharmony_ci read_testfile(tc, 0, testfile, testfile_size, &read_bytes, &usec, 243f08c3bdfSopenharmony_ci &cached); 244f08c3bdfSopenharmony_ci if (cached > cached_low) 245f08c3bdfSopenharmony_ci cached = cached - cached_low; 246f08c3bdfSopenharmony_ci else 247f08c3bdfSopenharmony_ci cached = 0; 248f08c3bdfSopenharmony_ci 249f08c3bdfSopenharmony_ci sync(); 250f08c3bdfSopenharmony_ci drop_caches(); 251f08c3bdfSopenharmony_ci cached_low = get_cached_size(); 252f08c3bdfSopenharmony_ci tst_res(TINFO, "read_testfile(1)"); 253f08c3bdfSopenharmony_ci ret = read_testfile(tc, 1, testfile, testfile_size, &read_bytes_ra, 254f08c3bdfSopenharmony_ci &usec_ra, &cached_ra); 255f08c3bdfSopenharmony_ci 256f08c3bdfSopenharmony_ci if (ret == EINVAL) { 257f08c3bdfSopenharmony_ci if (tc->use_fadvise && 258f08c3bdfSopenharmony_ci (!tc->use_overlay || !fadvise_supported)) { 259f08c3bdfSopenharmony_ci fadvise_supported = 0; 260f08c3bdfSopenharmony_ci tst_res(TCONF, "CONFIG_ADVISE_SYSCALLS not configured " 261f08c3bdfSopenharmony_ci "in kernel?"); 262f08c3bdfSopenharmony_ci return; 263f08c3bdfSopenharmony_ci } 264f08c3bdfSopenharmony_ci 265f08c3bdfSopenharmony_ci if (!tc->use_overlay || !readahead_supported) { 266f08c3bdfSopenharmony_ci readahead_supported = 0; 267f08c3bdfSopenharmony_ci tst_res(TCONF, "readahead not supported on %s", 268f08c3bdfSopenharmony_ci tst_device->fs_type); 269f08c3bdfSopenharmony_ci return; 270f08c3bdfSopenharmony_ci } 271f08c3bdfSopenharmony_ci } 272f08c3bdfSopenharmony_ci 273f08c3bdfSopenharmony_ci if (ret) { 274f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "%s failed on %s", 275f08c3bdfSopenharmony_ci tc->use_fadvise ? "fadvise" : "readahead", 276f08c3bdfSopenharmony_ci tc->use_overlay ? "overlayfs" : 277f08c3bdfSopenharmony_ci tst_device->fs_type); 278f08c3bdfSopenharmony_ci return; 279f08c3bdfSopenharmony_ci } 280f08c3bdfSopenharmony_ci 281f08c3bdfSopenharmony_ci if (cached_ra > cached_low) 282f08c3bdfSopenharmony_ci cached_ra = cached_ra - cached_low; 283f08c3bdfSopenharmony_ci else 284f08c3bdfSopenharmony_ci cached_ra = 0; 285f08c3bdfSopenharmony_ci 286f08c3bdfSopenharmony_ci tst_res(TINFO, "read_testfile(0) took: %lli usec", usec); 287f08c3bdfSopenharmony_ci tst_res(TINFO, "read_testfile(1) took: %lli usec", usec_ra); 288f08c3bdfSopenharmony_ci if (has_file(PROC_IO_FNAME, 0)) { 289f08c3bdfSopenharmony_ci tst_res(TINFO, "read_testfile(0) read: %ld bytes", read_bytes); 290f08c3bdfSopenharmony_ci tst_res(TINFO, "read_testfile(1) read: %ld bytes", 291f08c3bdfSopenharmony_ci read_bytes_ra); 292f08c3bdfSopenharmony_ci /* actual number of read bytes depends on total RAM */ 293f08c3bdfSopenharmony_ci if (read_bytes_ra < read_bytes) 294f08c3bdfSopenharmony_ci tst_res(TPASS, "readahead saved some I/O"); 295f08c3bdfSopenharmony_ci else 296f08c3bdfSopenharmony_ci tst_res(TFAIL, "readahead failed to save any I/O"); 297f08c3bdfSopenharmony_ci } else { 298f08c3bdfSopenharmony_ci tst_res(TCONF, "Your system doesn't have /proc/self/io," 299f08c3bdfSopenharmony_ci " unable to determine read bytes during test"); 300f08c3bdfSopenharmony_ci } 301f08c3bdfSopenharmony_ci 302f08c3bdfSopenharmony_ci tst_res(TINFO, "cache can hold at least: %ld kB", cached_max); 303f08c3bdfSopenharmony_ci tst_res(TINFO, "read_testfile(0) used cache: %ld kB", cached); 304f08c3bdfSopenharmony_ci tst_res(TINFO, "read_testfile(1) used cache: %ld kB", cached_ra); 305f08c3bdfSopenharmony_ci 306f08c3bdfSopenharmony_ci if (cached_max * 1024 >= testfile_size) { 307f08c3bdfSopenharmony_ci /* 308f08c3bdfSopenharmony_ci * if cache can hold ~testfile_size then cache increase 309f08c3bdfSopenharmony_ci * for readahead should be at least testfile_size/2 310f08c3bdfSopenharmony_ci */ 311f08c3bdfSopenharmony_ci if (cached_ra * 1024 > testfile_size / 2) 312f08c3bdfSopenharmony_ci tst_res(TPASS, "using cache as expected"); 313f08c3bdfSopenharmony_ci else if (!cached_ra) 314f08c3bdfSopenharmony_ci tst_res(TFAIL, "readahead failed to use any cache"); 315f08c3bdfSopenharmony_ci else 316f08c3bdfSopenharmony_ci tst_res(TWARN, "using less cache than expected"); 317f08c3bdfSopenharmony_ci } else { 318f08c3bdfSopenharmony_ci tst_res(TCONF, "Page cache on your system is too small " 319f08c3bdfSopenharmony_ci "to hold whole testfile."); 320f08c3bdfSopenharmony_ci } 321f08c3bdfSopenharmony_ci 322f08c3bdfSopenharmony_ci /* 323f08c3bdfSopenharmony_ci * The time consuming of readahead quite depending on the platform IO 324f08c3bdfSopenharmony_ci * speed, sometime test timeout when the default max_runtime is used up. 325f08c3bdfSopenharmony_ci * 326f08c3bdfSopenharmony_ci * readahead02.c:221: TINFO: Test #2: POSIX_FADV_WILLNEED on file 327f08c3bdfSopenharmony_ci * readahead02.c:285: TINFO: read_testfile(0) took: 26317623 usec 328f08c3bdfSopenharmony_ci * readahead02.c:286: TINFO: read_testfile(1) took: 26101484 usec 329f08c3bdfSopenharmony_ci * 330f08c3bdfSopenharmony_ci * Here raise the maximum runtime dynamically. 331f08c3bdfSopenharmony_ci */ 332f08c3bdfSopenharmony_ci if ((tc+1)->readahead) 333f08c3bdfSopenharmony_ci tst_set_max_runtime(test.max_runtime + (usec + usec_ra) / 1000000); 334f08c3bdfSopenharmony_ci} 335f08c3bdfSopenharmony_ci 336f08c3bdfSopenharmony_ci 337f08c3bdfSopenharmony_ci/* 338f08c3bdfSopenharmony_ci * We try raising bdi readahead limit as much as we can. We write 339f08c3bdfSopenharmony_ci * and read back "read_ahead_kb" sysfs value, starting with filesize. 340f08c3bdfSopenharmony_ci * If that fails, we try again with lower value. 341f08c3bdfSopenharmony_ci * readahead_length used in the test is then set to MIN(bdi limit, 2M), 342f08c3bdfSopenharmony_ci * to respect kernels prior to commit 600e19afc5f8a6c. 343f08c3bdfSopenharmony_ci */ 344f08c3bdfSopenharmony_cistatic void setup_readahead_length(void) 345f08c3bdfSopenharmony_ci{ 346f08c3bdfSopenharmony_ci struct stat sbuf; 347f08c3bdfSopenharmony_ci char tmp[PATH_MAX], *backing_dev; 348f08c3bdfSopenharmony_ci int ra_new_limit, ra_limit; 349f08c3bdfSopenharmony_ci 350f08c3bdfSopenharmony_ci /* Find out backing device name */ 351f08c3bdfSopenharmony_ci SAFE_LSTAT(tst_device->dev, &sbuf); 352f08c3bdfSopenharmony_ci if (S_ISLNK(sbuf.st_mode)) 353f08c3bdfSopenharmony_ci SAFE_READLINK(tst_device->dev, tmp, PATH_MAX); 354f08c3bdfSopenharmony_ci else 355f08c3bdfSopenharmony_ci strcpy(tmp, tst_device->dev); 356f08c3bdfSopenharmony_ci 357f08c3bdfSopenharmony_ci backing_dev = basename(tmp); 358f08c3bdfSopenharmony_ci sprintf(sys_bdi_ra_path, "/sys/class/block/%s/bdi/read_ahead_kb", 359f08c3bdfSopenharmony_ci backing_dev); 360f08c3bdfSopenharmony_ci if (access(sys_bdi_ra_path, F_OK)) 361f08c3bdfSopenharmony_ci return; 362f08c3bdfSopenharmony_ci 363f08c3bdfSopenharmony_ci SAFE_FILE_SCANF(sys_bdi_ra_path, "%d", &orig_bdi_limit); 364f08c3bdfSopenharmony_ci 365f08c3bdfSopenharmony_ci /* raise bdi limit as much as kernel allows */ 366f08c3bdfSopenharmony_ci ra_new_limit = testfile_size / 1024; 367f08c3bdfSopenharmony_ci while (ra_new_limit > pagesize / 1024) { 368f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(sys_bdi_ra_path, "%d", ra_new_limit); 369f08c3bdfSopenharmony_ci SAFE_FILE_SCANF(sys_bdi_ra_path, "%d", &ra_limit); 370f08c3bdfSopenharmony_ci 371f08c3bdfSopenharmony_ci if (ra_limit == ra_new_limit) { 372f08c3bdfSopenharmony_ci readahead_length = MIN(ra_new_limit * 1024, 373f08c3bdfSopenharmony_ci 2 * 1024 * 1024); 374f08c3bdfSopenharmony_ci break; 375f08c3bdfSopenharmony_ci } 376f08c3bdfSopenharmony_ci ra_new_limit = ra_new_limit / 2; 377f08c3bdfSopenharmony_ci } 378f08c3bdfSopenharmony_ci} 379f08c3bdfSopenharmony_ci 380f08c3bdfSopenharmony_cistatic void setup(void) 381f08c3bdfSopenharmony_ci{ 382f08c3bdfSopenharmony_ci if (opt_fsizestr) { 383f08c3bdfSopenharmony_ci testfile_size = SAFE_STRTOL(opt_fsizestr, 1, INT_MAX); 384f08c3bdfSopenharmony_ci tst_set_max_runtime(1 + testfile_size / (DEFAULT_FILESIZE/32)); 385f08c3bdfSopenharmony_ci } 386f08c3bdfSopenharmony_ci 387f08c3bdfSopenharmony_ci if (access(PROC_IO_FNAME, F_OK)) 388f08c3bdfSopenharmony_ci tst_brk(TCONF, "Requires " PROC_IO_FNAME); 389f08c3bdfSopenharmony_ci 390f08c3bdfSopenharmony_ci has_file(DROP_CACHES_FNAME, 1); 391f08c3bdfSopenharmony_ci has_file(MEMINFO_FNAME, 1); 392f08c3bdfSopenharmony_ci 393f08c3bdfSopenharmony_ci /* check if readahead is supported */ 394f08c3bdfSopenharmony_ci tst_syscall(__NR_readahead, 0, 0, 0); 395f08c3bdfSopenharmony_ci 396f08c3bdfSopenharmony_ci pagesize = getpagesize(); 397f08c3bdfSopenharmony_ci 398f08c3bdfSopenharmony_ci setup_readahead_length(); 399f08c3bdfSopenharmony_ci tst_res(TINFO, "readahead length: %d", readahead_length); 400f08c3bdfSopenharmony_ci 401f08c3bdfSopenharmony_ci ovl_mounted = TST_MOUNT_OVERLAY(); 402f08c3bdfSopenharmony_ci} 403f08c3bdfSopenharmony_ci 404f08c3bdfSopenharmony_cistatic void cleanup(void) 405f08c3bdfSopenharmony_ci{ 406f08c3bdfSopenharmony_ci if (ovl_mounted) 407f08c3bdfSopenharmony_ci SAFE_UMOUNT(OVL_MNT); 408f08c3bdfSopenharmony_ci 409f08c3bdfSopenharmony_ci if (orig_bdi_limit) 410f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(sys_bdi_ra_path, "%d", orig_bdi_limit); 411f08c3bdfSopenharmony_ci} 412f08c3bdfSopenharmony_ci 413f08c3bdfSopenharmony_cistatic struct tst_test test = { 414f08c3bdfSopenharmony_ci .needs_root = 1, 415f08c3bdfSopenharmony_ci .mount_device = 1, 416f08c3bdfSopenharmony_ci .mntpoint = mntpoint, 417f08c3bdfSopenharmony_ci .setup = setup, 418f08c3bdfSopenharmony_ci .cleanup = cleanup, 419f08c3bdfSopenharmony_ci .options = (struct tst_option[]) { 420f08c3bdfSopenharmony_ci {"s:", &opt_fsizestr, "Testfile size (default 64MB)"}, 421f08c3bdfSopenharmony_ci {} 422f08c3bdfSopenharmony_ci }, 423f08c3bdfSopenharmony_ci .test = test_readahead, 424f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 425f08c3bdfSopenharmony_ci .max_runtime = 30, 426f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 427f08c3bdfSopenharmony_ci {"linux-git", "b833a3660394"}, 428f08c3bdfSopenharmony_ci {"linux-git", "5b910bd615ba"}, 429f08c3bdfSopenharmony_ci {} 430f08c3bdfSopenharmony_ci } 431f08c3bdfSopenharmony_ci}; 432