1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker * Description: run various openat(2) tests
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 <limits.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 FDS 800
18*25da2beaSAndroid Build Coastguard Worker
19*25da2beaSAndroid Build Coastguard Worker static int no_direct_pick;
20*25da2beaSAndroid Build Coastguard Worker
submit_wait(struct io_uring * ring)21*25da2beaSAndroid Build Coastguard Worker static int submit_wait(struct io_uring *ring)
22*25da2beaSAndroid Build Coastguard Worker {
23*25da2beaSAndroid Build Coastguard Worker struct io_uring_cqe *cqe;
24*25da2beaSAndroid Build Coastguard Worker int ret;
25*25da2beaSAndroid Build Coastguard Worker
26*25da2beaSAndroid Build Coastguard Worker ret = io_uring_submit(ring);
27*25da2beaSAndroid Build Coastguard Worker if (ret <= 0) {
28*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "sqe submit failed: %d\n", ret);
29*25da2beaSAndroid Build Coastguard Worker return 1;
30*25da2beaSAndroid Build Coastguard Worker }
31*25da2beaSAndroid Build Coastguard Worker ret = io_uring_wait_cqe(ring, &cqe);
32*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
33*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "wait completion %d\n", ret);
34*25da2beaSAndroid Build Coastguard Worker return 1;
35*25da2beaSAndroid Build Coastguard Worker }
36*25da2beaSAndroid Build Coastguard Worker
37*25da2beaSAndroid Build Coastguard Worker ret = cqe->res;
38*25da2beaSAndroid Build Coastguard Worker io_uring_cqe_seen(ring, cqe);
39*25da2beaSAndroid Build Coastguard Worker return ret;
40*25da2beaSAndroid Build Coastguard Worker }
41*25da2beaSAndroid Build Coastguard Worker
try_close(struct io_uring * ring,int slot)42*25da2beaSAndroid Build Coastguard Worker static inline int try_close(struct io_uring *ring, int slot)
43*25da2beaSAndroid Build Coastguard Worker {
44*25da2beaSAndroid Build Coastguard Worker struct io_uring_sqe *sqe;
45*25da2beaSAndroid Build Coastguard Worker
46*25da2beaSAndroid Build Coastguard Worker sqe = io_uring_get_sqe(ring);
47*25da2beaSAndroid Build Coastguard Worker io_uring_prep_close_direct(sqe, slot);
48*25da2beaSAndroid Build Coastguard Worker return submit_wait(ring);
49*25da2beaSAndroid Build Coastguard Worker }
50*25da2beaSAndroid Build Coastguard Worker
do_opens(struct io_uring * ring,const char * path,int nr,int expect_enfile)51*25da2beaSAndroid Build Coastguard Worker static int do_opens(struct io_uring *ring, const char *path, int nr,
52*25da2beaSAndroid Build Coastguard Worker int expect_enfile)
53*25da2beaSAndroid Build Coastguard Worker {
54*25da2beaSAndroid Build Coastguard Worker struct io_uring_cqe *cqe;
55*25da2beaSAndroid Build Coastguard Worker struct io_uring_sqe *sqe;
56*25da2beaSAndroid Build Coastguard Worker int i, ret;
57*25da2beaSAndroid Build Coastguard Worker
58*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < nr; i++) {
59*25da2beaSAndroid Build Coastguard Worker sqe = io_uring_get_sqe(ring);
60*25da2beaSAndroid Build Coastguard Worker if (!sqe) {
61*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "get sqe failed\n");
62*25da2beaSAndroid Build Coastguard Worker goto err;
63*25da2beaSAndroid Build Coastguard Worker }
64*25da2beaSAndroid Build Coastguard Worker io_uring_prep_openat_direct(sqe, -1, path, O_RDONLY, 0, 0);
65*25da2beaSAndroid Build Coastguard Worker sqe->file_index = UINT_MAX;
66*25da2beaSAndroid Build Coastguard Worker
67*25da2beaSAndroid Build Coastguard Worker ret = io_uring_submit(ring);
68*25da2beaSAndroid Build Coastguard Worker if (ret <= 0) {
69*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "sqe submit failed: %d\n", ret);
70*25da2beaSAndroid Build Coastguard Worker goto err;
71*25da2beaSAndroid Build Coastguard Worker }
72*25da2beaSAndroid Build Coastguard Worker }
73*25da2beaSAndroid Build Coastguard Worker
74*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < nr; i++) {
75*25da2beaSAndroid Build Coastguard Worker ret = io_uring_wait_cqe(ring, &cqe);
76*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
77*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "wait completion %d\n", ret);
78*25da2beaSAndroid Build Coastguard Worker goto err;
79*25da2beaSAndroid Build Coastguard Worker }
80*25da2beaSAndroid Build Coastguard Worker ret = cqe->res;
81*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
82*25da2beaSAndroid Build Coastguard Worker if (!expect_enfile || ret != -ENFILE) {
83*25da2beaSAndroid Build Coastguard Worker printf("open=%d, %d\n", cqe->res, i);
84*25da2beaSAndroid Build Coastguard Worker goto err;
85*25da2beaSAndroid Build Coastguard Worker }
86*25da2beaSAndroid Build Coastguard Worker if (!i && ret == -EINVAL) {
87*25da2beaSAndroid Build Coastguard Worker no_direct_pick = 1;
88*25da2beaSAndroid Build Coastguard Worker return 0;
89*25da2beaSAndroid Build Coastguard Worker }
90*25da2beaSAndroid Build Coastguard Worker }
91*25da2beaSAndroid Build Coastguard Worker io_uring_cqe_seen(ring, cqe);
92*25da2beaSAndroid Build Coastguard Worker }
93*25da2beaSAndroid Build Coastguard Worker return 0;
94*25da2beaSAndroid Build Coastguard Worker err:
95*25da2beaSAndroid Build Coastguard Worker return 1;
96*25da2beaSAndroid Build Coastguard Worker }
97*25da2beaSAndroid Build Coastguard Worker
test_openat(struct io_uring * ring,const char * path)98*25da2beaSAndroid Build Coastguard Worker static int test_openat(struct io_uring *ring, const char *path)
99*25da2beaSAndroid Build Coastguard Worker {
100*25da2beaSAndroid Build Coastguard Worker int ret, i;
101*25da2beaSAndroid Build Coastguard Worker
102*25da2beaSAndroid Build Coastguard Worker /* open all */
103*25da2beaSAndroid Build Coastguard Worker ret = do_opens(ring, path, FDS, 0);
104*25da2beaSAndroid Build Coastguard Worker if (ret)
105*25da2beaSAndroid Build Coastguard Worker goto err;
106*25da2beaSAndroid Build Coastguard Worker if (no_direct_pick)
107*25da2beaSAndroid Build Coastguard Worker return 0;
108*25da2beaSAndroid Build Coastguard Worker
109*25da2beaSAndroid Build Coastguard Worker /* now close 100 randomly */
110*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < 100; i++) {
111*25da2beaSAndroid Build Coastguard Worker do {
112*25da2beaSAndroid Build Coastguard Worker int slot = rand() % FDS;
113*25da2beaSAndroid Build Coastguard Worker ret = try_close(ring, slot);
114*25da2beaSAndroid Build Coastguard Worker if (ret == -EBADF)
115*25da2beaSAndroid Build Coastguard Worker continue;
116*25da2beaSAndroid Build Coastguard Worker break;
117*25da2beaSAndroid Build Coastguard Worker } while (1);
118*25da2beaSAndroid Build Coastguard Worker }
119*25da2beaSAndroid Build Coastguard Worker
120*25da2beaSAndroid Build Coastguard Worker /* opening 100 should work, we closed 100 */
121*25da2beaSAndroid Build Coastguard Worker ret = do_opens(ring, path, 100, 0);
122*25da2beaSAndroid Build Coastguard Worker if (ret)
123*25da2beaSAndroid Build Coastguard Worker goto err;
124*25da2beaSAndroid Build Coastguard Worker
125*25da2beaSAndroid Build Coastguard Worker /* we should be full now, expect -ENFILE */
126*25da2beaSAndroid Build Coastguard Worker ret = do_opens(ring, path, 1, 1);
127*25da2beaSAndroid Build Coastguard Worker if (ret)
128*25da2beaSAndroid Build Coastguard Worker goto err;
129*25da2beaSAndroid Build Coastguard Worker
130*25da2beaSAndroid Build Coastguard Worker return ret;
131*25da2beaSAndroid Build Coastguard Worker err:
132*25da2beaSAndroid Build Coastguard Worker fprintf(stderr,"%s: err=%d\n", __FUNCTION__, ret);
133*25da2beaSAndroid Build Coastguard Worker return -1;
134*25da2beaSAndroid Build Coastguard Worker }
135*25da2beaSAndroid Build Coastguard Worker
main(int argc,char * argv[])136*25da2beaSAndroid Build Coastguard Worker int main(int argc, char *argv[])
137*25da2beaSAndroid Build Coastguard Worker {
138*25da2beaSAndroid Build Coastguard Worker struct io_uring ring;
139*25da2beaSAndroid Build Coastguard Worker const char *path;
140*25da2beaSAndroid Build Coastguard Worker int ret;
141*25da2beaSAndroid Build Coastguard Worker
142*25da2beaSAndroid Build Coastguard Worker if (argc > 1)
143*25da2beaSAndroid Build Coastguard Worker return 0;
144*25da2beaSAndroid Build Coastguard Worker
145*25da2beaSAndroid Build Coastguard Worker ret = io_uring_queue_init(8, &ring, 0);
146*25da2beaSAndroid Build Coastguard Worker if (ret) {
147*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "ring setup failed\n");
148*25da2beaSAndroid Build Coastguard Worker return 1;
149*25da2beaSAndroid Build Coastguard Worker }
150*25da2beaSAndroid Build Coastguard Worker
151*25da2beaSAndroid Build Coastguard Worker ret = io_uring_register_files_sparse(&ring, FDS);
152*25da2beaSAndroid Build Coastguard Worker if (ret ) {
153*25da2beaSAndroid Build Coastguard Worker if (ret != -EINVAL) {
154*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "Sparse file registration failed\n");
155*25da2beaSAndroid Build Coastguard Worker return 1;
156*25da2beaSAndroid Build Coastguard Worker }
157*25da2beaSAndroid Build Coastguard Worker /* skip, kernel doesn't support sparse file array */
158*25da2beaSAndroid Build Coastguard Worker return 0;
159*25da2beaSAndroid Build Coastguard Worker }
160*25da2beaSAndroid Build Coastguard Worker
161*25da2beaSAndroid Build Coastguard Worker path = "/tmp/.open.close";
162*25da2beaSAndroid Build Coastguard Worker t_create_file(path, 4096);
163*25da2beaSAndroid Build Coastguard Worker
164*25da2beaSAndroid Build Coastguard Worker ret = test_openat(&ring, path);
165*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
166*25da2beaSAndroid Build Coastguard Worker if (ret == -EINVAL) {
167*25da2beaSAndroid Build Coastguard Worker fprintf(stdout, "Open not supported, skipping\n");
168*25da2beaSAndroid Build Coastguard Worker goto done;
169*25da2beaSAndroid Build Coastguard Worker }
170*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "test_openat absolute failed: %d\n", ret);
171*25da2beaSAndroid Build Coastguard Worker goto err;
172*25da2beaSAndroid Build Coastguard Worker }
173*25da2beaSAndroid Build Coastguard Worker
174*25da2beaSAndroid Build Coastguard Worker done:
175*25da2beaSAndroid Build Coastguard Worker unlink(path);
176*25da2beaSAndroid Build Coastguard Worker return 0;
177*25da2beaSAndroid Build Coastguard Worker err:
178*25da2beaSAndroid Build Coastguard Worker unlink(path);
179*25da2beaSAndroid Build Coastguard Worker return 1;
180*25da2beaSAndroid Build Coastguard Worker }
181