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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/examples/bm_side_running.rb +83 -0
  4. data/examples/bm_sqlite.rb +1 -1
  5. data/ext/um/um.c +17 -1
  6. data/ext/um/um.h +29 -0
  7. data/ext/um/um_ext.c +2 -0
  8. data/ext/um/um_stream.c +344 -0
  9. data/ext/um/um_stream_class.c +140 -0
  10. data/lib/uringmachine/version.rb +1 -1
  11. data/lib/uringmachine.rb +20 -16
  12. data/test/test_stream.rb +133 -0
  13. data/test/test_um.rb +63 -0
  14. data/vendor/liburing/.github/workflows/{build.yml → ci.yml} +107 -42
  15. data/vendor/liburing/.gitignore +1 -0
  16. data/vendor/liburing/CHANGELOG +10 -0
  17. data/vendor/liburing/README +5 -0
  18. data/vendor/liburing/configure +1 -1
  19. data/vendor/liburing/examples/Makefile +1 -0
  20. data/vendor/liburing/examples/helpers.c +25 -0
  21. data/vendor/liburing/examples/helpers.h +13 -0
  22. data/vendor/liburing/examples/io_uring-test.c +3 -0
  23. data/vendor/liburing/examples/proxy.c +1 -1
  24. data/vendor/liburing/examples/reg-wait.c +41 -6
  25. data/vendor/liburing/examples/send-zerocopy.c +79 -32
  26. data/vendor/liburing/examples/zcrx.c +436 -0
  27. data/vendor/liburing/liburing.spec +1 -1
  28. data/vendor/liburing/src/Makefile +0 -1
  29. data/vendor/liburing/src/arch/generic/syscall.h +2 -2
  30. data/vendor/liburing/src/arch/syscall-defs.h +2 -2
  31. data/vendor/liburing/src/include/liburing/io_uring.h +101 -17
  32. data/vendor/liburing/src/include/liburing.h +179 -59
  33. data/vendor/liburing/src/int_flags.h +4 -1
  34. data/vendor/liburing/src/liburing-ffi.map +14 -2
  35. data/vendor/liburing/src/liburing.map +9 -2
  36. data/vendor/liburing/src/queue.c +35 -30
  37. data/vendor/liburing/src/register.c +46 -15
  38. data/vendor/liburing/src/sanitize.c +6 -9
  39. data/vendor/liburing/src/setup.c +37 -71
  40. data/vendor/liburing/src/syscall.c +2 -2
  41. data/vendor/liburing/test/232c93d07b74.c +1 -0
  42. data/vendor/liburing/test/Makefile +9 -0
  43. data/vendor/liburing/test/accept-test.c +1 -0
  44. data/vendor/liburing/test/cmd-discard.c +16 -8
  45. data/vendor/liburing/test/connect.c +11 -7
  46. data/vendor/liburing/test/epwait.c +420 -0
  47. data/vendor/liburing/test/eventfd-ring.c +30 -5
  48. data/vendor/liburing/test/fallocate.c +1 -1
  49. data/vendor/liburing/test/fixed-hugepage.c +10 -7
  50. data/vendor/liburing/test/fixed-seg.c +187 -0
  51. data/vendor/liburing/test/helpers.c +121 -0
  52. data/vendor/liburing/test/helpers.h +13 -0
  53. data/vendor/liburing/test/init-mem.c +2 -0
  54. data/vendor/liburing/test/io_uring_passthrough.c +78 -62
  55. data/vendor/liburing/test/iopoll-overflow.c +5 -4
  56. data/vendor/liburing/test/iopoll.c +20 -10
  57. data/vendor/liburing/test/iowait.c +141 -0
  58. data/vendor/liburing/test/nvme.h +2 -0
  59. data/vendor/liburing/test/pipe-bug.c +11 -5
  60. data/vendor/liburing/test/pipe-eof.c +11 -1
  61. data/vendor/liburing/test/read-inc-file.c +150 -0
  62. data/vendor/liburing/test/read-write.c +21 -14
  63. data/vendor/liburing/test/recv-bundle-short-ooo.c +435 -0
  64. data/vendor/liburing/test/recv-multishot.c +2 -2
  65. data/vendor/liburing/test/reg-wait.c +449 -120
  66. data/vendor/liburing/test/regbuf-clone.c +53 -0
  67. data/vendor/liburing/test/resize-rings.c +25 -2
  68. data/vendor/liburing/test/rsrc_tags.c +67 -14
  69. data/vendor/liburing/test/send-zerocopy.c +52 -130
  70. data/vendor/liburing/test/sendmsg_iov_clean.c +216 -0
  71. data/vendor/liburing/test/socket-nb.c +158 -0
  72. data/vendor/liburing/test/sqwait.c +9 -11
  73. data/vendor/liburing/test/timeout.c +198 -0
  74. data/vendor/liburing/test/vec-regbuf.c +609 -0
  75. data/vendor/liburing/test/wait-timeout.c +1 -1
  76. data/vendor/liburing/test/wq-aff.c +5 -1
  77. data/vendor/liburing/test/zcrx.c +928 -0
  78. metadata +16 -4
  79. data/vendor/liburing/.github/workflows/codespell.yml +0 -25
  80. data/vendor/liburing/.github/workflows/shellcheck.yml +0 -20
