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