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
@@ -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
|
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,
|
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
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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 = (
|
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 (
|
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 =
|
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 +=
|
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 !=
|
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 <
|
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 =
|
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 <
|
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
|
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
|
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 =
|
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
|
431
|
-
int
|
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)
|