This adds support for the new IORING_OP_FREMOVEXATTR and IORING_OP_FLISTXATTR opcodes: - Add opcodes to src/include/liburing/io_uring.h - Register sanitizers in src/sanitize.c (updating static assert) - Implement inline prep functions in src/include/liburing.h: - io_uring_prep_fremovexattr() - io_uring_prep_flistxattr() - Add full functional and negative failure tests in test/xattr.c Signed-off-by: Aditya Prakash Srivastava --- src/include/liburing.h | 17 ++++ src/include/liburing/io_uring.h | 2 + src/sanitize.c | 4 +- test/xattr.c | 173 ++++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 1 deletion(-) diff --git a/src/include/liburing.h b/src/include/liburing.h index 0188937b..f99f51fe 100644 --- a/src/include/liburing.h +++ b/src/include/liburing.h @@ -1513,6 +1513,23 @@ IOURINGINLINE void io_uring_prep_fsetxattr(struct io_uring_sqe *sqe, int fd, sqe->xattr_flags = flags; } +IOURINGINLINE void io_uring_prep_fremovexattr(struct io_uring_sqe *sqe, int fd, + const char *name) + LIBURING_NOEXCEPT +{ + io_uring_prep_rw(IORING_OP_FREMOVEXATTR, sqe, fd, name, 0, 0); + sqe->xattr_flags = 0; +} + +IOURINGINLINE void io_uring_prep_flistxattr(struct io_uring_sqe *sqe, int fd, + char *list, unsigned int len) + LIBURING_NOEXCEPT +{ + io_uring_prep_rw(IORING_OP_FLISTXATTR, sqe, fd, NULL, len, + (__u64) (uintptr_t) list); + sqe->xattr_flags = 0; +} + IOURINGINLINE void io_uring_prep_socket(struct io_uring_sqe *sqe, int domain, int type, int protocol, unsigned int flags) diff --git a/src/include/liburing/io_uring.h b/src/include/liburing/io_uring.h index b9ec1ebf..89480960 100644 --- a/src/include/liburing/io_uring.h +++ b/src/include/liburing/io_uring.h @@ -312,6 +312,8 @@ enum io_uring_op { IORING_OP_PIPE, IORING_OP_NOP128, IORING_OP_URING_CMD128, + IORING_OP_FREMOVEXATTR, + IORING_OP_FLISTXATTR, /* this goes last, obviously */ IORING_OP_LAST, diff --git a/src/sanitize.c b/src/sanitize.c index 37fb63e6..45f6f60c 100644 --- a/src/sanitize.c +++ b/src/sanitize.c @@ -121,8 +121,10 @@ static const sanitize_sqe_handler sanitize_handlers[IORING_OP_LAST] = { [IORING_OP_PIPE] = sanitize_sqe_addr, [IORING_OP_NOP128] = sanitize_sqe_nop, [IORING_OP_URING_CMD128] = sanitize_sqe_optval, + [IORING_OP_FREMOVEXATTR] = sanitize_sqe_addr, + [IORING_OP_FLISTXATTR] = sanitize_sqe_addr2, }; -_Static_assert(IORING_OP_URING_CMD128 + 1 == IORING_OP_LAST, +_Static_assert(IORING_OP_FLISTXATTR + 1 == IORING_OP_LAST, "Need an implementation for all IORING_OP_* codes"); void liburing_sanitize_ring(struct io_uring *ring) diff --git a/test/xattr.c b/test/xattr.c index 6448e063..4b7338c8 100644 --- a/test/xattr.c +++ b/test/xattr.c @@ -173,6 +173,71 @@ static int io_uring_getxattr(struct io_uring *ring, const char *path, return ret; } +/* Submit fremovexattr request. */ +static int io_uring_fremovexattr(struct io_uring *ring, int fd, const char *name) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + int ret; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "Error cannot get sqe\n"); + return -1; + } + + io_uring_prep_fremovexattr(sqe, fd, name); + + ret = io_uring_submit(ring); + if (ret != 1) { + fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret); + return -1; + } + + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret); + return -1; + } + + ret = cqe->res; + io_uring_cqe_seen(ring, cqe); + return ret; +} + +/* Submit flistxattr request. */ +static int io_uring_flistxattr(struct io_uring *ring, int fd, char *list, + size_t size) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + int ret; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "Error cannot get sqe\n"); + return -1; + } + + io_uring_prep_flistxattr(sqe, fd, list, size); + + ret = io_uring_submit(ring); + if (ret != 1) { + fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret); + return -1; + } + + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret); + return -1; + } + + ret = cqe->res; + io_uring_cqe_seen(ring, cqe); + return ret; +} + /* Test driver for fsetxattr and fgetxattr. */ static int test_fxattr(void) { @@ -227,6 +292,104 @@ static int test_fxattr(void) goto Exit; } + /* Test flistxattr. */ + char list_buf[XATTR_SIZE]; + int list_len; + + list_len = io_uring_flistxattr(&ring, fd, list_buf, XATTR_SIZE); + if (list_len < 0) { + fprintf(stderr, "Error: flistxattr failed with %d\n", list_len); + rc = -1; + goto Exit; + } + + int found_key1 = 0, found_key2 = 0; + char *p; + + p = list_buf; + while (p < list_buf + list_len) { + if (strcmp(p, KEY1) == 0) + found_key1 = 1; + else if (strcmp(p, KEY2) == 0) + found_key2 = 1; + p += strlen(p) + 1; + } + if (!found_key1 || !found_key2) { + fprintf(stderr, "Error: flistxattr did not return both keys\n"); + rc = -1; + goto Exit; + } + + /* Test fremovexattr for key1. */ + ret = io_uring_fremovexattr(&ring, fd, KEY1); + if (ret < 0) { + fprintf(stderr, "Error: fremovexattr on key1 failed with %d\n", ret); + rc = -1; + goto Exit; + } + + /* Verify key1 is gone via fgetxattr. */ + ret = io_uring_fgetxattr(&ring, fd, KEY1, value, XATTR_SIZE); + if (ret >= 0) { + fprintf(stderr, "Error: fgetxattr key1 should have failed after fremovexattr\n"); + rc = -1; + goto Exit; + } + + /* Verify flistxattr now only has key2. */ + list_len = io_uring_flistxattr(&ring, fd, list_buf, XATTR_SIZE); + if (list_len < 0) { + fprintf(stderr, "Error: second flistxattr failed with %d\n", list_len); + rc = -1; + goto Exit; + } + + found_key1 = 0; found_key2 = 0; + p = list_buf; + while (p < list_buf + list_len) { + if (strcmp(p, KEY1) == 0) + found_key1 = 1; + else if (strcmp(p, KEY2) == 0) + found_key2 = 1; + p += strlen(p) + 1; + } + if (found_key1 || !found_key2) { + fprintf(stderr, "Error: flistxattr unexpected keys after removing key1\n"); + rc = -1; + goto Exit; + } + + /* Test fremovexattr for key2. */ + ret = io_uring_fremovexattr(&ring, fd, KEY2); + if (ret < 0) { + fprintf(stderr, "Error: fremovexattr on key2 failed with %d\n", ret); + rc = -1; + goto Exit; + } + + /* Verify both are gone from flistxattr. */ + list_len = io_uring_flistxattr(&ring, fd, list_buf, XATTR_SIZE); + if (list_len < 0) { + fprintf(stderr, "Error: third flistxattr failed with %d\n", list_len); + rc = -1; + goto Exit; + } + + found_key1 = 0; found_key2 = 0; + p = list_buf; + while (p < list_buf + list_len) { + if (strcmp(p, KEY1) == 0) + found_key1 = 1; + else if (strcmp(p, KEY2) == 0) + found_key2 = 1; + p += strlen(p) + 1; + } + if (found_key1 || found_key2) { + fprintf(stderr, "Error: flistxattr returned keys after removing all keys\n"); + rc = -1; + goto Exit; + } + /* Cleanup. */ Exit: close(fd); @@ -331,6 +494,16 @@ static int test_failure_fxattr(void) if (io_uring_fgetxattr(&ring, fd, KEY1, value, 0) != 0) return 1; + /* Test list attributes failures. */ + if (io_uring_flistxattr(&ring, -1, value, XATTR_SIZE) >= 0) + return 1; + + /* Test remove attributes failures. */ + if (io_uring_fremovexattr(&ring, -1, KEY1) >= 0) + return 1; + if (io_uring_fremovexattr(&ring, fd, NULL) >= 0) + return 1; + /* Cleanup. */ close(fd); unlink(FILENAME); -- 2.47.3