• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *   Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
4  */
5 
6 /*\
7  * [Description]
8  *
9  * Create a file using buffered writes while other processes are doing
10  * O_DIRECT reads and check if the buffer reads always see zero.
11  */
12 
13 #define _GNU_SOURCE
14 
15 #include <unistd.h>
16 #include <limits.h>
17 #include <string.h>
18 #include <fcntl.h>
19 #include <sys/mman.h>
20 #include "tst_test.h"
21 #include "common.h"
22 
23 static char *str_numchildren;
24 static char *str_writesize;
25 static char *str_readsize;
26 static char *str_filesize;
27 
28 static char *filename = "file.bin";
29 static int numchildren = 8;
30 static long long writesize = 32 * 1024 * 1024;
31 static long long readsize = 32 * 1024 * 1024;
32 static long long filesize = 128 * 1024 * 1024;
33 static int *children_completed;
34 static char *iobuf;
35 static int fd;
36 
do_buffered_writes(int fd,char * bufptr,long long fsize,long long wsize,int pattern)37 static void do_buffered_writes(int fd, char *bufptr, long long fsize, long long wsize, int pattern)
38 {
39 	long long offset;
40 	long long w;
41 
42 	memset(bufptr, pattern, wsize);
43 
44 	tst_res(TINFO, "child %i writing file", getpid());
45 
46 	for (offset = 0; offset + wsize <= fsize; offset += wsize) {
47 		w = pwrite(fd, bufptr, wsize, offset);
48 		if (w < 0)
49 			tst_brk(TBROK, "pwrite: %s", tst_strerrno(-w));
50 		if (w != wsize)
51 			tst_brk(TBROK, "pwrite: wrote %lld bytes out of %lld", w, wsize);
52 
53 		SAFE_FSYNC(fd);
54 	}
55 }
56 
do_direct_reads(char * filename,char * bufptr,long long fsize,long long rsize)57 static int do_direct_reads(char *filename, char *bufptr, long long fsize, long long rsize)
58 {
59 	int fd;
60 	long long offset;
61 	long long w;
62 	int fail = 0;
63 	int iter = 1;
64 
65 	fd = SAFE_OPEN(filename, O_RDONLY | O_DIRECT, 0666);
66 
67 	while (1) {
68 		for (offset = 0; offset + rsize < fsize; offset += rsize) {
69 			char *bufoff;
70 
71 			if (*children_completed >= numchildren) {
72 				tst_res(TINFO,
73 					"Writers finshed, exitting reader (iteration %i)",
74 					iter);
75 				goto exit;
76 			}
77 
78 			w = pread(fd, bufptr, rsize, offset);
79 			if (w < 0)
80 				tst_brk(TBROK, "pread: %s", tst_strerrno(-w));
81 			if (w != rsize)
82 				tst_brk(TBROK, "pread: read %lld bytes out of %lld", w, rsize);
83 
84 			bufoff = check_zero(bufptr, rsize);
85 			if (bufoff) {
86 				fail = 1;
87 				goto exit;
88 			}
89 
90 			iter++;
91 		}
92 	}
93 
94 exit:
95 	SAFE_CLOSE(fd);
96 
97 	return fail;
98 }
99 
setup(void)100 static void setup(void)
101 {
102 	struct stat sb;
103 	long long buffsize;
104 	long long alignment;
105 
106 	if (tst_parse_int(str_numchildren, &numchildren, 1, INT_MAX))
107 		tst_brk(TBROK, "Invalid number of children '%s'", str_numchildren);
108 
109 	if (tst_parse_filesize(str_filesize, &filesize, 1, LLONG_MAX))
110 		tst_brk(TBROK, "Invalid file size '%s'", str_filesize);
111 
112 	if (tst_parse_filesize(str_writesize, &writesize, 1, filesize))
113 		tst_brk(TBROK, "Invalid write blocks size '%s'", str_writesize);
114 
115 	if (tst_parse_filesize(str_readsize, &readsize, 1, filesize))
116 		tst_brk(TBROK, "Invalid read blocks size '%s'", str_readsize);
117 
118 	SAFE_STAT(".", &sb);
119 	alignment = sb.st_blksize;
120 
121 	buffsize = readsize > writesize ? readsize : writesize;
122 
123 	iobuf = SAFE_MEMALIGN(alignment, buffsize);
124 
125 	children_completed = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
126 
127 	fd = SAFE_OPEN(filename, O_CREAT | O_TRUNC | O_RDWR, 0666);
128 }
129 
cleanup(void)130 static void cleanup(void)
131 {
132 	SAFE_CLOSE(fd);
133 }
134 
run(void)135 static void run(void)
136 {
137 	int i;
138 	int fail;
139 
140 	// Fill the file with a known pattern so that the blocks
141 	// on disk can be detected if they become exposed
142 	do_buffered_writes(fd, iobuf, filesize, writesize, 1);
143 	SAFE_FSYNC(fd);
144 	SAFE_FTRUNCATE(fd, 0);
145 	SAFE_FSYNC(fd);
146 
147 	SAFE_FTRUNCATE(fd, filesize);
148 
149 	*children_completed = 0;
150 
151 	for (i = 0; i < numchildren; i++) {
152 		if (!SAFE_FORK()) {
153 			do_buffered_writes(fd, iobuf, filesize, writesize, 0);
154 			tst_atomic_add_return(1, children_completed);
155 			return;
156 		}
157 	}
158 
159 	fail = do_direct_reads(filename, iobuf, filesize, readsize);
160 
161 	if (fail)
162 		tst_res(TFAIL, "Non zero bytes read");
163 	else
164 		tst_res(TPASS, "All bytes read were zeroed");
165 }
166 
167 static struct tst_test test = {
168 	.test_all = run,
169 	.setup = setup,
170 	.cleanup = cleanup,
171 	.needs_tmpdir = 1,
172 	.forks_child = 1,
173 	.options = (struct tst_option[]) {
174 		{"n:", &str_numchildren, "Number of threads (default 8)"},
175 		{"w:", &str_writesize, "Size of writing blocks (default 32M)"},
176 		{"r:", &str_readsize, "Size of reading blocks (default 32M)"},
177 		{"s:", &str_filesize, "File size (default 128M)"},
178 		{}
179 	},
180 	.skip_filesystems = (const char *[]) {
181 		"tmpfs",
182 		NULL
183 	},
184 };
185