@@ -43,6 +43,8 @@
43
43
 
44
44
  #include "liburing.h"
45
45
 
46
+ #define PATTERN_SIZE 26
47
+
46
48
  #define ZC_TAG 0xfffffffULL
47
49
  #define MAX_SUBMIT_NR 512
48
50
  #define MAX_THREADS 100
@@ -68,6 +70,7 @@ static bool cfg_defer_taskrun = 0;
68
70
  static int cfg_cpu = -1;
69
71
  static bool cfg_rx = 0;
70
72
  static unsigned cfg_nr_threads = 1;
73
+ static const char *cfg_ifname;
71
74
 
72
75
  static int cfg_family = PF_UNSPEC;
73
76
  static int cfg_type = 0;
@@ -75,11 +78,12 @@ static int cfg_payload_len;
75
78
  static int cfg_port = 8000;
76
79
  static int cfg_runtime_ms = 4200;
77
80
  static bool cfg_rx_poll = false;
81
+ static bool cfg_verify;
78
82
 
79
83
  static socklen_t cfg_alen;
80
84
  static char *str_addr = NULL;
81
85
 
82
- static char payload_buf[IP_MAXPACKET] __attribute__((aligned(4096)));
86
+ static char payload_buf[IP_MAXPACKET + PATTERN_SIZE] __attribute__((aligned(4096)));
83
87
  static char *payload;
84
88
  static struct thread_data threads[MAX_THREADS];
85
89
  static pthread_barrier_t barrier;
@@ -343,6 +347,16 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
343
347
  if (fd == -1)
344
348
  t_error(1, errno, "socket t");
345
349
 
350
+ if (cfg_ifname) {
351
+ struct ifreq ifr;
352
+
353
+ memset(&ifr, 0, sizeof(ifr));
354
+ strncpy(ifr.ifr_name, cfg_ifname, sizeof(ifr.ifr_name));
355
+
356
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
357
+ t_error(1, errno, "Binding to device failed\n");
358
+ }
359
+
346
360
  if (connect(fd, (void *)&td->dst_addr, cfg_alen))
347
361
  t_error(1, errno, "connect, idx %i", td->idx);
348
362
 
@@ -365,7 +379,7 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
365
379
  }
366
380
 
367
381
  iov.iov_base = payload;
368
- iov.iov_len = cfg_payload_len;
382
+ iov.iov_len = cfg_payload_len + PATTERN_SIZE;
369
383
 
370
384
  ret = io_uring_register_buffers(&ring, &iov, 1);
371
385
  if (ret)
@@ -392,13 +406,18 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
392
406
  unsigned msg_flags = MSG_WAITALL;
393
407
 
