Skip to content

Commit

Permalink
test/regbuf-clone: test offset and replacement cloning
Browse files Browse the repository at this point in the history
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
axboe committed Nov 1, 2024
1 parent 4c2dd9c commit bb0804d
Showing 1 changed file with 263 additions and 0 deletions.
263 changes: 263 additions & 0 deletions test/regbuf-clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <stdlib.h>
#include <sys/uio.h>
#include <string.h>
#include <limits.h>

#include "liburing.h"
#include "helpers.h"
Expand All @@ -17,6 +18,38 @@
#define BUF_SIZE 8192

static int no_buf_clone;
static int no_buf_offset;

static void fdinfo_read(struct io_uring *ring)
{
char fd_name[128];
char *buf;
int fd;

buf = malloc(4096);

sprintf(fd_name, "/proc/self/fdinfo/%d", ring->ring_fd);
fd = open(fd_name, O_RDONLY);
if (fd < 0) {
perror("open");
return;
}

do {
int ret = read(fd, buf, 4096);

if (ret < 0) {
perror("fdinfo read");
break;
} else if (ret == 4096) {
continue;
}
break;
} while (1);

close(fd);
free(buf);
}

static int use_buf(struct io_uring *ring, void *addr, int index)
{
Expand All @@ -25,6 +58,8 @@ static int use_buf(struct io_uring *ring, void *addr, int index)
char src_buf[32];
int fds[2], ret;

fdinfo_read(ring);

if (pipe(fds) < 0)
return -errno;

Expand Down Expand Up @@ -53,6 +88,224 @@ static int use_buf(struct io_uring *ring, void *addr, int index)
return 0;
}

