From ca5c208ecb40eac1eeeedb6b41404bb83b159847 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sat, 2 Nov 2024 12:08:58 -0600 Subject: [PATCH] test/regbuf-clone: add test case for sparse buffer merging Development series had a bug where the kernel would dereference a NULL pointer node, which is just a sparse node, rather than skipping it. Add a test case for that. Not really a cloning issue, but let's add it in here anyway. Requires a huge page to hit it. Signed-off-by: Jens Axboe --- test/regbuf-clone.c | 62 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/test/regbuf-clone.c b/test/regbuf-clone.c index ce3226fc0..c391260ee 100644 --- a/test/regbuf-clone.c +++ b/test/regbuf-clone.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "liburing.h" #include "helpers.h" @@ -519,6 +520,61 @@ static int test_dummy(void) return T_EXIT_PASS; } +/* + * Register sparse buffer table, then try updating that with a few huge + * page entries. + */ +static int test_merge(void) +{ + int ret, res = T_EXIT_SKIP; + struct iovec vecs[8]; + struct io_uring ring; + __u64 tags[2]; + void *p1; + + p1 = mmap(NULL, 2*1024*1024, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_HUGETLB | MAP_HUGE_2MB | MAP_ANONYMOUS, + -1, 0); + if (p1 == MAP_FAILED) + return T_EXIT_SKIP; + + ret = io_uring_queue_init(1, &ring, 0); + if (ret) { + fprintf(stderr, "ring_init: %d\n", ret); + return T_EXIT_FAIL; + } + + memset(vecs, 0, sizeof(vecs)); + + ret = io_uring_register_buffers(&ring, vecs, 8); + if (ret < 0) { + if (ret == -EINVAL) + goto skip; + fprintf(stderr, "failed to register initial buffers: %d\n", ret); + return T_EXIT_FAIL; + } + + vecs[0].iov_base = p1; + vecs[0].iov_len = 4096; + vecs[1].iov_base = p1 + 4096; + vecs[1].iov_len = 4096; + + tags[0] = 1; + tags[1] = 2; + ret = io_uring_register_buffers_update_tag(&ring, 4, vecs, tags, 2); + if (ret < 0) { + if (ret == -EINVAL) + goto skip; + fprintf(stderr, "failed to register merge buffers: %d\n", ret); + return T_EXIT_FAIL; + } + res = T_EXIT_PASS; +skip: + munmap(p1, 2*1024*1024); + io_uring_queue_exit(&ring); + return res; +} + int main(int argc, char *argv[]) { int ret; @@ -526,6 +582,12 @@ int main(int argc, char *argv[]) if (argc > 1) return T_EXIT_SKIP; + ret = test_merge(); + if (ret == T_EXIT_FAIL) { + fprintf(stderr, "test_merge failed\n"); + return T_EXIT_FAIL; + } + ret = test(0, 0); if (ret == T_EXIT_SKIP) { return T_EXIT_SKIP;