uringmachine 0.10 → 0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/examples/bm_side_running.rb +83 -0
- data/examples/bm_sqlite.rb +1 -1
- data/ext/um/um.c +17 -1
- data/ext/um/um.h +29 -0
- data/ext/um/um_ext.c +2 -0
- data/ext/um/um_stream.c +344 -0
- data/ext/um/um_stream_class.c +140 -0
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +20 -16
- data/test/test_stream.rb +133 -0
- data/test/test_um.rb +63 -0
- data/vendor/liburing/.github/workflows/{build.yml → ci.yml} +107 -42
- data/vendor/liburing/.gitignore +1 -0
- data/vendor/liburing/CHANGELOG +10 -0
- data/vendor/liburing/README +5 -0
- data/vendor/liburing/configure +1 -1
- data/vendor/liburing/examples/Makefile +1 -0
- data/vendor/liburing/examples/helpers.c +25 -0
- data/vendor/liburing/examples/helpers.h +13 -0
- data/vendor/liburing/examples/io_uring-test.c +3 -0
- data/vendor/liburing/examples/proxy.c +1 -1
- data/vendor/liburing/examples/reg-wait.c +41 -6
- data/vendor/liburing/examples/send-zerocopy.c +79 -32
- data/vendor/liburing/examples/zcrx.c +436 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/Makefile +0 -1
- data/vendor/liburing/src/arch/generic/syscall.h +2 -2
- data/vendor/liburing/src/arch/syscall-defs.h +2 -2
- data/vendor/liburing/src/include/liburing/io_uring.h +101 -17
- data/vendor/liburing/src/include/liburing.h +179 -59
- data/vendor/liburing/src/int_flags.h +4 -1
- data/vendor/liburing/src/liburing-ffi.map +14 -2
- data/vendor/liburing/src/liburing.map +9 -2
- data/vendor/liburing/src/queue.c +35 -30
- data/vendor/liburing/src/register.c +46 -15
- data/vendor/liburing/src/sanitize.c +6 -9
- data/vendor/liburing/src/setup.c +37 -71
- data/vendor/liburing/src/syscall.c +2 -2
- data/vendor/liburing/test/232c93d07b74.c +1 -0
- data/vendor/liburing/test/Makefile +9 -0
- data/vendor/liburing/test/accept-test.c +1 -0
- data/vendor/liburing/test/cmd-discard.c +16 -8
- data/vendor/liburing/test/connect.c +11 -7
- data/vendor/liburing/test/epwait.c +420 -0
- data/vendor/liburing/test/eventfd-ring.c +30 -5
- data/vendor/liburing/test/fallocate.c +1 -1
- data/vendor/liburing/test/fixed-hugepage.c +10 -7
- data/vendor/liburing/test/fixed-seg.c +187 -0
- data/vendor/liburing/test/helpers.c +121 -0
- data/vendor/liburing/test/helpers.h +13 -0
- data/vendor/liburing/test/init-mem.c +2 -0
- data/vendor/liburing/test/io_uring_passthrough.c +78 -62
- data/vendor/liburing/test/iopoll-overflow.c +5 -4
- data/vendor/liburing/test/iopoll.c +20 -10
- data/vendor/liburing/test/iowait.c +141 -0
- data/vendor/liburing/test/nvme.h +2 -0
- data/vendor/liburing/test/pipe-bug.c +11 -5
- data/vendor/liburing/test/pipe-eof.c +11 -1
- data/vendor/liburing/test/read-inc-file.c +150 -0
- data/vendor/liburing/test/read-write.c +21 -14
- data/vendor/liburing/test/recv-bundle-short-ooo.c +435 -0
- data/vendor/liburing/test/recv-multishot.c +2 -2
- data/vendor/liburing/test/reg-wait.c +449 -120
- data/vendor/liburing/test/regbuf-clone.c +53 -0
- data/vendor/liburing/test/resize-rings.c +25 -2
- data/vendor/liburing/test/rsrc_tags.c +67 -14
- data/vendor/liburing/test/send-zerocopy.c +52 -130
- data/vendor/liburing/test/sendmsg_iov_clean.c +216 -0
- data/vendor/liburing/test/socket-nb.c +158 -0
- data/vendor/liburing/test/sqwait.c +9 -11
- data/vendor/liburing/test/timeout.c +198 -0
- data/vendor/liburing/test/vec-regbuf.c +609 -0
- data/vendor/liburing/test/wait-timeout.c +1 -1
- data/vendor/liburing/test/wq-aff.c +5 -1
- data/vendor/liburing/test/zcrx.c +928 -0
- metadata +16 -4
- data/vendor/liburing/.github/workflows/codespell.yml +0 -25
- data/vendor/liburing/.github/workflows/shellcheck.yml +0 -20
@@ -9,128 +9,67 @@
|
|
9
9
|
#include <string.h>
|
10
10
|
#include <fcntl.h>
|
11
11
|
#include <sys/time.h>
|
12
|
+
#include <sys/mman.h>
|
13
|
+
#include <linux/mman.h>
|
12
14
|
|
13
15
|
#include "liburing.h"
|
14
16
|
#include "helpers.h"
|
15
17
|
#include "test.h"
|
18
|
+
#include "../src/syscall.h"
|
16
19
|
|
17
|
-
static struct io_uring_reg_wait
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
void *buf, *ptr;
|
23
|
-
int ret;
|
24
|
-
|
25
|
-
io_uring_queue_init(1, &ring, 0);
|
26
|
-
|
27
|
-
if (posix_memalign(&buf, 4096, 4096))
|
28
|
-
return T_EXIT_FAIL;
|
29
|
-
memset(buf, 0, 4096);
|
30
|
-
ptr = buf + 4096 - 32;
|
20
|
+
static const struct io_uring_reg_wait brief_wait = {
|
21
|
+
.flags = IORING_REG_WAIT_TS,
|
22
|
+
.ts.tv_sec = 0,
|
23
|
+
.ts.tv_nsec = 1000,
|
24
|
+
};
|
31
25
|
|
32
|
-
|
33
|
-
if (ret != -EINVAL) {
|
34
|
-
fprintf(stderr, "register cqwait: %d\n", ret);
|
35
|
-
return T_EXIT_FAIL;
|
36
|
-
}
|
37
|
-
|
38
|
-
ptr = buf + (sizeof(struct io_uring_reg_wait) / 2);
|
39
|
-
ret = io_uring_register_wait_reg(&ring, ptr, 1);
|
40
|
-
if (ret != -EINVAL) {
|
41
|
-
fprintf(stderr, "register cqwait: %d\n", ret);
|
42
|
-
return T_EXIT_FAIL;
|
43
|
-
}
|
44
|
-
|
45
|
-
free(buf);
|
46
|
-
buf = (void *) 0x1000;
|
47
|
-
ret = io_uring_register_wait_reg(&ring, buf, 1);
|
48
|
-
if (ret != -EFAULT) {
|
49
|
-
fprintf(stderr, "register cqwait: %d\n", ret);
|
50
|
-
return T_EXIT_FAIL;
|
51
|
-
}
|
52
|
-
|
53
|
-
buf = (void *) 0x1240;
|
54
|
-
ret = io_uring_register_wait_reg(&ring, buf, 1);
|
55
|
-
if (ret != -EFAULT) {
|
56
|
-
fprintf(stderr, "register cqwait: %d\n", ret);
|
57
|
-
return T_EXIT_FAIL;
|
58
|
-
}
|
59
|
-
|
60
|
-
buf = (void *) 0x1241;
|
61
|
-
ret = io_uring_register_wait_reg(&ring, buf, 1);
|
62
|
-
if (ret != -EINVAL) {
|
63
|
-
fprintf(stderr, "register cqwait: %d\n", ret);
|
64
|
-
return T_EXIT_FAIL;
|
65
|
-
}
|
26
|
+
static bool has_kernel_regions;
|
66
27
|
|
67
|
-
|
68
|
-
|
28
|
+
static int test_wait_reg_offset(struct io_uring *ring,
|
29
|
+
unsigned wait_nr, unsigned long offset)
|
30
|
+
{
|
31
|
+
return __sys_io_uring_enter2(ring->ring_fd, 0, wait_nr,
|
32
|
+
IORING_ENTER_GETEVENTS |
|
33
|
+
IORING_ENTER_EXT_ARG |
|
34
|
+
IORING_ENTER_EXT_ARG_REG,
|
35
|
+
(void *)offset,
|
36
|
+
sizeof(struct io_uring_reg_wait));
|
69
37
|
}
|
70
38
|
|
71
|
-
static int
|
39
|
+
static int __init_ring_with_region(struct io_uring *ring, unsigned ring_flags,
|
40
|
+
struct io_uring_mem_region_reg *pr,
|
41
|
+
bool disabled)
|
72
42
|
{
|
73
|
-
|
74
|
-
struct io_uring_cqe *cqe;
|
75
|
-
struct io_uring ring;
|
76
|
-
struct timeval tv;
|
77
|
-
void *buf, *ptr;
|
43
|
+
int flags = disabled ? IORING_SETUP_R_DISABLED : 0;
|
78
44
|
int ret;
|
79
45
|
|
80
|
-
io_uring_queue_init(
|
81
|
-
|
82
|
-
if (posix_memalign(&buf, 4096, 4096))
|
83
|
-
return T_EXIT_FAIL;
|
84
|
-
memset(buf, 0, 4096);
|
85
|
-
ptr = buf + 512;
|
86
|
-
ireg = ptr;
|
87
|
-
|
88
|
-
ret = io_uring_register_wait_reg(&ring, ireg, 56);
|
46
|
+
ret = io_uring_queue_init(8, ring, flags);
|
89
47
|
if (ret) {
|
90
|
-
|
91
|
-
|
48
|
+
if (ret != -EINVAL)
|
49
|
+
fprintf(stderr, "ring setup failed: %d\n", ret);
|
50
|
+
return ret;
|
92
51
|
}
|
93
52
|
|
94
|
-
|
95
|
-
|
96
|
-
ireg->ts.tv_sec = 1;
|
97
|
-
ireg->ts.tv_nsec = 0;
|
98
|
-
ireg->flags = IORING_REG_WAIT_TS;
|
99
|
-
|
100
|
-
gettimeofday(&tv, NULL);
|
101
|
-
ret = io_uring_submit_and_wait_reg(&ring, &cqe, 1, 0);
|
102
|
-
if (ret != -ETIME) {
|
103
|
-
fprintf(stderr, "wait_reg failed: %d\n", ret);
|
104
|
-
return T_EXIT_FAIL;
|
105
|
-
}
|
106
|
-
|
107
|
-
ret = mtime_since_now(&tv);
|
108
|
-
/* allow some slack, should be around 1.1s */
|
109
|
-
if (ret < 1000 || ret > 1200) {
|
110
|
-
fprintf(stderr, "wait too long or short: %d\n", ret);
|
53
|
+
ret = io_uring_register_region(ring, pr);
|
54
|
+
if (ret)
|
111
55
|
goto err;
|
112
|
-
}
|
113
56
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
ret = io_uring_submit_and_wait_reg(&ring, &cqe, 1, 56);
|
121
|
-
if (ret != -EFAULT) {
|
122
|
-
fprintf(stderr, "out-of-range reg_wait failed: %d\n", ret);
|
123
|
-
return T_EXIT_FAIL;
|
57
|
+
if (disabled) {
|
58
|
+
ret = io_uring_enable_rings(ring);
|
59
|
+
if (ret) {
|
60
|
+
fprintf(stderr, "io_uring_enable_rings failure %i\n", ret);
|
61
|
+
goto err;
|
62
|
+
}
|
124
63
|
}
|
125
|
-
|
126
|
-
free(buf);
|
127
|
-
io_uring_queue_exit(&ring);
|
128
|
-
return T_EXIT_PASS;
|
64
|
+
return 0;
|
129
65
|
err:
|
130
|
-
io_uring_queue_exit(
|
131
|
-
return
|
66
|
+
io_uring_queue_exit(ring);
|
67
|
+
return ret;
|
132
68
|
}
|
133
69
|
|
70
|
+
static int page_size;
|
71
|
+
static struct io_uring_reg_wait *reg;
|
72
|
+
|
134
73
|
static int test_invalid_sig(struct io_uring *ring)
|
135
74
|
{
|
136
75
|
struct io_uring_cqe *cqe;
|
@@ -164,6 +103,70 @@ static int test_invalid_sig(struct io_uring *ring)
|
|
164
103
|
return T_EXIT_PASS;
|
165
104
|
}
|
166
105
|
|
106
|
+
static int test_offsets(struct io_uring *ring, struct io_uring_reg_wait *base,
|
107
|
+
size_t size, bool overallocated)
|
108
|
+
{
|
109
|
+
struct io_uring_cqe *cqe;
|
110
|
+
int max_index = size / sizeof(struct io_uring_reg_wait);
|
111
|
+
struct io_uring_reg_wait *rw;
|
112
|
+
unsigned long offset;
|
113
|
+
int copy_size;
|
114
|
+
void *rw_ptr;
|
115
|
+
int ret;
|
116
|
+
|
117
|
+
rw = base;
|
118
|
+
memcpy(rw, &brief_wait, sizeof(brief_wait));
|
119
|
+
ret = io_uring_submit_and_wait_reg(ring, &cqe, 1, 0);
|
120
|
+
if (ret != -ETIME) {
|
121
|
+
fprintf(stderr, "0 index failed: %d\n", ret);
|
122
|
+
return T_EXIT_FAIL;
|
123
|
+
}
|
124
|
+
|
125
|
+
if (overallocated) {
|
126
|
+
rw = base + max_index;
|
127
|
+
memcpy(rw, &brief_wait, sizeof(brief_wait));
|
128
|
+
}
|
129
|
+
ret = io_uring_submit_and_wait_reg(ring, &cqe, 1, max_index);
|
130
|
+
if (ret != -EFAULT) {
|
131
|
+
fprintf(stderr, "max+1 index failed: %d\n", ret);
|
132
|
+
return T_EXIT_FAIL;
|
133
|
+
}
|
134
|
+
|
135
|
+
rw = base + max_index - 1;
|
136
|
+
memcpy(rw, &brief_wait, sizeof(brief_wait));
|
137
|
+
ret = io_uring_submit_and_wait_reg(ring, &cqe, 1, max_index - 1);
|
138
|
+
if (ret != -ETIME) {
|
139
|
+
fprintf(stderr, "last index failed: %d\n", ret);
|
140
|
+
return T_EXIT_FAIL;
|
141
|
+
}
|
142
|
+
|
143
|
+
offset = 0UL - sizeof(long);
|
144
|
+
ret = test_wait_reg_offset(ring, 1, offset);
|
145
|
+
if (ret != -EFAULT) {
|
146
|
+
fprintf(stderr, "overflow offset failed: %d\n", ret);
|
147
|
+
return T_EXIT_FAIL;
|
148
|
+
}
|
149
|
+
|
150
|
+
offset = size - sizeof(long);
|
151
|
+
rw = (void *)base + offset;
|
152
|
+
copy_size = overallocated ? sizeof(brief_wait) : sizeof(long);
|
153
|
+
memcpy(rw, &brief_wait, copy_size);
|
154
|
+
|
155
|
+
ret = test_wait_reg_offset(ring, 1, offset);
|
156
|
+
if (ret != -EFAULT) {
|
157
|
+
fprintf(stderr, "OOB offset failed: %d\n", ret);
|
158
|
+
return T_EXIT_FAIL;
|
159
|
+
}
|
160
|
+
|
161
|
+
offset = 1;
|
162
|
+
rw_ptr = (void *) base + offset;
|
163
|
+
memcpy(rw_ptr, &brief_wait, sizeof(brief_wait));
|
164
|
+
/* undefined behaviour, check the kernel doesn't crash */
|
165
|
+
(void)test_wait_reg_offset(ring, 1, offset);
|
166
|
+
|
167
|
+
return 0;
|
168
|
+
}
|
169
|
+
|
167
170
|
static int test_basic(struct io_uring *ring)
|
168
171
|
{
|
169
172
|
struct io_uring_cqe *cqe;
|
@@ -192,27 +195,50 @@ err:
|
|
192
195
|
return T_EXIT_FAIL;
|
193
196
|
}
|
194
197
|
|
195
|
-
static int
|
198
|
+
static int test_wait_arg(void)
|
196
199
|
{
|
200
|
+
struct io_uring_region_desc rd = {};
|
201
|
+
struct io_uring_mem_region_reg mr = {};
|
197
202
|
struct io_uring ring;
|
198
|
-
|
203
|
+
void *buffer;
|
199
204
|
int ret;
|
200
205
|
|
201
|
-
|
202
|
-
ret = io_uring_queue_init_params(8, &ring, &p);
|
206
|
+
ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED);
|
203
207
|
if (ret) {
|
208
|
+
if (ret == -EINVAL) {
|
209
|
+
printf("IORING_SETUP_R_DISABLED not supported, skip\n");
|
210
|
+
return 0;
|
211
|
+
}
|
204
212
|
fprintf(stderr, "ring setup failed: %d\n", ret);
|
213
|
+
return T_EXIT_FAIL;
|
214
|
+
}
|
215
|
+
|
216
|
+
buffer = aligned_alloc(page_size, page_size * 4);
|
217
|
+
if (!buffer) {
|
218
|
+
fprintf(stderr, "allocation failed\n");
|
219
|
+
return T_EXIT_FAIL;
|
220
|
+
}
|
221
|
+
|
222
|
+
rd.user_addr = (__u64)(unsigned long)buffer;
|
223
|
+
rd.size = page_size;
|
224
|
+
rd.flags = IORING_MEM_REGION_TYPE_USER;
|
225
|
+
mr.region_uptr = (__u64)(unsigned long)&rd;
|
226
|
+
mr.flags = IORING_MEM_REGION_REG_WAIT_ARG;
|
227
|
+
|
228
|
+
ret = io_uring_register_region(&ring, &mr);
|
229
|
+
if (ret) {
|
230
|
+
fprintf(stderr, "region reg failed %i\n", ret);
|
205
231
|
return 1;
|
206
232
|
}
|
207
233
|
|
208
|
-
|
209
|
-
if (
|
210
|
-
|
211
|
-
return T_EXIT_SKIP;
|
212
|
-
fprintf(stderr, "setup_reg_wait: %d\n", ret);
|
234
|
+
ret = io_uring_enable_rings(&ring);
|
235
|
+
if (ret) {
|
236
|
+
fprintf(stderr, "io_uring_enable_rings failure %i\n", ret);
|
213
237
|
return T_EXIT_FAIL;
|
214
238
|
}
|
215
239
|
|
240
|
+
reg = buffer;
|
241
|
+
|
216
242
|
ret = test_basic(&ring);
|
217
243
|
if (ret == T_EXIT_FAIL) {
|
218
244
|
fprintf(stderr, "test failed\n");
|
@@ -225,27 +251,330 @@ static int test_ring(void)
|
|
225
251
|
goto err;
|
226
252
|
}
|
227
253
|
|
228
|
-
ret =
|
254
|
+
ret = test_offsets(&ring, buffer, page_size, true);
|
229
255
|
if (ret == T_EXIT_FAIL) {
|
230
|
-
fprintf(stderr, "
|
256
|
+
fprintf(stderr, "test_offsets failed\n");
|
231
257
|
goto err;
|
232
258
|
}
|
233
|
-
|
234
|
-
ret = test_invalid_reg2();
|
235
|
-
if (ret == T_EXIT_FAIL) {
|
236
|
-
fprintf(stderr, "test_invalid_reg2 failed\n");
|
237
|
-
goto err;
|
238
|
-
}
|
239
|
-
|
240
259
|
err:
|
260
|
+
free(buffer);
|
241
261
|
io_uring_queue_exit(&ring);
|
242
262
|
return ret;
|
243
263
|
}
|
244
264
|
|
265
|
+
static int test_try_register_region(struct io_uring_mem_region_reg *pr,
|
266
|
+
bool disabled)
|
267
|
+
{
|
268
|
+
struct io_uring ring;
|
269
|
+
int ret;
|
270
|
+
|
271
|
+
ret = __init_ring_with_region(&ring, 0, pr, disabled);
|
272
|
+
if (!ret)
|
273
|
+
io_uring_queue_exit(&ring);
|
274
|
+
return ret;
|
275
|
+
}
|
276
|
+
|
277
|
+
static int test_regions(void)
|
278
|
+
{
|
279
|
+
struct io_uring_region_desc rd = {};
|
280
|
+
struct io_uring_mem_region_reg mr = {};
|
281
|
+
void *buffer;
|
282
|
+
int ret;
|
283
|
+
|
284
|
+
buffer = aligned_alloc(page_size, page_size * 4);
|
285
|
+
if (!buffer) {
|
286
|
+
fprintf(stderr, "allocation failed\n");
|
287
|
+
return T_EXIT_FAIL;
|
288
|
+
}
|
289
|
+
|
290
|
+
rd.user_addr = (__u64)(unsigned long)buffer;
|
291
|
+
rd.size = page_size;
|
292
|
+
rd.flags = IORING_MEM_REGION_TYPE_USER;
|
293
|
+
|
294
|
+
mr.region_uptr = (__u64)(unsigned long)&rd;
|
295
|
+
mr.flags = IORING_MEM_REGION_REG_WAIT_ARG;
|
296
|
+
|
297
|
+
ret = test_try_register_region(&mr, true);
|
298
|
+
if (ret == -EINVAL) {
|
299
|
+
free(buffer);
|
300
|
+
return T_EXIT_SKIP;
|
301
|
+
}
|
302
|
+
if (ret) {
|
303
|
+
fprintf(stderr, "region: register normal fail %i\n", ret);
|
304
|
+
return T_EXIT_FAIL;
|
305
|
+
}
|
306
|
+
|
307
|
+
ret = test_try_register_region(&mr, false);
|
308
|
+
if (ret != -EINVAL) {
|
309
|
+
fprintf(stderr, "region: register with !R_DISABLED fail %i\n", ret);
|
310
|
+
return T_EXIT_FAIL;
|
311
|
+
}
|
312
|
+
|
313
|
+
rd.size = page_size * 4;
|
314
|
+
ret = test_try_register_region(&mr, true);
|
315
|
+
if (ret) {
|
316
|
+
fprintf(stderr, "test_try_register_region() 16KB fail %i\n", ret);
|
317
|
+
return T_EXIT_FAIL;
|
318
|
+
}
|
319
|
+
rd.size = page_size;
|
320
|
+
|
321
|
+
rd.user_addr = 0;
|
322
|
+
ret = test_try_register_region(&mr, true);
|
323
|
+
if (ret != -EFAULT) {
|
324
|
+
fprintf(stderr, "test_try_register_region() null uptr fail %i\n", ret);
|
325
|
+
return T_EXIT_FAIL;
|
326
|
+
}
|
327
|
+
rd.user_addr = (__u64)(unsigned long)buffer;
|
328
|
+
|
329
|
+
rd.flags = 0;
|
330
|
+
ret = test_try_register_region(&mr, true);
|
331
|
+
if (!ret) {
|
332
|
+
fprintf(stderr, "test_try_register_region() kernel alloc with uptr fail %i\n", ret);
|
333
|
+
return T_EXIT_FAIL;
|
334
|
+
}
|
335
|
+
rd.flags = IORING_MEM_REGION_TYPE_USER;
|
336
|
+
|
337
|
+
rd.size = 0;
|
338
|
+
ret = test_try_register_region(&mr, true);
|
339
|
+
if (!ret) {
|
340
|
+
fprintf(stderr, "test_try_register_region() 0-size fail %i\n", ret);
|
341
|
+
return T_EXIT_FAIL;
|
342
|
+
}
|
343
|
+
rd.size = page_size;
|
344
|
+
|
345
|
+
mr.region_uptr = 0;
|
346
|
+
ret = test_try_register_region(&mr, true);
|
347
|
+
if (!ret) {
|
348
|
+
fprintf(stderr, "test_try_register_region() NULL region %i\n", ret);
|
349
|
+
return T_EXIT_FAIL;
|
350
|
+
}
|
351
|
+
mr.region_uptr = (__u64)(unsigned long)&rd;
|
352
|
+
|
353
|
+
rd.user_addr += 16;
|
354
|
+
ret = test_try_register_region(&mr, true);
|
355
|
+
if (!ret) {
|
356
|
+
fprintf(stderr, "test_try_register_region() misaligned region %i\n", ret);
|
357
|
+
return T_EXIT_FAIL;
|
358
|
+
}
|
359
|
+
|
360
|
+
rd.user_addr = 0x1000;
|
361
|
+
ret = test_try_register_region(&mr, true);
|
362
|
+
if (!ret) {
|
363
|
+
fprintf(stderr, "test_try_register_region() bogus uptr %i\n", ret);
|
364
|
+
return T_EXIT_FAIL;
|
365
|
+
}
|
366
|
+
rd.user_addr = (__u64)(unsigned long)buffer;
|
367
|
+
free(buffer);
|
368
|
+
|
369
|
+
buffer = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
370
|
+
if (buffer == MAP_FAILED) {
|
371
|
+
fprintf(stderr, "mmap alloc failed\n");
|
372
|
+
return 1;
|
373
|
+
}
|
374
|
+
|
375
|
+
rd.user_addr = (__u64)(unsigned long)buffer;
|
376
|
+
ret = test_try_register_region(&mr, true);
|
377
|
+
if (ret != -EFAULT) {
|
378
|
+
fprintf(stderr, "test_try_register_region() RO uptr %i\n", ret);
|
379
|
+
return T_EXIT_FAIL;
|
380
|
+
}
|
381
|
+
|
382
|
+
rd.flags = 0;
|
383
|
+
rd.user_addr = 0;
|
384
|
+
ret = test_try_register_region(&mr, true);
|
385
|
+
if (ret == -EINVAL) {
|
386
|
+
has_kernel_regions = false;
|
387
|
+
goto out;
|
388
|
+
}
|
389
|
+
if (ret) {
|
390
|
+
fprintf(stderr, "test_try_register_region() failed kernel alloc %i\n", ret);
|
391
|
+
return T_EXIT_FAIL;
|
392
|
+
}
|
393
|
+
|
394
|
+
has_kernel_regions = true;
|
395
|
+
rd.flags = 0;
|
396
|
+
rd.user_addr = (__u64)(unsigned long)buffer;
|
397
|
+
ret = test_try_register_region(&mr, true);
|
398
|
+
if (!ret) {
|
399
|
+
fprintf(stderr, "test_try_register_region() failed uptr w kernel alloc %i\n", ret);
|
400
|
+
return T_EXIT_FAIL;
|
401
|
+
}
|
402
|
+
out:
|
403
|
+
munmap(buffer, page_size);
|
404
|
+
return 0;
|
405
|
+
}
|
406
|
+
|
407
|
+
struct t_region {
|
408
|
+
void *ptr;
|
409
|
+
bool user_mem;
|
410
|
+
size_t size;
|
411
|
+
};
|
412
|
+
|
413
|
+
static void t_region_free(struct t_region *r)
|
414
|
+
{
|
415
|
+
if (r->ptr)
|
416
|
+
munmap(r->ptr, r->size);
|
417
|
+
}
|
418
|
+
|
419
|
+
static int t_region_create_kernel(struct t_region *r,
|
420
|
+
struct io_uring *ring)
|
421
|
+
{
|
422
|
+
struct io_uring_region_desc rd = { .size = r->size, };
|
423
|
+
struct io_uring_mem_region_reg mr = {
|
424
|
+
.region_uptr = (__u64)(unsigned long)&rd,
|
425
|
+
.flags = IORING_MEM_REGION_REG_WAIT_ARG,
|
426
|
+
};
|
427
|
+
void *p;
|
428
|
+
int ret;
|
429
|
+
|
430
|
+
ret = io_uring_register_region(ring, &mr);
|
431
|
+
if (ret)
|
432
|
+
return ret;
|
433
|
+
|
434
|
+
p = mmap(NULL, r->size, PROT_READ | PROT_WRITE,
|
435
|
+
MAP_SHARED | MAP_POPULATE, ring->ring_fd, rd.mmap_offset);
|
436
|
+
if (p == MAP_FAILED)
|
437
|
+
return -EFAULT;
|
438
|
+
|
439
|
+
r->ptr = p;
|
440
|
+
r->user_mem = false;
|
441
|
+
return 0;
|
442
|
+
}
|
443
|
+
|
444
|
+
static int t_region_create_user(struct t_region *r,
|
445
|
+
struct io_uring *ring,
|
446
|
+
bool huge)
|
447
|
+
{
|
448
|
+
struct io_uring_region_desc rd = {};
|
449
|
+
struct io_uring_mem_region_reg mr = {};
|
450
|
+
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
451
|
+
void *p;
|
452
|
+
int ret;
|
453
|
+
|
454
|
+
if (huge)
|
455
|
+
flags |= MAP_HUGETLB | MAP_HUGE_2MB;
|
456
|
+
|
457
|
+
p = mmap(NULL, r->size, PROT_READ | PROT_WRITE, flags, -1, 0);
|
458
|
+
if (p == MAP_FAILED)
|
459
|
+
return -ENOMEM;
|
460
|
+
|
461
|
+
mr.region_uptr = (__u64)(unsigned long)&rd;
|
462
|
+
mr.flags = IORING_MEM_REGION_REG_WAIT_ARG;
|
463
|
+
rd.user_addr = (__u64)(unsigned long)p;
|
464
|
+
rd.flags = IORING_MEM_REGION_TYPE_USER;
|
465
|
+
rd.size = r->size;
|
466
|
+
|
467
|
+
ret = io_uring_register_region(ring, &mr);
|
468
|
+
if (ret) {
|
469
|
+
munmap(p, r->size);
|
470
|
+
return ret;
|
471
|
+
}
|
472
|
+
r->ptr = p;
|
473
|
+
r->user_mem = true;
|
474
|
+
return 0;
|
475
|
+
}
|
476
|
+
|
477
|
+
struct test_param {
|
478
|
+
size_t size;
|
479
|
+
bool huge_page;
|
480
|
+
bool kern_buf;
|
481
|
+
};
|
482
|
+
|
483
|
+
static int test_region_buffer_types(void)
|
484
|
+
{
|
485
|
+
const size_t huge_size = 1024 * 1024 * 2;
|
486
|
+
struct test_param params[] = {
|
487
|
+
{ .size = page_size },
|
488
|
+
/* forcing vmap */
|
489
|
+
{ .size = page_size * 2 },
|
490
|
+
{ .size = page_size * 16 },
|
491
|
+
/* huge page w/o vmap */
|
492
|
+
{ .size = huge_size, .huge_page = true },
|
493
|
+
/* huge page w/ vmap */
|
494
|
+
{ .size = huge_size * 2, .huge_page = true },
|
495
|
+
{ .size = page_size, .kern_buf = true },
|
496
|
+
/* likely to be a compound page */
|
497
|
+
{ .size = page_size * 2, .kern_buf = true },
|
498
|
+
{ .size = page_size * 8, .kern_buf = true },
|
499
|
+
/* kernel allocation + vmap */
|
500
|
+
{ .size = page_size * 512, .kern_buf = true },
|
501
|
+
};
|
502
|
+
struct io_uring ring;
|
503
|
+
int i, ret;
|
504
|
+
|
505
|
+
for (i = 0; i < ARRAY_SIZE(params); i++) {
|
506
|
+
struct t_region r = { .size = params[i].size, };
|
507
|
+
|
508
|
+
ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED);
|
509
|
+
if (ret) {
|
510
|
+
fprintf(stderr, "ring setup failed: %d\n", ret);
|
511
|
+
return ret;
|
512
|
+
}
|
513
|
+
|
514
|
+
if (params[i].kern_buf)
|
515
|
+
ret = t_region_create_kernel(&r, &ring);
|
516
|
+
else
|
517
|
+
ret = t_region_create_user(&r, &ring, params[i].huge_page);
|
518
|
+
if (ret) {
|
519
|
+
io_uring_queue_exit(&ring);
|
520
|
+
if (ret == -ENOMEM || ret == -EINVAL)
|
521
|
+
continue;
|
522
|
+
fprintf(stderr, "t_region_create_user failed, idx %i\n", i);
|
523
|
+
return 1;
|
524
|
+
}
|
525
|
+
|
526
|
+
ret = io_uring_enable_rings(&ring);
|
527
|
+
if (ret) {
|
528
|
+
fprintf(stderr, "io_uring_enable_rings failure %i\n", ret);
|
529
|
+
return ret;
|
530
|
+
}
|
531
|
+
|
532
|
+
ret = test_offsets(&ring, r.ptr, r.size, false);
|
533
|
+
if (ret) {
|
534
|
+
fprintf(stderr, "test_offsets failed, idx %i\n", i);
|
535
|
+
return 1;
|
536
|
+
}
|
537
|
+
|
538
|
+
t_region_free(&r);
|
539
|
+
io_uring_queue_exit(&ring);
|
540
|
+
}
|
541
|
+
|
542
|
+
return 0;
|
543
|
+
}
|
544
|
+
|
245
545
|
int main(int argc, char *argv[])
|
246
546
|
{
|
547
|
+
int ret;
|
548
|
+
|
247
549
|
if (argc > 1)
|
248
550
|
return 0;
|
249
551
|
|
250
|
-
|
552
|
+
page_size = sysconf(_SC_PAGESIZE);
|
553
|
+
if (page_size < 0) {
|
554
|
+
perror("sysconf(_SC_PAGESIZE)");
|
555
|
+
return 1;
|
556
|
+
}
|
557
|
+
|
558
|
+
ret = test_regions();
|
559
|
+
if (ret == T_EXIT_SKIP) {
|
560
|
+
printf("regions are not supported, skip\n");
|
561
|
+
return 0;
|
562
|
+
} else if (ret) {
|
563
|
+
fprintf(stderr, "test_region failed\n");
|
564
|
+
return 1;
|
565
|
+
}
|
566
|
+
|
567
|
+
ret = test_wait_arg();
|
568
|
+
if (ret == T_EXIT_FAIL) {
|
569
|
+
fprintf(stderr, "test_wait_arg failed\n");
|
570
|
+
return 1;
|
571
|
+
}
|
572
|
+
|
573
|
+
ret = test_region_buffer_types();
|
574
|
+
if (ret == T_EXIT_FAIL) {
|
575
|
+
fprintf(stderr, "test_region_buffer_types failed\n");
|
576
|
+
return 1;
|
577
|
+
}
|
578
|
+
|
579
|
+
return 0;
|
251
580
|
}
|
@@ -305,6 +305,9 @@ static int test_offsets(void)
|
|
305
305
|
return T_EXIT_FAIL;
|
306
306
|
}
|
307
307
|
|
308
|
+
for (i = 0; i < NR_VECS; i++)
|
309
|
+
free(vecs[i].iov_base);
|
310
|
+
|
308
311
|
return T_EXIT_PASS;
|
309
312
|
}
|
310
313
|
|
@@ -576,6 +579,48 @@ skip:
|
|
576
579
|
return res;
|
577
580
|
}
|
578
581
|
|
582
|
+
static int test_same(void)
|
583
|
+
{
|
584
|
+
struct iovec vecs[2] = { };
|
585
|
+
struct io_uring src;
|
586
|
+
int ret;
|
587
|
+
|
588
|
+
ret = io_uring_queue_init(1, &src, 0);
|
589
|
+
if (ret) {
|
590
|
+
fprintf(stderr, "ring_init: %d\n", ret);
|
591
|
+
return T_EXIT_FAIL;
|
592
|
+
}
|
593
|
+
|
594
|
+
if (posix_memalign(&vecs[0].iov_base, 4096, BUF_SIZE))
|
595
|
+
return T_EXIT_SKIP;
|
596
|
+
vecs[0].iov_len = BUF_SIZE;
|
597
|
+
|
598
|
+
vecs[1].iov_base = NULL;
|
599
|
+
vecs[1].iov_len = 0;
|
600
|
+
|
601
|
+
ret = io_uring_register_buffers(&src, vecs, 2);
|
602
|
+
if (ret) {
|
603
|
+
fprintf(stderr, "reg buffers: %d\n", ret);
|
604
|
+
return T_EXIT_FAIL;
|
605
|
+
}
|
606
|
+
|
607
|
+
ret = io_uring_clone_buffers_offset(&src, &src, 1, 0, 2, IORING_REGISTER_DST_REPLACE);
|
608
|
+
if (ret) {
|
609
|
+
fprintf(stderr, "clone offset: %d\n", ret);
|
610
|
+
return T_EXIT_FAIL;
|
611
|
+
}
|
612
|
+
|
613
|
+
ret = io_uring_unregister_buffers(&src);
|
614
|
+
if (ret) {
|
615
|
+
fprintf(stderr, "rsc unregister buffers: %d\n", ret);
|
616
|
+
return T_EXIT_FAIL;
|
617
|
+
}
|
618
|
+
|
619
|
+
free(vecs[0].iov_base);
|
620
|
+
io_uring_queue_exit(&src);
|
621
|
+
return T_EXIT_PASS;
|
622
|
+
}
|
623
|
+
|
579
624
|
int main(int argc, char *argv[])
|
580
625
|
{
|
581
626
|
int ret;
|
@@ -641,5 +686,13 @@ int main(int argc, char *argv[])
|
|
641
686
|
if (no_buf_offset)
|
642
687
|
return T_EXIT_PASS;
|
643
688
|
|
689
|
+
ret = test_same();
|
690
|
+
if (ret == T_EXIT_SKIP) {
|
691
|
+
return T_EXIT_PASS;
|
692
|
+
} else if (ret != T_EXIT_PASS) {
|
693
|
+
fprintf(stderr, "test_same failed\n");
|
694
|
+
return T_EXIT_FAIL;
|
695
|
+
}
|
696
|
+
|
644
697
|
return T_EXIT_PASS;
|
645
698
|
}
|