uringmachine 0.8.2 → 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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/TODO.md +0 -1
  4. data/examples/bm_side_running.rb +83 -0
  5. data/examples/bm_sqlite.rb +1 -1
  6. data/ext/um/um.c +66 -4
  7. data/ext/um/um.h +36 -0
  8. data/ext/um/um_class.c +6 -0
  9. data/ext/um/um_const.c +36 -0
  10. data/ext/um/um_ext.c +2 -0
  11. data/ext/um/um_stream.c +344 -0
  12. data/ext/um/um_stream_class.c +140 -0
  13. data/ext/um/um_utils.c +4 -0
  14. data/lib/uringmachine/actor.rb +1 -1
  15. data/lib/uringmachine/version.rb +1 -1
  16. data/lib/uringmachine.rb +35 -17
  17. data/test/test_fiber.rb +23 -3
  18. data/test/test_stream.rb +133 -0
  19. data/test/test_um.rb +109 -2
  20. data/uringmachine.gemspec +0 -2
  21. data/vendor/liburing/.github/workflows/{build.yml → ci.yml} +107 -42
  22. data/vendor/liburing/.gitignore +1 -0
  23. data/vendor/liburing/CHANGELOG +10 -0
  24. data/vendor/liburing/README +5 -0
  25. data/vendor/liburing/configure +1 -1
  26. data/vendor/liburing/examples/Makefile +1 -0
  27. data/vendor/liburing/examples/helpers.c +25 -0
  28. data/vendor/liburing/examples/helpers.h +13 -0
  29. data/vendor/liburing/examples/io_uring-test.c +3 -0
  30. data/vendor/liburing/examples/proxy.c +1 -1
  31. data/vendor/liburing/examples/reg-wait.c +41 -6
  32. data/vendor/liburing/examples/send-zerocopy.c +79 -32
  33. data/vendor/liburing/examples/zcrx.c +436 -0
  34. data/vendor/liburing/liburing.spec +1 -1
  35. data/vendor/liburing/src/Makefile +0 -1
  36. data/vendor/liburing/src/arch/generic/syscall.h +2 -2
  37. data/vendor/liburing/src/arch/syscall-defs.h +2 -2
  38. data/vendor/liburing/src/include/liburing/io_uring.h +101 -17
  39. data/vendor/liburing/src/include/liburing.h +179 -59
  40. data/vendor/liburing/src/int_flags.h +4 -1
  41. data/vendor/liburing/src/liburing-ffi.map +14 -2
  42. data/vendor/liburing/src/liburing.map +9 -2
  43. data/vendor/liburing/src/queue.c +35 -30
  44. data/vendor/liburing/src/register.c +46 -15
  45. data/vendor/liburing/src/sanitize.c +6 -9
  46. data/vendor/liburing/src/setup.c +37 -71
  47. data/vendor/liburing/src/syscall.c +2 -2
  48. data/vendor/liburing/test/232c93d07b74.c +1 -0
  49. data/vendor/liburing/test/Makefile +9 -0
  50. data/vendor/liburing/test/accept-test.c +1 -0
  51. data/vendor/liburing/test/cmd-discard.c +16 -8
  52. data/vendor/liburing/test/connect.c +11 -7
  53. data/vendor/liburing/test/epwait.c +420 -0
  54. data/vendor/liburing/test/eventfd-ring.c +30 -5
  55. data/vendor/liburing/test/fallocate.c +1 -1
  56. data/vendor/liburing/test/fixed-hugepage.c +10 -7
  57. data/vendor/liburing/test/fixed-seg.c +187 -0
  58. data/vendor/liburing/test/helpers.c +121 -0
  59. data/vendor/liburing/test/helpers.h +13 -0
  60. data/vendor/liburing/test/init-mem.c +2 -0
  61. data/vendor/liburing/test/io_uring_passthrough.c +78 -62
  62. data/vendor/liburing/test/iopoll-overflow.c +5 -4
  63. data/vendor/liburing/test/iopoll.c +20 -10
  64. data/vendor/liburing/test/iowait.c +141 -0
  65. data/vendor/liburing/test/nvme.h +2 -0
  66. data/vendor/liburing/test/pipe-bug.c +11 -5
  67. data/vendor/liburing/test/pipe-eof.c +11 -1
  68. data/vendor/liburing/test/read-inc-file.c +150 -0
  69. data/vendor/liburing/test/read-write.c +21 -14
  70. data/vendor/liburing/test/recv-bundle-short-ooo.c +435 -0
  71. data/vendor/liburing/test/recv-multishot.c +2 -2
  72. data/vendor/liburing/test/reg-wait.c +449 -120
  73. data/vendor/liburing/test/regbuf-clone.c +53 -0
  74. data/vendor/liburing/test/resize-rings.c +25 -2
  75. data/vendor/liburing/test/rsrc_tags.c +67 -14
  76. data/vendor/liburing/test/send-zerocopy.c +52 -130
  77. data/vendor/liburing/test/sendmsg_iov_clean.c +216 -0
  78. data/vendor/liburing/test/socket-nb.c +158 -0
  79. data/vendor/liburing/test/sqwait.c +9 -11
  80. data/vendor/liburing/test/timeout.c +198 -0
  81. data/vendor/liburing/test/vec-regbuf.c +609 -0
  82. data/vendor/liburing/test/wait-timeout.c +1 -1
  83. data/vendor/liburing/test/wq-aff.c +5 -1
  84. data/vendor/liburing/test/zcrx.c +928 -0
  85. metadata +16 -32
  86. data/vendor/liburing/.github/workflows/codespell.yml +0 -25
  87. data/vendor/liburing/.github/workflows/shellcheck.yml +0 -20