394
408
  for (i = 0; i < cfg_nr_reqs; i++) {
409
+ char *buf = payload;
410
+
411
+ if (cfg_verify && cfg_type == SOCK_STREAM)
412
+ buf += td->bytes % PATTERN_SIZE;
413
+
395
414
  sqe = io_uring_get_sqe(&ring);
396
415
 
397
416
  if (!cfg_zc)
398
- io_uring_prep_send(sqe, fd, payload,
417
+ io_uring_prep_send(sqe, fd, buf,
399
418
  cfg_payload_len, 0);
400
419
  else {
401
- io_uring_prep_send_zc(sqe, fd, payload,
420
+ io_uring_prep_send_zc(sqe, fd, buf,
402
421
  cfg_payload_len, msg_flags, 0);
403
422
  if (cfg_fixed_buf) {
404
423
  sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
@@ -439,7 +458,7 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
439
458
  td->bytes += cqe->res;
440
459
  } else if (cqe->res == -ECONNREFUSED || cqe->res == -EPIPE ||
441
460
  cqe->res == -ECONNRESET) {
442
- fprintf(stderr, "Connection failure\n");
461
+ printf("Connection failure %i\n", cqe->res);
443
462
  goto out_fail;
444
463
  } else if (cqe->res != -EAGAIN) {
445
464
  t_error(1, cqe->res, "send failed");
@@ -450,9 +469,9 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
450
469
  break;
451
470
  } while ((++loop % 16 != 0) || gettimeofday_ms() < tstart + cfg_runtime_ms);
452
471
 
472
+ out_fail:
453
473
  td->dt_ms = gettimeofday_ms() - tstart;
454
474
 
455
- out_fail:
456
475
  shutdown(fd, SHUT_RDWR);
457
476
  if (close(fd))
458
477
  t_error(1, errno, "close");
@@ -488,7 +507,6 @@ static void usage(const char *filepath)
488
507
  printf(" -D <address>\tDestination address\n");
489
508
  printf(" -p <port>\tServer port to listen on/connect to\n");
490
509
  printf(" -s <size>\tBytes per request\n");
491
- printf(" -s <size>\tBytes per request\n");
492
510
  printf(" -n <nr>\tNumber of parallel requests\n");
493
511
  printf(" -z <mode>\tZerocopy mode, 0 to disable, enabled otherwise\n");
494
512
  printf(" -b <mode>\tUse registered buffers\n");
@@ -502,6 +520,7 @@ static void usage(const char *filepath)
502
520
 
503
521
  static void parse_opts(int argc, char **argv)
504
522
  {
523
+ const char *cfg_test;
505
524
  const int max_payload_len = IP_MAXPACKET -
506
525
  sizeof(struct ipv6hdr) -
507
526
  sizeof(struct tcphdr) -
@@ -516,7 +535,7 @@ static void parse_opts(int argc, char **argv)
516
535
 
517
536
  cfg_payload_len = max_payload_len;
518
537
 
519
- while ((c = getopt(argc, argv, "46D:p:s:t:n:z:b:l:dC:T:Ry")) != -1) {
538
+ while ((c = getopt(argc, argv, "46D:p:s:t:n:z:I:b:l:dC:T:Ryv")) != -1) {
520
539
  switch (c) {
521
540
  case '4':
522
541
  if (cfg_family != PF_UNSPEC)
@@ -530,6 +549,9 @@ static void parse_opts(int argc, char **argv)
530
549
  cfg_family = PF_INET6;
531
550
  cfg_alen = sizeof(struct sockaddr_in6);
532
551
  break;
552
+ case 'I':
553
+ cfg_ifname = optarg;
554
+ break;
533
555
  case 'D':
534
556
  daddr = optarg;
535
557
  break;
@@ -568,16 +590,38 @@ static void parse_opts(int argc, char **argv)
568
590
  case 'R':
569
591
  cfg_rx = 1;
570
592
  break;
593
+ case 'v':
594
+ cfg_verify = true;
595
+ break;
571
596
  case 'y':
572
597
  cfg_rx_poll = 1;
573
598
  break;
574
599
  }
575
600
  }
576
601
 
602
+ cfg_test = argv[argc - 1];
603
+ if (!strcmp(cfg_test, "tcp"))
604
+ cfg_type = SOCK_STREAM;
605
+ else if (!strcmp(cfg_test, "udp"))
606
+ cfg_type = SOCK_DGRAM;
607
+ else
608
+ t_error(1, 0, "unknown cfg_test %s", cfg_test);
609
+
577
610
  if (cfg_nr_reqs > MAX_SUBMIT_NR)
578
611
  t_error(1, 0, "-n: submit batch nr exceeds max (%d)", MAX_SUBMIT_NR);
579
612
  if (cfg_payload_len > max_payload_len)
580
613
  t_error(1, 0, "-s: payload exceeds max (%d)", max_payload_len);
614
+ if (!cfg_nr_reqs)
615
+ t_error(1, 0, "-n: submit batch can't be zero");
616
+ if (cfg_ifname && cfg_rx)
617
+ t_error(1, 0, "Interface can only be specified for tx");
618
+ if (cfg_nr_reqs > 1 && cfg_type == SOCK_STREAM) {
619
+ printf("warning: submit batching >1 with TCP sockets will cause data reordering");
620
+ if (cfg_verify)
621
+ t_error(1, 0, "can't verify data because of reordering");
622
+ }
623
+ if (cfg_rx && cfg_verify)
624
+ t_error(1, 0, "Server mode doesn't support data verification");
581
625
 
582
626
  str_addr = daddr;
583
627
 
@@ -585,42 +629,45 @@ static void parse_opts(int argc, char **argv)
585
629
  usage(argv[0]);
586
630
  }
587
631
 
632
+ static void init_buffers(void)
633
+ {
634
+ size_t size;
635
+ int i;
636
+
637
+ payload = payload_buf;
638
+ size = sizeof(payload_buf);
639
+
640
+ if (cfg_hugetlb) {
641
+ size = 1 << 21;
642
+ payload = mmap(NULL, size, PROT_READ | PROT_WRITE,
643
+ MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_2MB | MAP_ANONYMOUS,
644
+ -1, 0);
645
+ if (payload == MAP_FAILED)
646
+ t_error(0, 1, "huge pages alloc failed");
647
+ }
648
+
649
+ if (cfg_payload_len + PATTERN_SIZE > size)
650
+ t_error(1, 0, "Buffers are too small");
651
+
652
+ if (cfg_verify) {
653
+ for (i = 0; i < size; i++)
654
+ payload[i] = 'a' + (i % PATTERN_SIZE);
655
+ }
656
+ }
657
+
588
658
  int main(int argc, char **argv)
589
659
  {
590
660
  unsigned long long tsum = 0;
591
661
  unsigned long long packets = 0, bytes = 0;
592
662
  struct thread_data *td;
593
- const char *cfg_test;
594
663
  unsigned int i;
595
664
  void *res;
596
665
 
597
666
  parse_opts(argc, argv);
667
+ init_buffers();
598
668
  set_cpu_affinity();
599
669
 
600
- payload = payload_buf;
601
- if (cfg_hugetlb) {
602
- payload = mmap(NULL, 2*1024*1024, PROT_READ | PROT_WRITE,
603
- MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_2MB | MAP_ANONYMOUS,
604
- -1, 0);
605
- if (payload == MAP_FAILED) {
606
- fprintf(stderr, "hugetlb alloc failed\n");
607
- return 1;
608
- }
609
- }
610
-
611
- cfg_test = argv[argc - 1];
612
- if (!strcmp(cfg_test, "tcp"))
613
- cfg_type = SOCK_STREAM;
614
- else if (!strcmp(cfg_test, "udp"))
615
- cfg_type = SOCK_DGRAM;
616
- else
617
- t_error(1, 0, "unknown cfg_test %s", cfg_test);
618
-
619
670
  pthread_barrier_init(&barrier, NULL, cfg_nr_threads);
620
-
621
- for (i = 0; i < IP_MAXPACKET; i++)
622
- payload[i] = 'a' + (i % 26);
623
-
624
671
  for (i = 0; i < cfg_nr_threads; i++) {
625
672
  td = &threads[i];
626
673
  td->idx = i;
@@ -0,0 +1,436 @@
1
+ // SPDX-License-Identifier: GPL-2.0
2
+ #include <assert.h>
3
+ #include <errno.h>
4
+ #include <error.h>
5
+ #include <fcntl.h>
6
+ #include <limits.h>
7
+ #include <stdbool.h>
8
+ #include <stdint.h>
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+ #include <string.h>
12
+ #include <unistd.h>
13
+ #include <stdarg.h>
14
+
15
+ #include <arpa/inet.h>
16
+ #include <linux/errqueue.h>
17
+ #include <linux/if_packet.h>
18
+ #include <linux/ipv6.h>
19
+ #include <linux/socket.h>
20
+ #include <linux/sockios.h>
21
+ #include <net/ethernet.h>
22
+ #include <net/if.h>
23
+ #include <netinet/in.h>
24
+ #include <netinet/ip.h>
25
+ #include <netinet/ip6.h>
26
+ #include <netinet/tcp.h>
27
+ #include <netinet/udp.h>
28
+ #include <sys/epoll.h>
29
+ #include <sys/ioctl.h>
30
+ #include <sys/mman.h>
31
+ #include <sys/resource.h>
32
+ #include <sys/socket.h>
33
+ #include <sys/stat.h>
34
+ #include <sys/time.h>
35
+ #include <sys/types.h>
36
+ #include <sys/un.h>
37
+ #include <sys/wait.h>
38
+ #include <linux/mman.h>
39
+
40
+ #include <linux/memfd.h>
41
+ #include <linux/dma-buf.h>
42
+ #include <linux/udmabuf.h>
43
+
44
+ #include "liburing.h"
45
+ #include "helpers.h"
46
+
47
+ enum {
48
+ RQ_ALLOC_USER,
49
+ RQ_ALLOC_KERNEL,
50
+
51
+ __RQ_ALLOC_MAX,
52
+ };
53
+
54
+ static long page_size;
55
+ #define AREA_SIZE (8192 * page_size)
56
+
57
+ #define REQ_TYPE_SHIFT 3
58
+ #define REQ_TYPE_MASK ((1UL << REQ_TYPE_SHIFT) - 1)
59
+
60
+ enum {
61
+ AREA_TYPE_NORMAL,
62
+ AREA_TYPE_HUGE_PAGES,
63
+ AREA_TYPE_DMABUF,
64
+ __AREA_TYPE_MAX,
65
+ };
66
+
67
+ enum {
68
+ REQ_TYPE_ACCEPT = 1,
69
+ REQ_TYPE_RX = 2,
70
+ };
71
+
72
+ static int cfg_port = 8000;
73
+ static const char *cfg_ifname;
74
+ static int cfg_queue_id = -1;
75
+ static bool cfg_verify_data = false;
76
+ static size_t cfg_size = 0;
77
+ static unsigned cfg_rq_alloc_mode = RQ_ALLOC_USER;
78
+ static unsigned cfg_area_type = AREA_TYPE_NORMAL;
79
+ static struct sockaddr_in6 cfg_addr;
80
+
81
+ static void *area_ptr;
82
+ static void *ring_ptr;
83
+ static size_t ring_size;
84
+ static struct io_uring_zcrx_rq rq_ring;
85
+ static unsigned long area_token;
86
+ static int connfd;
87
+ static bool stop;
88
+ static size_t received;
89
+ static __u32 zcrx_id;
90
+
91
+ static int dmabuf_fd;
92
+ static int memfd;
93
+
94
+ static inline size_t get_refill_ring_size(unsigned int rq_entries)
95
+ {
96
+ ring_size = rq_entries * sizeof(struct io_uring_zcrx_rqe);
97
+ /* add space for the header (head/tail/etc.) */
98
+ ring_size += page_size;
99
+ return T_ALIGN_UP(ring_size, page_size);
100
+ }
101
+
102
+ static void zcrx_populate_area_udmabuf(struct io_uring_zcrx_area_reg *area_reg)
103
+ {
104
+ struct udmabuf_create create;
105
+ int ret, devfd;
106
+
107
+ devfd = open("/dev/udmabuf", O_RDWR);
108
+ if (devfd < 0)
109
+ t_error(1, devfd, "Failed to open udmabuf dev");
110
+
111
+ memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);
112
+ if (memfd < 0)
113
+ t_error(1, memfd, "Failed to open udmabuf dev");
114
+
115
+ ret = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);
116
+ if (ret < 0)
117
+ t_error(1, 0, "Failed to set seals");
118
+
119
+ ret = ftruncate(memfd, AREA_SIZE);
120
+ if (ret == -1)
121
+ t_error(1, 0, "Failed to resize udmabuf");
122
+
123
+ memset(&create, 0, sizeof(create));
124
+ create.memfd = memfd;
125
+ create.offset = 0;
126
+ create.size = AREA_SIZE;
127
+ dmabuf_fd = ioctl(devfd, UDMABUF_CREATE, &create);
128
+ if (dmabuf_fd < 0)
129
+ t_error(1, dmabuf_fd, "Failed to create udmabuf");
130
+
131
+ area_ptr = mmap(NULL, AREA_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
132
+ dmabuf_fd, 0);
133
+ if (area_ptr == MAP_FAILED)
134
+ t_error(1, 0, "Failed to mmap udmabuf");
135
+
136
+ memset(area_reg, 0, sizeof(*area_reg));
137
+ area_reg->addr = 0; /* offset into dmabuf */
138
+ area_reg->len = AREA_SIZE;
139
+ area_reg->flags |= IORING_ZCRX_AREA_DMABUF;
140
+ area_reg->dmabuf_fd = dmabuf_fd;
141
+
142
+ close(devfd);
143
+ }
144
+
145
+ static void zcrx_populate_area(struct io_uring_zcrx_area_reg *area_reg)
146
+ {
147
+ unsigned flags = MAP_PRIVATE | MAP_ANONYMOUS;
148
+ unsigned prot = PROT_READ | PROT_WRITE;
149
+
150
+ if (cfg_area_type == AREA_TYPE_DMABUF) {
151
+ zcrx_populate_area_udmabuf(area_reg);
152
+ return;
153
+ }
154
+ if (cfg_area_type == AREA_TYPE_NORMAL) {
155
+ area_ptr = mmap(NULL, AREA_SIZE, prot,
156
+ flags, 0, 0);
157
+ } else if (cfg_area_type == AREA_TYPE_HUGE_PAGES) {
158
+ area_ptr = mmap(NULL, AREA_SIZE, prot,
159
+ flags | MAP_HUGETLB | MAP_HUGE_2MB, -1, 0);
160
+ }
161
+
162
+ if (area_ptr == MAP_FAILED)
163
+ t_error(1, 0, "mmap(): area allocation failed");
164
+
165
+ memset(area_reg, 0, sizeof(*area_reg));
166
+ area_reg->addr = (__u64)(unsigned long)area_ptr;
167
+ area_reg->len = AREA_SIZE;
168
+ area_reg->flags = 0;
169
+ }
170
+
171
+ static void setup_zcrx(struct io_uring *ring)
172
+ {
173
+ struct io_uring_zcrx_area_reg area_reg;
174
+ unsigned int ifindex;
175
+ unsigned int rq_entries = 4096;
176
+ unsigned rq_flags = 0;
177
+ int ret;
178
+
179
+ ifindex = if_nametoindex(cfg_ifname);
180
+ if (!ifindex)
181
+ t_error(1, 0, "bad interface name: %s", cfg_ifname);
182
+
183
+ ring_size = get_refill_ring_size(rq_entries);
184
+ ring_ptr = NULL;
185
+ if (cfg_rq_alloc_mode == RQ_ALLOC_USER) {
186
+ ring_ptr = mmap(NULL, ring_size,
187
+ PROT_READ | PROT_WRITE,
188
+ MAP_ANONYMOUS | MAP_PRIVATE,
189
+ 0, 0);
190
+ if (ring_ptr == MAP_FAILED)
191
+ t_error(1, 0, "mmap(): refill ring");
192
+ rq_flags |= IORING_MEM_REGION_TYPE_USER;
193
+ }
194
+
195
+ struct io_uring_region_desc region_reg = {
196
+ .size = ring_size,
197
+ .user_addr = (__u64)(unsigned long)ring_ptr,
198
+ .flags = rq_flags,
199
+ };
200
+
201
+ zcrx_populate_area(&area_reg);
202
+
203
+ struct io_uring_zcrx_ifq_reg reg = {
204
+ .if_idx = ifindex,
205
+ .if_rxq = cfg_queue_id,
206
+ .rq_entries = rq_entries,
207
+ .area_ptr = (__u64)(unsigned long)&area_reg,
208
+ .region_ptr = (__u64)(unsigned long)&region_reg,
209
+ };
210
+
211
+ ret = io_uring_register_ifq(ring, &reg);
212
+ if (ret)
213
+ t_error(1, 0, "io_uring_register_ifq(): %d", ret);
214
+
215
+ if (cfg_rq_alloc_mode == RQ_ALLOC_KERNEL) {
216
+ ring_ptr = mmap(NULL, ring_size,
217
+ PROT_READ | PROT_WRITE,
218
+ MAP_SHARED | MAP_POPULATE,
219
+ ring->ring_fd, region_reg.mmap_offset);
220
+ if (ring_ptr == MAP_FAILED)
221
+ t_error(1, 0, "mmap(): refill ring");
222
+ }
223
+
224
+ rq_ring.khead = (unsigned int *)((char *)ring_ptr + reg.offsets.head);
225
+ rq_ring.ktail = (unsigned int *)((char *)ring_ptr + reg.offsets.tail);
226
+ rq_ring.rqes = (struct io_uring_zcrx_rqe *)((char *)ring_ptr + reg.offsets.rqes);
227
+ rq_ring.rq_tail = 0;
228
+ rq_ring.ring_entries = reg.rq_entries;
229
+
230
+ zcrx_id = reg.zcrx_id;
231
+ area_token = area_reg.rq_area_token;
232
+ }
233
+
234
+ static void add_accept(struct io_uring *ring, int sockfd)
235
+ {
236
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
237
+
238
+ io_uring_prep_accept(sqe, sockfd, NULL, NULL, 0);
239
+ sqe->user_data = REQ_TYPE_ACCEPT;
240
+ }
241
+
242
+ static void add_recvzc(struct io_uring *ring, int sockfd, size_t len)
243
+ {
244
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
245
+
246
+ io_uring_prep_rw(IORING_OP_RECV_ZC, sqe, sockfd, NULL, len, 0);
247
+ sqe->ioprio |= IORING_RECV_MULTISHOT;
248
+ sqe->zcrx_ifq_idx = zcrx_id;
249
+ sqe->user_data = REQ_TYPE_RX;
250
+ }
251
+
252
+ static void process_accept(struct io_uring *ring, struct io_uring_cqe *cqe)
253
+ {
254
+ if (cqe->res < 0)
255
+ t_error(1, 0, "accept()");
256
+ if (connfd)
257
+ t_error(1, 0, "Unexpected second connection");
258
+
259
+ connfd = cqe->res;
260
+ add_recvzc(ring, connfd, cfg_size);
261
+ }
262
+
263
+ static void verify_data(char *data, size_t size, unsigned long seq)
264
+ {
265
+ int i;
266
+
267
+ if (!cfg_verify_data)
268
+ return;
269
+
270
+ for (i = 0; i < size; i++) {
271
+ char expected = 'a' + (seq + i) % 26;
272
+
273
+ if (data[i] != expected)
274
+ t_error(1, 0, "payload mismatch at %i: expected %i vs got %i, seq %li",
275
+ i, expected, data[i], seq);
276
+ }
277
+ }
278
+
279
+ static void process_recvzc(struct io_uring __attribute__((unused)) *ring,
280
+ struct io_uring_cqe *cqe)
281
+ {
282
+ unsigned rq_mask = rq_ring.ring_entries - 1;
283
+ struct io_uring_zcrx_cqe *rcqe;
284
+ struct io_uring_zcrx_rqe *rqe;
285
+ uint64_t mask;
286
+ char *data;
287
+
288
+ if (!(cqe->flags & IORING_CQE_F_MORE)) {
289
+ if (!cfg_size || cqe->res != 0)
290
+ t_error(1, 0, "invalid final recvzc ret %i", cqe->res);
291
+ if (received != cfg_size)
292
+ t_error(1, 0, "total receive size mismatch %lu / %lu",
293
+ received, cfg_size);
294
+ stop = true;
295
+ return;
296
+ }
297
+ if (cqe->res < 0)
298
+ t_error(1, 0, "recvzc(): %d", cqe->res);
299
+
300
+ rcqe = (struct io_uring_zcrx_cqe *)(cqe + 1);
301
+ mask = (1ULL << IORING_ZCRX_AREA_SHIFT) - 1;
302
+ data = (char *)area_ptr + (rcqe->off & mask);
303
+
304
+ verify_data(data, cqe->res, received);
305
+ received += cqe->res;
306
+
307
+ /* processed, return back to the kernel */
308
+ rqe = &rq_ring.rqes[rq_ring.rq_tail & rq_mask];
309
+ rqe->off = (rcqe->off & ~IORING_ZCRX_AREA_MASK) | area_token;
310
+ rqe->len = cqe->res;
311
+ io_uring_smp_store_release(rq_ring.ktail, ++rq_ring.rq_tail);
312
+ }
313
+
314
+ static void server_loop(struct io_uring *ring)
315
+ {
316
+ struct io_uring_cqe *cqe;
317
+ unsigned int head, count = 0;
318
+
319
+ io_uring_submit_and_wait(ring, 1);
320
+
321
+ io_uring_for_each_cqe(ring, head, cqe) {
322
+ switch (cqe->user_data & REQ_TYPE_MASK) {
323
+ case REQ_TYPE_ACCEPT:
324
+ process_accept(ring, cqe);
325
+ break;
326
+ case REQ_TYPE_RX:
327
+ process_recvzc(ring, cqe);
328
+ break;
329
+ default:
330
+ t_error(1, 0, "unknown cqe");
331
+ }
332
+ count++;
333
+ }
334
+ io_uring_cq_advance(ring, count);
335
+ }
336
+
337
+ static void run_server(void)
338
+ {
339
+ unsigned int flags = 0;
340
+ struct io_uring ring;
341
+ int fd, enable, ret;
342
+
343
+ fd = socket(AF_INET6, SOCK_STREAM, 0);
344
+ if (fd == -1)
345
+ t_error(1, 0, "socket()");
346
+
347
+ enable = 1;
348
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
349
+ if (ret < 0)
350
+ t_error(1, 0, "setsockopt(SO_REUSEADDR)");
351
+
352
+ ret = bind(fd, (struct sockaddr *)&cfg_addr, sizeof(cfg_addr));
353
+ if (ret < 0)
354
+ t_error(1, 0, "bind()");
355
+
356
+ if (listen(fd, 1024) < 0)
357
+ t_error(1, 0, "listen()");
358
+
359
+ flags |= IORING_SETUP_COOP_TASKRUN;
360
+ flags |= IORING_SETUP_SINGLE_ISSUER;
361
+ flags |= IORING_SETUP_DEFER_TASKRUN;
362
+ flags |= IORING_SETUP_SUBMIT_ALL;
363
+ flags |= IORING_SETUP_CQE32;
364
+
365
+ ret = io_uring_queue_init(512, &ring, flags);
366
+ if (ret)
367
+ t_error(1, ret, "ring init failed");
368
+
369
+ setup_zcrx(&ring);
370
+ add_accept(&ring, fd);
371
+
372
+ while (!stop)
373
+ server_loop(&ring);
374
+ }
375
+
376
+ static void usage(const char *filepath)
377
+ {
378
+ t_error(1, 0, "Usage: %s (-4|-6) -p<port> -i<ifname> -q<rxq_id>", filepath);
379
+ }
380
+
381
+ static void parse_opts(int argc, char **argv)
382
+ {
383
+ struct sockaddr_in6 *addr6 = (void *) &cfg_addr;
384
+ int c;
385
+
386
+ if (argc <= 1)
387
+ usage(argv[0]);
388
+
389
+ while ((c = getopt(argc, argv, "vp:i:q:s:r:A:")) != -1) {
390
+ switch (c) {
391
+ case 'p':
392
+ cfg_port = strtoul(optarg, NULL, 0);
393
+ break;
394
+ case 'i':
395
+ cfg_ifname = optarg;
396
+ break;
397
+ case 's':
398
+ cfg_size = strtoul(optarg, NULL, 0);
399
+ break;
400
+ case 'q':
401
+ cfg_queue_id = strtoul(optarg, NULL, 0);
402
+ break;
403
+ case 'v':
404
+ cfg_verify_data = true;
405
+ break;
406
+ case 'r':
407
+ cfg_rq_alloc_mode = strtoul(optarg, NULL, 0);
408
+ if (cfg_rq_alloc_mode >= __RQ_ALLOC_MAX)
409
+ t_error(1, 0, "invalid RQ allocation mode");
410
+ break;
411
+ case 'A':
412
+ cfg_area_type = strtoul(optarg, NULL, 0);
413
+ if (cfg_area_type >= __AREA_TYPE_MAX)
414
+ t_error(1, 0, "Invalid area type");
415
+ break;
416
+ }
417
+ }
418
+
419
+ memset(addr6, 0, sizeof(*addr6));
420
+ addr6->sin6_family = AF_INET6;
421
+ addr6->sin6_port = htons(cfg_port);
422
+ addr6->sin6_addr = in6addr_any;
423
+ }
424
+
425
+ int main(int argc, char **argv)
426
+ {
427
+ page_size = sysconf(_SC_PAGESIZE);
428
+ if (page_size < 0) {
429
+ perror("sysconf(_SC_PAGESIZE)");
430
+ return 1;
431
+ }
432
+
433
+ parse_opts(argc, argv);
434
+ run_server();
435
+ return 0;
436
+ }
@@ -1,5 +1,5 @@
1
1
  Name: liburing
2
- Version: 2.9
2
+ Version: 2.10
3
3
  Release: 1%{?dist}
4
4
  Summary: Linux-native io_uring I/O access library
5
5
  License: (GPLv2 with exceptions and LGPLv2+) or MIT
@@ -101,7 +101,6 @@ install: $(all_targets)
101
101
  install -D -m 644 include/liburing.h $(includedir)/liburing.h
102
102
  install -D -m 644 include/liburing/compat.h $(includedir)/liburing/compat.h
103
103
  install -D -m 644 include/liburing/barrier.h $(includedir)/liburing/barrier.h
104
- install -D -m 644 include/liburing/sanitize.h $(includedir)/liburing/sanitize.h
105
104
  install -D -m 644 include/liburing/io_uring_version.h $(includedir)/liburing/io_uring_version.h
106
105
  install -D -m 644 liburing.a $(libdevdir)/liburing.a
107
106
  install -D -m 644 liburing-ffi.a $(libdevdir)/liburing-ffi.a
@@ -23,12 +23,12 @@ static inline int __sys_io_uring_setup(unsigned int entries,
23
23
 
24
24
  static inline int __sys_io_uring_enter2(unsigned int fd, unsigned int to_submit,
25
25
  unsigned int min_complete,
26
- unsigned int flags, sigset_t *sig,
26
+ unsigned int flags, void *arg,
27
27
  size_t sz)
28
28
  {
29
29
  int ret;
30
30
  ret = syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags,
31
- sig, sz);
31
+ arg, sz);
32
32
  return (ret < 0) ? -errno : ret;
33
33
  }
34
34