static int test_offsets(void)
{
struct iovec vecs[NR_VECS];
struct io_uring src, dst;
unsigned int i, offset, nr;
int ret;

ret = io_uring_queue_init(1, &src, 0);
if (ret) {
fprintf(stderr, "ring_init: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_queue_init(1, &dst, 0);
if (ret) {
fprintf(stderr, "ring_init: %d\n", ret);
return T_EXIT_FAIL;
}

for (i = 0; i < NR_VECS; i++) {
if (posix_memalign(&vecs[i].iov_base, 4096, BUF_SIZE))
return T_EXIT_FAIL;
vecs[i].iov_len = BUF_SIZE;
}

ret = io_uring_register_buffers(&src, vecs, NR_VECS);
if (ret < 0) {
if (ret == -ENOMEM)
return T_EXIT_SKIP;
return T_EXIT_FAIL;
}

/* clone half the buffers, src offset 0, but ask for too many */
offset = NR_VECS / 2;
nr = NR_VECS;
ret = io_uring_clone_buffers_offset(&dst, &src, 0, offset, nr, 0);
if (ret != -EOVERFLOW) {
if (ret == -EINVAL) {
no_buf_offset = 1;
return T_EXIT_SKIP;
}
fprintf(stderr, "Offset and too big total failed: %d\n", ret);
return T_EXIT_FAIL;
}

/* ask for too many buffers */
nr = NR_VECS + 1;
ret = io_uring_clone_buffers_offset(&dst, &src, 0, 0, nr, 0);
if (ret != -EINVAL) {
fprintf(stderr, "Too many buffers total failed: %d\n", ret);
return T_EXIT_FAIL;
}

/* clone half the buffers into start of src offset */
nr = NR_VECS / 2;
ret = io_uring_clone_buffers_offset(&dst, &src, 0, nr, nr, 0);
if (ret) {
fprintf(stderr, "Half clone with offset failed: %d\n", ret);
return T_EXIT_FAIL;
}

/* 'nr' offset should be 0 on the src side */
ret = use_buf(&dst, vecs[nr].iov_base, 0);
if (ret) {
fprintf(stderr, "1 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

ret = io_uring_unregister_buffers(&dst);
if (ret) {
fprintf(stderr, "Failed to unregister partial dst: %d\n", ret);
return T_EXIT_FAIL;
}

ret = use_buf(&dst, vecs[0].iov_base, 0);
if (ret != -EFAULT) {
fprintf(stderr, "2 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

/* clone half the buffers into middle of src offset */
nr = NR_VECS / 2;
ret = io_uring_clone_buffers_offset(&dst, &src, nr, nr, nr, 0);
if (ret) {
fprintf(stderr, "Half buffers and middle offset failed: %d\n", ret);
return T_EXIT_FAIL;
}

ret = use_buf(&dst, vecs[0].iov_base, 0);
if (ret != -EFAULT) {
fprintf(stderr, "3 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

ret = use_buf(&dst, vecs[nr].iov_base, nr);
if (ret) {
fprintf(stderr, "4 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

ret = io_uring_unregister_buffers(&dst);
if (ret) {
fprintf(stderr, "Failed to unregister partial dst: %d\n", ret);
return T_EXIT_FAIL;
}

/* clone buffers, but specify overflowing dst offset */
offset = UINT_MAX - 32;
nr = NR_VECS;
ret = io_uring_clone_buffers_offset(&dst, &src, 0, offset, nr, 0);
if (ret != -EOVERFLOW) {
fprintf(stderr, "Overflow dst offset failed: %d\n", ret);
return T_EXIT_FAIL;
}

/* clone half the buffers into middle of src offset */
nr = NR_VECS / 2;
ret = io_uring_clone_buffers_offset(&dst, &src, nr, nr, nr, 0);
if (ret) {
fprintf(stderr, "Clone half middle src offset failed: %d\n", ret);
return T_EXIT_FAIL;
}

ret = use_buf(&dst, vecs[nr].iov_base, nr);
if (ret) {
fprintf(stderr, "5 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

ret = use_buf(&dst, vecs[0].iov_base, 0);
if (ret != -EFAULT) {
fprintf(stderr, "5 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

/* should get -EBUSY now, REPLACE not set */
nr = NR_VECS / 2;
ret = io_uring_clone_buffers_offset(&dst, &src, nr, nr, nr, 0);
if (ret != -EBUSY) {
fprintf(stderr, "Replace buffers failed: %d\n", ret);
return T_EXIT_FAIL;
}

/* now replace the initial 0..n in dst (which are dummy nodes) */
ret = io_uring_clone_buffers_offset(&dst, &src, 0, 0, nr, IORING_REGISTER_DST_REPLACE);
if (ret) {
fprintf(stderr, "Buffer replace failed: %d\n", ret);
return T_EXIT_FAIL;
}

ret = use_buf(&dst, vecs[0].iov_base, 0);
if (ret) {
fprintf(stderr, "6 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

ret = io_uring_unregister_buffers(&dst);
if (ret) {
fprintf(stderr, "Failed to unregister partial dst: %d\n", ret);
return T_EXIT_FAIL;
}

ret = io_uring_register_buffers_sparse(&dst, NR_VECS);
if (ret) {
fprintf(stderr, "Register sparse buffers failed: %d\n", ret);
return T_EXIT_FAIL;
}

/* dst has a full sparse table, replace first NR_VECS / 2 with bufs */
nr = NR_VECS / 2;
ret = io_uring_clone_buffers_offset(&dst, &src, 0, 0, nr, 0);
if (ret != -EBUSY) {
fprintf(stderr, "Buffer replace failed: %d\n", ret);
return T_EXIT_FAIL;
}

ret = io_uring_clone_buffers_offset(&dst, &src, 0, 0, nr, IORING_REGISTER_DST_REPLACE);
if (ret) {
fprintf(stderr, "Buffer replace failed: %d\n", ret);
return T_EXIT_FAIL;
}

ret = use_buf(&dst, vecs[0].iov_base, 0);
if (ret) {
fprintf(stderr, "7 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

/* now expand existing dst table, from to NR_VECS + NR_VECS / 2 */
nr = NR_VECS;
offset = NR_VECS / 2;
ret = io_uring_clone_buffers_offset(&dst, &src, offset, 0, nr, IORING_REGISTER_DST_REPLACE);
if (ret) {
fprintf(stderr, "Buffer replace failed: %d\n", ret);
return T_EXIT_FAIL;
}

ret = use_buf(&dst, vecs[0].iov_base, 0);
if (ret) {
fprintf(stderr, "8 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

offset = NR_VECS + (NR_VECS / 2) - 1;
ret = use_buf(&dst, vecs[NR_VECS - 1].iov_base, offset);
if (ret) {
fprintf(stderr, "8b use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

ret = use_buf(&dst, vecs[NR_VECS / 2].iov_base, NR_VECS);
if (ret) {
fprintf(stderr, "9 use_buf=%d\n", ret);
return T_EXIT_FAIL;
}

return T_EXIT_PASS;
}

static int test(int reg_src, int reg_dst)
{
struct iovec vecs[NR_VECS];
Expand Down Expand Up @@ -315,5 +568,15 @@ int main(int argc, char *argv[])
return T_EXIT_FAIL;
}

ret = test_offsets();
if (ret == T_EXIT_SKIP) {
return T_EXIT_PASS;
} else if (ret != T_EXIT_PASS) {
fprintf(stderr, "test_offset failed\n");
return T_EXIT_FAIL;
}
if (no_buf_offset)
return T_EXIT_PASS;

return T_EXIT_PASS;
}

0 comments on commit bb0804d

Please sign in to comment.