1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker * io_uring_setup.c
4*25da2beaSAndroid Build Coastguard Worker *
5*25da2beaSAndroid Build Coastguard Worker * Description: Unit tests for the io_uring_setup system call.
6*25da2beaSAndroid Build Coastguard Worker *
7*25da2beaSAndroid Build Coastguard Worker * Copyright 2019, Red Hat, Inc.
8*25da2beaSAndroid Build Coastguard Worker * Author: Jeff Moyer <[email protected]>
9*25da2beaSAndroid Build Coastguard Worker */
10*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
11*25da2beaSAndroid Build Coastguard Worker #include <fcntl.h>
12*25da2beaSAndroid Build Coastguard Worker #include <string.h>
13*25da2beaSAndroid Build Coastguard Worker #include <stdlib.h>
14*25da2beaSAndroid Build Coastguard Worker #include <unistd.h>
15*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
16*25da2beaSAndroid Build Coastguard Worker #include <sys/sysinfo.h>
17*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
18*25da2beaSAndroid Build Coastguard Worker
19*25da2beaSAndroid Build Coastguard Worker #include "../syscall.h"
20*25da2beaSAndroid Build Coastguard Worker
features_string(struct io_uring_params * p)21*25da2beaSAndroid Build Coastguard Worker char *features_string(struct io_uring_params *p)
22*25da2beaSAndroid Build Coastguard Worker {
23*25da2beaSAndroid Build Coastguard Worker static char flagstr[64];
24*25da2beaSAndroid Build Coastguard Worker
25*25da2beaSAndroid Build Coastguard Worker if (!p || !p->features)
26*25da2beaSAndroid Build Coastguard Worker return "none";
27*25da2beaSAndroid Build Coastguard Worker
28*25da2beaSAndroid Build Coastguard Worker if (p->features & ~IORING_FEAT_SINGLE_MMAP) {
29*25da2beaSAndroid Build Coastguard Worker snprintf(flagstr, 64, "0x%.8x", p->features);
30*25da2beaSAndroid Build Coastguard Worker return flagstr;
31*25da2beaSAndroid Build Coastguard Worker }
32*25da2beaSAndroid Build Coastguard Worker
33*25da2beaSAndroid Build Coastguard Worker if (p->features & IORING_FEAT_SINGLE_MMAP)
34*25da2beaSAndroid Build Coastguard Worker strncat(flagstr, "IORING_FEAT_SINGLE_MMAP", 64 - strlen(flagstr));
35*25da2beaSAndroid Build Coastguard Worker
36*25da2beaSAndroid Build Coastguard Worker return flagstr;
37*25da2beaSAndroid Build Coastguard Worker }
38*25da2beaSAndroid Build Coastguard Worker
39*25da2beaSAndroid Build Coastguard Worker /*
40*25da2beaSAndroid Build Coastguard Worker * Attempt the call with the given args. Return 0 when expect matches
41*25da2beaSAndroid Build Coastguard Worker * the return value of the system call, 1 otherwise.
42*25da2beaSAndroid Build Coastguard Worker */
43*25da2beaSAndroid Build Coastguard Worker char *
flags_string(struct io_uring_params * p)44*25da2beaSAndroid Build Coastguard Worker flags_string(struct io_uring_params *p)
45*25da2beaSAndroid Build Coastguard Worker {
46*25da2beaSAndroid Build Coastguard Worker static char flagstr[64];
47*25da2beaSAndroid Build Coastguard Worker int add_pipe = 0;
48*25da2beaSAndroid Build Coastguard Worker
49*25da2beaSAndroid Build Coastguard Worker memset(flagstr, 0, sizeof(flagstr));
50*25da2beaSAndroid Build Coastguard Worker
51*25da2beaSAndroid Build Coastguard Worker if (!p || p->flags == 0)
52*25da2beaSAndroid Build Coastguard Worker return "none";
53*25da2beaSAndroid Build Coastguard Worker
54*25da2beaSAndroid Build Coastguard Worker /*
55*25da2beaSAndroid Build Coastguard Worker * If unsupported flags are present, just print the bitmask.
56*25da2beaSAndroid Build Coastguard Worker */
57*25da2beaSAndroid Build Coastguard Worker if (p->flags & ~(IORING_SETUP_IOPOLL | IORING_SETUP_SQPOLL |
58*25da2beaSAndroid Build Coastguard Worker IORING_SETUP_SQ_AFF)) {
59*25da2beaSAndroid Build Coastguard Worker snprintf(flagstr, 64, "0x%.8x", p->flags);
60*25da2beaSAndroid Build Coastguard Worker return flagstr;
61*25da2beaSAndroid Build Coastguard Worker }
62*25da2beaSAndroid Build Coastguard Worker
63*25da2beaSAndroid Build Coastguard Worker if (p->flags & IORING_SETUP_IOPOLL) {
64*25da2beaSAndroid Build Coastguard Worker strncat(flagstr, "IORING_SETUP_IOPOLL", 64 - strlen(flagstr));
65*25da2beaSAndroid Build Coastguard Worker add_pipe = 1;
66*25da2beaSAndroid Build Coastguard Worker }
67*25da2beaSAndroid Build Coastguard Worker if (p->flags & IORING_SETUP_SQPOLL) {
68*25da2beaSAndroid Build Coastguard Worker if (add_pipe)
69*25da2beaSAndroid Build Coastguard Worker strncat(flagstr, "|", 64 - strlen(flagstr));
70*25da2beaSAndroid Build Coastguard Worker else
71*25da2beaSAndroid Build Coastguard Worker add_pipe = 1;
72*25da2beaSAndroid Build Coastguard Worker strncat(flagstr, "IORING_SETUP_SQPOLL", 64 - strlen(flagstr));
73*25da2beaSAndroid Build Coastguard Worker }
74*25da2beaSAndroid Build Coastguard Worker if (p->flags & IORING_SETUP_SQ_AFF) {
75*25da2beaSAndroid Build Coastguard Worker if (add_pipe)
76*25da2beaSAndroid Build Coastguard Worker strncat(flagstr, "|", 64 - strlen(flagstr));
77*25da2beaSAndroid Build Coastguard Worker strncat(flagstr, "IORING_SETUP_SQ_AFF", 64 - strlen(flagstr));
78*25da2beaSAndroid Build Coastguard Worker }
79*25da2beaSAndroid Build Coastguard Worker
80*25da2beaSAndroid Build Coastguard Worker return flagstr;
81*25da2beaSAndroid Build Coastguard Worker }
82*25da2beaSAndroid Build Coastguard Worker
83*25da2beaSAndroid Build Coastguard Worker char *
dump_resv(struct io_uring_params * p)84*25da2beaSAndroid Build Coastguard Worker dump_resv(struct io_uring_params *p)
85*25da2beaSAndroid Build Coastguard Worker {
86*25da2beaSAndroid Build Coastguard Worker static char resvstr[4096];
87*25da2beaSAndroid Build Coastguard Worker
88*25da2beaSAndroid Build Coastguard Worker if (!p)
89*25da2beaSAndroid Build Coastguard Worker return "";
90*25da2beaSAndroid Build Coastguard Worker
91*25da2beaSAndroid Build Coastguard Worker sprintf(resvstr, "0x%.8x 0x%.8x 0x%.8x", p->resv[0],
92*25da2beaSAndroid Build Coastguard Worker p->resv[1], p->resv[2]);
93*25da2beaSAndroid Build Coastguard Worker
94*25da2beaSAndroid Build Coastguard Worker return resvstr;
95*25da2beaSAndroid Build Coastguard Worker }
96*25da2beaSAndroid Build Coastguard Worker
97*25da2beaSAndroid Build Coastguard Worker /* bogus: setup returns a valid fd on success... expect can't predict the
98*25da2beaSAndroid Build Coastguard Worker fd we'll get, so this really only takes 1 parameter: error */
99*25da2beaSAndroid Build Coastguard Worker int
try_io_uring_setup(unsigned entries,struct io_uring_params * p,int expect,int error)100*25da2beaSAndroid Build Coastguard Worker try_io_uring_setup(unsigned entries, struct io_uring_params *p, int expect, int error)
101*25da2beaSAndroid Build Coastguard Worker {
102*25da2beaSAndroid Build Coastguard Worker int ret, err;
103*25da2beaSAndroid Build Coastguard Worker
104*25da2beaSAndroid Build Coastguard Worker ret = __sys_io_uring_setup(entries, p);
105*25da2beaSAndroid Build Coastguard Worker if (ret != expect) {
106*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "expected %d, got %d\n", expect, ret);
107*25da2beaSAndroid Build Coastguard Worker /* if we got a valid uring, close it */
108*25da2beaSAndroid Build Coastguard Worker if (ret > 0)
109*25da2beaSAndroid Build Coastguard Worker close(ret);
110*25da2beaSAndroid Build Coastguard Worker return 1;
111*25da2beaSAndroid Build Coastguard Worker }
112*25da2beaSAndroid Build Coastguard Worker err = errno;
113*25da2beaSAndroid Build Coastguard Worker if (expect == -1 && error != err) {
114*25da2beaSAndroid Build Coastguard Worker if (err == EPERM && geteuid() != 0) {
115*25da2beaSAndroid Build Coastguard Worker printf("Needs root, not flagging as an error\n");
116*25da2beaSAndroid Build Coastguard Worker return 0;
117*25da2beaSAndroid Build Coastguard Worker }
118*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "expected errno %d, got %d\n", error, err);
119*25da2beaSAndroid Build Coastguard Worker return 1;
120*25da2beaSAndroid Build Coastguard Worker }
121*25da2beaSAndroid Build Coastguard Worker
122*25da2beaSAndroid Build Coastguard Worker return 0;
123*25da2beaSAndroid Build Coastguard Worker }
124*25da2beaSAndroid Build Coastguard Worker
125*25da2beaSAndroid Build Coastguard Worker int
main(int argc,char ** argv)126*25da2beaSAndroid Build Coastguard Worker main(int argc, char **argv)
127*25da2beaSAndroid Build Coastguard Worker {
128*25da2beaSAndroid Build Coastguard Worker int fd;
129*25da2beaSAndroid Build Coastguard Worker unsigned int status = 0;
130*25da2beaSAndroid Build Coastguard Worker struct io_uring_params p;
131*25da2beaSAndroid Build Coastguard Worker
132*25da2beaSAndroid Build Coastguard Worker if (argc > 1)
133*25da2beaSAndroid Build Coastguard Worker return 0;
134*25da2beaSAndroid Build Coastguard Worker
135*25da2beaSAndroid Build Coastguard Worker memset(&p, 0, sizeof(p));
136*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_setup(0, &p, -1, EINVAL);
137*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_setup(1, NULL, -1, EFAULT);
138*25da2beaSAndroid Build Coastguard Worker
139*25da2beaSAndroid Build Coastguard Worker /* resv array is non-zero */
140*25da2beaSAndroid Build Coastguard Worker memset(&p, 0, sizeof(p));
141*25da2beaSAndroid Build Coastguard Worker p.resv[0] = p.resv[1] = p.resv[2] = 1;
142*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_setup(1, &p, -1, EINVAL);
143*25da2beaSAndroid Build Coastguard Worker
144*25da2beaSAndroid Build Coastguard Worker /* invalid flags */
145*25da2beaSAndroid Build Coastguard Worker memset(&p, 0, sizeof(p));
146*25da2beaSAndroid Build Coastguard Worker p.flags = ~0U;
147*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_setup(1, &p, -1, EINVAL);
148*25da2beaSAndroid Build Coastguard Worker
149*25da2beaSAndroid Build Coastguard Worker /* IORING_SETUP_SQ_AFF set but not IORING_SETUP_SQPOLL */
150*25da2beaSAndroid Build Coastguard Worker memset(&p, 0, sizeof(p));
151*25da2beaSAndroid Build Coastguard Worker p.flags = IORING_SETUP_SQ_AFF;
152*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_setup(1, &p, -1, EINVAL);
153*25da2beaSAndroid Build Coastguard Worker
154*25da2beaSAndroid Build Coastguard Worker /* attempt to bind to invalid cpu */
155*25da2beaSAndroid Build Coastguard Worker memset(&p, 0, sizeof(p));
156*25da2beaSAndroid Build Coastguard Worker p.flags = IORING_SETUP_SQPOLL | IORING_SETUP_SQ_AFF;
157*25da2beaSAndroid Build Coastguard Worker p.sq_thread_cpu = get_nprocs_conf();
158*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_setup(1, &p, -1, EINVAL);
159*25da2beaSAndroid Build Coastguard Worker
160*25da2beaSAndroid Build Coastguard Worker /* I think we can limit a process to a set of cpus. I assume
161*25da2beaSAndroid Build Coastguard Worker * we shouldn't be able to setup a kernel thread outside of that.
162*25da2beaSAndroid Build Coastguard Worker * try to do that. (task->cpus_allowed) */
163*25da2beaSAndroid Build Coastguard Worker
164*25da2beaSAndroid Build Coastguard Worker /* read/write on io_uring_fd */
165*25da2beaSAndroid Build Coastguard Worker memset(&p, 0, sizeof(p));
166*25da2beaSAndroid Build Coastguard Worker fd = __sys_io_uring_setup(1, &p);
167*25da2beaSAndroid Build Coastguard Worker if (fd < 0) {
168*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "io_uring_setup failed with %d, expected success\n",
169*25da2beaSAndroid Build Coastguard Worker errno);
170*25da2beaSAndroid Build Coastguard Worker status = 1;
171*25da2beaSAndroid Build Coastguard Worker } else {
172*25da2beaSAndroid Build Coastguard Worker char buf[4096];
173*25da2beaSAndroid Build Coastguard Worker int ret;
174*25da2beaSAndroid Build Coastguard Worker ret = read(fd, buf, 4096);
175*25da2beaSAndroid Build Coastguard Worker if (ret >= 0) {
176*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "read from io_uring fd succeeded. expected fail\n");
177*25da2beaSAndroid Build Coastguard Worker status = 1;
178*25da2beaSAndroid Build Coastguard Worker }
179*25da2beaSAndroid Build Coastguard Worker }
180*25da2beaSAndroid Build Coastguard Worker
181*25da2beaSAndroid Build Coastguard Worker if (!status)
182*25da2beaSAndroid Build Coastguard Worker return 0;
183*25da2beaSAndroid Build Coastguard Worker
184*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "FAIL\n");
185*25da2beaSAndroid Build Coastguard Worker return -1;
186*25da2beaSAndroid Build Coastguard Worker }
187