1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2022 SUSE LLC <rpalethorpe@suse.com> 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci/*\ 6f08c3bdfSopenharmony_ci * 7f08c3bdfSopenharmony_ci * [Description] 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * Perform some I/O on a file and check if at least some of it is 10f08c3bdfSopenharmony_ci * recorded by the I/O controller. 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * The exact amount of I/O performed is dependent on the file system, 13f08c3bdfSopenharmony_ci * page cache, scheduler and block driver. We call sync and drop the 14f08c3bdfSopenharmony_ci * file's page cache to force reading and writing. We also write 15f08c3bdfSopenharmony_ci * random data to try to prevent compression. 16f08c3bdfSopenharmony_ci * 17f08c3bdfSopenharmony_ci * The pagecache is a particular issue for reading. If the call to 18f08c3bdfSopenharmony_ci * fadvise is ignored then the data may only be read from the 19f08c3bdfSopenharmony_ci * cache. So that no I/O requests are made. 20f08c3bdfSopenharmony_ci */ 21f08c3bdfSopenharmony_ci 22f08c3bdfSopenharmony_ci#include <stdio.h> 23f08c3bdfSopenharmony_ci#include <stdlib.h> 24f08c3bdfSopenharmony_ci#include <sys/sysmacros.h> 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#include "tst_test.h" 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_cistruct io_stats { 29f08c3bdfSopenharmony_ci unsigned int mjr; 30f08c3bdfSopenharmony_ci unsigned int mnr; 31f08c3bdfSopenharmony_ci unsigned long rbytes; 32f08c3bdfSopenharmony_ci unsigned long wbytes; 33f08c3bdfSopenharmony_ci unsigned long rios; 34f08c3bdfSopenharmony_ci unsigned long wios; 35f08c3bdfSopenharmony_ci unsigned long dbytes; 36f08c3bdfSopenharmony_ci unsigned long dios; 37f08c3bdfSopenharmony_ci}; 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_cistatic unsigned int dev_major, dev_minor; 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_cistatic int read_io_stats(const char *const line, struct io_stats *const stat) 42f08c3bdfSopenharmony_ci{ 43f08c3bdfSopenharmony_ci return sscanf(line, 44f08c3bdfSopenharmony_ci "%u:%u rbytes=%lu wbytes=%lu rios=%lu wios=%lu dbytes=%lu dios=%lu", 45f08c3bdfSopenharmony_ci &stat->mjr, &stat->mnr, 46f08c3bdfSopenharmony_ci &stat->rbytes, &stat->wbytes, &stat->rios, &stat->wios, 47f08c3bdfSopenharmony_ci &stat->dbytes, &stat->dios); 48f08c3bdfSopenharmony_ci} 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_cistatic void run(void) 51f08c3bdfSopenharmony_ci{ 52f08c3bdfSopenharmony_ci int i, fd; 53f08c3bdfSopenharmony_ci char *line, *buf_ptr; 54f08c3bdfSopenharmony_ci const size_t pgsz = SAFE_SYSCONF(_SC_PAGESIZE); 55f08c3bdfSopenharmony_ci char *buf = SAFE_MALLOC(MAX((size_t)BUFSIZ, pgsz)); 56f08c3bdfSopenharmony_ci struct io_stats start; 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci memset(&start, 0, sizeof(struct io_stats)); 59f08c3bdfSopenharmony_ci SAFE_CG_READ(tst_cg, "io.stat", buf, BUFSIZ - 1); 60f08c3bdfSopenharmony_ci line = strtok_r(buf, "\n", &buf_ptr); 61f08c3bdfSopenharmony_ci while (line) { 62f08c3bdfSopenharmony_ci const int convs = read_io_stats(line, &start); 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_ci if (convs < 2) 65f08c3bdfSopenharmony_ci continue; 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci tst_res(TINFO, "Found %u:%u in io.stat", dev_major, dev_minor); 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_ci if (start.mjr == dev_major || start.mnr == dev_minor) 70f08c3bdfSopenharmony_ci break; 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci line = strtok_r(NULL, "\n", &buf_ptr); 73f08c3bdfSopenharmony_ci } 74f08c3bdfSopenharmony_ci 75f08c3bdfSopenharmony_ci SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci fd = SAFE_OPEN("/dev/urandom", O_RDONLY, 0600); 78f08c3bdfSopenharmony_ci SAFE_READ(1, fd, buf, pgsz); 79f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci fd = SAFE_OPEN("mnt/dat", O_WRONLY | O_CREAT, 0600); 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci for (i = 0; i < 4; i++) { 84f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, pgsz); 85f08c3bdfSopenharmony_ci SAFE_FSYNC(fd); 86f08c3bdfSopenharmony_ci TST_EXP_PASS_SILENT(posix_fadvise(fd, pgsz * i, pgsz, POSIX_FADV_DONTNEED)); 87f08c3bdfSopenharmony_ci } 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 90f08c3bdfSopenharmony_ci fd = SAFE_OPEN("mnt/dat", O_RDONLY, 0600); 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci for (i = 0; i < 4; i++) 93f08c3bdfSopenharmony_ci SAFE_READ(1, fd, buf, pgsz); 94f08c3bdfSopenharmony_ci 95f08c3bdfSopenharmony_ci tst_res(TPASS, "Did some IO in the IO controller"); 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci SAFE_CG_READ(tst_cg, "io.stat", buf, BUFSIZ - 1); 98f08c3bdfSopenharmony_ci line = strtok_r(buf, "\n", &buf_ptr); 99f08c3bdfSopenharmony_ci while (line) { 100f08c3bdfSopenharmony_ci struct io_stats end; 101f08c3bdfSopenharmony_ci const int convs = read_io_stats(line, &end); 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci if (convs < 8) 104f08c3bdfSopenharmony_ci break; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci if (end.mjr != dev_major || end.mnr != dev_minor) { 107f08c3bdfSopenharmony_ci line = strtok_r(NULL, "\n", &buf_ptr); 108f08c3bdfSopenharmony_ci continue; 109f08c3bdfSopenharmony_ci } 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci tst_res(TPASS, "Found %u:%u in io.stat", dev_major, dev_minor); 112f08c3bdfSopenharmony_ci TST_EXP_EXPR(end.rbytes > start.rbytes, 113f08c3bdfSopenharmony_ci "(rbytes=%lu) > (st_rbytes=%lu)", 114f08c3bdfSopenharmony_ci end.rbytes, start.rbytes); 115f08c3bdfSopenharmony_ci TST_EXP_EXPR(end.wbytes > start.wbytes, 116f08c3bdfSopenharmony_ci "(wbytes=%lu) > (st_wbytes=%lu)", 117f08c3bdfSopenharmony_ci end.wbytes, start.wbytes); 118f08c3bdfSopenharmony_ci TST_EXP_EXPR(end.rios > start.rios, 119f08c3bdfSopenharmony_ci "(rios=%lu) > (st_rios=%lu)", 120f08c3bdfSopenharmony_ci end.rios, start.rios); 121f08c3bdfSopenharmony_ci TST_EXP_EXPR(end.wios > start.wios, 122f08c3bdfSopenharmony_ci "(wios=%lu) > (st_wios=%lu)", 123f08c3bdfSopenharmony_ci end.wios, start.wios); 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci goto out; 126f08c3bdfSopenharmony_ci } 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci tst_res(TINFO, "io.stat:\n%s", buf); 129f08c3bdfSopenharmony_ci tst_res(TFAIL, "Did not find %u:%u in io.stat", dev_major, dev_minor); 130f08c3bdfSopenharmony_ciout: 131f08c3bdfSopenharmony_ci free(buf); 132f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 133f08c3bdfSopenharmony_ci SAFE_UNLINK("mnt/dat"); 134f08c3bdfSopenharmony_ci} 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_cistatic void setup(void) 137f08c3bdfSopenharmony_ci{ 138f08c3bdfSopenharmony_ci char buf[PATH_MAX] = { 0 }; 139f08c3bdfSopenharmony_ci char *path = SAFE_GETCWD(buf, PATH_MAX - sizeof("mnt") - 1); 140f08c3bdfSopenharmony_ci struct stat st; 141f08c3bdfSopenharmony_ci 142f08c3bdfSopenharmony_ci strcpy(path + strlen(path), "/mnt"); 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci tst_stat_mount_dev(path, &st); 145f08c3bdfSopenharmony_ci dev_major = major(st.st_rdev); 146f08c3bdfSopenharmony_ci dev_minor = minor(st.st_rdev); 147f08c3bdfSopenharmony_ci} 148f08c3bdfSopenharmony_ci 149f08c3bdfSopenharmony_cistatic struct tst_test test = { 150f08c3bdfSopenharmony_ci .test_all = run, 151f08c3bdfSopenharmony_ci .setup = setup, 152f08c3bdfSopenharmony_ci .mntpoint = "mnt", 153f08c3bdfSopenharmony_ci .mount_device = 1, 154f08c3bdfSopenharmony_ci .all_filesystems = 1, 155f08c3bdfSopenharmony_ci .skip_filesystems = (const char *const[]){ "ntfs", "tmpfs", NULL }, 156f08c3bdfSopenharmony_ci .needs_cgroup_ver = TST_CG_V2, 157f08c3bdfSopenharmony_ci .needs_cgroup_ctrls = (const char *const[]){ "io", NULL }, 158f08c3bdfSopenharmony_ci}; 159