• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2004 Daniel McNeil <daniel@osdl.org>
4  *               2004 Open Source Development Lab
5  *
6  * Copyright (c) 2004 Marty Ridgeway <mridge@us.ibm.com>
7  *
8  * Copyright (c) 2011 Cyril Hrubis <chrubis@suse.cz>
9  * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
10  */
11 
12 /*\
13  * [Description]
14  *
15  * Create a sparse file and write zeroes to it using libaio while other
16  * processes are doing buffered reads and check if the buffer reads always see
17  * zero.
18  */
19 
20 #define _GNU_SOURCE
21 
22 #include "tst_test.h"
23 
24 #ifdef HAVE_LIBAIO
25 #include <stdlib.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #include <libaio.h>
29 #include "common.h"
30 
31 static volatile int *run_child;
32 
33 static char *str_numchildren;
34 static char *str_writesize;
35 static char *str_filesize;
36 static char *str_numaio;
37 
38 static int numchildren = 16;
39 static long long writesize = 1024;
40 static long long filesize = 100 * 1024 * 1024;
41 static long long alignment;
42 static int numaio = 16;
43 
check_event(struct io_event event)44 static void check_event(struct io_event event)
45 {
46 	struct iocb *iocbp;
47 
48 	iocbp = (struct iocb *)event.obj;
49 	if (event.res2 != 0 || event.res != iocbp->u.c.nbytes) {
50 		tst_brk(TBROK, "AIO write offset %lld expected %ld got %ld",
51 			iocbp->u.c.offset, iocbp->u.c.nbytes, event.res);
52 	}
53 }
54 
aiodio_sparse(char * filename,long long align,long long ws,long long fs,int naio)55 static void aiodio_sparse(char *filename, long long align, long long ws,
56 			  long long fs, int naio)
57 {
58 	int fd;
59 	int i, w;
60 	struct iocb **iocbs;
61 	struct iocb *iocb;
62 	off_t offset;
63 	io_context_t myctx;
64 	struct io_event event;
65 	int aio_inflight;
66 
67 	fd = SAFE_OPEN(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666);
68 	SAFE_FTRUNCATE(fd, fs);
69 
70 	memset(&myctx, 0, sizeof(myctx));
71 	io_queue_init(naio, &myctx);
72 
73 	iocbs = SAFE_MALLOC(sizeof(struct iocb *) * naio);
74 	iocb = SAFE_MALLOC(sizeof(struct iocb) * naio);
75 
76 	for (i = 0; i < naio; i++)
77 		iocbs[i] = iocb + i;
78 
79 	offset = 0;
80 	for (i = 0; i < naio; i++) {
81 		void *bufptr;
82 
83 		bufptr = SAFE_MEMALIGN(align, ws);
84 		memset(bufptr, 0, ws);
85 		io_prep_pwrite(iocbs[i], fd, bufptr, ws, offset);
86 		offset += ws;
87 	}
88 
89 	w = io_submit(myctx, naio, iocbs);
90 	if (w < 0)
91 		tst_brk(TBROK, "io_submit: %s", tst_strerrno(-w));
92 
93 	aio_inflight = naio;
94 
95 	while (offset < fs) {
96 		int n;
97 		struct iocb *iocbp;
98 
99 		n = io_getevents(myctx, 1, 1, &event, 0);
100 
101 		if (-n == EINTR)
102 			continue;
103 
104 		if (n != 1)
105 			tst_brk(TBROK, "io_getevents: %s", tst_strerrno(-n));
106 
107 		aio_inflight--;
108 
109 		check_event(event);
110 
111 		/* start next write */
112 		iocbp = (struct iocb *)event.obj;
113 
114 		io_prep_pwrite(iocbp, fd, iocbp->u.c.buf, ws, offset);
115 		offset += ws;
116 		w = io_submit(myctx, 1, &iocbp);
117 		if (w < 0)
118 			tst_brk(TBROK, "io_submit: %s", tst_strerrno(-w));
119 
120 		aio_inflight++;
121 	}
122 
123 	while (aio_inflight > 0) {
124 		int n;
125 
126 		n = io_getevents(myctx, 1, 1, &event, 0);
127 
128 		if (-n == EINTR)
129 			continue;
130 
131 		if (n != 1)
132 			tst_brk(TBROK, "io_getevents failed");
133 
134 		aio_inflight--;
135 
136 		check_event(event);
137 	}
138 
139 	free(iocb);
140 	free(iocbs);
141 }
142 
setup(void)143 static void setup(void)
144 {
145 	struct stat sb;
146 
147 	if (tst_parse_int(str_numchildren, &numchildren, 1, INT_MAX)) {
148 		tst_brk(TBROK, "Invalid number of children '%s'",
149 			str_numchildren);
150 	}
151 
152 	if (tst_parse_filesize(str_writesize, &writesize, 1, LLONG_MAX))
153 		tst_brk(TBROK, "Invalid write blocks size '%s'", str_writesize);
154 
155 	if (tst_parse_filesize(str_filesize, &filesize, 1, LLONG_MAX))
156 		tst_brk(TBROK, "Invalid file size '%s'", str_filesize);
157 
158 	if (tst_parse_int(str_numaio, &numaio, 1, INT_MAX)) {
159 		tst_brk(TBROK, "Invalid number of AIO control blocks '%s'",
160 			str_numaio);
161 	}
162 
163 	if ((numaio * writesize) > filesize) {
164 		numaio = filesize / writesize;
165 		tst_res(TINFO,
166 			"Numbers of AIO have been reduced to %d so we fit filesize",
167 			numaio);
168 	}
169 
170 	SAFE_STAT(".", &sb);
171 	alignment = sb.st_blksize;
172 
173 	run_child = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE,
174 			      MAP_SHARED | MAP_ANONYMOUS, -1, 0);
175 
176 	tst_res(TINFO, "Dirtying free blocks");
177 	dirty_freeblocks(filesize);
178 }
179 
cleanup(void)180 static void cleanup(void)
181 {
182 	if (run_child) {
183 		*run_child = 0;
184 		SAFE_MUNMAP((void *)run_child, sizeof(int));
185 	}
186 }
187 
run(void)188 static void run(void)
189 {
190 	char *filename = "file.bin";
191 	int i, pid;
192 
193 	*run_child = 1;
194 
195 	for (i = 0; i < numchildren; i++) {
196 		if (!SAFE_FORK()) {
197 			io_read(filename, filesize, run_child);
198 			return;
199 		}
200 	}
201 
202 	pid = SAFE_FORK();
203 	if (!pid) {
204 		aiodio_sparse(filename, alignment, writesize, filesize, numaio);
205 		return;
206 	}
207 
208 	tst_res(TINFO, "Child %i creates a sparse file", pid);
209 
210 	for (;;) {
211 		if (SAFE_WAITPID(pid, NULL, WNOHANG))
212 			break;
213 
214 		sleep(1);
215 
216 		if (!tst_remaining_runtime()) {
217 			tst_res(TINFO, "Test out of runtime, exiting");
218 			kill(pid, SIGKILL);
219 			SAFE_WAITPID(pid, NULL, 0);
220 			break;
221 		}
222 	}
223 
224 	*run_child = 0;
225 
226 	if (!tst_validate_children(numchildren))
227 		tst_res(TPASS, "All bytes read were zeroed");
228 }
229 
230 static struct tst_test test = {
231 	.test_all = run,
232 	.setup = setup,
233 	.cleanup = cleanup,
234 	.needs_tmpdir = 1,
235 	.forks_child = 1,
236 	.options = (struct tst_option[]) {
237 		{"n:", &str_numchildren, "Number of threads (default 16)"},
238 		{"w:", &str_writesize, "Size of writing blocks (default 1K)"},
239 		{"s:", &str_filesize, "Size of file (default 100M)"},
240 		{"o:", &str_numaio, "Number of AIO control blocks (default 16)"},
241 		{},
242 	},
243 	.skip_filesystems = (const char *[]) {
244 		"tmpfs",
245 		NULL
246 	},
247 	.max_runtime = 1800,
248 };
249 #else
250 TST_TEST_TCONF("test requires libaio and its development packages");
251 #endif
252