Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2019 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : : #include "spdk/config.h"
8 : :
9 : : #include <linux/errqueue.h>
10 : : #include <sys/epoll.h>
11 : : #include <liburing.h>
12 : :
13 : : #include "spdk/barrier.h"
14 : : #include "spdk/env.h"
15 : : #include "spdk/log.h"
16 : : #include "spdk/pipe.h"
17 : : #include "spdk/sock.h"
18 : : #include "spdk/string.h"
19 : : #include "spdk/util.h"
20 : :
21 : : #include "spdk_internal/sock.h"
22 : : #include "spdk_internal/assert.h"
23 : : #include "spdk/net.h"
24 : :
25 : : #define MAX_TMPBUF 1024
26 : : #define PORTNUMLEN 32
27 : : #define SPDK_SOCK_GROUP_QUEUE_DEPTH 4096
28 : : #define SPDK_SOCK_CMG_INFO_SIZE (sizeof(struct cmsghdr) + sizeof(struct sock_extended_err))
29 : :
30 : : enum uring_task_type {
31 : : URING_TASK_READ = 0,
32 : : URING_TASK_ERRQUEUE,
33 : : URING_TASK_WRITE,
34 : : URING_TASK_CANCEL,
35 : : };
36 : :
37 : : #if defined(SO_ZEROCOPY) && defined(MSG_ZEROCOPY)
38 : : #define SPDK_ZEROCOPY
39 : : #endif
40 : :
41 : : /* We don't know how big the buffers that the user posts will be, but this
42 : : * is the maximum we'll ever allow it to receive in a single command.
43 : : * If the user buffers are smaller, it will just receive less. */
44 : : #define URING_MAX_RECV_SIZE (128 * 1024)
45 : :
46 : : /* We don't know how many buffers the user will post, but this is the
47 : : * maximum number we'll take from the pool to post per group. */
48 : : #define URING_BUF_POOL_SIZE 128
49 : :
50 : : /* We use 1 just so it's not zero and we can validate it's right. */
51 : : #define URING_BUF_GROUP_ID 1
52 : :
53 : : enum spdk_uring_sock_task_status {
54 : : SPDK_URING_SOCK_TASK_NOT_IN_USE = 0,
55 : : SPDK_URING_SOCK_TASK_IN_PROCESS,
56 : : };
57 : :
58 : : struct spdk_uring_task {
59 : : enum spdk_uring_sock_task_status status;
60 : : enum uring_task_type type;
61 : : struct spdk_uring_sock *sock;
62 : : struct msghdr msg;
63 : : struct iovec iovs[IOV_BATCH_SIZE];
64 : : int iov_cnt;
65 : : struct spdk_sock_request *last_req;
66 : : bool is_zcopy;
67 : : STAILQ_ENTRY(spdk_uring_task) link;
68 : : };
69 : :
70 : : struct spdk_uring_sock {
71 : : struct spdk_sock base;
72 : : int fd;
73 : : uint32_t sendmsg_idx;
74 : : struct spdk_uring_sock_group_impl *group;
75 : : STAILQ_HEAD(, spdk_uring_buf_tracker) recv_stream;
76 : : size_t recv_offset;
77 : : struct spdk_uring_task write_task;
78 : : struct spdk_uring_task errqueue_task;
79 : : struct spdk_uring_task read_task;
80 : : struct spdk_uring_task cancel_task;
81 : : struct spdk_pipe *recv_pipe;
82 : : void *recv_buf;
83 : : int recv_buf_sz;
84 : : bool zcopy;
85 : : bool pending_recv;
86 : : bool pending_group_remove;
87 : : int zcopy_send_flags;
88 : : int connection_status;
89 : : int placement_id;
90 : : uint8_t reserved[4];
91 : : uint8_t buf[SPDK_SOCK_CMG_INFO_SIZE];
92 : : TAILQ_ENTRY(spdk_uring_sock) link;
93 : : };
94 : : /* 'struct cmsghdr' is mapped to the buffer 'buf', and while first element
95 : : * of this control message header has a size of 8 bytes, 'buf'
96 : : * must be 8-byte aligned.
97 : : */
98 : : SPDK_STATIC_ASSERT(offsetof(struct spdk_uring_sock, buf) % 8 == 0,
99 : : "Incorrect alignment: `buf` must be aligned to 8 bytes");
100 : :
101 : : TAILQ_HEAD(pending_recv_list, spdk_uring_sock);
102 : :
103 : : struct spdk_uring_buf_tracker {
104 : : void *buf;
105 : : size_t buflen;
106 : : size_t len;
107 : : void *ctx;
108 : : int id;
109 : : STAILQ_ENTRY(spdk_uring_buf_tracker) link;
110 : : };
111 : :
112 : : struct spdk_uring_sock_group_impl {
113 : : struct spdk_sock_group_impl base;
114 : : struct io_uring uring;
115 : : uint32_t io_inflight;
116 : : uint32_t io_queued;
117 : : uint32_t io_avail;
118 : : struct pending_recv_list pending_recv;
119 : :
120 : : struct io_uring_buf_ring *buf_ring;
121 : : uint32_t buf_ring_count;
122 : : struct spdk_uring_buf_tracker *trackers;
123 : : STAILQ_HEAD(, spdk_uring_buf_tracker) free_trackers;
124 : : };
125 : :
126 : : static struct spdk_sock_impl_opts g_spdk_uring_sock_impl_opts = {
127 : : .recv_buf_size = DEFAULT_SO_RCVBUF_SIZE,
128 : : .send_buf_size = DEFAULT_SO_SNDBUF_SIZE,
129 : : .enable_recv_pipe = true,
130 : : .enable_quickack = false,
131 : : .enable_placement_id = PLACEMENT_NONE,
132 : : .enable_zerocopy_send_server = false,
133 : : .enable_zerocopy_send_client = false,
134 : : .zerocopy_threshold = 0,
135 : : .tls_version = 0,
136 : : .enable_ktls = false,
137 : : .psk_key = NULL,
138 : : .psk_identity = NULL
139 : : };
140 : :
141 : : static struct spdk_sock_map g_map = {
142 : : .entries = STAILQ_HEAD_INITIALIZER(g_map.entries),
143 : : .mtx = PTHREAD_MUTEX_INITIALIZER
144 : : };
145 : :
146 : : __attribute((destructor)) static void
147 : 379 : uring_sock_map_cleanup(void)
148 : : {
149 : 379 : spdk_sock_map_cleanup(&g_map);
150 : 379 : }
151 : :
152 : : #define SPDK_URING_SOCK_REQUEST_IOV(req) ((struct iovec *)((uint8_t *)req + sizeof(struct spdk_sock_request)))
153 : :
154 : : #define __uring_sock(sock) (struct spdk_uring_sock *)sock
155 : : #define __uring_group_impl(group) (struct spdk_uring_sock_group_impl *)group
156 : :
157 : : static void
158 : 35 : uring_sock_copy_impl_opts(struct spdk_sock_impl_opts *dest, const struct spdk_sock_impl_opts *src,
159 : : size_t len)
160 : : {
161 : : #define FIELD_OK(field) \
162 : : offsetof(struct spdk_sock_impl_opts, field) + sizeof(src->field) <= len
163 : :
164 : : #define SET_FIELD(field) \
165 : : if (FIELD_OK(field)) { \
166 : : dest->field = src->field; \
167 : : }
168 : :
169 [ + - ]: 35 : SET_FIELD(recv_buf_size);
170 [ + - ]: 35 : SET_FIELD(send_buf_size);
171 [ + - - + ]: 35 : SET_FIELD(enable_recv_pipe);
172 [ + - - + ]: 35 : SET_FIELD(enable_quickack);
173 [ + - ]: 35 : SET_FIELD(enable_placement_id);
174 [ + - - + ]: 35 : SET_FIELD(enable_zerocopy_send_server);
175 [ + - - + ]: 35 : SET_FIELD(enable_zerocopy_send_client);
176 [ + - ]: 35 : SET_FIELD(zerocopy_threshold);
177 [ + - ]: 35 : SET_FIELD(tls_version);
178 [ + - - + ]: 35 : SET_FIELD(enable_ktls);
179 [ + - ]: 35 : SET_FIELD(psk_key);
180 [ + - ]: 35 : SET_FIELD(psk_identity);
181 : :
182 : : #undef SET_FIELD
183 : : #undef FIELD_OK
184 : 35 : }
185 : :
186 : : static int
187 : 26 : uring_sock_impl_get_opts(struct spdk_sock_impl_opts *opts, size_t *len)
188 : : {
189 [ + - - + ]: 26 : if (!opts || !len) {
190 : 0 : errno = EINVAL;
191 : 0 : return -1;
192 : : }
193 : :
194 [ - + ]: 26 : assert(sizeof(*opts) >= *len);
195 [ - + ]: 26 : memset(opts, 0, *len);
196 : :
197 : 26 : uring_sock_copy_impl_opts(opts, &g_spdk_uring_sock_impl_opts, *len);
198 : 26 : *len = spdk_min(*len, sizeof(g_spdk_uring_sock_impl_opts));
199 : :
200 : 26 : return 0;
201 : : }
202 : :
203 : : static int
204 : 9 : uring_sock_impl_set_opts(const struct spdk_sock_impl_opts *opts, size_t len)
205 : : {
206 [ - + ]: 9 : if (!opts) {
207 : 0 : errno = EINVAL;
208 : 0 : return -1;
209 : : }
210 : :
211 [ - + ]: 9 : assert(sizeof(*opts) >= len);
212 : 9 : uring_sock_copy_impl_opts(&g_spdk_uring_sock_impl_opts, opts, len);
213 : :
214 : 9 : return 0;
215 : : }
216 : :
217 : : static void
218 : 509 : uring_opts_get_impl_opts(const struct spdk_sock_opts *opts, struct spdk_sock_impl_opts *dest)
219 : : {
220 : : /* Copy the default impl_opts first to cover cases when user's impl_opts is smaller */
221 [ - + - + ]: 509 : memcpy(dest, &g_spdk_uring_sock_impl_opts, sizeof(*dest));
222 : :
223 [ - + ]: 509 : if (opts->impl_opts != NULL) {
224 [ # # ]: 0 : assert(sizeof(*dest) >= opts->impl_opts_size);
225 : 0 : uring_sock_copy_impl_opts(dest, opts->impl_opts, opts->impl_opts_size);
226 : : }
227 : 509 : }
228 : :
229 : : static int
230 : 1276 : uring_sock_getaddr(struct spdk_sock *_sock, char *saddr, int slen, uint16_t *sport,
231 : : char *caddr, int clen, uint16_t *cport)
232 : : {
233 : 1276 : struct spdk_uring_sock *sock = __uring_sock(_sock);
234 : :
235 [ - + ]: 1276 : assert(sock != NULL);
236 : 1276 : return spdk_net_getaddr(sock->fd, saddr, slen, sport, caddr, clen, cport);
237 : : }
238 : :
239 : : enum uring_sock_create_type {
240 : : SPDK_SOCK_CREATE_LISTEN,
241 : : SPDK_SOCK_CREATE_CONNECT,
242 : : };
243 : :
244 : : static int
245 : 3701 : uring_sock_alloc_pipe(struct spdk_uring_sock *sock, int sz)
246 : : {
247 : : uint8_t *new_buf;
248 : : struct spdk_pipe *new_pipe;
249 : : struct iovec siov[2];
250 : : struct iovec diov[2];
251 : : int sbytes;
252 : : ssize_t bytes;
253 : : int rc;
254 : :
255 [ + + ]: 3701 : if (sock->recv_buf_sz == sz) {
256 : 2541 : return 0;
257 : : }
258 : :
259 : : /* If the new size is 0, just free the pipe */
260 [ - + ]: 1160 : if (sz == 0) {
261 : 0 : spdk_pipe_destroy(sock->recv_pipe);
262 : 0 : free(sock->recv_buf);
263 : 0 : sock->recv_pipe = NULL;
264 : 0 : sock->recv_buf = NULL;
265 : 0 : return 0;
266 [ - + ]: 1160 : } else if (sz < MIN_SOCK_PIPE_SIZE) {
267 : 0 : SPDK_ERRLOG("The size of the pipe must be larger than %d\n", MIN_SOCK_PIPE_SIZE);
268 : 0 : return -1;
269 : : }
270 : :
271 : : /* Round up to next 64 byte multiple */
272 [ - + ]: 1160 : rc = posix_memalign((void **)&new_buf, 64, sz);
273 [ - + ]: 1160 : if (rc != 0) {
274 : 0 : SPDK_ERRLOG("socket recv buf allocation failed\n");
275 : 0 : return -ENOMEM;
276 : : }
277 [ - + ]: 1160 : memset(new_buf, 0, sz);
278 : :
279 : 1160 : new_pipe = spdk_pipe_create(new_buf, sz);
280 [ - + ]: 1160 : if (new_pipe == NULL) {
281 : 0 : SPDK_ERRLOG("socket pipe allocation failed\n");
282 : 0 : free(new_buf);
283 : 0 : return -ENOMEM;
284 : : }
285 : :
286 [ - + ]: 1160 : if (sock->recv_pipe != NULL) {
287 : : /* Pull all of the data out of the old pipe */
288 : 0 : sbytes = spdk_pipe_reader_get_buffer(sock->recv_pipe, sock->recv_buf_sz, siov);
289 [ # # ]: 0 : if (sbytes > sz) {
290 : : /* Too much data to fit into the new pipe size */
291 : 0 : spdk_pipe_destroy(new_pipe);
292 : 0 : free(new_buf);
293 : 0 : return -EINVAL;
294 : : }
295 : :
296 : 0 : sbytes = spdk_pipe_writer_get_buffer(new_pipe, sz, diov);
297 [ # # ]: 0 : assert(sbytes == sz);
298 : :
299 : 0 : bytes = spdk_iovcpy(siov, 2, diov, 2);
300 : 0 : spdk_pipe_writer_advance(new_pipe, bytes);
301 : :
302 : 0 : spdk_pipe_destroy(sock->recv_pipe);
303 : 0 : free(sock->recv_buf);
304 : : }
305 : :
306 : 1160 : sock->recv_buf_sz = sz;
307 : 1160 : sock->recv_buf = new_buf;
308 : 1160 : sock->recv_pipe = new_pipe;
309 : :
310 : 1160 : return 0;
311 : : }
312 : :
313 : : static int
314 : 3701 : uring_sock_set_recvbuf(struct spdk_sock *_sock, int sz)
315 : : {
316 : 3701 : struct spdk_uring_sock *sock = __uring_sock(_sock);
317 : : int min_size;
318 : : int rc;
319 : :
320 [ - + ]: 3701 : assert(sock != NULL);
321 : :
322 [ - + + - ]: 3701 : if (_sock->impl_opts.enable_recv_pipe) {
323 : 3701 : rc = uring_sock_alloc_pipe(sock, sz);
324 [ - + ]: 3701 : if (rc) {
325 : 0 : SPDK_ERRLOG("unable to allocate sufficient recvbuf with sz=%d on sock=%p\n", sz, _sock);
326 : 0 : return rc;
327 : : }
328 : : }
329 : :
330 : : /* Set kernel buffer size to be at least MIN_SO_RCVBUF_SIZE and
331 : : * g_spdk_uring_sock_impl_opts.recv_buf_size. */
332 : 3701 : min_size = spdk_max(MIN_SO_RCVBUF_SIZE, g_spdk_uring_sock_impl_opts.recv_buf_size);
333 : :
334 [ + - ]: 3701 : if (sz < min_size) {
335 : 3701 : sz = min_size;
336 : : }
337 : :
338 : 3701 : rc = setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz));
339 [ - + ]: 3701 : if (rc < 0) {
340 : 0 : return rc;
341 : : }
342 : :
343 : 3701 : _sock->impl_opts.recv_buf_size = sz;
344 : :
345 : 3701 : return 0;
346 : : }
347 : :
348 : : static int
349 : 0 : uring_sock_set_sendbuf(struct spdk_sock *_sock, int sz)
350 : : {
351 : 0 : struct spdk_uring_sock *sock = __uring_sock(_sock);
352 : : int min_size;
353 : : int rc;
354 : :
355 [ # # ]: 0 : assert(sock != NULL);
356 : :
357 : : /* Set kernel buffer size to be at least MIN_SO_SNDBUF_SIZE and
358 : : * g_spdk_uring_sock_impl_opts.seend_buf_size. */
359 : 0 : min_size = spdk_max(MIN_SO_SNDBUF_SIZE, g_spdk_uring_sock_impl_opts.send_buf_size);
360 : :
361 [ # # ]: 0 : if (sz < min_size) {
362 : 0 : sz = min_size;
363 : : }
364 : :
365 : 0 : rc = setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF, &sz, sizeof(sz));
366 [ # # ]: 0 : if (rc < 0) {
367 : 0 : return rc;
368 : : }
369 : :
370 : 0 : _sock->impl_opts.send_buf_size = sz;
371 : :
372 : 0 : return 0;
373 : : }
374 : :
375 : : static struct spdk_uring_sock *
376 : 1266 : uring_sock_alloc(int fd, struct spdk_sock_impl_opts *impl_opts, bool enable_zero_copy)
377 : : {
378 : : struct spdk_uring_sock *sock;
379 : : #if defined(__linux__)
380 : : int flag;
381 : : int rc;
382 : : #endif
383 : :
384 : 1266 : sock = calloc(1, sizeof(*sock));
385 [ - + ]: 1266 : if (sock == NULL) {
386 : 0 : SPDK_ERRLOG("sock allocation failed\n");
387 : 0 : return NULL;
388 : : }
389 : :
390 : 1266 : sock->fd = fd;
391 [ - + - + ]: 1266 : memcpy(&sock->base.impl_opts, impl_opts, sizeof(*impl_opts));
392 : :
393 : 1266 : STAILQ_INIT(&sock->recv_stream);
394 : :
395 : : #if defined(__linux__)
396 : 1266 : flag = 1;
397 : :
398 [ - + - + ]: 1266 : if (sock->base.impl_opts.enable_quickack) {
399 : 0 : rc = setsockopt(sock->fd, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(flag));
400 [ # # ]: 0 : if (rc != 0) {
401 : 0 : SPDK_ERRLOG("quickack was failed to set\n");
402 : : }
403 : : }
404 : :
405 : 1266 : spdk_sock_get_placement_id(sock->fd, sock->base.impl_opts.enable_placement_id,
406 : : &sock->placement_id);
407 : : #ifdef SPDK_ZEROCOPY
408 : : /* Try to turn on zero copy sends */
409 : 1266 : flag = 1;
410 : :
411 [ - + ]: 1266 : if (enable_zero_copy) {
412 : 0 : rc = setsockopt(sock->fd, SOL_SOCKET, SO_ZEROCOPY, &flag, sizeof(flag));
413 [ # # ]: 0 : if (rc == 0) {
414 : 0 : sock->zcopy = true;
415 : 0 : sock->zcopy_send_flags = MSG_ZEROCOPY;
416 : : }
417 : : }
418 : : #endif
419 : : #endif
420 : :
421 : 1266 : return sock;
422 : : }
423 : :
424 : : static struct spdk_sock *
425 : 509 : uring_sock_create(const char *ip, int port,
426 : : enum uring_sock_create_type type,
427 : : struct spdk_sock_opts *opts)
428 : : {
429 : : struct spdk_uring_sock *sock;
430 : : struct spdk_sock_impl_opts impl_opts;
431 : : char buf[MAX_TMPBUF];
432 : : char portnum[PORTNUMLEN];
433 : : char *p;
434 : : struct addrinfo hints, *res, *res0;
435 : : int fd, flag;
436 : 509 : int val = 1;
437 : : int rc;
438 : 509 : bool enable_zcopy_impl_opts = false;
439 : 509 : bool enable_zcopy_user_opts = true;
440 : :
441 [ - + ]: 509 : assert(opts != NULL);
442 : 509 : uring_opts_get_impl_opts(opts, &impl_opts);
443 : :
444 [ - + ]: 509 : if (ip == NULL) {
445 : 0 : return NULL;
446 : : }
447 [ - + ]: 509 : if (ip[0] == '[') {
448 : 0 : snprintf(buf, sizeof(buf), "%s", ip + 1);
449 : 0 : p = strchr(buf, ']');
450 [ # # ]: 0 : if (p != NULL) {
451 : 0 : *p = '\0';
452 : : }
453 : 0 : ip = (const char *) &buf[0];
454 : : }
455 : :
456 : 509 : snprintf(portnum, sizeof portnum, "%d", port);
457 : 509 : memset(&hints, 0, sizeof hints);
458 : 509 : hints.ai_family = PF_UNSPEC;
459 : 509 : hints.ai_socktype = SOCK_STREAM;
460 : 509 : hints.ai_flags = AI_NUMERICSERV;
461 : 509 : hints.ai_flags |= AI_PASSIVE;
462 : 509 : hints.ai_flags |= AI_NUMERICHOST;
463 : 509 : rc = getaddrinfo(ip, portnum, &hints, &res0);
464 [ - + ]: 509 : if (rc != 0) {
465 : 0 : SPDK_ERRLOG("getaddrinfo() failed %s (%d)\n", gai_strerror(rc), rc);
466 : 0 : return NULL;
467 : : }
468 : :
469 : : /* try listen */
470 : 509 : fd = -1;
471 [ + + ]: 525 : for (res = res0; res != NULL; res = res->ai_next) {
472 : 509 : retry:
473 : 509 : fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
474 [ - + ]: 509 : if (fd < 0) {
475 : : /* error */
476 : 0 : continue;
477 : : }
478 : :
479 : 509 : val = impl_opts.recv_buf_size;
480 : 509 : rc = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof val);
481 : : if (rc) {
482 : : /* Not fatal */
483 : : }
484 : :
485 : 509 : val = impl_opts.send_buf_size;
486 : 509 : rc = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof val);
487 : : if (rc) {
488 : : /* Not fatal */
489 : : }
490 : :
491 : 509 : rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
492 [ - + ]: 509 : if (rc != 0) {
493 : 0 : close(fd);
494 : 0 : fd = -1;
495 : : /* error */
496 : 0 : continue;
497 : : }
498 : 509 : rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val);
499 [ - + ]: 509 : if (rc != 0) {
500 : 0 : close(fd);
501 : 0 : fd = -1;
502 : : /* error */
503 : 0 : continue;
504 : : }
505 : :
506 [ + + ]: 509 : if (opts->ack_timeout) {
507 : : #if defined(__linux__)
508 : 11 : val = opts->ack_timeout;
509 : 11 : rc = setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &val, sizeof val);
510 [ - + ]: 11 : if (rc != 0) {
511 : 0 : close(fd);
512 : 0 : fd = -1;
513 : : /* error */
514 : 0 : continue;
515 : : }
516 : : #else
517 : : SPDK_WARNLOG("TCP_USER_TIMEOUT is not supported.\n");
518 : : #endif
519 : : }
520 : :
521 : :
522 : :
523 : : #if defined(SO_PRIORITY)
524 [ + - - + ]: 509 : if (opts != NULL && opts->priority) {
525 : 0 : rc = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &opts->priority, sizeof val);
526 [ # # ]: 0 : if (rc != 0) {
527 : 0 : close(fd);
528 : 0 : fd = -1;
529 : : /* error */
530 : 0 : continue;
531 : : }
532 : : }
533 : : #endif
534 [ - + ]: 509 : if (res->ai_family == AF_INET6) {
535 : 0 : rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof val);
536 [ # # ]: 0 : if (rc != 0) {
537 : 0 : close(fd);
538 : 0 : fd = -1;
539 : : /* error */
540 : 0 : continue;
541 : : }
542 : : }
543 : :
544 [ + + ]: 509 : if (type == SPDK_SOCK_CREATE_LISTEN) {
545 : 74 : rc = bind(fd, res->ai_addr, res->ai_addrlen);
546 [ - + ]: 74 : if (rc != 0) {
547 : 0 : SPDK_ERRLOG("bind() failed at port %d, errno = %d\n", port, errno);
548 [ # # # ]: 0 : switch (errno) {
549 : 0 : case EINTR:
550 : : /* interrupted? */
551 : 0 : close(fd);
552 : 0 : goto retry;
553 : 0 : case EADDRNOTAVAIL:
554 : 0 : SPDK_ERRLOG("IP address %s not available. "
555 : : "Verify IP address in config file "
556 : : "and make sure setup script is "
557 : : "run before starting spdk app.\n", ip);
558 : : /* FALLTHROUGH */
559 : 0 : default:
560 : : /* try next family */
561 : 0 : close(fd);
562 : 0 : fd = -1;
563 : 0 : continue;
564 : : }
565 : : }
566 : : /* bind OK */
567 : 74 : rc = listen(fd, 512);
568 [ - + ]: 74 : if (rc != 0) {
569 : 0 : SPDK_ERRLOG("listen() failed, errno = %d\n", errno);
570 : 0 : close(fd);
571 : 0 : fd = -1;
572 : 0 : break;
573 : : }
574 : :
575 : 74 : flag = fcntl(fd, F_GETFL);
576 [ - + ]: 74 : if (fcntl(fd, F_SETFL, flag | O_NONBLOCK) < 0) {
577 : 0 : SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%d)\n", fd, errno);
578 : 0 : close(fd);
579 : 0 : fd = -1;
580 : 0 : break;
581 : : }
582 : :
583 [ - + ]: 74 : enable_zcopy_impl_opts = impl_opts.enable_zerocopy_send_server;
584 [ + - ]: 435 : } else if (type == SPDK_SOCK_CREATE_CONNECT) {
585 : 435 : rc = connect(fd, res->ai_addr, res->ai_addrlen);
586 [ + + ]: 435 : if (rc != 0) {
587 : 16 : SPDK_ERRLOG("connect() failed, errno = %d\n", errno);
588 : : /* try next family */
589 : 16 : close(fd);
590 : 16 : fd = -1;
591 : 16 : continue;
592 : : }
593 : :
594 : 419 : flag = fcntl(fd, F_GETFL);
595 [ - + ]: 419 : if (fcntl(fd, F_SETFL, flag & ~O_NONBLOCK) < 0) {
596 : 0 : SPDK_ERRLOG("fcntl can't set blocking mode for socket, fd: %d (%d)\n", fd, errno);
597 : 0 : close(fd);
598 : 0 : fd = -1;
599 : 0 : break;
600 : : }
601 : :
602 [ - + ]: 419 : enable_zcopy_impl_opts = impl_opts.enable_zerocopy_send_client;
603 : : }
604 : 493 : break;
605 : : }
606 : 509 : freeaddrinfo(res0);
607 : :
608 [ + + ]: 509 : if (fd < 0) {
609 : 16 : return NULL;
610 : : }
611 : :
612 [ - + + + : 493 : enable_zcopy_user_opts = opts->zcopy && !spdk_net_is_loopback(fd);
+ + ]
613 [ + + - + ]: 493 : sock = uring_sock_alloc(fd, &impl_opts, enable_zcopy_user_opts && enable_zcopy_impl_opts);
614 [ - + ]: 493 : if (sock == NULL) {
615 : 0 : SPDK_ERRLOG("sock allocation failed\n");
616 : 0 : close(fd);
617 : 0 : return NULL;
618 : : }
619 : :
620 : 493 : return &sock->base;
621 : : }
622 : :
623 : : static struct spdk_sock *
624 : 74 : uring_sock_listen(const char *ip, int port, struct spdk_sock_opts *opts)
625 : : {
626 [ - + ]: 74 : if (spdk_interrupt_mode_is_enabled()) {
627 : 0 : SPDK_ERRLOG("Interrupt mode is not supported in the uring sock implementation.");
628 : 0 : return NULL;
629 : : }
630 : :
631 : 74 : return uring_sock_create(ip, port, SPDK_SOCK_CREATE_LISTEN, opts);
632 : : }
633 : :
634 : : static struct spdk_sock *
635 : 435 : uring_sock_connect(const char *ip, int port, struct spdk_sock_opts *opts)
636 : : {
637 [ - + ]: 435 : if (spdk_interrupt_mode_is_enabled()) {
638 : 0 : SPDK_ERRLOG("Interrupt mode is not supported in the uring sock implementation.");
639 : 0 : return NULL;
640 : : }
641 : :
642 : 435 : return uring_sock_create(ip, port, SPDK_SOCK_CREATE_CONNECT, opts);
643 : : }
644 : :
645 : : static struct spdk_sock *
646 : 358251 : uring_sock_accept(struct spdk_sock *_sock)
647 : : {
648 : 358251 : struct spdk_uring_sock *sock = __uring_sock(_sock);
649 : : struct sockaddr_storage sa;
650 : : socklen_t salen;
651 : : int rc, fd;
652 : : struct spdk_uring_sock *new_sock;
653 : : int flag;
654 : :
655 : 358251 : memset(&sa, 0, sizeof(sa));
656 : 358251 : salen = sizeof(sa);
657 : :
658 [ - + ]: 358251 : assert(sock != NULL);
659 : :
660 : 358251 : rc = accept(sock->fd, (struct sockaddr *)&sa, &salen);
661 : :
662 [ + + ]: 358251 : if (rc == -1) {
663 : 357478 : return NULL;
664 : : }
665 : :
666 : 773 : fd = rc;
667 : :
668 : 773 : flag = fcntl(fd, F_GETFL);
669 [ - + - - ]: 773 : if ((flag & O_NONBLOCK) && (fcntl(fd, F_SETFL, flag & ~O_NONBLOCK) < 0)) {
670 : 0 : SPDK_ERRLOG("fcntl can't set blocking mode for socket, fd: %d (%d)\n", fd, errno);
671 : 0 : close(fd);
672 : 0 : return NULL;
673 : : }
674 : :
675 : : #if defined(SO_PRIORITY)
676 : : /* The priority is not inherited, so call this function again */
677 [ - + ]: 773 : if (sock->base.opts.priority) {
678 : 0 : rc = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &sock->base.opts.priority, sizeof(int));
679 [ # # ]: 0 : if (rc != 0) {
680 : 0 : close(fd);
681 : 0 : return NULL;
682 : : }
683 : : }
684 : : #endif
685 : :
686 [ - + ]: 773 : new_sock = uring_sock_alloc(fd, &sock->base.impl_opts, sock->zcopy);
687 [ - + ]: 773 : if (new_sock == NULL) {
688 : 0 : close(fd);
689 : 0 : return NULL;
690 : : }
691 : :
692 : 773 : return &new_sock->base;
693 : : }
694 : :
695 : : static int
696 : 1266 : uring_sock_close(struct spdk_sock *_sock)
697 : : {
698 : 1266 : struct spdk_uring_sock *sock = __uring_sock(_sock);
699 : :
700 [ - + ]: 1266 : assert(TAILQ_EMPTY(&_sock->pending_reqs));
701 [ - + ]: 1266 : assert(sock->group == NULL);
702 : :
703 : : /* If the socket fails to close, the best choice is to
704 : : * leak the fd but continue to free the rest of the sock
705 : : * memory. */
706 : 1266 : close(sock->fd);
707 : :
708 : 1266 : spdk_pipe_destroy(sock->recv_pipe);
709 : 1266 : free(sock->recv_buf);
710 : 1266 : free(sock);
711 : :
712 : 1266 : return 0;
713 : : }
714 : :
715 : : static ssize_t
716 : 23380668 : uring_sock_recv_from_pipe(struct spdk_uring_sock *sock, struct iovec *diov, int diovcnt)
717 : : {
718 : : struct iovec siov[2];
719 : : int sbytes;
720 : : ssize_t bytes;
721 : : struct spdk_uring_sock_group_impl *group;
722 : :
723 : 23380668 : sbytes = spdk_pipe_reader_get_buffer(sock->recv_pipe, sock->recv_buf_sz, siov);
724 [ - + ]: 23380668 : if (sbytes < 0) {
725 : 0 : errno = EINVAL;
726 : 0 : return -1;
727 [ - + ]: 23380668 : } else if (sbytes == 0) {
728 : 0 : errno = EAGAIN;
729 : 0 : return -1;
730 : : }
731 : :
732 : 23380668 : bytes = spdk_iovcpy(siov, 2, diov, diovcnt);
733 : :
734 [ - + ]: 23380668 : if (bytes == 0) {
735 : : /* The only way this happens is if diov is 0 length */
736 : 0 : errno = EINVAL;
737 : 0 : return -1;
738 : : }
739 : :
740 : 23380668 : spdk_pipe_reader_advance(sock->recv_pipe, bytes);
741 : :
742 : : /* If we drained the pipe, take it off the level-triggered list */
743 [ + + + + ]: 23380668 : if (sock->base.group_impl && spdk_pipe_reader_bytes_available(sock->recv_pipe) == 0) {
744 : 2360140 : group = __uring_group_impl(sock->base.group_impl);
745 [ + + ]: 2360140 : TAILQ_REMOVE(&group->pending_recv, sock, link);
746 : 2360140 : sock->pending_recv = false;
747 : : }
748 : :
749 : 23380668 : return bytes;
750 : : }
751 : :
752 : : static inline ssize_t
753 : 96326210 : sock_readv(int fd, struct iovec *iov, int iovcnt)
754 : : {
755 : 96326210 : struct msghdr msg = {
756 : : .msg_iov = iov,
757 : : .msg_iovlen = iovcnt,
758 : : };
759 : :
760 : 96326210 : return recvmsg(fd, &msg, MSG_DONTWAIT);
761 : : }
762 : :
763 : : static inline ssize_t
764 : 91861112 : uring_sock_read(struct spdk_uring_sock *sock)
765 : : {
766 : : struct iovec iov[2];
767 : : int bytes;
768 : : struct spdk_uring_sock_group_impl *group;
769 : :
770 : 91861112 : bytes = spdk_pipe_writer_get_buffer(sock->recv_pipe, sock->recv_buf_sz, iov);
771 : :
772 [ + - ]: 91861112 : if (bytes > 0) {
773 : 91861112 : bytes = sock_readv(sock->fd, iov, 2);
774 [ + + ]: 91861112 : if (bytes > 0) {
775 : 2364868 : spdk_pipe_writer_advance(sock->recv_pipe, bytes);
776 [ + + - + : 2364868 : if (sock->base.group_impl && !sock->pending_recv) {
+ + ]
777 : 377854 : group = __uring_group_impl(sock->base.group_impl);
778 : 377854 : TAILQ_INSERT_TAIL(&group->pending_recv, sock, link);
779 : 377854 : sock->pending_recv = true;
780 : : }
781 : : }
782 : : }
783 : :
784 : 91861112 : return bytes;
785 : : }
786 : :
787 : : static int
788 : 0 : uring_sock_recv_next(struct spdk_sock *_sock, void **_buf, void **ctx)
789 : : {
790 : 0 : struct spdk_uring_sock *sock = __uring_sock(_sock);
791 : : struct spdk_uring_sock_group_impl *group;
792 : : struct spdk_uring_buf_tracker *tr;
793 : :
794 [ # # ]: 0 : if (sock->connection_status < 0) {
795 : 0 : errno = -sock->connection_status;
796 : 0 : return -1;
797 : : }
798 : :
799 [ # # ]: 0 : if (sock->recv_pipe != NULL) {
800 : 0 : errno = ENOTSUP;
801 : 0 : return -1;
802 : : }
803 : :
804 : 0 : group = __uring_group_impl(_sock->group_impl);
805 : :
806 : 0 : tr = STAILQ_FIRST(&sock->recv_stream);
807 [ # # ]: 0 : if (tr == NULL) {
808 [ # # ]: 0 : if (sock->group->buf_ring_count > 0) {
809 : : /* There are buffers posted, but data hasn't arrived. */
810 : 0 : errno = EAGAIN;
811 : : } else {
812 : : /* There are no buffers posted, so this won't ever
813 : : * make forward progress. */
814 : 0 : errno = ENOBUFS;
815 : : }
816 : 0 : return -1;
817 : : }
818 [ # # # # ]: 0 : assert(sock->pending_recv == true);
819 [ # # ]: 0 : assert(tr->buf != NULL);
820 : :
821 : 0 : *_buf = tr->buf + sock->recv_offset;
822 : 0 : *ctx = tr->ctx;
823 : :
824 [ # # ]: 0 : STAILQ_REMOVE_HEAD(&sock->recv_stream, link);
825 [ # # ]: 0 : STAILQ_INSERT_HEAD(&group->free_trackers, tr, link);
826 : :
827 [ # # ]: 0 : if (STAILQ_EMPTY(&sock->recv_stream)) {
828 : 0 : sock->pending_recv = false;
829 [ # # ]: 0 : TAILQ_REMOVE(&group->pending_recv, sock, link);
830 : : }
831 : :
832 : 0 : return tr->len - sock->recv_offset;
833 : : }
834 : :
835 : : static ssize_t
836 : 143876 : uring_sock_readv_no_pipe(struct spdk_sock *_sock, struct iovec *iovs, int iovcnt)
837 : : {
838 : 143876 : struct spdk_uring_sock *sock = __uring_sock(_sock);
839 : : struct spdk_uring_buf_tracker *tr;
840 : : struct iovec iov;
841 : : ssize_t total, len;
842 : : int i;
843 : :
844 [ - + ]: 143876 : if (sock->connection_status < 0) {
845 : 0 : errno = -sock->connection_status;
846 : 0 : return -1;
847 : : }
848 : :
849 [ + + ]: 143876 : if (_sock->group_impl == NULL) {
850 : : /* If not in a group just read from the socket the regular way. */
851 : 16274 : return sock_readv(sock->fd, iovs, iovcnt);
852 : : }
853 : :
854 [ + - ]: 127602 : if (STAILQ_EMPTY(&sock->recv_stream)) {
855 [ + - ]: 127602 : if (sock->group->buf_ring_count == 0) {
856 : : /* If the user hasn't posted any buffers, read from the socket
857 : : * directly. */
858 : :
859 [ - + + + ]: 127602 : if (sock->pending_recv) {
860 : 125307 : sock->pending_recv = false;
861 [ + + ]: 125307 : TAILQ_REMOVE(&(__uring_group_impl(_sock->group_impl))->pending_recv, sock, link);
862 : : }
863 : :
864 : 127602 : return sock_readv(sock->fd, iovs, iovcnt);
865 : : }
866 : :
867 : 0 : errno = EAGAIN;
868 : 0 : return -1;
869 : : }
870 : :
871 : 0 : total = 0;
872 [ # # ]: 0 : for (i = 0; i < iovcnt; i++) {
873 : : /* Copy to stack so we can change it */
874 : 0 : iov = iovs[i];
875 : :
876 : 0 : tr = STAILQ_FIRST(&sock->recv_stream);
877 [ # # ]: 0 : while (tr != NULL) {
878 : 0 : len = spdk_min(iov.iov_len, tr->len - sock->recv_offset);
879 [ # # # # ]: 0 : memcpy(iov.iov_base, tr->buf + sock->recv_offset, len);
880 : :
881 : 0 : total += len;
882 : 0 : sock->recv_offset += len;
883 : 0 : iov.iov_base += len;
884 : 0 : iov.iov_len -= len;
885 : :
886 [ # # ]: 0 : if (sock->recv_offset == tr->len) {
887 : 0 : sock->recv_offset = 0;
888 [ # # ]: 0 : STAILQ_REMOVE_HEAD(&sock->recv_stream, link);
889 [ # # ]: 0 : STAILQ_INSERT_HEAD(&sock->group->free_trackers, tr, link);
890 : 0 : spdk_sock_group_provide_buf(sock->group->base.group, tr->buf, tr->buflen, tr->ctx);
891 : 0 : tr = STAILQ_FIRST(&sock->recv_stream);
892 : : }
893 : :
894 [ # # ]: 0 : if (iov.iov_len == 0) {
895 : 0 : break;
896 : : }
897 : : }
898 : : }
899 : :
900 [ # # ]: 0 : if (STAILQ_EMPTY(&sock->recv_stream)) {
901 : : struct spdk_uring_sock_group_impl *group;
902 : :
903 : 0 : group = __uring_group_impl(_sock->group_impl);
904 : 0 : sock->pending_recv = false;
905 [ # # ]: 0 : TAILQ_REMOVE(&group->pending_recv, sock, link);
906 : : }
907 : :
908 [ # # ]: 0 : assert(total > 0);
909 : 0 : return total;
910 : : }
911 : :
912 : : static ssize_t
913 : 117342010 : uring_sock_readv(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
914 : : {
915 : 117342010 : struct spdk_uring_sock *sock = __uring_sock(_sock);
916 : : int rc, i;
917 : : size_t len;
918 : :
919 [ - + ]: 117342010 : if (sock->connection_status < 0) {
920 : 0 : errno = -sock->connection_status;
921 : 0 : return -1;
922 : : }
923 : :
924 [ + + ]: 117342010 : if (sock->recv_pipe == NULL) {
925 : 143876 : return uring_sock_readv_no_pipe(_sock, iov, iovcnt);
926 : : }
927 : :
928 : 117198134 : len = 0;
929 [ + + ]: 234829407 : for (i = 0; i < iovcnt; i++) {
930 : 117631273 : len += iov[i].iov_len;
931 : : }
932 : :
933 [ + + ]: 117198134 : if (spdk_pipe_reader_bytes_available(sock->recv_pipe) == 0) {
934 : : /* If the user is receiving a sufficiently large amount of data,
935 : : * receive directly to their buffers. */
936 [ + + ]: 96182334 : if (len >= MIN_SOCK_PIPE_SIZE) {
937 : 4321222 : return sock_readv(sock->fd, iov, iovcnt);
938 : : }
939 : :
940 : : /* Otherwise, do a big read into our pipe */
941 : 91861112 : rc = uring_sock_read(sock);
942 [ + + ]: 91861112 : if (rc <= 0) {
943 : 89496244 : return rc;
944 : : }
945 : : }
946 : :
947 : 23380668 : return uring_sock_recv_from_pipe(sock, iov, iovcnt);
948 : : }
949 : :
950 : : static ssize_t
951 : 116928151 : uring_sock_recv(struct spdk_sock *sock, void *buf, size_t len)
952 : : {
953 : : struct iovec iov[1];
954 : :
955 : 116928151 : iov[0].iov_base = buf;
956 : 116928151 : iov[0].iov_len = len;
957 : :
958 : 116928151 : return uring_sock_readv(sock, iov, 1);
959 : : }
960 : :
961 : : static ssize_t
962 : 0 : uring_sock_writev(struct spdk_sock *_sock, struct iovec *iov, int iovcnt)
963 : : {
964 : 0 : struct spdk_uring_sock *sock = __uring_sock(_sock);
965 : 0 : struct msghdr msg = {
966 : : .msg_iov = iov,
967 : : .msg_iovlen = iovcnt,
968 : : };
969 : :
970 [ # # ]: 0 : if (sock->write_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE) {
971 : 0 : errno = EAGAIN;
972 : 0 : return -1;
973 : : }
974 : :
975 : 0 : return sendmsg(sock->fd, &msg, MSG_DONTWAIT);
976 : : }
977 : :
978 : : static ssize_t
979 : 11357596 : sock_request_advance_offset(struct spdk_sock_request *req, ssize_t rc)
980 : : {
981 : : unsigned int offset;
982 : : size_t len;
983 : : int i;
984 : :
985 : 11357596 : offset = req->internal.offset;
986 [ + + ]: 33613143 : for (i = 0; i < req->iovcnt; i++) {
987 : : /* Advance by the offset first */
988 [ + + ]: 22351573 : if (offset >= SPDK_SOCK_REQUEST_IOV(req, i)->iov_len) {
989 : 207605 : offset -= SPDK_SOCK_REQUEST_IOV(req, i)->iov_len;
990 : 207605 : continue;
991 : : }
992 : :
993 : : /* Calculate the remaining length of this element */
994 : 22143968 : len = SPDK_SOCK_REQUEST_IOV(req, i)->iov_len - offset;
995 : :
996 [ + + ]: 22143968 : if (len > (size_t)rc) {
997 : 96026 : req->internal.offset += rc;
998 : 96026 : return -1;
999 : : }
1000 : :
1001 : 22047942 : offset = 0;
1002 : 22047942 : req->internal.offset += len;
1003 : 22047942 : rc -= len;
1004 : : }
1005 : :
1006 : 11261570 : return rc;
1007 : : }
1008 : :
1009 : : static int
1010 : 1875390 : sock_complete_write_reqs(struct spdk_sock *_sock, ssize_t rc, bool is_zcopy)
1011 : : {
1012 : 1875390 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1013 : : struct spdk_sock_request *req;
1014 : : int retval;
1015 : :
1016 [ - + ]: 1875390 : if (is_zcopy) {
1017 : : /* Handling overflow case, because we use psock->sendmsg_idx - 1 for the
1018 : : * req->internal.offset, so sendmsg_idx should not be zero */
1019 [ # # ]: 0 : if (spdk_unlikely(sock->sendmsg_idx == UINT32_MAX)) {
1020 : 0 : sock->sendmsg_idx = 1;
1021 : : } else {
1022 : 0 : sock->sendmsg_idx++;
1023 : : }
1024 : : }
1025 : :
1026 : : /* Consume the requests that were actually written */
1027 : 1875390 : req = TAILQ_FIRST(&_sock->queued_reqs);
1028 [ + - ]: 11357596 : while (req) {
1029 : : /* req->internal.is_zcopy is true when the whole req or part of it is sent with zerocopy */
1030 : 11357596 : req->internal.is_zcopy = is_zcopy;
1031 : :
1032 : 11357596 : rc = sock_request_advance_offset(req, rc);
1033 [ + + ]: 11357596 : if (rc < 0) {
1034 : : /* This element was partially sent. */
1035 : 96026 : return 0;
1036 : : }
1037 : :
1038 : : /* Handled a full request. */
1039 : 11261570 : spdk_sock_request_pend(_sock, req);
1040 : :
1041 [ - + + - : 11261570 : if (!req->internal.is_zcopy && req == TAILQ_FIRST(&_sock->pending_reqs)) {
+ - ]
1042 : 11261570 : retval = spdk_sock_request_put(_sock, req, 0);
1043 [ - + ]: 11261570 : if (retval) {
1044 : 0 : return retval;
1045 : : }
1046 : : } else {
1047 : : /* Re-use the offset field to hold the sendmsg call index. The
1048 : : * index is 0 based, so subtract one here because we've already
1049 : : * incremented above. */
1050 : 0 : req->internal.offset = sock->sendmsg_idx - 1;
1051 : : }
1052 : :
1053 [ + + ]: 11261570 : if (rc == 0) {
1054 : 1779364 : break;
1055 : : }
1056 : :
1057 : 9482206 : req = TAILQ_FIRST(&_sock->queued_reqs);
1058 : : }
1059 : :
1060 : 1779364 : return 0;
1061 : : }
1062 : :
1063 : : #ifdef SPDK_ZEROCOPY
1064 : : static int
1065 : 0 : _sock_check_zcopy(struct spdk_sock *_sock, int status)
1066 : : {
1067 : 0 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1068 : : ssize_t rc;
1069 : : struct sock_extended_err *serr;
1070 : : struct cmsghdr *cm;
1071 : : uint32_t idx;
1072 : : struct spdk_sock_request *req, *treq;
1073 : : bool found;
1074 : :
1075 [ # # # # ]: 0 : assert(sock->zcopy == true);
1076 [ # # ]: 0 : if (spdk_unlikely(status) < 0) {
1077 [ # # ]: 0 : if (!TAILQ_EMPTY(&_sock->pending_reqs)) {
1078 : 0 : SPDK_ERRLOG("Attempting to receive from ERRQUEUE yielded error, but pending list still has orphaned entries, status =%d\n",
1079 : : status);
1080 : : } else {
1081 : 0 : SPDK_WARNLOG("Recvmsg yielded an error!\n");
1082 : : }
1083 : 0 : return 0;
1084 : : }
1085 : :
1086 [ # # ]: 0 : cm = CMSG_FIRSTHDR(&sock->errqueue_task.msg);
1087 [ # # # # ]: 0 : if (!((cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_RECVERR) ||
1088 [ # # # # ]: 0 : (cm->cmsg_level == SOL_IPV6 && cm->cmsg_type == IPV6_RECVERR))) {
1089 : 0 : SPDK_WARNLOG("Unexpected cmsg level or type!\n");
1090 : 0 : return 0;
1091 : : }
1092 : :
1093 : 0 : serr = (struct sock_extended_err *)CMSG_DATA(cm);
1094 [ # # # # ]: 0 : if (serr->ee_errno != 0 || serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) {
1095 : 0 : SPDK_WARNLOG("Unexpected extended error origin\n");
1096 : 0 : return 0;
1097 : : }
1098 : :
1099 : : /* Most of the time, the pending_reqs array is in the exact
1100 : : * order we need such that all of the requests to complete are
1101 : : * in order, in the front. It is guaranteed that all requests
1102 : : * belonging to the same sendmsg call are sequential, so once
1103 : : * we encounter one match we can stop looping as soon as a
1104 : : * non-match is found.
1105 : : */
1106 [ # # ]: 0 : for (idx = serr->ee_info; idx <= serr->ee_data; idx++) {
1107 : 0 : found = false;
1108 [ # # ]: 0 : TAILQ_FOREACH_SAFE(req, &_sock->pending_reqs, internal.link, treq) {
1109 [ # # # # ]: 0 : if (!req->internal.is_zcopy) {
1110 : : /* This wasn't a zcopy request. It was just waiting in line to complete */
1111 : 0 : rc = spdk_sock_request_put(_sock, req, 0);
1112 [ # # ]: 0 : if (rc < 0) {
1113 : 0 : return rc;
1114 : : }
1115 [ # # ]: 0 : } else if (req->internal.offset == idx) {
1116 : 0 : found = true;
1117 : 0 : rc = spdk_sock_request_put(_sock, req, 0);
1118 [ # # ]: 0 : if (rc < 0) {
1119 : 0 : return rc;
1120 : : }
1121 [ # # ]: 0 : } else if (found) {
1122 : 0 : break;
1123 : : }
1124 : : }
1125 : : }
1126 : :
1127 : 0 : return 0;
1128 : : }
1129 : :
1130 : : static void
1131 : 0 : _sock_prep_errqueue(struct spdk_sock *_sock)
1132 : : {
1133 : 0 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1134 : 0 : struct spdk_uring_task *task = &sock->errqueue_task;
1135 : : struct io_uring_sqe *sqe;
1136 : :
1137 [ # # ]: 0 : if (task->status == SPDK_URING_SOCK_TASK_IN_PROCESS) {
1138 : 0 : return;
1139 : : }
1140 : :
1141 [ # # # # ]: 0 : if (sock->pending_group_remove) {
1142 : 0 : return;
1143 : : }
1144 : :
1145 [ # # ]: 0 : assert(sock->group != NULL);
1146 : 0 : sock->group->io_queued++;
1147 : :
1148 : 0 : sqe = io_uring_get_sqe(&sock->group->uring);
1149 : 0 : io_uring_prep_recvmsg(sqe, sock->fd, &task->msg, MSG_ERRQUEUE);
1150 : 0 : io_uring_sqe_set_data(sqe, task);
1151 : 0 : task->status = SPDK_URING_SOCK_TASK_IN_PROCESS;
1152 : : }
1153 : :
1154 : : #endif
1155 : :
1156 : : static void
1157 : 94188073 : _sock_flush(struct spdk_sock *_sock)
1158 : : {
1159 : 94188073 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1160 : 94188073 : struct spdk_uring_task *task = &sock->write_task;
1161 : : uint32_t iovcnt;
1162 : : struct io_uring_sqe *sqe;
1163 : : int flags;
1164 : :
1165 [ - + ]: 94188073 : if (task->status == SPDK_URING_SOCK_TASK_IN_PROCESS) {
1166 : 92038150 : return;
1167 : : }
1168 : :
1169 : : #ifdef SPDK_ZEROCOPY
1170 [ - + - + ]: 94188073 : if (sock->zcopy) {
1171 : 0 : flags = MSG_DONTWAIT | sock->zcopy_send_flags;
1172 : : } else
1173 : : #endif
1174 : : {
1175 : 94188073 : flags = MSG_DONTWAIT;
1176 : : }
1177 : :
1178 : 94188073 : iovcnt = spdk_sock_prep_reqs(&sock->base, task->iovs, task->iov_cnt, &task->last_req, &flags);
1179 [ + + ]: 94188073 : if (!iovcnt) {
1180 : 92038150 : return;
1181 : : }
1182 : :
1183 : 2149923 : task->iov_cnt = iovcnt;
1184 [ - + ]: 2149923 : assert(sock->group != NULL);
1185 : 2149923 : task->msg.msg_iov = task->iovs;
1186 : 2149923 : task->msg.msg_iovlen = task->iov_cnt;
1187 : : #ifdef SPDK_ZEROCOPY
1188 : 2149923 : task->is_zcopy = (flags & MSG_ZEROCOPY) ? true : false;
1189 : : #endif
1190 : 2149923 : sock->group->io_queued++;
1191 : :
1192 : 2149923 : sqe = io_uring_get_sqe(&sock->group->uring);
1193 : 2149923 : io_uring_prep_sendmsg(sqe, sock->fd, &sock->write_task.msg, flags);
1194 : 2149923 : io_uring_sqe_set_data(sqe, task);
1195 : 2149923 : task->status = SPDK_URING_SOCK_TASK_IN_PROCESS;
1196 : : }
1197 : :
1198 : : static void
1199 : 94192174 : _sock_prep_read(struct spdk_sock *_sock)
1200 : : {
1201 : 94192174 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1202 : 94192174 : struct spdk_uring_task *task = &sock->read_task;
1203 : : struct io_uring_sqe *sqe;
1204 : :
1205 : : /* Do not prepare read event */
1206 [ - + ]: 94192174 : if (task->status == SPDK_URING_SOCK_TASK_IN_PROCESS) {
1207 : 0 : return;
1208 : : }
1209 : :
1210 [ - + + + ]: 94192174 : if (sock->pending_group_remove) {
1211 : 1193 : return;
1212 : : }
1213 : :
1214 [ - + ]: 94190981 : assert(sock->group != NULL);
1215 : 94190981 : sock->group->io_queued++;
1216 : :
1217 : 94190981 : sqe = io_uring_get_sqe(&sock->group->uring);
1218 : 94190981 : io_uring_prep_recv(sqe, sock->fd, NULL, URING_MAX_RECV_SIZE, 0);
1219 : 94190981 : sqe->buf_group = URING_BUF_GROUP_ID;
1220 : 94190981 : sqe->flags |= IOSQE_BUFFER_SELECT;
1221 : 94190981 : io_uring_sqe_set_data(sqe, task);
1222 : 94190981 : task->status = SPDK_URING_SOCK_TASK_IN_PROCESS;
1223 : : }
1224 : :
1225 : : static void
1226 : 1193 : _sock_prep_cancel_task(struct spdk_sock *_sock, void *user_data)
1227 : : {
1228 : 1193 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1229 : 1193 : struct spdk_uring_task *task = &sock->cancel_task;
1230 : : struct io_uring_sqe *sqe;
1231 : :
1232 [ - + ]: 1193 : if (task->status == SPDK_URING_SOCK_TASK_IN_PROCESS) {
1233 : 0 : return;
1234 : : }
1235 : :
1236 [ - + ]: 1193 : assert(sock->group != NULL);
1237 : 1193 : sock->group->io_queued++;
1238 : :
1239 : 1193 : sqe = io_uring_get_sqe(&sock->group->uring);
1240 : 1193 : io_uring_prep_cancel(sqe, user_data, 0);
1241 : 1193 : io_uring_sqe_set_data(sqe, task);
1242 : 1193 : task->status = SPDK_URING_SOCK_TASK_IN_PROCESS;
1243 : : }
1244 : :
1245 : : static void
1246 : 1 : uring_sock_fail(struct spdk_uring_sock *sock, int status)
1247 : : {
1248 : 1 : struct spdk_uring_sock_group_impl *group = sock->group;
1249 : : int rc;
1250 : :
1251 : 1 : sock->connection_status = status;
1252 : 1 : rc = spdk_sock_abort_requests(&sock->base);
1253 : :
1254 : : /* The user needs to be notified that this socket is dead. */
1255 [ - + - - ]: 1 : if (rc == 0 && sock->base.cb_fn != NULL &&
1256 [ # # # # ]: 0 : sock->pending_recv == false) {
1257 : 0 : sock->pending_recv = true;
1258 : 0 : TAILQ_INSERT_TAIL(&group->pending_recv, sock, link);
1259 : : }
1260 : 1 : }
1261 : :
1262 : : static int
1263 : 64886829 : sock_uring_group_reap(struct spdk_uring_sock_group_impl *group, int max, int max_read_events,
1264 : : struct spdk_sock **socks)
1265 : : {
1266 : : int i, count, ret;
1267 : : struct io_uring_cqe *cqe;
1268 : : struct spdk_uring_sock *sock, *tmp;
1269 : : struct spdk_uring_task *task;
1270 : : int status, bid, flags;
1271 : : bool is_zcopy;
1272 : :
1273 [ + + ]: 161228926 : for (i = 0; i < max; i++) {
1274 : 96342097 : ret = io_uring_peek_cqe(&group->uring, &cqe);
1275 [ - + ]: 96342097 : if (ret != 0) {
1276 : 0 : break;
1277 : : }
1278 : :
1279 [ - + ]: 96342097 : if (cqe == NULL) {
1280 : 0 : break;
1281 : : }
1282 : :
1283 : 96342097 : task = (struct spdk_uring_task *)cqe->user_data;
1284 [ - + ]: 96342097 : assert(task != NULL);
1285 : 96342097 : sock = task->sock;
1286 [ - + ]: 96342097 : assert(sock != NULL);
1287 [ - + ]: 96342097 : assert(sock->group != NULL);
1288 [ - + ]: 96342097 : assert(sock->group == group);
1289 : 96342097 : sock->group->io_inflight--;
1290 : 96342097 : sock->group->io_avail++;
1291 : 96342097 : status = cqe->res;
1292 : 96342097 : flags = cqe->flags;
1293 : 96342097 : io_uring_cqe_seen(&group->uring, cqe);
1294 : :
1295 : 96342097 : task->status = SPDK_URING_SOCK_TASK_NOT_IN_USE;
1296 : :
1297 [ + + - + : 96342097 : switch (task->type) {
- ]
1298 : 94190981 : case URING_TASK_READ:
1299 [ + - - + ]: 94190981 : if (status == -EAGAIN || status == -EWOULDBLOCK) {
1300 : : /* This likely shouldn't happen, but would indicate that the
1301 : : * kernel didn't have enough resources to queue a task internally. */
1302 : 0 : _sock_prep_read(&sock->base);
1303 [ - + ]: 94190981 : } else if (status == -ECANCELED) {
1304 : 0 : continue;
1305 [ + - ]: 94190981 : } else if (status == -ENOBUFS) {
1306 : : /* There's data in the socket but the user hasn't provided any buffers.
1307 : : * We need to notify the user that the socket has data pending. */
1308 [ + - ]: 94190981 : if (sock->base.cb_fn != NULL &&
1309 [ - + + + ]: 94190981 : sock->pending_recv == false) {
1310 : 2108786 : sock->pending_recv = true;
1311 : 2108786 : TAILQ_INSERT_TAIL(&group->pending_recv, sock, link);
1312 : : }
1313 : :
1314 : 94190981 : _sock_prep_read(&sock->base);
1315 [ # # ]: 0 : } else if (spdk_unlikely(status <= 0)) {
1316 [ # # ]: 0 : uring_sock_fail(sock, status < 0 ? status : -ECONNRESET);
1317 : : } else {
1318 : : struct spdk_uring_buf_tracker *tracker;
1319 : :
1320 [ # # ]: 0 : assert((flags & IORING_CQE_F_BUFFER) != 0);
1321 : :
1322 : 0 : bid = flags >> IORING_CQE_BUFFER_SHIFT;
1323 : 0 : tracker = &group->trackers[bid];
1324 : :
1325 [ # # ]: 0 : assert(tracker->buf != NULL);
1326 [ # # ]: 0 : assert(tracker->len != 0);
1327 : :
1328 : : /* Append this data to the stream */
1329 : 0 : tracker->len = status;
1330 : 0 : STAILQ_INSERT_TAIL(&sock->recv_stream, tracker, link);
1331 [ # # ]: 0 : assert(group->buf_ring_count > 0);
1332 : 0 : group->buf_ring_count--;
1333 : :
1334 [ # # ]: 0 : if (sock->base.cb_fn != NULL &&
1335 [ # # # # ]: 0 : sock->pending_recv == false) {
1336 : 0 : sock->pending_recv = true;
1337 : 0 : TAILQ_INSERT_TAIL(&group->pending_recv, sock, link);
1338 : : }
1339 : :
1340 : 0 : _sock_prep_read(&sock->base);
1341 : : }
1342 : 94190981 : break;
1343 : 2149923 : case URING_TASK_WRITE:
1344 [ + + + - : 2149923 : if (status == -EAGAIN || status == -EWOULDBLOCK ||
- + ]
1345 [ - - - - : 1869986 : (status == -ENOBUFS && sock->zcopy) ||
- + ]
1346 : : status == -ECANCELED) {
1347 : 279937 : continue;
1348 [ + + ]: 1869986 : } else if (spdk_unlikely(status) < 0) {
1349 : 1 : uring_sock_fail(sock, status);
1350 : : } else {
1351 : 1869985 : task->last_req = NULL;
1352 : 1869985 : task->iov_cnt = 0;
1353 [ - + ]: 1869985 : is_zcopy = task->is_zcopy;
1354 : 1869985 : task->is_zcopy = false;
1355 : 1869985 : sock_complete_write_reqs(&sock->base, status, is_zcopy);
1356 : : }
1357 : :
1358 : 1869986 : break;
1359 : : #ifdef SPDK_ZEROCOPY
1360 : 0 : case URING_TASK_ERRQUEUE:
1361 [ # # # # ]: 0 : if (status == -EAGAIN || status == -EWOULDBLOCK) {
1362 : 0 : _sock_prep_errqueue(&sock->base);
1363 [ # # ]: 0 : } else if (status == -ECANCELED) {
1364 : 0 : continue;
1365 [ # # ]: 0 : } else if (spdk_unlikely(status < 0)) {
1366 : 0 : uring_sock_fail(sock, status);
1367 : : } else {
1368 : 0 : _sock_check_zcopy(&sock->base, status);
1369 : 0 : _sock_prep_errqueue(&sock->base);
1370 : : }
1371 : 0 : break;
1372 : : #endif
1373 : 1193 : case URING_TASK_CANCEL:
1374 : : /* Do nothing */
1375 : 1193 : break;
1376 : 0 : default:
1377 : 0 : SPDK_UNREACHABLE();
1378 : : }
1379 : : }
1380 : :
1381 [ + + ]: 64886829 : if (!socks) {
1382 : 1193 : return 0;
1383 : : }
1384 : 64885636 : count = 0;
1385 [ + + ]: 159073483 : TAILQ_FOREACH_SAFE(sock, &group->pending_recv, link, tmp) {
1386 [ - + ]: 94187847 : if (count == max_read_events) {
1387 : 0 : break;
1388 : : }
1389 : :
1390 : : /* If the socket's cb_fn is NULL, do not add it to socks array */
1391 [ - + ]: 94187847 : if (spdk_unlikely(sock->base.cb_fn == NULL)) {
1392 [ # # # # ]: 0 : assert(sock->pending_recv == true);
1393 : 0 : sock->pending_recv = false;
1394 [ # # ]: 0 : TAILQ_REMOVE(&group->pending_recv, sock, link);
1395 : 0 : continue;
1396 : : }
1397 : :
1398 : 94187847 : socks[count++] = &sock->base;
1399 : : }
1400 : :
1401 : :
1402 : : /* Cycle the pending_recv list so that each time we poll things aren't
1403 : : * in the same order. Say we have 6 sockets in the list, named as follows:
1404 : : * A B C D E F
1405 : : * And all 6 sockets had the poll events, but max_events is only 3. That means
1406 : : * psock currently points at D. We want to rearrange the list to the following:
1407 : : * D E F A B C
1408 : : *
1409 : : * The variables below are named according to this example to make it easier to
1410 : : * follow the swaps.
1411 : : */
1412 [ + - ]: 64885636 : if (sock != NULL) {
1413 : : struct spdk_uring_sock *ua, *uc, *ud, *uf;
1414 : :
1415 : : /* Capture pointers to the elements we need */
1416 : 0 : ud = sock;
1417 : :
1418 : 0 : ua = TAILQ_FIRST(&group->pending_recv);
1419 [ # # ]: 0 : if (ua == ud) {
1420 : 0 : goto end;
1421 : : }
1422 : :
1423 : 0 : uf = TAILQ_LAST(&group->pending_recv, pending_recv_list);
1424 [ # # ]: 0 : if (uf == ud) {
1425 [ # # ]: 0 : TAILQ_REMOVE(&group->pending_recv, ud, link);
1426 [ # # ]: 0 : TAILQ_INSERT_HEAD(&group->pending_recv, ud, link);
1427 : 0 : goto end;
1428 : : }
1429 : :
1430 : 0 : uc = TAILQ_PREV(ud, pending_recv_list, link);
1431 [ # # ]: 0 : assert(uc != NULL);
1432 : :
1433 : : /* Break the link between C and D */
1434 : 0 : uc->link.tqe_next = NULL;
1435 : :
1436 : : /* Connect F to A */
1437 : 0 : uf->link.tqe_next = ua;
1438 : 0 : ua->link.tqe_prev = &uf->link.tqe_next;
1439 : :
1440 : : /* Fix up the list first/last pointers */
1441 : 0 : group->pending_recv.tqh_first = ud;
1442 : 0 : group->pending_recv.tqh_last = &uc->link.tqe_next;
1443 : :
1444 : : /* D is in front of the list, make tqe prev pointer point to the head of list */
1445 : 0 : ud->link.tqe_prev = &group->pending_recv.tqh_first;
1446 : : }
1447 : :
1448 : 64885636 : end:
1449 : 64885636 : return count;
1450 : : }
1451 : :
1452 : : static int uring_sock_flush(struct spdk_sock *_sock);
1453 : :
1454 : : static void
1455 : 11261729 : uring_sock_writev_async(struct spdk_sock *_sock, struct spdk_sock_request *req)
1456 : : {
1457 : 11261729 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1458 : : int rc;
1459 : :
1460 [ - + ]: 11261729 : if (spdk_unlikely(sock->connection_status)) {
1461 : 0 : req->cb_fn(req->cb_arg, sock->connection_status);
1462 : 0 : return;
1463 : : }
1464 : :
1465 : 11261729 : spdk_sock_request_queue(_sock, req);
1466 : :
1467 [ + + ]: 11261729 : if (!sock->group) {
1468 [ - + ]: 5861 : if (_sock->queued_iovcnt >= IOV_BATCH_SIZE) {
1469 : 0 : rc = uring_sock_flush(_sock);
1470 [ # # # # ]: 0 : if (rc < 0 && errno != EAGAIN) {
1471 : 0 : spdk_sock_abort_requests(_sock);
1472 : : }
1473 : : }
1474 : : }
1475 : : }
1476 : :
1477 : : static int
1478 : 773 : uring_sock_set_recvlowat(struct spdk_sock *_sock, int nbytes)
1479 : : {
1480 : 773 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1481 : : int val;
1482 : : int rc;
1483 : :
1484 [ - + ]: 773 : assert(sock != NULL);
1485 : :
1486 : 773 : val = nbytes;
1487 : 773 : rc = setsockopt(sock->fd, SOL_SOCKET, SO_RCVLOWAT, &val, sizeof val);
1488 [ - + ]: 773 : if (rc != 0) {
1489 : 0 : return -1;
1490 : : }
1491 : 773 : return 0;
1492 : : }
1493 : :
1494 : : static bool
1495 : 0 : uring_sock_is_ipv6(struct spdk_sock *_sock)
1496 : : {
1497 : 0 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1498 : : struct sockaddr_storage sa;
1499 : : socklen_t salen;
1500 : : int rc;
1501 : :
1502 [ # # ]: 0 : assert(sock != NULL);
1503 : :
1504 : 0 : memset(&sa, 0, sizeof sa);
1505 : 0 : salen = sizeof sa;
1506 : 0 : rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen);
1507 [ # # ]: 0 : if (rc != 0) {
1508 : 0 : SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
1509 : 0 : return false;
1510 : : }
1511 : :
1512 : 0 : return (sa.ss_family == AF_INET6);
1513 : : }
1514 : :
1515 : : static bool
1516 : 1010 : uring_sock_is_ipv4(struct spdk_sock *_sock)
1517 : : {
1518 : 1010 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1519 : : struct sockaddr_storage sa;
1520 : : socklen_t salen;
1521 : : int rc;
1522 : :
1523 [ - + ]: 1010 : assert(sock != NULL);
1524 : :
1525 : 1010 : memset(&sa, 0, sizeof sa);
1526 : 1010 : salen = sizeof sa;
1527 : 1010 : rc = getsockname(sock->fd, (struct sockaddr *) &sa, &salen);
1528 [ - + ]: 1010 : if (rc != 0) {
1529 : 0 : SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
1530 : 0 : return false;
1531 : : }
1532 : :
1533 : 1010 : return (sa.ss_family == AF_INET);
1534 : : }
1535 : :
1536 : : static bool
1537 : 37948 : uring_sock_is_connected(struct spdk_sock *_sock)
1538 : : {
1539 : 37948 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1540 : : uint8_t byte;
1541 : : int rc;
1542 : :
1543 : 37948 : rc = recv(sock->fd, &byte, 1, MSG_PEEK | MSG_DONTWAIT);
1544 [ + - ]: 37948 : if (rc == 0) {
1545 : 37948 : return false;
1546 : : }
1547 : :
1548 [ # # ]: 0 : if (rc < 0) {
1549 [ # # # # ]: 0 : if (errno == EAGAIN || errno == EWOULDBLOCK) {
1550 : 0 : return true;
1551 : : }
1552 : :
1553 : 0 : return false;
1554 : : }
1555 : :
1556 : 0 : return true;
1557 : : }
1558 : :
1559 : : static struct spdk_sock_group_impl *
1560 : 503 : uring_sock_group_impl_get_optimal(struct spdk_sock *_sock, struct spdk_sock_group_impl *hint)
1561 : : {
1562 : 503 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1563 : : struct spdk_sock_group_impl *group;
1564 : :
1565 [ - + ]: 503 : if (sock->placement_id != -1) {
1566 : 0 : spdk_sock_map_lookup(&g_map, sock->placement_id, &group, hint);
1567 : 0 : return group;
1568 : : }
1569 : :
1570 : 503 : return NULL;
1571 : : }
1572 : :
1573 : : static int
1574 : 782 : uring_sock_group_impl_buf_pool_free(struct spdk_uring_sock_group_impl *group_impl)
1575 : : {
1576 [ + - ]: 782 : if (group_impl->buf_ring) {
1577 : 782 : io_uring_unregister_buf_ring(&group_impl->uring, URING_BUF_GROUP_ID);
1578 : 782 : free(group_impl->buf_ring);
1579 : : }
1580 : :
1581 : 782 : free(group_impl->trackers);
1582 : :
1583 : 782 : return 0;
1584 : : }
1585 : :
1586 : : static int
1587 : 782 : uring_sock_group_impl_buf_pool_alloc(struct spdk_uring_sock_group_impl *group_impl)
1588 : : {
1589 : 782 : struct io_uring_buf_reg buf_reg = {};
1590 : : struct io_uring_buf_ring *buf_ring;
1591 : : int i, rc;
1592 : :
1593 [ - + ]: 782 : rc = posix_memalign((void **)&buf_ring, 0x1000, URING_BUF_POOL_SIZE * sizeof(struct io_uring_buf));
1594 [ - + ]: 782 : if (rc != 0) {
1595 : : /* posix_memalign returns positive errno values */
1596 : 0 : return -rc;
1597 : : }
1598 : :
1599 : 782 : buf_reg.ring_addr = (unsigned long long)buf_ring;
1600 : 782 : buf_reg.ring_entries = URING_BUF_POOL_SIZE;
1601 : 782 : buf_reg.bgid = URING_BUF_GROUP_ID;
1602 : :
1603 : 782 : rc = io_uring_register_buf_ring(&group_impl->uring, &buf_reg, 0);
1604 [ - + ]: 782 : if (rc != 0) {
1605 : 0 : free(buf_ring);
1606 : 0 : return rc;
1607 : : }
1608 : :
1609 : 782 : group_impl->buf_ring = buf_ring;
1610 : 782 : io_uring_buf_ring_init(group_impl->buf_ring);
1611 : 782 : group_impl->buf_ring_count = 0;
1612 : :
1613 : 782 : group_impl->trackers = calloc(URING_BUF_POOL_SIZE, sizeof(struct spdk_uring_buf_tracker));
1614 [ - + ]: 782 : if (group_impl->trackers == NULL) {
1615 : 0 : uring_sock_group_impl_buf_pool_free(group_impl);
1616 : 0 : return -ENOMEM;
1617 : : }
1618 : :
1619 : 782 : STAILQ_INIT(&group_impl->free_trackers);
1620 : :
1621 [ + + ]: 100878 : for (i = 0; i < URING_BUF_POOL_SIZE; i++) {
1622 : 100096 : struct spdk_uring_buf_tracker *tracker = &group_impl->trackers[i];
1623 : :
1624 : 100096 : tracker->buf = NULL;
1625 : 100096 : tracker->len = 0;
1626 : 100096 : tracker->ctx = NULL;
1627 : 100096 : tracker->id = i;
1628 : :
1629 : 100096 : STAILQ_INSERT_TAIL(&group_impl->free_trackers, tracker, link);
1630 : : }
1631 : :
1632 : 782 : return 0;
1633 : : }
1634 : :
1635 : : static struct spdk_sock_group_impl *
1636 : 782 : uring_sock_group_impl_create(void)
1637 : : {
1638 : : struct spdk_uring_sock_group_impl *group_impl;
1639 : :
1640 : 782 : group_impl = calloc(1, sizeof(*group_impl));
1641 [ - + ]: 782 : if (group_impl == NULL) {
1642 : 0 : SPDK_ERRLOG("group_impl allocation failed\n");
1643 : 0 : return NULL;
1644 : : }
1645 : :
1646 : 782 : group_impl->io_avail = SPDK_SOCK_GROUP_QUEUE_DEPTH;
1647 : :
1648 [ - + ]: 782 : if (io_uring_queue_init(SPDK_SOCK_GROUP_QUEUE_DEPTH, &group_impl->uring, 0) < 0) {
1649 : 0 : SPDK_ERRLOG("uring I/O context setup failure\n");
1650 : 0 : free(group_impl);
1651 : 0 : return NULL;
1652 : : }
1653 : :
1654 : 782 : TAILQ_INIT(&group_impl->pending_recv);
1655 : :
1656 [ - + ]: 782 : if (uring_sock_group_impl_buf_pool_alloc(group_impl) < 0) {
1657 : 0 : SPDK_ERRLOG("Failed to create buffer ring."
1658 : : "uring sock implementation is likely not supported on this kernel.\n");
1659 : 0 : io_uring_queue_exit(&group_impl->uring);
1660 : 0 : free(group_impl);
1661 : 0 : return NULL;
1662 : : }
1663 : :
1664 [ - + ]: 782 : if (g_spdk_uring_sock_impl_opts.enable_placement_id == PLACEMENT_CPU) {
1665 : 0 : spdk_sock_map_insert(&g_map, spdk_env_get_current_core(), &group_impl->base);
1666 : : }
1667 : :
1668 : 782 : return &group_impl->base;
1669 : : }
1670 : :
1671 : : static int
1672 : 1193 : uring_sock_group_impl_add_sock(struct spdk_sock_group_impl *_group,
1673 : : struct spdk_sock *_sock)
1674 : : {
1675 : 1193 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1676 : 1193 : struct spdk_uring_sock_group_impl *group = __uring_group_impl(_group);
1677 : : int rc;
1678 : :
1679 : 1193 : sock->group = group;
1680 : 1193 : sock->write_task.sock = sock;
1681 : 1193 : sock->write_task.type = URING_TASK_WRITE;
1682 : :
1683 : 1193 : sock->read_task.sock = sock;
1684 : 1193 : sock->read_task.type = URING_TASK_READ;
1685 : :
1686 : 1193 : sock->errqueue_task.sock = sock;
1687 : 1193 : sock->errqueue_task.type = URING_TASK_ERRQUEUE;
1688 : 1193 : sock->errqueue_task.msg.msg_control = sock->buf;
1689 : 1193 : sock->errqueue_task.msg.msg_controllen = sizeof(sock->buf);
1690 : :
1691 : 1193 : sock->cancel_task.sock = sock;
1692 : 1193 : sock->cancel_task.type = URING_TASK_CANCEL;
1693 : :
1694 : : /* switched from another polling group due to scheduling */
1695 [ + + - + ]: 1193 : if (spdk_unlikely(sock->recv_pipe != NULL &&
1696 : : (spdk_pipe_reader_bytes_available(sock->recv_pipe) > 0))) {
1697 [ # # # # ]: 0 : assert(sock->pending_recv == false);
1698 : 0 : sock->pending_recv = true;
1699 : 0 : TAILQ_INSERT_TAIL(&group->pending_recv, sock, link);
1700 : : }
1701 : :
1702 [ - + ]: 1193 : if (sock->placement_id != -1) {
1703 : 0 : rc = spdk_sock_map_insert(&g_map, sock->placement_id, &group->base);
1704 [ # # ]: 0 : if (rc != 0) {
1705 : 0 : SPDK_ERRLOG("Failed to insert sock group into map: %d", rc);
1706 : : /* Do not treat this as an error. The system will continue running. */
1707 : : }
1708 : : }
1709 : :
1710 : : /* We get an async read going immediately */
1711 : 1193 : _sock_prep_read(&sock->base);
1712 : : #ifdef SPDK_ZEROCOPY
1713 [ - + - + ]: 1193 : if (sock->zcopy) {
1714 : 0 : _sock_prep_errqueue(_sock);
1715 : : }
1716 : : #endif
1717 : :
1718 : 1193 : return 0;
1719 : : }
1720 : :
1721 : : static void
1722 : 64886829 : uring_sock_group_populate_buf_ring(struct spdk_uring_sock_group_impl *group)
1723 : : {
1724 : : struct spdk_uring_buf_tracker *tracker;
1725 : : int count, mask;
1726 : :
1727 [ - + + - ]: 64886829 : if (g_spdk_uring_sock_impl_opts.enable_recv_pipe) {
1728 : : /* If recv_pipe is enabled, we do not post buffers. */
1729 : 64886829 : return;
1730 : : }
1731 : :
1732 : : /* Try to re-populate the io_uring's buffer pool using user-provided buffers */
1733 : 0 : tracker = STAILQ_FIRST(&group->free_trackers);
1734 : 0 : count = 0;
1735 : 0 : mask = io_uring_buf_ring_mask(URING_BUF_POOL_SIZE);
1736 [ # # ]: 0 : while (tracker != NULL) {
1737 : 0 : tracker->buflen = spdk_sock_group_get_buf(group->base.group, &tracker->buf, &tracker->ctx);
1738 [ # # ]: 0 : if (tracker->buflen == 0) {
1739 : 0 : break;
1740 : : }
1741 : :
1742 [ # # ]: 0 : assert(tracker->buf != NULL);
1743 [ # # ]: 0 : STAILQ_REMOVE_HEAD(&group->free_trackers, link);
1744 [ # # ]: 0 : assert(STAILQ_FIRST(&group->free_trackers) != tracker);
1745 : :
1746 : 0 : io_uring_buf_ring_add(group->buf_ring, tracker->buf, tracker->buflen, tracker->id, mask, count);
1747 : 0 : count++;
1748 : 0 : tracker = STAILQ_FIRST(&group->free_trackers);
1749 : : }
1750 : :
1751 [ # # ]: 0 : if (count > 0) {
1752 : 0 : group->buf_ring_count += count;
1753 : 0 : io_uring_buf_ring_advance(group->buf_ring, count);
1754 : : }
1755 : : }
1756 : :
1757 : : static int
1758 : 64886829 : uring_sock_group_impl_poll(struct spdk_sock_group_impl *_group, int max_events,
1759 : : struct spdk_sock **socks)
1760 : : {
1761 : 64886829 : struct spdk_uring_sock_group_impl *group = __uring_group_impl(_group);
1762 : : int count, ret;
1763 : : int to_complete, to_submit;
1764 : : struct spdk_sock *_sock, *tmp;
1765 : : struct spdk_uring_sock *sock;
1766 : :
1767 [ + + ]: 64886829 : if (spdk_likely(socks)) {
1768 [ + + ]: 159073709 : TAILQ_FOREACH_SAFE(_sock, &group->base.socks, link, tmp) {
1769 : 94188073 : sock = __uring_sock(_sock);
1770 [ - + ]: 94188073 : if (spdk_unlikely(sock->connection_status)) {
1771 : 0 : continue;
1772 : : }
1773 : 94188073 : _sock_flush(_sock);
1774 : : }
1775 : : }
1776 : :
1777 : : /* Try to re-populate the io_uring's buffer pool using user-provided buffers */
1778 : 64886829 : uring_sock_group_populate_buf_ring(group);
1779 : :
1780 : 64886829 : to_submit = group->io_queued;
1781 : :
1782 : : /* For network I/O, it cannot be set with O_DIRECT, so we do not need to call spdk_io_uring_enter */
1783 [ + - ]: 64886829 : if (to_submit > 0) {
1784 : : /* If there are I/O to submit, use io_uring_submit here.
1785 : : * It will automatically call io_uring_enter appropriately. */
1786 : 64886829 : ret = io_uring_submit(&group->uring);
1787 [ - + ]: 64886829 : if (ret < 0) {
1788 : 0 : return 1;
1789 : : }
1790 : 64886829 : group->io_queued = 0;
1791 : 64886829 : group->io_inflight += to_submit;
1792 : 64886829 : group->io_avail -= to_submit;
1793 : : }
1794 : :
1795 : 64886829 : count = 0;
1796 : 64886829 : to_complete = group->io_inflight;
1797 [ - + - - ]: 64886829 : if (to_complete > 0 || !TAILQ_EMPTY(&group->pending_recv)) {
1798 : 64886829 : count = sock_uring_group_reap(group, to_complete, max_events, socks);
1799 : : }
1800 : :
1801 : 64886829 : return count;
1802 : : }
1803 : :
1804 : : static int
1805 : 1193 : uring_sock_group_impl_remove_sock(struct spdk_sock_group_impl *_group,
1806 : : struct spdk_sock *_sock)
1807 : : {
1808 : 1193 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1809 : 1193 : struct spdk_uring_sock_group_impl *group = __uring_group_impl(_group);
1810 : :
1811 : 1193 : sock->pending_group_remove = true;
1812 : :
1813 [ - + ]: 1193 : if (sock->write_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE) {
1814 : 0 : _sock_prep_cancel_task(_sock, &sock->write_task);
1815 : : /* Since spdk_sock_group_remove_sock is not asynchronous interface, so
1816 : : * currently can use a while loop here. */
1817 [ # # ]: 0 : while ((sock->write_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE) ||
1818 [ # # ]: 0 : (sock->cancel_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE)) {
1819 : 0 : uring_sock_group_impl_poll(_group, 32, NULL);
1820 : : }
1821 : : }
1822 : :
1823 [ + - ]: 1193 : if (sock->read_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE) {
1824 : 1193 : _sock_prep_cancel_task(_sock, &sock->read_task);
1825 : : /* Since spdk_sock_group_remove_sock is not asynchronous interface, so
1826 : : * currently can use a while loop here. */
1827 [ + + ]: 2386 : while ((sock->read_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE) ||
1828 [ - + ]: 1193 : (sock->cancel_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE)) {
1829 : 1193 : uring_sock_group_impl_poll(_group, 32, NULL);
1830 : : }
1831 : : }
1832 : :
1833 [ - + ]: 1193 : if (sock->errqueue_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE) {
1834 : 0 : _sock_prep_cancel_task(_sock, &sock->errqueue_task);
1835 : : /* Since spdk_sock_group_remove_sock is not asynchronous interface, so
1836 : : * currently can use a while loop here. */
1837 [ # # ]: 0 : while ((sock->errqueue_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE) ||
1838 [ # # ]: 0 : (sock->cancel_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE)) {
1839 : 0 : uring_sock_group_impl_poll(_group, 32, NULL);
1840 : : }
1841 : : }
1842 : :
1843 : : /* Make sure the cancelling the tasks above didn't cause sending new requests */
1844 [ - + ]: 1193 : assert(sock->write_task.status == SPDK_URING_SOCK_TASK_NOT_IN_USE);
1845 [ - + ]: 1193 : assert(sock->read_task.status == SPDK_URING_SOCK_TASK_NOT_IN_USE);
1846 [ - + ]: 1193 : assert(sock->errqueue_task.status == SPDK_URING_SOCK_TASK_NOT_IN_USE);
1847 : :
1848 [ - + + - ]: 1193 : if (sock->pending_recv) {
1849 [ + + ]: 1193 : TAILQ_REMOVE(&group->pending_recv, sock, link);
1850 : 1193 : sock->pending_recv = false;
1851 : : }
1852 [ - + - + ]: 1193 : assert(sock->pending_recv == false);
1853 : :
1854 : : /* We have no way to handle this case. We could let the user read this
1855 : : * buffer, but the buffer came from a group and we have lost the association
1856 : : * to that so we couldn't release it. */
1857 [ - + ]: 1193 : assert(STAILQ_EMPTY(&sock->recv_stream));
1858 : :
1859 [ - + ]: 1193 : if (sock->placement_id != -1) {
1860 : 0 : spdk_sock_map_release(&g_map, sock->placement_id);
1861 : : }
1862 : :
1863 : 1193 : sock->pending_group_remove = false;
1864 : 1193 : sock->group = NULL;
1865 : 1193 : return 0;
1866 : : }
1867 : :
1868 : : static int
1869 : 782 : uring_sock_group_impl_close(struct spdk_sock_group_impl *_group)
1870 : : {
1871 : 782 : struct spdk_uring_sock_group_impl *group = __uring_group_impl(_group);
1872 : :
1873 : : /* try to reap all the active I/O */
1874 [ - + ]: 782 : while (group->io_inflight) {
1875 : 0 : uring_sock_group_impl_poll(_group, 32, NULL);
1876 : : }
1877 [ - + ]: 782 : assert(group->io_inflight == 0);
1878 [ - + ]: 782 : assert(group->io_avail == SPDK_SOCK_GROUP_QUEUE_DEPTH);
1879 : :
1880 : 782 : uring_sock_group_impl_buf_pool_free(group);
1881 : :
1882 : 782 : io_uring_queue_exit(&group->uring);
1883 : :
1884 [ - + ]: 782 : if (g_spdk_uring_sock_impl_opts.enable_placement_id == PLACEMENT_CPU) {
1885 : 0 : spdk_sock_map_release(&g_map, spdk_env_get_current_core());
1886 : : }
1887 : :
1888 : 782 : free(group);
1889 : 782 : return 0;
1890 : : }
1891 : :
1892 : : static int
1893 : 90265 : uring_sock_flush(struct spdk_sock *_sock)
1894 : : {
1895 : 90265 : struct spdk_uring_sock *sock = __uring_sock(_sock);
1896 : 90265 : struct msghdr msg = {};
1897 : : struct iovec iovs[IOV_BATCH_SIZE];
1898 : : int iovcnt;
1899 : : ssize_t rc;
1900 : 90265 : int flags = sock->zcopy_send_flags;
1901 : : int retval;
1902 : 90265 : bool is_zcopy = false;
1903 : 90265 : struct spdk_uring_task *task = &sock->errqueue_task;
1904 : :
1905 : : /* Can't flush from within a callback or we end up with recursive calls */
1906 [ - + ]: 90265 : if (_sock->cb_cnt > 0) {
1907 : 0 : errno = EAGAIN;
1908 : 0 : return -1;
1909 : : }
1910 : :
1911 : : /* Can't flush while a write is already outstanding */
1912 [ - + ]: 90265 : if (sock->write_task.status != SPDK_URING_SOCK_TASK_NOT_IN_USE) {
1913 : 0 : errno = EAGAIN;
1914 : 0 : return -1;
1915 : : }
1916 : :
1917 : : /* Gather an iov */
1918 : 90265 : iovcnt = spdk_sock_prep_reqs(_sock, iovs, 0, NULL, &flags);
1919 [ + + ]: 90265 : if (iovcnt == 0) {
1920 : : /* Nothing to send */
1921 : 84860 : return 0;
1922 : : }
1923 : :
1924 : : /* Perform the vectored write */
1925 : 5405 : msg.msg_iov = iovs;
1926 : 5405 : msg.msg_iovlen = iovcnt;
1927 : 5405 : rc = sendmsg(sock->fd, &msg, flags | MSG_DONTWAIT);
1928 [ - + ]: 5405 : if (rc <= 0) {
1929 [ # # # # : 0 : if (rc == 0 || errno == EAGAIN || errno == EWOULDBLOCK || (errno == ENOBUFS && sock->zcopy)) {
# # # # #
# # # ]
1930 : 0 : errno = EAGAIN;
1931 : : }
1932 : 0 : return -1;
1933 : : }
1934 : :
1935 : : #ifdef SPDK_ZEROCOPY
1936 : 5405 : is_zcopy = flags & MSG_ZEROCOPY;
1937 : : #endif
1938 : 5405 : retval = sock_complete_write_reqs(_sock, rc, is_zcopy);
1939 [ - + ]: 5405 : if (retval < 0) {
1940 : : /* if the socket is closed, return to avoid heap-use-after-free error */
1941 : 0 : errno = ENOTCONN;
1942 : 0 : return -1;
1943 : : }
1944 : :
1945 : : #ifdef SPDK_ZEROCOPY
1946 : : /* At least do once to check zero copy case */
1947 [ - + - + : 5405 : if (sock->zcopy && !TAILQ_EMPTY(&_sock->pending_reqs)) {
- - ]
1948 : 0 : retval = recvmsg(sock->fd, &task->msg, MSG_ERRQUEUE);
1949 [ # # ]: 0 : if (retval < 0) {
1950 [ # # # # ]: 0 : if (errno == EWOULDBLOCK || errno == EAGAIN) {
1951 : 0 : return rc;
1952 : : }
1953 : : }
1954 : 0 : _sock_check_zcopy(_sock, retval);;
1955 : : }
1956 : : #endif
1957 : :
1958 : 5405 : return rc;
1959 : : }
1960 : :
1961 : : static int
1962 : 0 : uring_sock_group_impl_register_interrupt(struct spdk_sock_group_impl *_group, uint32_t events,
1963 : : spdk_interrupt_fn fn, void *arg, const char *name)
1964 : : {
1965 : 0 : SPDK_ERRLOG("Interrupt mode is not supported in the uring sock implementation.");
1966 : :
1967 : 0 : return -ENOTSUP;
1968 : : }
1969 : :
1970 : : static void
1971 : 0 : uring_sock_group_impl_unregister_interrupt(struct spdk_sock_group_impl *_group)
1972 : : {
1973 : 0 : }
1974 : :
1975 : : static struct spdk_net_impl g_uring_net_impl = {
1976 : : .name = "uring",
1977 : : .getaddr = uring_sock_getaddr,
1978 : : .connect = uring_sock_connect,
1979 : : .listen = uring_sock_listen,
1980 : : .accept = uring_sock_accept,
1981 : : .close = uring_sock_close,
1982 : : .recv = uring_sock_recv,
1983 : : .readv = uring_sock_readv,
1984 : : .writev = uring_sock_writev,
1985 : : .recv_next = uring_sock_recv_next,
1986 : : .writev_async = uring_sock_writev_async,
1987 : : .flush = uring_sock_flush,
1988 : : .set_recvlowat = uring_sock_set_recvlowat,
1989 : : .set_recvbuf = uring_sock_set_recvbuf,
1990 : : .set_sendbuf = uring_sock_set_sendbuf,
1991 : : .is_ipv6 = uring_sock_is_ipv6,
1992 : : .is_ipv4 = uring_sock_is_ipv4,
1993 : : .is_connected = uring_sock_is_connected,
1994 : : .group_impl_get_optimal = uring_sock_group_impl_get_optimal,
1995 : : .group_impl_create = uring_sock_group_impl_create,
1996 : : .group_impl_add_sock = uring_sock_group_impl_add_sock,
1997 : : .group_impl_remove_sock = uring_sock_group_impl_remove_sock,
1998 : : .group_impl_poll = uring_sock_group_impl_poll,
1999 : : .group_impl_register_interrupt = uring_sock_group_impl_register_interrupt,
2000 : : .group_impl_unregister_interrupt = uring_sock_group_impl_unregister_interrupt,
2001 : : .group_impl_close = uring_sock_group_impl_close,
2002 : : .get_opts = uring_sock_impl_get_opts,
2003 : : .set_opts = uring_sock_impl_set_opts,
2004 : : };
2005 : :
2006 : : __attribute__((constructor)) static void
2007 : 379 : net_impl_register_uring(void)
2008 : : {
2009 : : struct spdk_sock_group_impl *impl;
2010 : :
2011 : : /* Check if we can create a uring sock group before we register
2012 : : * it as a valid impl. */
2013 : 379 : impl = uring_sock_group_impl_create();
2014 [ + - ]: 379 : if (impl) {
2015 : 379 : uring_sock_group_impl_close(impl);
2016 : 379 : spdk_net_impl_register(&g_uring_net_impl);
2017 : : }
2018 : 379 : }
|