Skip to content

Commit

Permalink
test: convert reg-wait to regions
Browse files Browse the repository at this point in the history
liburing doesn't have a good region registration API yet so use raw
syscalls. Also locally add test_wait_reg_offset with which we can pass a
byte offset for testing unlike the safer exported API operating with
indexes.

Signed-off-by: Pavel Begunkov <[email protected]>
  • Loading branch information
isilence committed Nov 15, 2024
1 parent 68be527 commit cc4d6f7
Showing 1 changed file with 115 additions and 126 deletions.
241 changes: 115 additions & 126 deletions test/reg-wait.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,155 +13,121 @@
#include "liburing.h"
#include "helpers.h"
#include "test.h"
#include "../src/syscall.h"

static struct io_uring_reg_wait *reg;
static int test_register_region(struct io_uring *ring,
struct io_uring_mem_region_reg *reg)
{
return __sys_io_uring_register(ring->ring_fd, IORING_REGISTER_MEM_REGION,
reg, 1);
}

static int test_invalid_reg2(void)
static int test_wait_reg_offset(struct io_uring *ring,
unsigned wait_nr, unsigned long offset)
{
struct io_uring ring;
void *buf, *ptr;
int ret;
return __sys_io_uring_enter2(ring->ring_fd, 0, wait_nr,
IORING_ENTER_GETEVENTS,
(void *)offset,
sizeof(struct io_uring_reg_wait));
}

io_uring_queue_init(1, &ring, 0);
static struct io_uring_reg_wait *reg;

if (posix_memalign(&buf, 4096, 4096))
return T_EXIT_FAIL;
memset(buf, 0, 4096);
ptr = buf + 4096 - 32;
static int test_invalid_sig(struct io_uring *ring)
{
struct io_uring_cqe *cqe;
sigset_t sig;
int ret;

ret = io_uring_register_wait_reg(&ring, ptr, 1);
if (ret != -EINVAL) {
fprintf(stderr, "register cqwait: %d\n", ret);
return T_EXIT_FAIL;
}
memset(reg, 0, sizeof(*reg));
reg->ts.tv_sec = 1;
reg->ts.tv_nsec = 0;
reg->sigmask = (unsigned long) &sig;
reg->sigmask_sz = 1;

ptr = buf + (sizeof(struct io_uring_reg_wait) / 2);
ret = io_uring_register_wait_reg(&ring, ptr, 1);
ret = io_uring_submit_and_wait_reg(ring, &cqe, 1, 0);
if (ret != -EINVAL) {
fprintf(stderr, "register cqwait: %d\n", ret);
fprintf(stderr, "sigmask_sz failed: %d\n", ret);
return T_EXIT_FAIL;
}

free(buf);
buf = (void *) 0x1000;
ret = io_uring_register_wait_reg(&ring, buf, 1);
if (ret != -EFAULT) {
fprintf(stderr, "register cqwait: %d\n", ret);
return T_EXIT_FAIL;
}
memset(reg, 0, sizeof(*reg));
reg->ts.tv_sec = 1;
reg->ts.tv_nsec = 0;
reg->sigmask = 100;
reg->sigmask_sz = 8;

buf = (void *) 0x1240;
ret = io_uring_register_wait_reg(&ring, buf, 1);
ret = io_uring_submit_and_wait_reg(ring, &cqe, 1, 0);
if (ret != -EFAULT) {
fprintf(stderr, "register cqwait: %d\n", ret);
return T_EXIT_FAIL;
}

buf = (void *) 0x1241;
ret = io_uring_register_wait_reg(&ring, buf, 1);
if (ret != -EINVAL) {
fprintf(stderr, "register cqwait: %d\n", ret);
fprintf(stderr, "sigmask invalid failed: %d\n", ret);
return T_EXIT_FAIL;
}

io_uring_queue_exit(&ring);
return T_EXIT_PASS;
}

