xref: /aosp_15_r20/external/ltp/testcases/kernel/io/ltp-aiodio/dio_read.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *   Copyright (C) 2021 SUSE LLC Andrea Cervesato <[email protected]>
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 		if (!tst_remaining_runtime())
56 			return;
57 	}
58 }
59 
do_direct_reads(char * filename,char * bufptr,long long fsize,long long rsize)60 static int do_direct_reads(char *filename, char *bufptr, long long fsize, long long rsize)
61 {
62 	int fd;
63 	long long offset;
64 	long long w;
65 	int fail = 0;
66 	int iter = 1;
67 
68 	fd = SAFE_OPEN(filename, O_RDONLY | O_DIRECT, 0666);
69 
70 	while (1) {
71 		for (offset = 0; offset + rsize < fsize; offset += rsize) {
72 			char *bufoff;
73 
74 			if (*children_completed >= numchildren) {
75 				tst_res(TINFO,
76 					"Writers finshed, exiting reader (iteration %i)",
77 					iter);
78 				goto exit;
79 			}
80 
81 			if (!tst_remaining_runtime()) {
82 				tst_res(TINFO, "Test out of runtime, exiting");
83 				goto exit;
84 			}
85 
86 			w = pread(fd, bufptr, rsize, offset);
87 			if (w < 0)
88 				tst_brk(TBROK, "pread: %s", tst_strerrno(-w));
89 			if (w != rsize)
90 				tst_brk(TBROK, "pread: read %lld bytes out of %lld", w, rsize);
91 
92 			bufoff = check_zero(bufptr, rsize);
93 			if (bufoff) {
94 				fail = 1;
95 				goto exit;
96 			}
97 
98 			iter++;
99 		}
100 	}
101 
102 exit:
103 	SAFE_CLOSE(fd);
104 
105 	return fail;
106 }
107 
setup(void)108 static void setup(void)
109 {
110 	struct stat sb;
111 	long long buffsize;
112 	long long alignment;
113 
114 	if (tst_parse_int(str_numchildren, &numchildren, 1, INT_MAX))
115 		tst_brk(TBROK, "Invalid number of children '%s'", str_numchildren);
116 
117 	if (tst_parse_filesize(str_filesize, &filesize, 1, LLONG_MAX))
118 		tst_brk(TBROK, "Invalid file size '%s'", str_filesize);
119 
120 	if (tst_parse_filesize(str_writesize, &writesize, 1, filesize))
121 		tst_brk(TBROK, "Invalid write blocks size '%s'", str_writesize);
122 
123 	if (tst_parse_filesize(str_readsize, &readsize, 1, filesize))
124 		tst_brk(TBROK, "Invalid read blocks size '%s'", str_readsize);
125 
126 	SAFE_STAT(".", &sb);
127 	alignment = sb.st_blksize;
128 
129 	buffsize = readsize > writesize ? readsize : writesize;
130 
131 	iobuf = SAFE_MEMALIGN(alignment, buffsize);
132 
133 	children_completed = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
134 
135 	fd = SAFE_OPEN(filename, O_CREAT | O_TRUNC | O_RDWR, 0666);
136 }
137 
cleanup(void)138 static void cleanup(void)
139 {
140 	SAFE_CLOSE(fd);
141 }
142 
run(void)143 static void run(void)
144 {
145 	int i;
146 	int fail;
147 
148 	// Fill the file with a known pattern so that the blocks
149 	// on disk can be detected if they become exposed
150 	do_buffered_writes(fd, iobuf, filesize, writesize, 1);
151 	SAFE_FSYNC(fd);
152 	SAFE_FTRUNCATE(fd, 0);
153 	SAFE_FSYNC(fd);
154 
155 	SAFE_FTRUNCATE(fd, filesize);
156 
157 	*children_completed = 0;
158 
159 	for (i = 0; i < numchildren; i++) {
160 		if (!SAFE_FORK()) {
161 			do_buffered_writes(fd, iobuf, filesize, writesize, 0);
162 			tst_atomic_add_return(1, children_completed);
163 			return;
164 		}
165 	}
166 
167 	fail = do_direct_reads(filename, iobuf, filesize, readsize);
168 
169 	if (fail)
170 		tst_res(TFAIL, "Non zero bytes read");
171 	else
172 		tst_res(TPASS, "All bytes read were zeroed");
173 }
174 
175 static struct tst_test test = {
176 	.test_all = run,
177 	.setup = setup,
178 	.cleanup = cleanup,
179 	.needs_tmpdir = 1,
180 	.forks_child = 1,
181 	.max_runtime = 1800,
182 	.options = (struct tst_option[]) {
183 		{"n:", &str_numchildren, "Number of threads (default 8)"},
184 		{"w:", &str_writesize, "Size of writing blocks (default 32M)"},
185 		{"r:", &str_readsize, "Size of reading blocks (default 32M)"},
186 		{"s:", &str_filesize, "File size (default 128M)"},
187 		{}
188 	},
189 	.skip_filesystems = (const char *[]) {
190 		"tmpfs",
191 		NULL
192 	},
193 };
194