2 * Copyright (c) 2017 Red Hat Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write the Free Software Foundation,
15 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Fork N children, each child writes to and reads from its own region of the
20 * same test file, and check if what it reads is what it writes. The test
21 * region is determined by N * blksz. Write and read operation can be either
29 #include <sys/types.h>
39 #define DEF_BLKSZ 4096
43 static void usage(const char *prog)
45 fprintf(stderr, "Usage: %s [-Fhptrwv] [-b blksz] [-n nr_child] [-i iterations] [-o offset] <-f filename>\n", prog);
46 fprintf(stderr, "\t-F\tPreallocate all blocks by writing them before test\n");
47 fprintf(stderr, "\t-p\tPreallocate all blocks using fallocate(2) before test\n");
48 fprintf(stderr, "\t-t\tTruncate test file to largest size before test\n");
49 fprintf(stderr, "\t-r\tDo direct read\n");
50 fprintf(stderr, "\t-w\tDo direct write\n");
51 fprintf(stderr, "\t-v\tBe verbose\n");
52 fprintf(stderr, "\t-h\tshow this help message\n");
56 static int cmpbuf(char *b1, char *b2, int bsize)
60 for (i = 0; i < bsize; i++) {
62 fprintf(stderr, "cmpbuf: offset %d: Expected: 0x%x,"
63 " got 0x%x\n", i, b1[i], b2[i]);
70 static void kill_children(pid_t *pids, int nr_child)
75 for (i = 0; i < nr_child; i++) {
83 static int wait_children(pid_t *pids, int nr_child)
85 int i, status, ret = 0;
88 for (i = 0; i < nr_child; i++) {
92 waitpid(pid, &status, 0);
93 ret += WEXITSTATUS(status);
98 static void dumpbuf(char *buf, int size, int blksz)
102 printf("dumping buffer content\n");
103 for (i = 0; i < size; i++) {
104 if (((i % blksz) == 0) || ((i % 64) == 0))
106 printf("%x", buf[i]);
111 static int run_test(const char *filename, int n_child, int blksz, off_t offset,
112 int nr_iter, int flag_rd, int flag_wr)
121 seekoff = offset + blksz * n_child;
123 page_size = sysconf(_SC_PAGESIZE);
124 ret = posix_memalign((void **)&buf_rd, (size_t)page_size,
125 blksz > page_size ? blksz : (size_t)page_size);
127 fprintf(stderr, "posix_memalign(buf_rd, %d, %d) failed: %d\n",
131 memset(buf_rd, 0, blksz);
132 ret = posix_memalign((void **)&buf_wr, (size_t)page_size,
133 blksz > page_size ? blksz : (size_t)page_size);
135 fprintf(stderr, "posix_memalign(buf_wr, %d, %d) failed: %d\n",
139 memset(buf_wr, 0, blksz);
141 fd_rd = open(filename, flag_rd);
143 perror("open readonly for read");
147 fd_wr = open(filename, flag_wr);
149 perror("open writeonly for direct write");
153 #define log(format, ...) \
155 printf("[%d:%d] ", n_child, i); \
156 printf(format, __VA_ARGS__); \
160 /* seek, write, read and verify */
161 for (i = 0; i < nr_iter; i++) {
162 memset(buf_wr, i + 1, blksz);
163 log("pwrite(fd_wr, %p, %d, %lu)\n", buf_wr, blksz, seekoff);
164 if (pwrite(fd_wr, buf_wr, blksz, seekoff) != blksz) {
165 perror("direct write");
169 /* make sure buffer write hits disk before direct read */
170 if (!(flag_wr & O_DIRECT)) {
171 if (fsync(fd_wr) < 0) {
172 perror("fsync(fd_wr)");
177 log("pread(fd_rd, %p, %d, %lu)\n", buf_rd, blksz, seekoff);
178 if (pread(fd_rd, buf_rd, blksz, seekoff) != blksz) {
179 perror("buffer read");
182 if (cmpbuf(buf_wr, buf_rd, blksz) != 0) {
183 fprintf(stderr, "[%d:%d] FAIL - comparison failed, "
184 "offset %d\n", n_child, i, (int)seekoff);
186 dumpbuf(buf_rd, blksz, blksz);
193 int main(int argc, char *argv[])
197 int blksz = DEF_BLKSZ;
199 int flag_rd = O_RDONLY;
200 int flag_wr = O_WRONLY;
207 char *filename = NULL;
209 while ((i = getopt(argc, argv, "b:i:n:f:Fpo:tvrw")) != -1) {
212 if ((blksz = atoi(optarg)) <= 0) {
213 fprintf(stderr, "blksz must be > 0\n");
216 if (blksz % 512 != 0) {
217 fprintf(stderr, "blksz must be multiple of 512\n");
222 if ((nr_iter = atoi(optarg)) <= 0) {
223 fprintf(stderr, "iterations must be > 0\n");
228 if ((nr_child = atoi(optarg)) <= 0) {
229 fprintf(stderr, "no of children must be > 0\n");
252 if ((offset = atol(optarg)) < 0) {
253 fprintf(stderr, "offset must be >= 0\n");
260 case 'h': /* fall through */
266 if (filename == NULL)
268 if (pre_fill && pre_alloc) {
269 fprintf(stderr, "Error: -F and -p are both specified\n");
273 pids = malloc(nr_child * sizeof(pid_t));
275 fprintf(stderr, "failed to malloc memory for pids\n");
278 memset(pids, 0, nr_child * sizeof(pid_t));
280 /* create & truncate testfile first */
281 fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0600);
283 perror("create & truncate testfile");
287 if (do_trunc && (ftruncate(fd, blksz * nr_child) < 0)) {
288 perror("ftruncate failed");
294 buf = malloc(blksz * nr_child);
295 memset(buf, 's', blksz * nr_child);
296 write(fd, buf, blksz * nr_child);
300 fallocate(fd, 0, 0, blksz * nr_child);
306 for (i = 0; i < nr_child; i++) {
310 kill_children(pids, nr_child);
313 } else if (pid == 0) {
315 run_test(filename, i, blksz, offset, nr_iter,
322 ret = wait_children(pids, nr_child);