1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker * Copyright (C) 2019 Cyril Hrubis <[email protected]>
4*49cdfc7eSAndroid Build Coastguard Worker */
5*49cdfc7eSAndroid Build Coastguard Worker
6*49cdfc7eSAndroid Build Coastguard Worker /*
7*49cdfc7eSAndroid Build Coastguard Worker * This is a basic functional test for RWF_NOWAIT flag, we are attempting to
8*49cdfc7eSAndroid Build Coastguard Worker * force preadv2() either to return a short read or EAGAIN with three
9*49cdfc7eSAndroid Build Coastguard Worker * concurently running threads:
10*49cdfc7eSAndroid Build Coastguard Worker *
11*49cdfc7eSAndroid Build Coastguard Worker * nowait_reader: reads from a random offset from a random file with
12*49cdfc7eSAndroid Build Coastguard Worker * RWF_NOWAIT flag and expects to get EAGAIN and short
13*49cdfc7eSAndroid Build Coastguard Worker * read sooner or later
14*49cdfc7eSAndroid Build Coastguard Worker *
15*49cdfc7eSAndroid Build Coastguard Worker * writer_thread: rewrites random file in order to keep the underlying device
16*49cdfc7eSAndroid Build Coastguard Worker * busy so that pages evicted from cache cannot be faulted
17*49cdfc7eSAndroid Build Coastguard Worker * immediately
18*49cdfc7eSAndroid Build Coastguard Worker *
19*49cdfc7eSAndroid Build Coastguard Worker * cache_dropper: attempts to evict pages from a cache in order for reader to
20*49cdfc7eSAndroid Build Coastguard Worker * hit evicted page sooner or later
21*49cdfc7eSAndroid Build Coastguard Worker */
22*49cdfc7eSAndroid Build Coastguard Worker
23*49cdfc7eSAndroid Build Coastguard Worker /*
24*49cdfc7eSAndroid Build Coastguard Worker * If test fails with EOPNOTSUPP you have likely hit a glibc bug:
25*49cdfc7eSAndroid Build Coastguard Worker *
26*49cdfc7eSAndroid Build Coastguard Worker * https://sourceware.org/bugzilla/show_bug.cgi?id=23579
27*49cdfc7eSAndroid Build Coastguard Worker *
28*49cdfc7eSAndroid Build Coastguard Worker * Which can be worked around by calling preadv2() directly by syscall() such as:
29*49cdfc7eSAndroid Build Coastguard Worker *
30*49cdfc7eSAndroid Build Coastguard Worker * static ssize_t sys_preadv2(int fd, const struct iovec *iov, int iovcnt,
31*49cdfc7eSAndroid Build Coastguard Worker * off_t offset, int flags)
32*49cdfc7eSAndroid Build Coastguard Worker * {
33*49cdfc7eSAndroid Build Coastguard Worker * return syscall(SYS_preadv2, fd, iov, iovcnt, offset, offset>>32, flags);
34*49cdfc7eSAndroid Build Coastguard Worker * }
35*49cdfc7eSAndroid Build Coastguard Worker *
36*49cdfc7eSAndroid Build Coastguard Worker */
37*49cdfc7eSAndroid Build Coastguard Worker
38*49cdfc7eSAndroid Build Coastguard Worker #define _GNU_SOURCE
39*49cdfc7eSAndroid Build Coastguard Worker #include <string.h>
40*49cdfc7eSAndroid Build Coastguard Worker #include <sys/uio.h>
41*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
42*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
43*49cdfc7eSAndroid Build Coastguard Worker #include <ctype.h>
44*49cdfc7eSAndroid Build Coastguard Worker #include <pthread.h>
45*49cdfc7eSAndroid Build Coastguard Worker
46*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
47*49cdfc7eSAndroid Build Coastguard Worker #include "tst_safe_pthread.h"
48*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/preadv2.h"
49*49cdfc7eSAndroid Build Coastguard Worker
50*49cdfc7eSAndroid Build Coastguard Worker #define CHUNK_SZ 4123
51*49cdfc7eSAndroid Build Coastguard Worker #define CHUNKS 60
52*49cdfc7eSAndroid Build Coastguard Worker #define MNTPOINT "mntpoint"
53*49cdfc7eSAndroid Build Coastguard Worker #define FILES 500
54*49cdfc7eSAndroid Build Coastguard Worker
55*49cdfc7eSAndroid Build Coastguard Worker static int fds[FILES];
56*49cdfc7eSAndroid Build Coastguard Worker
57*49cdfc7eSAndroid Build Coastguard Worker static volatile int stop;
58*49cdfc7eSAndroid Build Coastguard Worker
drop_caches(void)59*49cdfc7eSAndroid Build Coastguard Worker static void drop_caches(void)
60*49cdfc7eSAndroid Build Coastguard Worker {
61*49cdfc7eSAndroid Build Coastguard Worker SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3");
62*49cdfc7eSAndroid Build Coastguard Worker }
63*49cdfc7eSAndroid Build Coastguard Worker
64*49cdfc7eSAndroid Build Coastguard Worker /*
65*49cdfc7eSAndroid Build Coastguard Worker * All files are divided in chunks each filled with the same bytes starting with
66*49cdfc7eSAndroid Build Coastguard Worker * '0' at offset 0 and with increasing value on each next chunk.
67*49cdfc7eSAndroid Build Coastguard Worker *
68*49cdfc7eSAndroid Build Coastguard Worker * 000....000111....111.......AAA......AAA...
69*49cdfc7eSAndroid Build Coastguard Worker * | chunk0 || chunk1 | ... | chunk17 |
70*49cdfc7eSAndroid Build Coastguard Worker */
verify_short_read(struct iovec * iov,size_t iov_cnt,off_t off,size_t size)71*49cdfc7eSAndroid Build Coastguard Worker static int verify_short_read(struct iovec *iov, size_t iov_cnt,
72*49cdfc7eSAndroid Build Coastguard Worker off_t off, size_t size)
73*49cdfc7eSAndroid Build Coastguard Worker {
74*49cdfc7eSAndroid Build Coastguard Worker unsigned int i;
75*49cdfc7eSAndroid Build Coastguard Worker size_t j, checked = 0;
76*49cdfc7eSAndroid Build Coastguard Worker
77*49cdfc7eSAndroid Build Coastguard Worker for (i = 0; i < iov_cnt; i++) {
78*49cdfc7eSAndroid Build Coastguard Worker char *buf = iov[i].iov_base;
79*49cdfc7eSAndroid Build Coastguard Worker for (j = 0; j < iov[i].iov_len; j++) {
80*49cdfc7eSAndroid Build Coastguard Worker char exp_val = '0' + (off + checked)/CHUNK_SZ;
81*49cdfc7eSAndroid Build Coastguard Worker
82*49cdfc7eSAndroid Build Coastguard Worker if (exp_val != buf[j]) {
83*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL,
84*49cdfc7eSAndroid Build Coastguard Worker "Wrong value read pos %zu size %zu %c (%i) %c (%i)!",
85*49cdfc7eSAndroid Build Coastguard Worker checked, size, exp_val, exp_val,
86*49cdfc7eSAndroid Build Coastguard Worker isprint(buf[j]) ? buf[j] : ' ', buf[j]);
87*49cdfc7eSAndroid Build Coastguard Worker return 1;
88*49cdfc7eSAndroid Build Coastguard Worker }
89*49cdfc7eSAndroid Build Coastguard Worker
90*49cdfc7eSAndroid Build Coastguard Worker if (++checked >= size)
91*49cdfc7eSAndroid Build Coastguard Worker return 0;
92*49cdfc7eSAndroid Build Coastguard Worker }
93*49cdfc7eSAndroid Build Coastguard Worker }
94*49cdfc7eSAndroid Build Coastguard Worker
95*49cdfc7eSAndroid Build Coastguard Worker return 0;
96*49cdfc7eSAndroid Build Coastguard Worker }
97*49cdfc7eSAndroid Build Coastguard Worker
nowait_reader(void * unused LTP_ATTRIBUTE_UNUSED)98*49cdfc7eSAndroid Build Coastguard Worker static void *nowait_reader(void *unused LTP_ATTRIBUTE_UNUSED)
99*49cdfc7eSAndroid Build Coastguard Worker {
100*49cdfc7eSAndroid Build Coastguard Worker char buf1[CHUNK_SZ/2];
101*49cdfc7eSAndroid Build Coastguard Worker char buf2[CHUNK_SZ];
102*49cdfc7eSAndroid Build Coastguard Worker unsigned int full_read_cnt = 0, eagain_cnt = 0;
103*49cdfc7eSAndroid Build Coastguard Worker unsigned int short_read_cnt = 0, zero_read_cnt = 0;
104*49cdfc7eSAndroid Build Coastguard Worker
105*49cdfc7eSAndroid Build Coastguard Worker struct iovec rd_iovec[] = {
106*49cdfc7eSAndroid Build Coastguard Worker {buf1, sizeof(buf1)},
107*49cdfc7eSAndroid Build Coastguard Worker {buf2, sizeof(buf2)},
108*49cdfc7eSAndroid Build Coastguard Worker };
109*49cdfc7eSAndroid Build Coastguard Worker
110*49cdfc7eSAndroid Build Coastguard Worker while (!stop) {
111*49cdfc7eSAndroid Build Coastguard Worker if (eagain_cnt >= 100 && short_read_cnt >= 10)
112*49cdfc7eSAndroid Build Coastguard Worker stop = 1;
113*49cdfc7eSAndroid Build Coastguard Worker
114*49cdfc7eSAndroid Build Coastguard Worker /* Ensure short reads doesn't happen because of tripping on EOF */
115*49cdfc7eSAndroid Build Coastguard Worker off_t off = random() % ((CHUNKS - 2) * CHUNK_SZ);
116*49cdfc7eSAndroid Build Coastguard Worker int fd = fds[random() % FILES];
117*49cdfc7eSAndroid Build Coastguard Worker
118*49cdfc7eSAndroid Build Coastguard Worker TEST(preadv2(fd, rd_iovec, 2, off, RWF_NOWAIT));
119*49cdfc7eSAndroid Build Coastguard Worker
120*49cdfc7eSAndroid Build Coastguard Worker if (TST_RET < 0) {
121*49cdfc7eSAndroid Build Coastguard Worker if (TST_ERR != EAGAIN)
122*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK | TTERRNO, "preadv2() failed");
123*49cdfc7eSAndroid Build Coastguard Worker
124*49cdfc7eSAndroid Build Coastguard Worker eagain_cnt++;
125*49cdfc7eSAndroid Build Coastguard Worker continue;
126*49cdfc7eSAndroid Build Coastguard Worker }
127*49cdfc7eSAndroid Build Coastguard Worker
128*49cdfc7eSAndroid Build Coastguard Worker
129*49cdfc7eSAndroid Build Coastguard Worker if (TST_RET == 0) {
130*49cdfc7eSAndroid Build Coastguard Worker zero_read_cnt++;
131*49cdfc7eSAndroid Build Coastguard Worker continue;
132*49cdfc7eSAndroid Build Coastguard Worker }
133*49cdfc7eSAndroid Build Coastguard Worker
134*49cdfc7eSAndroid Build Coastguard Worker if (TST_RET != CHUNK_SZ + CHUNK_SZ/2) {
135*49cdfc7eSAndroid Build Coastguard Worker verify_short_read(rd_iovec, 2, off, TST_RET);
136*49cdfc7eSAndroid Build Coastguard Worker short_read_cnt++;
137*49cdfc7eSAndroid Build Coastguard Worker continue;
138*49cdfc7eSAndroid Build Coastguard Worker }
139*49cdfc7eSAndroid Build Coastguard Worker
140*49cdfc7eSAndroid Build Coastguard Worker full_read_cnt++;
141*49cdfc7eSAndroid Build Coastguard Worker }
142*49cdfc7eSAndroid Build Coastguard Worker
143*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO,
144*49cdfc7eSAndroid Build Coastguard Worker "Number of full_reads %u, short reads %u, zero len reads %u, EAGAIN(s) %u",
145*49cdfc7eSAndroid Build Coastguard Worker full_read_cnt, short_read_cnt, zero_read_cnt, eagain_cnt);
146*49cdfc7eSAndroid Build Coastguard Worker
147*49cdfc7eSAndroid Build Coastguard Worker return (void*)(long)eagain_cnt;
148*49cdfc7eSAndroid Build Coastguard Worker }
149*49cdfc7eSAndroid Build Coastguard Worker
writer_thread(void * unused)150*49cdfc7eSAndroid Build Coastguard Worker static void *writer_thread(void *unused)
151*49cdfc7eSAndroid Build Coastguard Worker {
152*49cdfc7eSAndroid Build Coastguard Worker char buf[CHUNK_SZ];
153*49cdfc7eSAndroid Build Coastguard Worker unsigned int j, write_cnt = 0;
154*49cdfc7eSAndroid Build Coastguard Worker
155*49cdfc7eSAndroid Build Coastguard Worker struct iovec wr_iovec[] = {
156*49cdfc7eSAndroid Build Coastguard Worker {buf, sizeof(buf)},
157*49cdfc7eSAndroid Build Coastguard Worker };
158*49cdfc7eSAndroid Build Coastguard Worker
159*49cdfc7eSAndroid Build Coastguard Worker while (!stop) {
160*49cdfc7eSAndroid Build Coastguard Worker int fd = fds[random() % FILES];
161*49cdfc7eSAndroid Build Coastguard Worker
162*49cdfc7eSAndroid Build Coastguard Worker for (j = 0; j < CHUNKS && !stop; j++) {
163*49cdfc7eSAndroid Build Coastguard Worker memset(buf, '0' + j, sizeof(buf));
164*49cdfc7eSAndroid Build Coastguard Worker
165*49cdfc7eSAndroid Build Coastguard Worker off_t off = CHUNK_SZ * j;
166*49cdfc7eSAndroid Build Coastguard Worker
167*49cdfc7eSAndroid Build Coastguard Worker if (pwritev(fd, wr_iovec, 1, off) < 0) {
168*49cdfc7eSAndroid Build Coastguard Worker if (errno == EBADF) {
169*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO | TERRNO, "FDs closed, exiting...");
170*49cdfc7eSAndroid Build Coastguard Worker return unused;
171*49cdfc7eSAndroid Build Coastguard Worker }
172*49cdfc7eSAndroid Build Coastguard Worker
173*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK | TERRNO, "pwritev()");
174*49cdfc7eSAndroid Build Coastguard Worker }
175*49cdfc7eSAndroid Build Coastguard Worker
176*49cdfc7eSAndroid Build Coastguard Worker write_cnt++;
177*49cdfc7eSAndroid Build Coastguard Worker }
178*49cdfc7eSAndroid Build Coastguard Worker }
179*49cdfc7eSAndroid Build Coastguard Worker
180*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO, "Number of writes %u", write_cnt);
181*49cdfc7eSAndroid Build Coastguard Worker
182*49cdfc7eSAndroid Build Coastguard Worker return unused;
183*49cdfc7eSAndroid Build Coastguard Worker }
184*49cdfc7eSAndroid Build Coastguard Worker
cache_dropper(void * unused)185*49cdfc7eSAndroid Build Coastguard Worker static void *cache_dropper(void *unused)
186*49cdfc7eSAndroid Build Coastguard Worker {
187*49cdfc7eSAndroid Build Coastguard Worker unsigned int drop_cnt = 0;
188*49cdfc7eSAndroid Build Coastguard Worker
189*49cdfc7eSAndroid Build Coastguard Worker while (!stop) {
190*49cdfc7eSAndroid Build Coastguard Worker drop_caches();
191*49cdfc7eSAndroid Build Coastguard Worker drop_cnt++;
192*49cdfc7eSAndroid Build Coastguard Worker }
193*49cdfc7eSAndroid Build Coastguard Worker
194*49cdfc7eSAndroid Build Coastguard Worker tst_res(TINFO, "Cache dropped %u times", drop_cnt);
195*49cdfc7eSAndroid Build Coastguard Worker
196*49cdfc7eSAndroid Build Coastguard Worker return unused;
197*49cdfc7eSAndroid Build Coastguard Worker }
198*49cdfc7eSAndroid Build Coastguard Worker
verify_preadv2(void)199*49cdfc7eSAndroid Build Coastguard Worker static void verify_preadv2(void)
200*49cdfc7eSAndroid Build Coastguard Worker {
201*49cdfc7eSAndroid Build Coastguard Worker pthread_t reader, dropper, writer;
202*49cdfc7eSAndroid Build Coastguard Worker void *eagains;
203*49cdfc7eSAndroid Build Coastguard Worker
204*49cdfc7eSAndroid Build Coastguard Worker stop = 0;
205*49cdfc7eSAndroid Build Coastguard Worker
206*49cdfc7eSAndroid Build Coastguard Worker drop_caches();
207*49cdfc7eSAndroid Build Coastguard Worker
208*49cdfc7eSAndroid Build Coastguard Worker SAFE_PTHREAD_CREATE(&dropper, NULL, cache_dropper, NULL);
209*49cdfc7eSAndroid Build Coastguard Worker SAFE_PTHREAD_CREATE(&reader, NULL, nowait_reader, NULL);
210*49cdfc7eSAndroid Build Coastguard Worker SAFE_PTHREAD_CREATE(&writer, NULL, writer_thread, NULL);
211*49cdfc7eSAndroid Build Coastguard Worker
212*49cdfc7eSAndroid Build Coastguard Worker while (!stop && tst_remaining_runtime())
213*49cdfc7eSAndroid Build Coastguard Worker usleep(100000);
214*49cdfc7eSAndroid Build Coastguard Worker
215*49cdfc7eSAndroid Build Coastguard Worker stop = 1;
216*49cdfc7eSAndroid Build Coastguard Worker
217*49cdfc7eSAndroid Build Coastguard Worker SAFE_PTHREAD_JOIN(reader, &eagains);
218*49cdfc7eSAndroid Build Coastguard Worker SAFE_PTHREAD_JOIN(dropper, NULL);
219*49cdfc7eSAndroid Build Coastguard Worker SAFE_PTHREAD_JOIN(writer, NULL);
220*49cdfc7eSAndroid Build Coastguard Worker
221*49cdfc7eSAndroid Build Coastguard Worker if (eagains)
222*49cdfc7eSAndroid Build Coastguard Worker tst_res(TPASS, "Got some EAGAIN");
223*49cdfc7eSAndroid Build Coastguard Worker else
224*49cdfc7eSAndroid Build Coastguard Worker tst_res(TFAIL, "Haven't got EAGAIN");
225*49cdfc7eSAndroid Build Coastguard Worker }
226*49cdfc7eSAndroid Build Coastguard Worker
check_preadv2_nowait(int fd)227*49cdfc7eSAndroid Build Coastguard Worker static void check_preadv2_nowait(int fd)
228*49cdfc7eSAndroid Build Coastguard Worker {
229*49cdfc7eSAndroid Build Coastguard Worker char buf[1];
230*49cdfc7eSAndroid Build Coastguard Worker struct iovec iovec[] = {
231*49cdfc7eSAndroid Build Coastguard Worker {buf, sizeof(buf)},
232*49cdfc7eSAndroid Build Coastguard Worker };
233*49cdfc7eSAndroid Build Coastguard Worker
234*49cdfc7eSAndroid Build Coastguard Worker TEST(preadv2(fd, iovec, 1, 0, RWF_NOWAIT));
235*49cdfc7eSAndroid Build Coastguard Worker
236*49cdfc7eSAndroid Build Coastguard Worker if (TST_ERR == EOPNOTSUPP)
237*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TCONF | TTERRNO, "preadv2()");
238*49cdfc7eSAndroid Build Coastguard Worker }
239*49cdfc7eSAndroid Build Coastguard Worker
setup(void)240*49cdfc7eSAndroid Build Coastguard Worker static void setup(void)
241*49cdfc7eSAndroid Build Coastguard Worker {
242*49cdfc7eSAndroid Build Coastguard Worker char path[1024];
243*49cdfc7eSAndroid Build Coastguard Worker char buf[CHUNK_SZ];
244*49cdfc7eSAndroid Build Coastguard Worker unsigned int i;
245*49cdfc7eSAndroid Build Coastguard Worker char j;
246*49cdfc7eSAndroid Build Coastguard Worker
247*49cdfc7eSAndroid Build Coastguard Worker for (i = 0; i < FILES; i++) {
248*49cdfc7eSAndroid Build Coastguard Worker snprintf(path, sizeof(path), MNTPOINT"/file_%i", i);
249*49cdfc7eSAndroid Build Coastguard Worker
250*49cdfc7eSAndroid Build Coastguard Worker fds[i] = SAFE_OPEN(path, O_RDWR | O_CREAT, 0644);
251*49cdfc7eSAndroid Build Coastguard Worker
252*49cdfc7eSAndroid Build Coastguard Worker if (i == 0)
253*49cdfc7eSAndroid Build Coastguard Worker check_preadv2_nowait(fds[i]);
254*49cdfc7eSAndroid Build Coastguard Worker
255*49cdfc7eSAndroid Build Coastguard Worker for (j = 0; j < CHUNKS; j++) {
256*49cdfc7eSAndroid Build Coastguard Worker memset(buf, '0' + j, sizeof(buf));
257*49cdfc7eSAndroid Build Coastguard Worker SAFE_WRITE(SAFE_WRITE_RETRY, fds[i], buf, sizeof(buf));
258*49cdfc7eSAndroid Build Coastguard Worker }
259*49cdfc7eSAndroid Build Coastguard Worker }
260*49cdfc7eSAndroid Build Coastguard Worker }
261*49cdfc7eSAndroid Build Coastguard Worker
do_cleanup(void)262*49cdfc7eSAndroid Build Coastguard Worker static void do_cleanup(void)
263*49cdfc7eSAndroid Build Coastguard Worker {
264*49cdfc7eSAndroid Build Coastguard Worker unsigned int i;
265*49cdfc7eSAndroid Build Coastguard Worker
266*49cdfc7eSAndroid Build Coastguard Worker for (i = 0; i < FILES; i++) {
267*49cdfc7eSAndroid Build Coastguard Worker if (fds[i] > 0)
268*49cdfc7eSAndroid Build Coastguard Worker SAFE_CLOSE(fds[i]);
269*49cdfc7eSAndroid Build Coastguard Worker }
270*49cdfc7eSAndroid Build Coastguard Worker }
271*49cdfc7eSAndroid Build Coastguard Worker
272*49cdfc7eSAndroid Build Coastguard Worker TST_DECLARE_ONCE_FN(cleanup, do_cleanup);
273*49cdfc7eSAndroid Build Coastguard Worker
274*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
275*49cdfc7eSAndroid Build Coastguard Worker .setup = setup,
276*49cdfc7eSAndroid Build Coastguard Worker .cleanup = cleanup,
277*49cdfc7eSAndroid Build Coastguard Worker .test_all = verify_preadv2,
278*49cdfc7eSAndroid Build Coastguard Worker .mntpoint = MNTPOINT,
279*49cdfc7eSAndroid Build Coastguard Worker .mount_device = 1,
280*49cdfc7eSAndroid Build Coastguard Worker .all_filesystems = 1,
281*49cdfc7eSAndroid Build Coastguard Worker .max_runtime = 60,
282*49cdfc7eSAndroid Build Coastguard Worker .needs_root = 1,
283*49cdfc7eSAndroid Build Coastguard Worker };
284