blob: 59b99e18654ed893fc081613880a6c21822ae77c [file] [log] [blame]
/* SPDX-License-Identifier: MIT */
/*
* Description: test buffer cloning between rings
*
*/
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/uio.h>
#include "liburing.h"
#include "helpers.h"
#define NR_VECS 64
#define BUF_SIZE 8192
static int no_buf_clone;
static int test(int reg_src, int reg_dst)
{
struct iovec vecs[NR_VECS];
struct io_uring src, dst;
int ret, i;
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;
}
if (reg_src) {
ret = io_uring_register_ring_fd(&src);
if (ret < 0) {
if (ret == -EINVAL)
return T_EXIT_SKIP;
fprintf(stderr, "register ring: %d\n", ret);
return T_EXIT_FAIL;
}
}
if (reg_dst) {
ret = io_uring_register_ring_fd(&dst);
if (ret < 0) {
if (ret == -EINVAL)
return T_EXIT_SKIP;
fprintf(stderr, "register ring: %d\n", ret);
return T_EXIT_FAIL;
}
}
/* test fail with no buffers in src */
ret = io_uring_clone_buffers(&dst, &src);
if (ret == -EINVAL) {
/* no buffer copy support */
no_buf_clone = true;
return T_EXIT_SKIP;
} else if (ret != -ENXIO) {
fprintf(stderr, "empty copy: %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;
}
/* copy should work now */
ret = io_uring_clone_buffers(&dst, &src);
if (ret) {
fprintf(stderr, "buffer copy: %d\n", ret);
return T_EXIT_FAIL;
}
/* try copy again, should get -EBUSY */
ret = io_uring_clone_buffers(&dst, &src);
if (ret != -EBUSY) {
fprintf(stderr, "busy copy: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_unregister_buffers(&dst);
if (ret) {
fprintf(stderr, "dst unregister buffers: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_unregister_buffers(&dst);
if (ret != -ENXIO) {
fprintf(stderr, "dst unregister empty buffers: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_unregister_buffers(&src);
if (ret) {
fprintf(stderr, "src unregister buffers: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_register_buffers(&dst, vecs, NR_VECS);
if (ret < 0) {
fprintf(stderr, "register buffers dst; %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_clone_buffers(&src, &dst);
if (ret) {
fprintf(stderr, "buffer copy reverse: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_unregister_buffers(&dst);
if (ret) {
fprintf(stderr, "dst unregister buffers: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_unregister_buffers(&dst);
if (ret != -ENXIO) {
fprintf(stderr, "dst unregister empty buffers: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_unregister_buffers(&src);
if (ret) {
fprintf(stderr, "src unregister buffers: %d\n", ret);
return T_EXIT_FAIL;
}
io_uring_queue_exit(&src);
io_uring_queue_exit(&dst);
for (i = 0; i < NR_VECS; i++)
free(vecs[i].iov_base);
return T_EXIT_PASS;
}
static int test_dummy(void)
{
struct iovec vec = { };
struct io_uring src, dst;
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;
}
ret = io_uring_register_buffers(&src, &vec, 1);
if (ret < 0) {
fprintf(stderr, "failed to register dummy buffer: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_clone_buffers(&dst, &src);
if (ret) {
fprintf(stderr, "clone dummy buf: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_unregister_buffers(&src);
if (ret) {
fprintf(stderr, "rsc unregister buffers: %d\n", ret);
return T_EXIT_FAIL;
}
ret = io_uring_unregister_buffers(&dst);
if (ret) {
fprintf(stderr, "dst unregister buffers: %d\n", ret);
return T_EXIT_FAIL;
}
io_uring_queue_exit(&src);
io_uring_queue_exit(&dst);
return T_EXIT_PASS;
}
int main(int argc, char *argv[])
{
int ret;
if (argc > 1)
return T_EXIT_SKIP;
ret = test(0, 0);
if (ret == T_EXIT_SKIP) {
return T_EXIT_SKIP;
} else if (ret != T_EXIT_PASS) {
fprintf(stderr, "test 0 0 failed\n");
return T_EXIT_FAIL;
}
if (no_buf_clone)
return T_EXIT_SKIP;
ret = test(0, 1);
if (ret == T_EXIT_SKIP) {
return T_EXIT_SKIP;
} else if (ret != T_EXIT_PASS) {
fprintf(stderr, "test 0 1 failed\n");
return T_EXIT_FAIL;
}
ret = test(1, 0);
if (ret == T_EXIT_SKIP) {
return T_EXIT_SKIP;
} else if (ret != T_EXIT_PASS) {
fprintf(stderr, "test 1 0 failed\n");
return T_EXIT_FAIL;
}
ret = test(1, 1);
if (ret == T_EXIT_SKIP) {
return T_EXIT_SKIP;
} else if (ret != T_EXIT_PASS) {
fprintf(stderr, "test 1 1 failed\n");
return T_EXIT_FAIL;
}
ret = test_dummy();
if (ret == T_EXIT_SKIP) {
return T_EXIT_SKIP;
} else if (ret != T_EXIT_PASS) {
fprintf(stderr, "test_dummy failed\n");
return T_EXIT_FAIL;
}
return T_EXIT_PASS;
}