@@ -0,0 +1,187 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Description: test various offset of fixed buffer read
4
+ *
5
+ */
6
+ #include <stdio.h>
7
+ #include <unistd.h>
8
+ #include <fcntl.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+ #include <sys/time.h>
12
+ #include <sys/ioctl.h>
13
+ #include <sys/stat.h>
14
+ #include "liburing.h"
15
+ #include "helpers.h"
16
+
17
+ static struct iovec rvec, wvec;
18
+
19
+ static int read_it(struct io_uring *ring, int fd, int len, int off)
20
+ {
21
+ struct io_uring_sqe *sqe;
22
+ struct io_uring_cqe *cqe;
23
+ int ret;
24
+
25
+ sqe = io_uring_get_sqe(ring);
26
+ io_uring_prep_read_fixed(sqe, fd, rvec.iov_base + off, len, 0, 0);
27
+ sqe->user_data = 1;
28
+
29
+ io_uring_submit(ring);
30
+
31
+ ret = io_uring_wait_cqe(ring, &cqe);
32
+ if (ret) {
33
+ fprintf(stderr, "wait %d\n", ret);
34
+ return 1;
35
+ }
36
+ if (cqe->res < 0) {
37
+ fprintf(stderr, "cqe res %s\n", strerror(-cqe->res));
38
+ return 1;
39
+ }
40
+ if (cqe->res != len) {
41
+ fprintf(stderr, "Bad read amount: %d\n", cqe->res);
42
+ return 1;
43
+ }
44
+ io_uring_cqe_seen(ring, cqe);
45
+
46
+ if (memcmp(wvec.iov_base, rvec.iov_base + off, len)) {
47
+ fprintf(stderr, "%d %d verify failed\n", len, off);
48
+ return 1;
49
+ }
50
+
51
+ return 0;
52
+ }
53
+
54
+ static int test(struct io_uring *ring, int fd, int vec_off)
55
+ {
56
+ struct iovec v = rvec;
57
+ int ret;
58
+
59
+ v.iov_base += vec_off;
60
+ v.iov_len -= vec_off;
61
+ ret = io_uring_register_buffers(ring, &v, 1);
62
+ if (ret) {
63
+ fprintf(stderr, "Vec register: %d\n", ret);
64
+ return T_EXIT_FAIL;
65
+ }
66
+
67
+ ret = read_it(ring, fd, 4096, vec_off);
68
+ if (ret) {
69
+ fprintf(stderr, "4096 0 failed\n");
70
+ return T_EXIT_FAIL;
71
+ }
72
+ ret = read_it(ring, fd, 8192, 4096);
73
+ if (ret) {
74
+ fprintf(stderr, "8192 4096 failed\n");
75
+ return T_EXIT_FAIL;
76
+ }
77
+ ret = read_it(ring, fd, 4096, 4096);
78
+ if (ret) {
79
+ fprintf(stderr, "4096 4096 failed\n");
80
+ return T_EXIT_FAIL;
81
+ }
82
+
83
+ io_uring_unregister_buffers(ring);
84
+ return T_EXIT_PASS;
85
+ }
86
+
87
+ static int is_bdev(int fd)
88
+ {
89
+ struct stat sb;
90
+
91
+ if (fstat(fd, &sb) < 0) {
92
+ perror("fstat");
93
+ return -1;
94
+ }
95
+
96
+ return S_ISBLK(sb.st_mode);
97
+ }
98
+
99
+ int main(int argc, char *argv[])
100
+ {
101
+ struct io_uring ring;
102
+ const char *fname;
103
+ char buf[256];
104
+ int fd, rnd_fd, ret, bs = 512;
105
+
106
+ if (argc > 1) {
107
+ fname = argv[1];
108
+ } else {
109
+ srand((unsigned)time(NULL));
110
+ snprintf(buf, sizeof(buf), ".fixed-seg-%u-%u", (unsigned) rand(),
111
+ (unsigned)getpid());
112
+ fname = buf;
113
+ t_create_file(fname, 128*1024);
114
+ }
115
+
116
+ fd = open(fname, O_RDWR | O_DIRECT | O_EXCL);
117
+ if (fd < 0) {
118
+ perror("open");
119
+ return 1;
120
+ }
121
+ ret = is_bdev(fd);
122
+ if (fd < 0)
123
+ return 1;
124
+ if (ret && ioctl(fd, BLKSSZGET, &bs) < 0) {
125
+ perror("ioctl BLKSSZGET,");
126
+ return 1;
127
+ }
128
+
129
+ rnd_fd = open("/dev/urandom", O_RDONLY);
130
+ if (fd < 0) {
131
+ perror("urandom: open");
132
+ goto err;
133
+ }
134
+
135
+ if (posix_memalign(&wvec.iov_base, 4096, 512*1024))
136
+ goto err;
137
+ wvec.iov_len = 512*1024;
138
+
139
+ ret = read(rnd_fd, wvec.iov_base, wvec.iov_len);
140
+ if (ret != wvec.iov_len) {
141
+ fprintf(stderr, "Precondition, urandom read failed, ret: %d\n", ret);
142
+ goto err;
143
+ }
144
+
145
+ ret = write(fd, wvec.iov_base, wvec.iov_len);
146
+ if (ret != wvec.iov_len) {
147
+ fprintf(stderr, "Precondition, write failed, ret: %d\n", ret);
148
+ goto err;
149
+ }
150
+
151
+ if (posix_memalign(&rvec.iov_base, 4096, 512*1024))
152
+ goto err;
153
+ rvec.iov_len = 512*1024;
154
+
155
+ ret = io_uring_queue_init(8, &ring, 0);
156
+ if (ret) {
157
+ fprintf(stderr, "queue_init: %d\n", ret);
158
+ goto err;
159
+ }
160
+
161
+ ret = test(&ring, fd, 0);
162
+ if (ret) {
163
+ fprintf(stderr, "test 0 failed\n");
164
+ goto err;
165
+ }
166
+
167
+ ret = test(&ring, fd, bs);
168
+ if (ret) {
169
+ fprintf(stderr, "test %d failed\n", bs);
170
+ goto err;
171
+ }
172
+
173
+ if ((bs == 512) && test(&ring, fd, 3584)) {
174
+ fprintf(stderr, "test 3584 failed\n");
175
+ goto err;
176
+ }
177
+
178
+ close(fd);
179
+ io_uring_queue_exit(&ring);
180
+ if (fname != argv[1])
181
+ unlink(fname);
182
+ return T_EXIT_PASS;
183
+ err:
184
+ if (fname != argv[1])
185
+ unlink(fname);
186
+ return T_EXIT_FAIL;
187
+ }
@@ -363,3 +363,124 @@ unsigned long long utime_since_now(struct timeval *tv)
363
363
  gettimeofday(&end, NULL);
