1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: link <open file><read from file><close file> with an existing
4 * file present in the opened slot, verifying that we get the new file
5 * rather than the old one.
6 *
7 */
8 #include <errno.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <fcntl.h>
14
15 #include "liburing.h"
16 #include "helpers.h"
17
18 #define MAX_FILES 8
19 #define FNAME1 ".slot.reuse.1"
20 #define FNAME2 ".slot.reuse.2"
21 #define PAT1 0xaa
22 #define PAT2 0x55
23 #define BSIZE 4096
24
test(struct io_uring * ring)25 static int test(struct io_uring *ring)
26 {
27 struct io_uring_cqe *cqe;
28 struct io_uring_sqe *sqe;
29 char buf[BSIZE];
30 int ret, i;
31
32 /* open FNAME1 in slot 0 */
33 sqe = io_uring_get_sqe(ring);
34 io_uring_prep_openat_direct(sqe, AT_FDCWD, FNAME1, O_RDONLY, 0, 0);
35 sqe->user_data = 1;
36
37 ret = io_uring_submit(ring);
38 if (ret != 1) {
39 fprintf(stderr, "sqe submit failed: %d\n", ret);
40 goto err;
41 }
42
43 ret = io_uring_wait_cqe(ring, &cqe);
44 if (ret < 0) {
45 fprintf(stderr, "wait completion %d\n", ret);
46 goto err;
47 }
48 if (cqe->res != 0) {
49 fprintf(stderr, "open res %d\n", ret);
50 goto err;
51 }
52 io_uring_cqe_seen(ring, cqe);
53
54 /*
55 * Now open FNAME2 in that same slot, verifying we get data from
56 * FNAME2 and not FNAME1.
57 */
58 sqe = io_uring_get_sqe(ring);
59 io_uring_prep_openat_direct(sqe, AT_FDCWD, FNAME2, O_RDONLY, 0, 0);
60 sqe->flags |= IOSQE_IO_LINK;
61 sqe->user_data = 2;
62
63 sqe = io_uring_get_sqe(ring);
64 io_uring_prep_read(sqe, 0, buf, sizeof(buf), 0);
65 sqe->flags |= IOSQE_FIXED_FILE;
66 sqe->flags |= IOSQE_IO_LINK;
67 sqe->user_data = 3;
68
69 sqe = io_uring_get_sqe(ring);
70 io_uring_prep_close_direct(sqe, 0);
71 sqe->user_data = 4;
72
73 ret = io_uring_submit(ring);
74 if (ret != 3) {
75 fprintf(stderr, "sqe submit failed: %d\n", ret);
76 goto err;
77 }
78
79 for (i = 0; i < 3; i++) {
80 ret = io_uring_wait_cqe(ring, &cqe);
81 if (ret < 0) {
82 fprintf(stderr, "wait completion %d\n", ret);
83 goto err;
84 }
85 switch (cqe->user_data) {
86 case 2:
87 if (cqe->res) {
88 fprintf(stderr, "bad open %d\n", cqe->res);
89 goto err;
90 }
91 break;
92 case 3:
93 if (cqe->res != sizeof(buf)) {
94 fprintf(stderr, "bad read %d\n", cqe->res);
95 goto err;
96 }
97 break;
98 case 4:
99 if (cqe->res) {
100 fprintf(stderr, "bad close %d\n", cqe->res);
101 goto err;
102 }
103 break;
104 }
105 io_uring_cqe_seen(ring, cqe);
106 }
107
108 for (i = 0; i < sizeof(buf); i++) {
109 if (buf[i] == PAT2)
110 continue;
111 fprintf(stderr, "Bad pattern %x at %d\n", buf[i], i);
112 goto err;
113 }
114
115 return 0;
116 err:
117 return 1;
118 }
119
main(int argc,char * argv[])120 int main(int argc, char *argv[])
121 {
122 struct io_uring ring;
123 struct io_uring_params p = { };
124 int ret, files[MAX_FILES];
125
126 if (argc > 1)
127 return 0;
128
129 ret = io_uring_queue_init_params(8, &ring, &p);
130 if (ret) {
131 fprintf(stderr, "ring setup failed: %d\n", ret);
132 return 1;
133 }
134 if (!(p.features & IORING_FEAT_CQE_SKIP))
135 return 0;
136
137 memset(files, -1, sizeof(files));
138 ret = io_uring_register_files(&ring, files, ARRAY_SIZE(files));
139 if (ret) {
140 fprintf(stderr, "Failed registering files\n");
141 return 1;
142 }
143
144 t_create_file_pattern(FNAME1, 4096, PAT1);
145 t_create_file_pattern(FNAME2, 4096, PAT2);
146
147 ret = test(&ring);
148 if (ret) {
149 fprintf(stderr, "test failed\n");
150 goto err;
151 }
152
153 unlink(FNAME1);
154 unlink(FNAME2);
155 return 0;
156 err:
157 unlink(FNAME1);
158 unlink(FNAME2);
159 return 1;
160 }
161