uringmachine 0.10 → 0.11.1

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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/examples/bm_http_parse.rb +108 -35
  4. data/examples/bm_side_running.rb +83 -0
  5. data/examples/bm_sqlite.rb +1 -1
  6. data/ext/um/um.c +17 -1
  7. data/ext/um/um.h +30 -0
  8. data/ext/um/um_ext.c +2 -0
  9. data/ext/um/um_stream.c +372 -0
  10. data/ext/um/um_stream_class.c +121 -0
  11. data/lib/uringmachine/version.rb +1 -1
  12. data/lib/uringmachine.rb +20 -16
  13. data/test/test_stream.rb +133 -0
  14. data/test/test_um.rb +63 -0
  15. data/uringmachine.gemspec +1 -0
  16. data/vendor/liburing/.github/workflows/{build.yml → ci.yml} +107 -42
  17. data/vendor/liburing/.gitignore +1 -0
  18. data/vendor/liburing/CHANGELOG +10 -0
  19. data/vendor/liburing/README +5 -0
  20. data/vendor/liburing/configure +1 -1
  21. data/vendor/liburing/examples/Makefile +1 -0
  22. data/vendor/liburing/examples/helpers.c +25 -0
  23. data/vendor/liburing/examples/helpers.h +13 -0
  24. data/vendor/liburing/examples/io_uring-test.c +3 -0
  25. data/vendor/liburing/examples/proxy.c +1 -1
  26. data/vendor/liburing/examples/reg-wait.c +41 -6
  27. data/vendor/liburing/examples/send-zerocopy.c +79 -32
  28. data/vendor/liburing/examples/zcrx.c +436 -0
  29. data/vendor/liburing/liburing.spec +1 -1
  30. data/vendor/liburing/src/Makefile +0 -1
  31. data/vendor/liburing/src/arch/generic/syscall.h +2 -2
  32. data/vendor/liburing/src/arch/syscall-defs.h +2 -2
  33. data/vendor/liburing/src/include/liburing/io_uring.h +101 -17
  34. data/vendor/liburing/src/include/liburing.h +179 -59
  35. data/vendor/liburing/src/int_flags.h +4 -1
  36. data/vendor/liburing/src/liburing-ffi.map +14 -2
  37. data/vendor/liburing/src/liburing.map +9 -2
  38. data/vendor/liburing/src/queue.c +35 -30
  39. data/vendor/liburing/src/register.c +46 -15
  40. data/vendor/liburing/src/sanitize.c +6 -9
  41. data/vendor/liburing/src/setup.c +37 -71
  42. data/vendor/liburing/src/syscall.c +2 -2
  43. data/vendor/liburing/test/232c93d07b74.c +1 -0
  44. data/vendor/liburing/test/Makefile +9 -0
  45. data/vendor/liburing/test/accept-test.c +1 -0
  46. data/vendor/liburing/test/cmd-discard.c +16 -8
  47. data/vendor/liburing/test/connect.c +11 -7
  48. data/vendor/liburing/test/epwait.c +420 -0
  49. data/vendor/liburing/test/eventfd-ring.c +30 -5
  50. data/vendor/liburing/test/fallocate.c +1 -1
  51. data/vendor/liburing/test/fixed-hugepage.c +10 -7
  52. data/vendor/liburing/test/fixed-seg.c +187 -0
  53. data/vendor/liburing/test/helpers.c +121 -0
  54. data/vendor/liburing/test/helpers.h +13 -0
  55. data/vendor/liburing/test/init-mem.c +2 -0
  56. data/vendor/liburing/test/io_uring_passthrough.c +78 -62
  57. data/vendor/liburing/test/iopoll-overflow.c +5 -4
  58. data/vendor/liburing/test/iopoll.c +20 -10
  59. data/vendor/liburing/test/iowait.c +141 -0
  60. data/vendor/liburing/test/nvme.h +2 -0
  61. data/vendor/liburing/test/pipe-bug.c +11 -5
  62. data/vendor/liburing/test/pipe-eof.c +11 -1
  63. data/vendor/liburing/test/read-inc-file.c +150 -0
  64. data/vendor/liburing/test/read-write.c +21 -14
  65. data/vendor/liburing/test/recv-bundle-short-ooo.c +435 -0
  66. data/vendor/liburing/test/recv-multishot.c +2 -2
  67. data/vendor/liburing/test/reg-wait.c +449 -120
  68. data/vendor/liburing/test/regbuf-clone.c +53 -0
  69. data/vendor/liburing/test/resize-rings.c +25 -2
  70. data/vendor/liburing/test/rsrc_tags.c +67 -14
  71. data/vendor/liburing/test/send-zerocopy.c +52 -130
  72. data/vendor/liburing/test/sendmsg_iov_clean.c +216 -0
  73. data/vendor/liburing/test/socket-nb.c +158 -0
  74. data/vendor/liburing/test/sqwait.c +9 -11
  75. data/vendor/liburing/test/timeout.c +198 -0
  76. data/vendor/liburing/test/vec-regbuf.c +609 -0
  77. data/vendor/liburing/test/wait-timeout.c +1 -1
  78. data/vendor/liburing/test/wq-aff.c +5 -1
  79. data/vendor/liburing/test/zcrx.c +928 -0
  80. metadata +30 -4
  81. data/vendor/liburing/.github/workflows/codespell.yml +0 -25
  82. 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 *reg;
18
-
19
- static int test_invalid_reg2(void)
20
- {
21
- struct io_uring ring;
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
- ret = io_uring_register_wait_reg(&ring, ptr, 1);
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
- io_uring_queue_exit(&ring);
68
- return T_EXIT_PASS;
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 test_invalid_reg(void)
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
- struct io_uring_reg_wait *ireg;
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(1, &ring, 0);
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
- fprintf(stderr, "register cqwait: %d\n", ret);
91
- return T_EXIT_FAIL;
48
+ if (ret != -EINVAL)
49
+ fprintf(stderr, "ring setup failed: %d\n", ret);
50
+ return ret;
92
51
  }
93
52
 
94
- ireg = ptr;
95
- memset(ireg, 0, sizeof(*ireg));
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
- memset(ireg, 0, sizeof(*ireg));
115
- ireg->ts.tv_sec = 1;
116
- ireg->ts.tv_nsec = 0;
117
- ireg->flags = IORING_REG_WAIT_TS;
118
-
119
- gettimeofday(&tv, NULL);
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(&ring);
131
- return T_EXIT_FAIL;
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 test_ring(void)
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
- struct io_uring_params p = { };
203
+ void *buffer;
199
204
  int ret;
200
205
 
201
- p.flags = 0;
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
- reg = io_uring_setup_reg_wait(&ring, 64, &ret);
209
- if (!reg) {
210
- if (ret == -EINVAL)
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 = test_invalid_reg();
254
+ ret = test_offsets(&ring, buffer, page_size, true);
229
255
  if (ret == T_EXIT_FAIL) {
230
- fprintf(stderr, "test_invalid_reg failed\n");
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
- return test_ring();
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
  }