1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /*
4 * Copyright (C) 2023 Cyril Hrubis <[email protected]>
5 */
6
7 #define TST_NO_DEFAULT_MAIN
8
9 #include <sys/epoll.h>
10 #include <sys/eventfd.h>
11 #include <sys/signalfd.h>
12 #include <sys/timerfd.h>
13 #include <sys/inotify.h>
14 #include <linux/perf_event.h>
15 #include <linux/fanotify.h>
16
17 #include "tst_test.h"
18 #include "tst_safe_macros.h"
19
20 #include "lapi/pidfd.h"
21 #include "lapi/io_uring.h"
22 #include "lapi/bpf.h"
23 #include "lapi/fsmount.h"
24
25 #include "tst_fd.h"
26
27 struct tst_fd_desc {
28 void (*open_fd)(struct tst_fd *fd);
29 void (*destroy)(struct tst_fd *fd);
30 const char *desc;
31 };
32
open_file(struct tst_fd * fd)33 static void open_file(struct tst_fd *fd)
34 {
35 fd->fd = SAFE_OPEN("fd_file", O_RDWR | O_CREAT, 0666);
36 SAFE_UNLINK("fd_file");
37 }
38
open_path(struct tst_fd * fd)39 static void open_path(struct tst_fd *fd)
40 {
41 int tfd;
42
43 tfd = SAFE_CREAT("fd_file", 0666);
44 SAFE_CLOSE(tfd);
45
46 fd->fd = SAFE_OPEN("fd_file", O_PATH);
47
48 SAFE_UNLINK("fd_file");
49 }
50
open_dir(struct tst_fd * fd)51 static void open_dir(struct tst_fd *fd)
52 {
53 SAFE_MKDIR("fd_dir", 0700);
54 fd->fd = SAFE_OPEN("fd_dir", O_DIRECTORY);
55 SAFE_RMDIR("fd_dir");
56 }
57
open_dev_zero(struct tst_fd * fd)58 static void open_dev_zero(struct tst_fd *fd)
59 {
60 fd->fd = SAFE_OPEN("/dev/zero", O_RDONLY);
61 }
62
open_proc_self_maps(struct tst_fd * fd)63 static void open_proc_self_maps(struct tst_fd *fd)
64 {
65 fd->fd = SAFE_OPEN("/proc/self/maps", O_RDONLY);
66 }
67
open_pipe_read(struct tst_fd * fd)68 static void open_pipe_read(struct tst_fd *fd)
69 {
70 int pipe[2];
71
72 SAFE_PIPE(pipe);
73 fd->fd = pipe[0];
74 fd->priv = pipe[1];
75 }
76
open_pipe_write(struct tst_fd * fd)77 static void open_pipe_write(struct tst_fd *fd)
78 {
79 int pipe[2];
80
81 SAFE_PIPE(pipe);
82 fd->fd = pipe[1];
83 fd->priv = pipe[0];
84 }
85
destroy_pipe(struct tst_fd * fd)86 static void destroy_pipe(struct tst_fd *fd)
87 {
88 SAFE_CLOSE(fd->priv);
89 }
90
open_unix_sock(struct tst_fd * fd)91 static void open_unix_sock(struct tst_fd *fd)
92 {
93 fd->fd = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
94 }
95
open_inet_sock(struct tst_fd * fd)96 static void open_inet_sock(struct tst_fd *fd)
97 {
98 fd->fd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
99 }
100
open_epoll(struct tst_fd * fd)101 static void open_epoll(struct tst_fd *fd)
102 {
103 fd->fd = epoll_create(1);
104
105 if (fd->fd < 0)
106 tst_res(TCONF | TERRNO, "epoll_create()");
107 }
108
open_eventfd(struct tst_fd * fd)109 static void open_eventfd(struct tst_fd *fd)
110 {
111 fd->fd = eventfd(0, 0);
112
113 if (fd->fd < 0)
114 tst_res(TCONF | TERRNO, "Skipping %s", tst_fd_desc(fd));
115 }
116
open_signalfd(struct tst_fd * fd)117 static void open_signalfd(struct tst_fd *fd)
118 {
119 sigset_t sfd_mask;
120
121 sigemptyset(&sfd_mask);
122
123 fd->fd = signalfd(-1, &sfd_mask, 0);
124 if (fd->fd < 0) {
125 tst_res(TCONF | TERRNO,
126 "Skipping %s", tst_fd_desc(fd));
127 }
128 }
129
open_timerfd(struct tst_fd * fd)130 static void open_timerfd(struct tst_fd *fd)
131 {
132 fd->fd = timerfd_create(CLOCK_REALTIME, 0);
133
134 if (fd->fd < 0) {
135 tst_res(TCONF | TERRNO,
136 "Skipping %s", tst_fd_desc(fd));
137 }
138 }
139
open_pidfd(struct tst_fd * fd)140 static void open_pidfd(struct tst_fd *fd)
141 {
142 fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
143 if (fd->fd < 0)
144 tst_res(TCONF | TERRNO, "pidfd_open()");
145 }
146
open_fanotify(struct tst_fd * fd)147 static void open_fanotify(struct tst_fd *fd)
148 {
149 fd->fd = syscall(__NR_fanotify_init, FAN_CLASS_NOTIF, O_RDONLY);
150 if (fd->fd < 0) {
151 tst_res(TCONF | TERRNO,
152 "Skipping %s", tst_fd_desc(fd));
153 }
154 }
155
open_inotify(struct tst_fd * fd)156 static void open_inotify(struct tst_fd *fd)
157 {
158 fd->fd = inotify_init();
159 if (fd->fd < 0) {
160 tst_res(TCONF | TERRNO,
161 "Skipping %s", tst_fd_desc(fd));
162 }
163 }
164
open_userfaultfd(struct tst_fd * fd)165 static void open_userfaultfd(struct tst_fd *fd)
166 {
167 fd->fd = syscall(__NR_userfaultfd, 0);
168
169 if (fd->fd < 0) {
170 tst_res(TCONF | TERRNO,
171 "Skipping %s", tst_fd_desc(fd));
172 }
173 }
174
open_perf_event(struct tst_fd * fd)175 static void open_perf_event(struct tst_fd *fd)
176 {
177 struct perf_event_attr pe_attr = {
178 .type = PERF_TYPE_SOFTWARE,
179 .size = sizeof(struct perf_event_attr),
180 .config = PERF_COUNT_SW_CPU_CLOCK,
181 .disabled = 1,
182 .exclude_kernel = 1,
183 .exclude_hv = 1,
184 };
185
186 fd->fd = syscall(__NR_perf_event_open, &pe_attr, 0, -1, -1, 0);
187 if (fd->fd < 0) {
188 tst_res(TCONF | TERRNO,
189 "Skipping %s", tst_fd_desc(fd));
190 }
191 }
192
open_io_uring(struct tst_fd * fd)193 static void open_io_uring(struct tst_fd *fd)
194 {
195 struct io_uring_params uring_params = {};
196
197 fd->fd = syscall(__NR_io_uring_setup, 1, &uring_params);
198 if (fd->fd < 0) {
199 tst_res(TCONF | TERRNO,
200 "Skipping %s", tst_fd_desc(fd));
201 }
202 }
203
open_bpf_map(struct tst_fd * fd)204 static void open_bpf_map(struct tst_fd *fd)
205 {
206 union bpf_attr array_attr = {
207 .map_type = BPF_MAP_TYPE_ARRAY,
208 .key_size = 4,
209 .value_size = 8,
210 .max_entries = 1,
211 };
212
213 fd->fd = syscall(__NR_bpf, BPF_MAP_CREATE, &array_attr, sizeof(array_attr));
214 if (fd->fd < 0) {
215 tst_res(TCONF | TERRNO,
216 "Skipping %s", tst_fd_desc(fd));
217 }
218 }
219
open_fsopen(struct tst_fd * fd)220 static void open_fsopen(struct tst_fd *fd)
221 {
222 fd->fd = syscall(__NR_fsopen, "ext2", 0);
223 if (fd->fd < 0) {
224 tst_res(TCONF | TERRNO,
225 "Skipping %s", tst_fd_desc(fd));
226 }
227 }
228
open_fspick(struct tst_fd * fd)229 static void open_fspick(struct tst_fd *fd)
230 {
231 fd->fd = syscall(__NR_fspick, AT_FDCWD, "/", 0);
232 if (fd->fd < 0) {
233 tst_res(TCONF | TERRNO,
234 "Skipping %s", tst_fd_desc(fd));
235 }
236 }
237
open_open_tree(struct tst_fd * fd)238 static void open_open_tree(struct tst_fd *fd)
239 {
240 fd->fd = syscall(__NR_open_tree, AT_FDCWD, "/", 0);
241 if (fd->fd < 0) {
242 tst_res(TCONF | TERRNO,
243 "Skipping %s", tst_fd_desc(fd));
244 }
245 }
246
open_memfd(struct tst_fd * fd)247 static void open_memfd(struct tst_fd *fd)
248 {
249 fd->fd = syscall(__NR_memfd_create, "ltp_memfd", 0);
250 if (fd->fd < 0) {
251 tst_res(TCONF | TERRNO,
252 "Skipping %s", tst_fd_desc(fd));
253 }
254 }
255
open_memfd_secret(struct tst_fd * fd)256 static void open_memfd_secret(struct tst_fd *fd)
257 {
258 fd->fd = syscall(__NR_memfd_secret, 0);
259 if (fd->fd < 0) {
260 tst_res(TCONF | TERRNO,
261 "Skipping %s", tst_fd_desc(fd));
262 }
263 }
264
265 static struct tst_fd_desc fd_desc[] = {
266 [TST_FD_FILE] = {.open_fd = open_file, .desc = "file"},
267 [TST_FD_PATH] = {.open_fd = open_path, .desc = "O_PATH file"},
268 [TST_FD_DIR] = {.open_fd = open_dir, .desc = "directory"},
269 [TST_FD_DEV_ZERO] = {.open_fd = open_dev_zero, .desc = "/dev/zero"},
270 [TST_FD_PROC_MAPS] = {.open_fd = open_proc_self_maps, .desc = "/proc/self/maps"},
271 [TST_FD_PIPE_READ] = {.open_fd = open_pipe_read, .desc = "pipe read end", .destroy = destroy_pipe},
272 [TST_FD_PIPE_WRITE] = {.open_fd = open_pipe_write, .desc = "pipe write end", .destroy = destroy_pipe},
273 [TST_FD_UNIX_SOCK] = {.open_fd = open_unix_sock, .desc = "unix socket"},
274 [TST_FD_INET_SOCK] = {.open_fd = open_inet_sock, .desc = "inet socket"},
275 [TST_FD_EPOLL] = {.open_fd = open_epoll, .desc = "epoll"},
276 [TST_FD_EVENTFD] = {.open_fd = open_eventfd, .desc = "eventfd"},
277 [TST_FD_SIGNALFD] = {.open_fd = open_signalfd, .desc = "signalfd"},
278 [TST_FD_TIMERFD] = {.open_fd = open_timerfd, .desc = "timerfd"},
279 [TST_FD_PIDFD] = {.open_fd = open_pidfd, .desc = "pidfd"},
280 [TST_FD_FANOTIFY] = {.open_fd = open_fanotify, .desc = "fanotify"},
281 [TST_FD_INOTIFY] = {.open_fd = open_inotify, .desc = "inotify"},
282 [TST_FD_USERFAULTFD] = {.open_fd = open_userfaultfd, .desc = "userfaultfd"},
283 [TST_FD_PERF_EVENT] = {.open_fd = open_perf_event, .desc = "perf event"},
284 [TST_FD_IO_URING] = {.open_fd = open_io_uring, .desc = "io uring"},
285 [TST_FD_BPF_MAP] = {.open_fd = open_bpf_map, .desc = "bpf map"},
286 [TST_FD_FSOPEN] = {.open_fd = open_fsopen, .desc = "fsopen"},
287 [TST_FD_FSPICK] = {.open_fd = open_fspick, .desc = "fspick"},
288 [TST_FD_OPEN_TREE] = {.open_fd = open_open_tree, .desc = "open_tree"},
289 [TST_FD_MEMFD] = {.open_fd = open_memfd, .desc = "memfd"},
290 [TST_FD_MEMFD_SECRET] = {.open_fd = open_memfd_secret, .desc = "memfd secret"},
291 };
292
tst_fd_desc(struct tst_fd * fd)293 const char *tst_fd_desc(struct tst_fd *fd)
294 {
295 if (fd->type >= ARRAY_SIZE(fd_desc))
296 return "invalid";
297
298 return fd_desc[fd->type].desc;
299 }
300
tst_fd_next(struct tst_fd * fd)301 int tst_fd_next(struct tst_fd *fd)
302 {
303 size_t len = ARRAY_SIZE(fd_desc);
304
305 if (fd->fd >= 0) {
306 SAFE_CLOSE(fd->fd);
307
308 if (fd_desc[fd->type].destroy)
309 fd_desc[fd->type].destroy(fd);
310
311 fd->type++;
312 }
313
314 for (;;) {
315 if (fd->type >= len)
316 return 0;
317
318 fd_desc[fd->type].open_fd(fd);
319
320 if (fd->fd >= 0)
321 return 1;
322
323 fd->type++;
324 }
325 }
326