1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: run various statx(2) tests
4 *
5 */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <sys/types.h>
13 #include <sys/syscall.h>
14 #include <sys/stat.h>
15
16 #include "helpers.h"
17 #include "liburing.h"
18
19 #ifdef __NR_statx
do_statx(int dfd,const char * path,int flags,unsigned mask,struct statx * statxbuf)20 static int do_statx(int dfd, const char *path, int flags, unsigned mask,
21 struct statx *statxbuf)
22 {
23 return syscall(__NR_statx, dfd, path, flags, mask, statxbuf);
24 }
25 #else
do_statx(int dfd,const char * path,int flags,unsigned mask,struct statx * statxbuf)26 static int do_statx(int dfd, const char *path, int flags, unsigned mask,
27 struct statx *statxbuf)
28 {
29 errno = ENOSYS;
30 return -1;
31 }
32 #endif
33
statx_syscall_supported(void)34 static int statx_syscall_supported(void)
35 {
36 return errno == ENOSYS ? 0 : -1;
37 }
38
test_statx(struct io_uring * ring,const char * path)39 static int test_statx(struct io_uring *ring, const char *path)
40 {
41 struct io_uring_cqe *cqe;
42 struct io_uring_sqe *sqe;
43 struct statx x1, x2;
44 int ret;
45
46 sqe = io_uring_get_sqe(ring);
47 if (!sqe) {
48 fprintf(stderr, "get sqe failed\n");
49 goto err;
50 }
51 io_uring_prep_statx(sqe, -1, path, 0, STATX_ALL, &x1);
52
53 ret = io_uring_submit(ring);
54 if (ret <= 0) {
55 fprintf(stderr, "sqe submit failed: %d\n", ret);
56 goto err;
57 }
58
59 ret = io_uring_wait_cqe(ring, &cqe);
60 if (ret < 0) {
61 fprintf(stderr, "wait completion %d\n", ret);
62 goto err;
63 }
64 ret = cqe->res;
65 io_uring_cqe_seen(ring, cqe);
66 if (ret)
67 return ret;
68 ret = do_statx(-1, path, 0, STATX_ALL, &x2);
69 if (ret < 0)
70 return statx_syscall_supported();
71 if (memcmp(&x1, &x2, sizeof(x1))) {
72 fprintf(stderr, "Miscompare between io_uring and statx\n");
73 goto err;
74 }
75 return 0;
76 err:
77 return -1;
78 }
79
test_statx_fd(struct io_uring * ring,const char * path)80 static int test_statx_fd(struct io_uring *ring, const char *path)
81 {
82 struct io_uring_cqe *cqe;
83 struct io_uring_sqe *sqe;
84 struct statx x1, x2;
85 int ret, fd;
86
87 fd = open(path, O_RDONLY);
88 if (fd < 0) {
89 perror("open");
90 return 1;
91 }
92
93 memset(&x1, 0, sizeof(x1));
94
95 sqe = io_uring_get_sqe(ring);
96 if (!sqe) {
97 fprintf(stderr, "get sqe failed\n");
98 goto err;
99 }
100 io_uring_prep_statx(sqe, fd, "", AT_EMPTY_PATH, STATX_ALL, &x1);
101
102 ret = io_uring_submit(ring);
103 if (ret <= 0) {
104 fprintf(stderr, "sqe submit failed: %d\n", ret);
105 goto err;
106 }
107
108 ret = io_uring_wait_cqe(ring, &cqe);
109 if (ret < 0) {
110 fprintf(stderr, "wait completion %d\n", ret);
111 goto err;
112 }
113 ret = cqe->res;
114 io_uring_cqe_seen(ring, cqe);
115 if (ret)
116 return ret;
117 memset(&x2, 0, sizeof(x2));
118 ret = do_statx(fd, "", AT_EMPTY_PATH, STATX_ALL, &x2);
119 if (ret < 0)
120 return statx_syscall_supported();
121 if (memcmp(&x1, &x2, sizeof(x1))) {
122 fprintf(stderr, "Miscompare between io_uring and statx\n");
123 goto err;
124 }
125 return 0;
126 err:
127 return -1;
128 }
129
main(int argc,char * argv[])130 int main(int argc, char *argv[])
131 {
132 struct io_uring ring;
133 const char *fname;
134 int ret;
135
136 ret = io_uring_queue_init(8, &ring, 0);
137 if (ret) {
138 fprintf(stderr, "ring setup failed\n");
139 return 1;
140 }
141
142 if (argc > 1) {
143 fname = argv[1];
144 } else {
145 fname = "/tmp/.statx";
146 t_create_file(fname, 4096);
147 }
148
149 ret = test_statx(&ring, fname);
150 if (ret) {
151 if (ret == -EINVAL) {
152 fprintf(stdout, "statx not supported, skipping\n");
153 goto done;
154 }
155 fprintf(stderr, "test_statx failed: %d\n", ret);
156 goto err;
157 }
158
159 ret = test_statx_fd(&ring, fname);
160 if (ret) {
161 fprintf(stderr, "test_statx_fd failed: %d\n", ret);
162 goto err;
163 }
164 done:
165 if (fname != argv[1])
166 unlink(fname);
167 return 0;
168 err:
169 if (fname != argv[1])
170 unlink(fname);
171 return 1;
172 }
173