static int test_invalid_reg(void)
static int test_offsets(struct io_uring *ring)
{
struct io_uring_reg_wait *ireg;
struct io_uring_cqe *cqe;
struct io_uring ring;
struct timeval tv;
void *buf, *ptr;
int max_index = 4096 / sizeof(struct io_uring_reg_wait);
struct io_uring_reg_wait *rw;
unsigned long offset;
int ret;

io_uring_queue_init(1, &ring, 0);
rw = reg + max_index;
memset(rw, 0, sizeof(*rw));
rw->ts.tv_sec = 0;
rw->ts.tv_nsec = 1000;

if (posix_memalign(&buf, 4096, 4096))
return T_EXIT_FAIL;
memset(buf, 0, 4096);
ptr = buf + 512;
ireg = ptr;

ret = io_uring_register_wait_reg(&ring, ireg, 56);
if (ret) {
fprintf(stderr, "register cqwait: %d\n", ret);
ret = io_uring_submit_and_wait_reg(ring, &cqe, 1, 0);
if (ret != -EFAULT) {
fprintf(stderr, "max+1 index failed: %d\n", ret);
return T_EXIT_FAIL;
}

ireg = ptr;
memset(ireg, 0, sizeof(*ireg));
ireg->ts.tv_sec = 1;
ireg->ts.tv_nsec = 0;
ireg->flags = IORING_REG_WAIT_TS;
rw = reg + max_index - 1;
memset(rw, 0, sizeof(*rw));
rw->flags = IORING_REG_WAIT_TS;
rw->ts.tv_sec = 0;
rw->ts.tv_nsec = 1000;

gettimeofday(&tv, NULL);
ret = io_uring_submit_and_wait_reg(&ring, &cqe, 1, 0);
ret = io_uring_submit_and_wait_reg(ring, &cqe, 1, max_index - 1);
if (ret != -ETIME) {
fprintf(stderr, "wait_reg failed: %d\n", ret);
fprintf(stderr, "last index failed: %d\n", ret);
return T_EXIT_FAIL;
}

ret = mtime_since_now(&tv);
/* allow some slack, should be around 1.1s */
if (ret < 1000 || ret > 1200) {
fprintf(stderr, "wait too long or short: %d\n", ret);
goto err;
}

memset(ireg, 0, sizeof(*ireg));
ireg->ts.tv_sec = 1;
ireg->ts.tv_nsec = 0;
ireg->flags = IORING_REG_WAIT_TS;

gettimeofday(&tv, NULL);
ret = io_uring_submit_and_wait_reg(&ring, &cqe, 1, 56);
offset = 0UL - sizeof(long);
ret = test_wait_reg_offset(ring, 1, offset);
if (ret != -EFAULT) {
fprintf(stderr, "out-of-range reg_wait failed: %d\n", ret);
fprintf(stderr, "overflow offset failed: %d\n", ret);
return T_EXIT_FAIL;
}

free(buf);
io_uring_queue_exit(&ring);
return T_EXIT_PASS;
err:
io_uring_queue_exit(&ring);
return T_EXIT_FAIL;
}

static int test_invalid_sig(struct io_uring *ring)
{
struct io_uring_cqe *cqe;
sigset_t sig;
int ret;
offset = 4096 - sizeof(long);
rw = (void *)reg + offset;
memset(rw, 0, sizeof(*rw));
rw->flags = IORING_REG_WAIT_TS;
rw->ts.tv_sec = 0;
rw->ts.tv_nsec = 1000;

memset(reg, 0, sizeof(*reg));
reg->ts.tv_sec = 1;
reg->ts.tv_nsec = 0;
reg->sigmask = (unsigned long) &sig;
reg->sigmask_sz = 1;

ret = io_uring_submit_and_wait_reg(ring, &cqe, 1, 0);
if (ret != -EINVAL) {
fprintf(stderr, "sigmask_sz failed: %d\n", ret);
ret = test_wait_reg_offset(ring, 1, offset);
if (ret != -EFAULT) {
fprintf(stderr, "OOB offset failed: %d\n", ret);
return T_EXIT_FAIL;
}

memset(reg, 0, sizeof(*reg));
reg->ts.tv_sec = 1;
reg->ts.tv_nsec = 0;
reg->sigmask = 100;
reg->sigmask_sz = 8;
offset = 1;
rw = (void *)reg + offset;
memset(rw, 0, sizeof(*rw));
rw->flags = IORING_REG_WAIT_TS;
rw->ts.tv_sec = 0;
rw->ts.tv_nsec = 1000;

ret = io_uring_submit_and_wait_reg(ring, &cqe, 1, 0);
if (ret != -EFAULT) {
fprintf(stderr, "sigmask invalid failed: %d\n", ret);
return T_EXIT_FAIL;
}
/* undefined behaviour, check the kernel doesn't crash */
(void)test_wait_reg_offset(ring, 1, offset);

return T_EXIT_PASS;
return 0;
}

static int test_basic(struct io_uring *ring)
Expand Down Expand Up @@ -192,27 +158,50 @@ static int test_basic(struct io_uring *ring)
return T_EXIT_FAIL;
}

static int test_ring(void)
static int test_wait_arg(void)
{
struct io_uring_region_desc rd = {};
struct io_uring_mem_region_reg mr = {};
struct io_uring ring;
struct io_uring_params p = { };
void *buffer;
int ret;

p.flags = 0;
ret = io_uring_queue_init_params(8, &ring, &p);
ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED);
if (ret) {
if (ret == -EINVAL) {
printf("IORING_SETUP_R_DISABLED not supported, skip\n");
return 0;
}
fprintf(stderr, "ring setup failed: %d\n", ret);
return T_EXIT_FAIL;
}

buffer = aligned_alloc(4096, 4096 * 4);
if (!buffer) {
fprintf(stderr, "allocation failed\n");
return T_EXIT_FAIL;
}

rd.user_addr = (__u64)(unsigned long)buffer;
rd.size = 4096;
rd.flags = IORING_MEM_REGION_TYPE_USER;
mr.region_uptr = (__u64)(unsigned long)&rd;
mr.flags = IORING_MEM_REGION_REG_WAIT_ARG;

ret = test_register_region(&ring, &mr);
if (ret) {
fprintf(stderr, "region reg failed %i\n", ret);
return 1;
}

reg = io_uring_setup_reg_wait(&ring, 64, &ret);
if (!reg) {
if (ret == -EINVAL)
return T_EXIT_SKIP;
fprintf(stderr, "setup_reg_wait: %d\n", ret);
ret = io_uring_enable_rings(&ring);
if (ret) {
fprintf(stderr, "io_uring_enable_rings failure %i\n", ret);
return T_EXIT_FAIL;
}

reg = buffer;

ret = test_basic(&ring);
if (ret == T_EXIT_FAIL) {
fprintf(stderr, "test failed\n");
Expand All @@ -225,27 +214,27 @@ static int test_ring(void)
goto err;
}

ret = test_invalid_reg();
if (ret == T_EXIT_FAIL) {
fprintf(stderr, "test_invalid_reg failed\n");
goto err;
}

ret = test_invalid_reg2();
ret = test_offsets(&ring);
if (ret == T_EXIT_FAIL) {
fprintf(stderr, "test_invalid_reg2 failed\n");
fprintf(stderr, "test_offsets failed\n");
goto err;
}

err:
io_uring_queue_exit(&ring);
return ret;
}

int main(int argc, char *argv[])
{
int ret;

if (argc > 1)
return 0;

return test_ring();
ret = test_wait_arg();
if (ret == T_EXIT_FAIL) {
fprintf(stderr, "test_wait_arg failed\n");
return 1;
}
return 0;
}

0 comments on commit cc4d6f7

Please sign in to comment.