1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker * Description: test io_uring fpos handling
4*25da2beaSAndroid Build Coastguard Worker *
5*25da2beaSAndroid Build Coastguard Worker */
6*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
7*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
8*25da2beaSAndroid Build Coastguard Worker #include <unistd.h>
9*25da2beaSAndroid Build Coastguard Worker #include <stdlib.h>
10*25da2beaSAndroid Build Coastguard Worker #include <string.h>
11*25da2beaSAndroid Build Coastguard Worker #include <fcntl.h>
12*25da2beaSAndroid Build Coastguard Worker #include <assert.h>
13*25da2beaSAndroid Build Coastguard Worker
14*25da2beaSAndroid Build Coastguard Worker #include "helpers.h"
15*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
16*25da2beaSAndroid Build Coastguard Worker
17*25da2beaSAndroid Build Coastguard Worker #define FILE_SIZE 5000
18*25da2beaSAndroid Build Coastguard Worker #define QUEUE_SIZE 2048
19*25da2beaSAndroid Build Coastguard Worker
create_file(const char * file,size_t size)20*25da2beaSAndroid Build Coastguard Worker static void create_file(const char *file, size_t size)
21*25da2beaSAndroid Build Coastguard Worker {
22*25da2beaSAndroid Build Coastguard Worker ssize_t ret;
23*25da2beaSAndroid Build Coastguard Worker char *buf;
24*25da2beaSAndroid Build Coastguard Worker size_t idx;
25*25da2beaSAndroid Build Coastguard Worker int fd;
26*25da2beaSAndroid Build Coastguard Worker
27*25da2beaSAndroid Build Coastguard Worker buf = t_malloc(size);
28*25da2beaSAndroid Build Coastguard Worker for (idx = 0; idx < size; ++idx) {
29*25da2beaSAndroid Build Coastguard Worker /* write 0 or 1 */
30*25da2beaSAndroid Build Coastguard Worker buf[idx] = (unsigned char)(idx & 0x01);
31*25da2beaSAndroid Build Coastguard Worker }
32*25da2beaSAndroid Build Coastguard Worker
33*25da2beaSAndroid Build Coastguard Worker fd = open(file, O_WRONLY | O_CREAT, 0644);
34*25da2beaSAndroid Build Coastguard Worker assert(fd >= 0);
35*25da2beaSAndroid Build Coastguard Worker
36*25da2beaSAndroid Build Coastguard Worker ret = write(fd, buf, size);
37*25da2beaSAndroid Build Coastguard Worker fsync(fd);
38*25da2beaSAndroid Build Coastguard Worker close(fd);
39*25da2beaSAndroid Build Coastguard Worker free(buf);
40*25da2beaSAndroid Build Coastguard Worker assert(ret == size);
41*25da2beaSAndroid Build Coastguard Worker }
42*25da2beaSAndroid Build Coastguard Worker
test_read(struct io_uring * ring,bool async,int blocksize)43*25da2beaSAndroid Build Coastguard Worker static int test_read(struct io_uring *ring, bool async, int blocksize)
44*25da2beaSAndroid Build Coastguard Worker {
45*25da2beaSAndroid Build Coastguard Worker int ret, fd, i;
46*25da2beaSAndroid Build Coastguard Worker bool done = false;
47*25da2beaSAndroid Build Coastguard Worker struct io_uring_sqe *sqe;
48*25da2beaSAndroid Build Coastguard Worker struct io_uring_cqe *cqe;
49*25da2beaSAndroid Build Coastguard Worker loff_t current, expected = 0;
50*25da2beaSAndroid Build Coastguard Worker int count_ok;
51*25da2beaSAndroid Build Coastguard Worker int count_0 = 0, count_1 = 0;
52*25da2beaSAndroid Build Coastguard Worker unsigned char buff[QUEUE_SIZE * blocksize];
53*25da2beaSAndroid Build Coastguard Worker unsigned char reordered[QUEUE_SIZE * blocksize];
54*25da2beaSAndroid Build Coastguard Worker
55*25da2beaSAndroid Build Coastguard Worker create_file(".test_fpos_read", FILE_SIZE);
56*25da2beaSAndroid Build Coastguard Worker fd = open(".test_fpos_read", O_RDONLY);
57*25da2beaSAndroid Build Coastguard Worker unlink(".test_fpos_read");
58*25da2beaSAndroid Build Coastguard Worker assert(fd >= 0);
59*25da2beaSAndroid Build Coastguard Worker
60*25da2beaSAndroid Build Coastguard Worker while (!done) {
61*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < QUEUE_SIZE; ++i) {
62*25da2beaSAndroid Build Coastguard Worker sqe = io_uring_get_sqe(ring);
63*25da2beaSAndroid Build Coastguard Worker if (!sqe) {
64*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "no sqe\n");
65*25da2beaSAndroid Build Coastguard Worker return -1;
66*25da2beaSAndroid Build Coastguard Worker }
67*25da2beaSAndroid Build Coastguard Worker io_uring_prep_read(sqe, fd,
68*25da2beaSAndroid Build Coastguard Worker buff + i * blocksize,
69*25da2beaSAndroid Build Coastguard Worker blocksize, -1);
70*25da2beaSAndroid Build Coastguard Worker sqe->user_data = i;
71*25da2beaSAndroid Build Coastguard Worker if (async)
72*25da2beaSAndroid Build Coastguard Worker sqe->flags |= IOSQE_ASYNC;
73*25da2beaSAndroid Build Coastguard Worker if (i != QUEUE_SIZE - 1)
74*25da2beaSAndroid Build Coastguard Worker sqe->flags |= IOSQE_IO_LINK;
75*25da2beaSAndroid Build Coastguard Worker }
76*25da2beaSAndroid Build Coastguard Worker ret = io_uring_submit_and_wait(ring, QUEUE_SIZE);
77*25da2beaSAndroid Build Coastguard Worker if (ret != QUEUE_SIZE) {
78*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "submit failed: %d\n", ret);
79*25da2beaSAndroid Build Coastguard Worker return 1;
80*25da2beaSAndroid Build Coastguard Worker }
81*25da2beaSAndroid Build Coastguard Worker count_ok = 0;
82*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < QUEUE_SIZE; ++i) {
83*25da2beaSAndroid Build Coastguard Worker int res;
84*25da2beaSAndroid Build Coastguard Worker
85*25da2beaSAndroid Build Coastguard Worker ret = io_uring_peek_cqe(ring, &cqe);
86*25da2beaSAndroid Build Coastguard Worker if (ret) {
87*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "peek failed: %d\n", ret);
88*25da2beaSAndroid Build Coastguard Worker return ret;
89*25da2beaSAndroid Build Coastguard Worker }
90*25da2beaSAndroid Build Coastguard Worker assert(cqe->user_data < QUEUE_SIZE);
91*25da2beaSAndroid Build Coastguard Worker memcpy(reordered + count_ok,
92*25da2beaSAndroid Build Coastguard Worker buff + cqe->user_data * blocksize, blocksize);
93*25da2beaSAndroid Build Coastguard Worker res = cqe->res;
94*25da2beaSAndroid Build Coastguard Worker io_uring_cqe_seen(ring, cqe);
95*25da2beaSAndroid Build Coastguard Worker if (res == 0) {
96*25da2beaSAndroid Build Coastguard Worker done = true;
97*25da2beaSAndroid Build Coastguard Worker } else if (res == -ECANCELED) {
98*25da2beaSAndroid Build Coastguard Worker /* cancelled, probably ok */
99*25da2beaSAndroid Build Coastguard Worker } else if (res < 0 || res > blocksize) {
100*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "bad read: %d\n", res);
101*25da2beaSAndroid Build Coastguard Worker return -1;
102*25da2beaSAndroid Build Coastguard Worker } else {
103*25da2beaSAndroid Build Coastguard Worker expected += res;
104*25da2beaSAndroid Build Coastguard Worker count_ok += res;
105*25da2beaSAndroid Build Coastguard Worker }
106*25da2beaSAndroid Build Coastguard Worker }
107*25da2beaSAndroid Build Coastguard Worker ret = 0;
108*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < count_ok; i++) {
109*25da2beaSAndroid Build Coastguard Worker if (reordered[i] == 1) {
110*25da2beaSAndroid Build Coastguard Worker count_1++;
111*25da2beaSAndroid Build Coastguard Worker } else if (reordered[i] == 0) {
112*25da2beaSAndroid Build Coastguard Worker count_0++;
113*25da2beaSAndroid Build Coastguard Worker } else {
114*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "odd read %d\n",
115*25da2beaSAndroid Build Coastguard Worker (int)reordered[i]);
116*25da2beaSAndroid Build Coastguard Worker ret = -1;
117*25da2beaSAndroid Build Coastguard Worker break;
118*25da2beaSAndroid Build Coastguard Worker }
119*25da2beaSAndroid Build Coastguard Worker }
120*25da2beaSAndroid Build Coastguard Worker if (labs(count_1 - count_0) > 1) {
121*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "inconsistent reads, got 0s:%d 1s:%d\n",
122*25da2beaSAndroid Build Coastguard Worker count_0, count_1);
123*25da2beaSAndroid Build Coastguard Worker ret = -1;
124*25da2beaSAndroid Build Coastguard Worker }
125*25da2beaSAndroid Build Coastguard Worker current = lseek(fd, 0, SEEK_CUR);
126*25da2beaSAndroid Build Coastguard Worker if (current != expected) {
127*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "f_pos incorrect, expected %ld have %ld\n",
128*25da2beaSAndroid Build Coastguard Worker (long) expected, (long) current);
129*25da2beaSAndroid Build Coastguard Worker ret = -1;
130*25da2beaSAndroid Build Coastguard Worker }
131*25da2beaSAndroid Build Coastguard Worker if (ret)
132*25da2beaSAndroid Build Coastguard Worker return ret;
133*25da2beaSAndroid Build Coastguard Worker }
134*25da2beaSAndroid Build Coastguard Worker return 0;
135*25da2beaSAndroid Build Coastguard Worker }
136*25da2beaSAndroid Build Coastguard Worker
137*25da2beaSAndroid Build Coastguard Worker
test_write(struct io_uring * ring,bool async,int blocksize)138*25da2beaSAndroid Build Coastguard Worker static int test_write(struct io_uring *ring, bool async, int blocksize)
139*25da2beaSAndroid Build Coastguard Worker {
140*25da2beaSAndroid Build Coastguard Worker int ret, fd, i;
141*25da2beaSAndroid Build Coastguard Worker struct io_uring_sqe *sqe;
142*25da2beaSAndroid Build Coastguard Worker struct io_uring_cqe *cqe;
143*25da2beaSAndroid Build Coastguard Worker bool fail = false;
144*25da2beaSAndroid Build Coastguard Worker loff_t current;
145*25da2beaSAndroid Build Coastguard Worker char data[blocksize+1];
146*25da2beaSAndroid Build Coastguard Worker char readbuff[QUEUE_SIZE*blocksize+1];
147*25da2beaSAndroid Build Coastguard Worker
148*25da2beaSAndroid Build Coastguard Worker fd = open(".test_fpos_write", O_RDWR | O_CREAT, 0644);
149*25da2beaSAndroid Build Coastguard Worker unlink(".test_fpos_write");
150*25da2beaSAndroid Build Coastguard Worker assert(fd >= 0);
151*25da2beaSAndroid Build Coastguard Worker
152*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < blocksize; i++)
153*25da2beaSAndroid Build Coastguard Worker data[i] = 'A' + i;
154*25da2beaSAndroid Build Coastguard Worker
155*25da2beaSAndroid Build Coastguard Worker data[blocksize] = '\0';
156*25da2beaSAndroid Build Coastguard Worker
157*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < QUEUE_SIZE; ++i) {
158*25da2beaSAndroid Build Coastguard Worker sqe = io_uring_get_sqe(ring);
159*25da2beaSAndroid Build Coastguard Worker if (!sqe) {
160*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "no sqe\n");
161*25da2beaSAndroid Build Coastguard Worker return -1;
162*25da2beaSAndroid Build Coastguard Worker }
163*25da2beaSAndroid Build Coastguard Worker io_uring_prep_write(sqe, fd, data + (i % blocksize), 1, -1);
164*25da2beaSAndroid Build Coastguard Worker sqe->user_data = 1;
165*25da2beaSAndroid Build Coastguard Worker if (async)
166*25da2beaSAndroid Build Coastguard Worker sqe->flags |= IOSQE_ASYNC;
167*25da2beaSAndroid Build Coastguard Worker if (i != QUEUE_SIZE - 1)
168*25da2beaSAndroid Build Coastguard Worker sqe->flags |= IOSQE_IO_LINK;
169*25da2beaSAndroid Build Coastguard Worker }
170*25da2beaSAndroid Build Coastguard Worker ret = io_uring_submit_and_wait(ring, QUEUE_SIZE);
171*25da2beaSAndroid Build Coastguard Worker if (ret != QUEUE_SIZE) {
172*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "submit failed: %d\n", ret);
173*25da2beaSAndroid Build Coastguard Worker return 1;
174*25da2beaSAndroid Build Coastguard Worker }
175*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < QUEUE_SIZE; ++i) {
176*25da2beaSAndroid Build Coastguard Worker int res;
177*25da2beaSAndroid Build Coastguard Worker
178*25da2beaSAndroid Build Coastguard Worker ret = io_uring_peek_cqe(ring, &cqe);
179*25da2beaSAndroid Build Coastguard Worker res = cqe->res;
180*25da2beaSAndroid Build Coastguard Worker if (ret) {
181*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "peek failed: %d\n", ret);
182*25da2beaSAndroid Build Coastguard Worker return ret;
183*25da2beaSAndroid Build Coastguard Worker }
184*25da2beaSAndroid Build Coastguard Worker io_uring_cqe_seen(ring, cqe);
185*25da2beaSAndroid Build Coastguard Worker if (!fail && res != 1) {
186*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "bad result %d\n", res);
187*25da2beaSAndroid Build Coastguard Worker fail = true;
188*25da2beaSAndroid Build Coastguard Worker }
189*25da2beaSAndroid Build Coastguard Worker }
190*25da2beaSAndroid Build Coastguard Worker current = lseek(fd, 0, SEEK_CUR);
191*25da2beaSAndroid Build Coastguard Worker if (current != QUEUE_SIZE) {
192*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "f_pos incorrect, expected %ld have %d\n",
193*25da2beaSAndroid Build Coastguard Worker (long) current, QUEUE_SIZE);
194*25da2beaSAndroid Build Coastguard Worker fail = true;
195*25da2beaSAndroid Build Coastguard Worker }
196*25da2beaSAndroid Build Coastguard Worker current = lseek(fd, 0, SEEK_SET);
197*25da2beaSAndroid Build Coastguard Worker if (current != 0) {
198*25da2beaSAndroid Build Coastguard Worker perror("seek to start");
199*25da2beaSAndroid Build Coastguard Worker return -1;
200*25da2beaSAndroid Build Coastguard Worker }
201*25da2beaSAndroid Build Coastguard Worker ret = read(fd, readbuff, QUEUE_SIZE);
202*25da2beaSAndroid Build Coastguard Worker if (ret != QUEUE_SIZE) {
203*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "did not write enough: %d\n", ret);
204*25da2beaSAndroid Build Coastguard Worker return -1;
205*25da2beaSAndroid Build Coastguard Worker }
206*25da2beaSAndroid Build Coastguard Worker i = 0;
207*25da2beaSAndroid Build Coastguard Worker while (i < QUEUE_SIZE - blocksize) {
208*25da2beaSAndroid Build Coastguard Worker if (strncmp(readbuff + i, data, blocksize)) {
209*25da2beaSAndroid Build Coastguard Worker char bad[QUEUE_SIZE+1];
210*25da2beaSAndroid Build Coastguard Worker
211*25da2beaSAndroid Build Coastguard Worker memcpy(bad, readbuff + i, blocksize);
212*25da2beaSAndroid Build Coastguard Worker bad[blocksize] = '\0';
213*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "unexpected data %s\n", bad);
214*25da2beaSAndroid Build Coastguard Worker fail = true;
215*25da2beaSAndroid Build Coastguard Worker }
216*25da2beaSAndroid Build Coastguard Worker i += blocksize;
217*25da2beaSAndroid Build Coastguard Worker }
218*25da2beaSAndroid Build Coastguard Worker
219*25da2beaSAndroid Build Coastguard Worker return fail ? -1 : 0;
220*25da2beaSAndroid Build Coastguard Worker }
221*25da2beaSAndroid Build Coastguard Worker
main(int argc,char * argv[])222*25da2beaSAndroid Build Coastguard Worker int main(int argc, char *argv[])
223*25da2beaSAndroid Build Coastguard Worker {
224*25da2beaSAndroid Build Coastguard Worker struct io_uring ring;
225*25da2beaSAndroid Build Coastguard Worker int ret;
226*25da2beaSAndroid Build Coastguard Worker
227*25da2beaSAndroid Build Coastguard Worker if (argc > 1)
228*25da2beaSAndroid Build Coastguard Worker return 0;
229*25da2beaSAndroid Build Coastguard Worker
230*25da2beaSAndroid Build Coastguard Worker ret = io_uring_queue_init(QUEUE_SIZE, &ring, 0);
231*25da2beaSAndroid Build Coastguard Worker if (ret) {
232*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "ring setup failed\n");
233*25da2beaSAndroid Build Coastguard Worker return 1;
234*25da2beaSAndroid Build Coastguard Worker }
235*25da2beaSAndroid Build Coastguard Worker
236*25da2beaSAndroid Build Coastguard Worker for (int test = 0; test < 8; test++) {
237*25da2beaSAndroid Build Coastguard Worker int async = test & 0x01;
238*25da2beaSAndroid Build Coastguard Worker int write = test & 0x02;
239*25da2beaSAndroid Build Coastguard Worker int blocksize = test & 0x04 ? 1 : 7;
240*25da2beaSAndroid Build Coastguard Worker
241*25da2beaSAndroid Build Coastguard Worker ret = write
242*25da2beaSAndroid Build Coastguard Worker ? test_write(&ring, !!async, blocksize)
243*25da2beaSAndroid Build Coastguard Worker : test_read(&ring, !!async, blocksize);
244*25da2beaSAndroid Build Coastguard Worker if (ret) {
245*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "failed %s async=%d blocksize=%d\n",
246*25da2beaSAndroid Build Coastguard Worker write ? "write" : "read",
247*25da2beaSAndroid Build Coastguard Worker async, blocksize);
248*25da2beaSAndroid Build Coastguard Worker return -1;
249*25da2beaSAndroid Build Coastguard Worker }
250*25da2beaSAndroid Build Coastguard Worker }
251*25da2beaSAndroid Build Coastguard Worker return 0;
252*25da2beaSAndroid Build Coastguard Worker }
253