364
364
  return utime_since(tv, &end);
365
365
  }
366
+
367
+ void *aligned_alloc(size_t alignment, size_t size)
368
+ {
369
+ void *ret;
370
+
371
+ if (posix_memalign(&ret, alignment, size))
372
+ return NULL;
373
+
374
+ return ret;
375
+ }
376
+
377
+ int t_create_socketpair_ip(struct sockaddr_storage *addr,
378
+ int *sock_client, int *sock_server,
379
+ bool ipv6, bool client_connect,
380
+ bool msg_zc, bool tcp, const char *name)
381
+ {
382
+ socklen_t addr_size;
383
+ int family, sock, listen_sock = -1;
384
+ int ret;
385
+
386
+ memset(addr, 0, sizeof(*addr));
387
+ if (ipv6) {
388
+ struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
389
+
390
+ family = AF_INET6;
391
+ saddr->sin6_family = family;
392
+ saddr->sin6_port = htons(0);
393
+ addr_size = sizeof(*saddr);
394
+ } else {
395
+ struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
396
+
397
+ family = AF_INET;
398
+ saddr->sin_family = family;
399
+ saddr->sin_port = htons(0);
400
+ saddr->sin_addr.s_addr = htonl(INADDR_ANY);
401
+ addr_size = sizeof(*saddr);
402
+ }
403
+
404
+ /* server sock setup */
405
+ if (tcp) {
406
+ sock = listen_sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
407
+ } else {
408
+ sock = *sock_server = socket(family, SOCK_DGRAM, 0);
409
+ }
410
+ if (sock < 0) {
411
+ perror("socket");
412
+ return 1;
413
+ }
414
+
415
+ ret = bind(sock, (struct sockaddr *)addr, addr_size);
416
+ if (ret < 0) {
417
+ perror("bind");
418
+ return 1;
419
+ }
420
+
421
+ ret = getsockname(sock, (struct sockaddr *)addr, &addr_size);
422
+ if (ret < 0) {
423
+ fprintf(stderr, "getsockname failed %i\n", errno);
424
+ return 1;
425
+ }
426
+
427
+ if (tcp) {
428
+ ret = listen(sock, 128);
429
+ assert(ret != -1);
430
+ }
431
+
432
+ if (ipv6) {
433
+ struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
434
+
435
+ inet_pton(AF_INET6, name, &(saddr->sin6_addr));
436
+ } else {
437
+ struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
438
+
439
+ inet_pton(AF_INET, name, &saddr->sin_addr);
440
+ }
441
+
442
+ /* client sock setup */
443
+ if (tcp) {
444
+ *sock_client = socket(family, SOCK_STREAM, IPPROTO_TCP);
445
+ assert(client_connect);
446
+ } else {
447
+ *sock_client = socket(family, SOCK_DGRAM, 0);
448
+ }
449
+ if (*sock_client < 0) {
450
+ perror("socket");
451
+ return 1;
452
+ }
453
+ if (client_connect) {
454
+ ret = connect(*sock_client, (struct sockaddr *)addr, addr_size);
455
+ if (ret < 0) {
456
+ perror("connect");
457
+ return 1;
458
+ }
459
+ }
460
+ if (msg_zc) {
461
+ #ifdef SO_ZEROCOPY
462
+ int val = 1;
463
+
464
+ /*
465
+ * NOTE: apps must not set SO_ZEROCOPY when using io_uring zc.
466
+ * It's only here to test interactions with MSG_ZEROCOPY.
467
+ */
468
+ if (setsockopt(*sock_client, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val))) {
469
+ perror("setsockopt zc");
470
+ return 1;
471
+ }
472
+ #else
473
+ fprintf(stderr, "no SO_ZEROCOPY\n");
474
+ return 1;
475
+ #endif
476
+ }
477
+ if (tcp) {
478
+ *sock_server = accept(listen_sock, NULL, NULL);
479
+ if (!*sock_server) {
480
+ fprintf(stderr, "can't accept\n");
481
+ return 1;
482
+ }
483
+ close(listen_sock);
484
+ }
485
+ return 0;
486
+ }
@@ -13,6 +13,7 @@ extern "C" {
13
13
  #include "../src/setup.h"
14
14
  #include <arpa/inet.h>
15
15
  #include <sys/time.h>
16
+ #include <stdlib.h>
16
17
 
17
18
  enum t_setup_ret {
18
19
  T_SETUP_OK = 0,
@@ -25,6 +26,13 @@ enum t_test_result {
25
26
  T_EXIT_SKIP = 77,
26
27
  };
27
28
 
29
+ /*
30
+ * Some Android versions lack aligned_alloc in stdlib.h.
31
+ * To avoid making large changes in tests, define a helper
32
+ * function that wraps posix_memalign as our own aligned_alloc.
33
+ */
34
+ void *aligned_alloc(size_t alignment, size_t size);
35
+
28
36
  /*
29
37
  * Helper for binding socket to an ephemeral port.
30
38
  * The port number to be bound is returned in @addr->sin_port.
@@ -73,6 +81,11 @@ struct iovec *t_create_buffers(size_t buf_num, size_t buf_size);
73
81
  */
74
82
  int t_create_socket_pair(int fd[2], bool stream);
75
83
 
84
+ int t_create_socketpair_ip(struct sockaddr_storage *addr,
85
+ int *sock_client, int *sock_server,
86
+ bool ipv6, bool client_connect,
87
+ bool msg_zc, bool tcp, const char *name);
88
+
76
89
  /*
77
90
  * Helper for setting up a ring and checking for user privs
78
91
  */
@@ -41,6 +41,8 @@ static int setup_ctx(struct ctx *ctx, struct q_entries *q)
41
41
  if (posix_memalign(&ctx->mem, 4096, 2*1024*1024))
42
42
  return T_EXIT_FAIL;
43
43
 
44
+ memset(ctx->mem, 0, 2*1024*1024);
45
+
44
46
  ctx->pre = ctx->mem + 4096 - sizeof(unsigned long long);
45
47
  *ctx->pre = PRE_RED;
46
48
 
@@ -13,12 +13,16 @@
13
13
  #include "../src/syscall.h"
14
14
  #include "nvme.h"
15
15
 
16
+ #define min(a, b) ((a) < (b) ? (a) : (b))
17
+
16
18
  #define FILE_SIZE (256 * 1024)
17
19
  #define BS 8192
18
20
  #define BUFFERS (FILE_SIZE / BS)
19
21
 
20
- static struct iovec *vecs;
22
+ static void *meta_mem;
23
+ static struct iovec *vecs, *backing_vec;
21
24
  static int no_pt;
25
+ static bool vec_fixed_supported = true;
22
26
 
23
27
  /*
24
28
  * Each offset in the file has the ((test_case / 2) * FILE_SIZE)
@@ -73,7 +77,7 @@ static int __test_io(const char *file, struct io_uring *ring, int tc, int read,
73
77
  struct nvme_uring_cmd *cmd;
74
78
  int open_flags;
75
79
  int do_fixed;
76
- int i, ret, fd = -1;
80
+ int i, ret, fd = -1, use_fd = -1, submit_count = 0;
77
81
  off_t offset;
78
82
  __u64 slba;
79
83
  __u32 nlb;
@@ -84,7 +88,7 @@ static int __test_io(const char *file, struct io_uring *ring, int tc, int read,
84
88
  open_flags = O_WRONLY;
85
89
 
86
90
  if (fixed) {
87
- ret = t_register_buffers(ring, vecs, BUFFERS);
91
+ ret = t_register_buffers(ring, backing_vec, 1);
88
92
  if (ret == T_SETUP_SKIP)
89
93
  return 0;
90
94
  if (ret != T_SETUP_OK) {
@@ -114,58 +118,28 @@ static int __test_io(const char *file, struct io_uring *ring, int tc, int read,
114
118
 
115
119
  offset = 0;
116
120
  for (i = 0; i < BUFFERS; i++) {
121
+ unsigned int iovcnt = 1;
122
+ size_t total_len;
123
+
117
124
  sqe = io_uring_get_sqe(ring);
118
125
  if (!sqe) {
119
126
  fprintf(stderr, "sqe get failed\n");
120
127
  goto err;
121
128
  }
122
- if (read) {
123
- int use_fd = fd;
124
-
125
- do_fixed = fixed;
126
-
127
- if (sqthread)
128
- use_fd = 0;
129
- if (fixed && (i & 1))
130
- do_fixed = 0;
131
- if (do_fixed) {
132
- io_uring_prep_read_fixed(sqe, use_fd, vecs[i].iov_base,
133
- vecs[i].iov_len,
134
- offset, i);
135
- sqe->cmd_op = NVME_URING_CMD_IO;
136
- } else if (nonvec) {
137
- io_uring_prep_read(sqe, use_fd, vecs[i].iov_base,
138
- vecs[i].iov_len, offset);
139
- sqe->cmd_op = NVME_URING_CMD_IO;
140
- } else {
141
- io_uring_prep_readv(sqe, use_fd, &vecs[i], 1,
142
- offset);
143
- sqe->cmd_op = NVME_URING_CMD_IO_VEC;
144
- }
145
- } else {
146
- int use_fd = fd;
147
-
148
- do_fixed = fixed;
149
-
150
- if (sqthread)
151
- use_fd = 0;
152
- if (fixed && (i & 1))
153
- do_fixed = 0;
154
- if (do_fixed) {
155
- io_uring_prep_write_fixed(sqe, use_fd, vecs[i].iov_base,
156
- vecs[i].iov_len,
157
- offset, i);
158
- sqe->cmd_op = NVME_URING_CMD_IO;
159
- } else if (nonvec) {
160
- io_uring_prep_write(sqe, use_fd, vecs[i].iov_base,
161
- vecs[i].iov_len, offset);
162
- sqe->cmd_op = NVME_URING_CMD_IO;
163
- } else {
164
- io_uring_prep_writev(sqe, use_fd, &vecs[i], 1,
165
- offset);
166
- sqe->cmd_op = NVME_URING_CMD_IO_VEC;
167
- }
168
- }
129
+ use_fd = fd;
130
+ do_fixed = fixed;
131
+
132
+ if (sqthread)
133
+ use_fd = 0;
134
+ if (fixed && (i & 1))
135
+ do_fixed = 0;
136
+ if (do_fixed)
137
+ sqe->buf_index = 0;
138
+ if (nonvec)
139
+ sqe->cmd_op = NVME_URING_CMD_IO;
140
+ else
141
+ sqe->cmd_op = NVME_URING_CMD_IO_VEC;
142
+ sqe->fd = use_fd;
169
143
  sqe->opcode = IORING_OP_URING_CMD;
170
144
  if (do_fixed)
171
145
  sqe->uring_cmd_flags |= IORING_URING_CMD_FIXED;
@@ -178,39 +152,58 @@ static int __test_io(const char *file, struct io_uring *ring, int tc, int read,
178
152
 
179
153
  cmd->opcode = read ? nvme_cmd_read : nvme_cmd_write;
180
154
 
155
+ if (!nonvec) {
156
+ iovcnt = (submit_count % 3 == 0) ? 1 : ((submit_count % 3 == 1) ? 3 : 9);
157
+ iovcnt = min(iovcnt, BUFFERS - i);
158
+ }
159
+ total_len = BS * iovcnt;
160
+
181
161
  slba = offset >> lba_shift;
182
- nlb = (BS >> lba_shift) - 1;
162
+ nlb = (total_len >> lba_shift) - 1;
183
163
 
184
164
  /* cdw10 and cdw11 represent starting lba */
185
165
  cmd->cdw10 = slba & 0xffffffff;
186
166
  cmd->cdw11 = slba >> 32;
187
167
  /* cdw12 represent number of lba's for read/write */
188
168
  cmd->cdw12 = nlb;
189
- if (do_fixed || nonvec) {
169
+ if (nonvec) {
190
170
  cmd->addr = (__u64)(uintptr_t)vecs[i].iov_base;
191
171
  cmd->data_len = vecs[i].iov_len;
192
172
  } else {
193
173
  cmd->addr = (__u64)(uintptr_t)&vecs[i];
194
- cmd->data_len = 1;
174
+ cmd->data_len = iovcnt;
175
+ }
176
+
177
+ if (meta_size) {
178
+ cmd->metadata = (__u64)(uintptr_t)(meta_mem +
179
+ meta_size * i * (nlb + 1));
180
+ cmd->metadata_len = meta_size * (nlb + 1);
195
181
  }
196
182
  cmd->nsid = nsid;
197
183
 
198
- offset += BS;
184
+ offset += total_len;
185
+ if (!nonvec)
186
+ i += iovcnt - 1;
187
+ submit_count++;
199
188
  }
200
189
 
201
190
  ret = io_uring_submit(ring);
202
- if (ret != BUFFERS) {
191
+ if (ret != submit_count) {
203
192
  fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
204
193
  goto err;
205
194
  }
206
195
 
207
- for (i = 0; i < BUFFERS; i++) {
196
+ for (i = 0; i < submit_count; i++) {
208
197
  ret = io_uring_wait_cqe(ring, &cqe);
209
198
  if (ret) {
210
199
  fprintf(stderr, "wait_cqe=%d\n", ret);
211
200
  goto err;
212
201
  }
213
202
  if (cqe->res != 0) {
203
+ if (cqe->res == -EINVAL && fixed && !nonvec) {
204
+ vec_fixed_supported = false;
205
+ goto cleanup_and_skip;
206
+ }
214
207
  if (!no_pt) {
215
208
  no_pt = 1;
216
209
  goto skip;
@@ -229,6 +222,7 @@ static int __test_io(const char *file, struct io_uring *ring, int tc, int read,
229
222
  }
230
223
  }
231
224
 
225
+ cleanup_and_skip:
232
226
  if (fixed) {
233
227
  ret = io_uring_unregister_buffers(ring);
234
228
  if (ret) {
@@ -254,7 +248,7 @@ err:
254
248
  }
255
249
 
256
250
  static int test_io(const char *file, int tc, int read, int sqthread,
257
- int fixed, int nonvec)
251
+ int fixed, int nonvec, int hybrid)
258
252
  {
259
253
  struct io_uring ring;
260
254
  int ret, ring_flags = 0;
@@ -265,6 +259,12 @@ static int test_io(const char *file, int tc, int read, int sqthread,
265
259
  if (sqthread)
266
260
  ring_flags |= IORING_SETUP_SQPOLL;
267
261
 
262
+ if (hybrid)
263
+ ring_flags |= IORING_SETUP_IOPOLL | IORING_SETUP_HYBRID_IOPOLL;
264
+
265
+ if (fixed && (!vec_fixed_supported && !nonvec))
266
+ return 0;
267
+
268
268
  ret = t_create_ring(64, &ring, ring_flags);
269
269
  if (ret == T_SETUP_SKIP)
270
270
  return 0;
@@ -401,6 +401,12 @@ static int test_io_uring_submit_enters(const char *file)
401
401
  cmd->addr = (__u64)(uintptr_t)&vecs[i];
402
402
  cmd->data_len = 1;
403
403
  cmd->nsid = nsid;
404
+
405
+ if (meta_size) {
406
+ cmd->metadata = (__u64)(uintptr_t)(meta_mem +
407
+ meta_size * i * (nlb + 1));
408
+ cmd->metadata_len = meta_size * (nlb + 1);
409
+ }
404
410
  }
405
411
 
406
412
  /* submit manually to avoid adding IORING_ENTER_GETEVENTS */
@@ -447,20 +453,30 @@ int main(int argc, char *argv[])
447
453
  if (ret)
448
454
  return T_EXIT_SKIP;
449
455
 
450
- vecs = t_create_buffers(BUFFERS, BS);
456
+ vecs = t_malloc(BUFFERS * sizeof(struct iovec));
457
+ backing_vec = t_create_buffers(1, BUFFERS * BS);
458
+ /* Slice single large backing_vec into multiple smaller vecs */
459
+ for (int i = 0; i < BUFFERS; i++) {
460
+ vecs[i].iov_base = backing_vec[0].iov_base + i * BS;
461
+ vecs[i].iov_len = BS;
462
+ }
463
+ if (meta_size)
464
+ t_posix_memalign(&meta_mem, 0x1000,
465
+ meta_size * BUFFERS * (BS >> lba_shift));
451
466
 
452
- for (i = 0; i < 16; i++) {
467
+ for (i = 0; i < 32; i++) {
453
468
  int read = (i & 1) != 0;
454
469
  int sqthread = (i & 2) != 0;
455
470
  int fixed = (i & 4) != 0;
456
471
  int nonvec = (i & 8) != 0;
472
+ int hybrid = (i & 16) != 0;
457
473
 
458
- ret = test_io(fname, i, read, sqthread, fixed, nonvec);
474
+ ret = test_io(fname, i, read, sqthread, fixed, nonvec, hybrid);
459
475
  if (no_pt)
460
476
  break;
461
477
  if (ret) {
462
- fprintf(stderr, "test_io failed %d/%d/%d/%d\n",
463
- read, sqthread, fixed, nonvec);
478
+ fprintf(stderr, "test_io failed %d/%d/%d/%d/%d\n",
479
+ read, sqthread, fixed, nonvec, hybrid);
464
480
  goto err;
465
481
  }
466
482
  }
@@ -73,14 +73,15 @@ int main(int argc, char *argv[])
73
73
  char *fname;
74
74
  int ret, fd;
75
75
 
76
- p.flags = IORING_SETUP_IOPOLL | IORING_SETUP_CQSIZE;
76
+ p.flags = IORING_SETUP_IOPOLL | IORING_SETUP_CQSIZE |
77
+ IORING_SETUP_SUBMIT_ALL;
77
78
  p.cq_entries = 64;
78
79
  ret = t_create_ring_params(64, &ring, &p);
79
- if (ret == T_SETUP_SKIP)
80
- return 0;
80
+ if (ret == T_SETUP_SKIP || ret == -EINVAL)
81
+ return T_EXIT_SKIP;
81
82
  if (ret != T_SETUP_OK) {
82
83
  fprintf(stderr, "ring create failed: %d\n", ret);
83
- return 1;
84
+ return T_EXIT_FAIL;
84
85
  }
85
86
 
86
87
  if (argc > 1) {
@@ -23,6 +23,7 @@
23
23
  static struct iovec *vecs;
24
24
  static int no_buf_select;
25
25
  static int no_iopoll;
26
+ static int no_hybrid;
26
27
 
27
28
  static int provide_buffers(struct io_uring *ring)
28
29
  {
@@ -351,7 +352,7 @@ ok:
351
352
  }
352
353
 
353
354
  static int test_io(const char *file, int write, int sqthread, int fixed,
354
- int buf_select, int defer)
355
+ int hybrid, int buf_select, int defer)
355
356
  {
356
357
  struct io_uring ring;
357
358
  int ret, ring_flags = IORING_SETUP_IOPOLL;
@@ -363,10 +364,18 @@ static int test_io(const char *file, int write, int sqthread, int fixed,
363
364
  ring_flags |= IORING_SETUP_SINGLE_ISSUER |
364
365
  IORING_SETUP_DEFER_TASKRUN;
365
366
 
367
+ if (hybrid)
368
+ ring_flags |= IORING_SETUP_HYBRID_IOPOLL;
369
+
366
370
  ret = t_create_ring(64, &ring, ring_flags);
367
- if (ret == T_SETUP_SKIP)
371
+ if (ret == T_SETUP_SKIP) {
368
372
  return 0;
373
+ }
369
374
  if (ret != T_SETUP_OK) {
375
+ if (ring_flags & IORING_SETUP_HYBRID_IOPOLL) {
376
+ no_hybrid = 1;
377
+ return 0;
378
+ }
370
379
  fprintf(stderr, "ring create failed: %d\n", ret);
371
380
  return 1;
372
381
  }
@@ -418,22 +427,23 @@ int main(int argc, char *argv[])
418
427
 
419
428
  vecs = t_create_buffers(BUFFERS, BS);
420
429
 
421
- nr = 32;
430
+ nr = 64;
422
431
  if (no_buf_select)
423
- nr = 8;
424
- else if (!t_probe_defer_taskrun())
425
432
  nr = 16;
433
+ else if (!t_probe_defer_taskrun())
434
+ nr = 32;
426
435
  for (i = 0; i < nr; i++) {
427
436
  int write = (i & 1) != 0;
428
437
  int sqthread = (i & 2) != 0;
429
438
  int fixed = (i & 4) != 0;
430
- int buf_select = (i & 8) != 0;
431
- int defer = (i & 16) != 0;
439
+ int hybrid = (i & 8) != 0;
440
+ int buf_select = (i & 16) != 0;
441
+ int defer = (i & 32) != 0;
432
442
 
433
- ret = test_io(fname, write, sqthread, fixed, buf_select, defer);
443
+ ret = test_io(fname, write, sqthread, fixed, hybrid, buf_select, defer);
434
444
  if (ret) {
435
- fprintf(stderr, "test_io failed %d/%d/%d/%d/%d\n",
436
- write, sqthread, fixed, buf_select, defer);
445
+ fprintf(stderr, "test_io failed %d/%d/%d/%d/%d/%d\n",
446
+ write, sqthread, fixed, hybrid, buf_select, defer);
437
447
  goto err;
438
448
  }
439
449
  if (no_iopoll)