aboutsummaryrefslogtreecommitdiff
path: root/test/fpos.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/fpos.c')
-rw-r--r--test/fpos.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/test/fpos.c b/test/fpos.c
new file mode 100644
index 0000000..78a6152
--- /dev/null
+++ b/test/fpos.c
@@ -0,0 +1,252 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test io_uring fpos handling
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include "helpers.h"
+#include "liburing.h"
+
+#define FILE_SIZE 5000
+#define QUEUE_SIZE 2048
+
+static void create_file(const char *file, size_t size)
+{
+ ssize_t ret;
+ char *buf;
+ size_t idx;
+ int fd;
+
+ buf = t_malloc(size);
+ for (idx = 0; idx < size; ++idx) {
+ /* write 0 or 1 */
+ buf[idx] = (unsigned char)(idx & 0x01);
+ }
+
+ fd = open(file, O_WRONLY | O_CREAT, 0644);
+ assert(fd >= 0);
+
+ ret = write(fd, buf, size);
+ fsync(fd);
+ close(fd);
+ free(buf);
+ assert(ret == size);
+}
+
+static int test_read(struct io_uring *ring, bool async, int blocksize)
+{
+ int ret, fd, i;
+ bool done = false;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ loff_t current, expected = 0;
+ int count_ok;
+ int count_0 = 0, count_1 = 0;
+ unsigned char buff[QUEUE_SIZE * blocksize];
+ unsigned char reordered[QUEUE_SIZE * blocksize];
+
+ create_file(".test_fpos_read", FILE_SIZE);
+ fd = open(".test_fpos_read", O_RDONLY);
+ unlink(".test_fpos_read");
+ assert(fd >= 0);
+
+ while (!done) {
+ for (i = 0; i < QUEUE_SIZE; ++i) {
+ sqe = io_uring_get_sqe(ring);
+ if (!sqe) {
+ fprintf(stderr, "no sqe\n");
+ return -1;
+ }
+ io_uring_prep_read(sqe, fd,
+ buff + i * blocksize,
+ blocksize, -1);
+ sqe->user_data = i;
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
+ if (i != QUEUE_SIZE - 1)
+ sqe->flags |= IOSQE_IO_LINK;
+ }
+ ret = io_uring_submit_and_wait(ring, QUEUE_SIZE);
+ if (ret != QUEUE_SIZE) {
+ fprintf(stderr, "submit failed: %d\n", ret);
+ return 1;
+ }
+ count_ok = 0;
+ for (i = 0; i < QUEUE_SIZE; ++i) {
+ int res;
+
+ ret = io_uring_peek_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "peek failed: %d\n", ret);
+ return ret;
+ }
+ assert(cqe->user_data < QUEUE_SIZE);
+ memcpy(reordered + count_ok,
+ buff + cqe->user_data * blocksize, blocksize);
+ res = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+ if (res == 0) {
+ done = true;
+ } else if (res == -ECANCELED) {
+ /* cancelled, probably ok */
+ } else if (res < 0 || res > blocksize) {
+ fprintf(stderr, "bad read: %d\n", res);
+ return -1;
+ } else {
+ expected += res;
+ count_ok += res;
+ }
+ }
+ ret = 0;
+ for (i = 0; i < count_ok; i++) {
+ if (reordered[i] == 1) {
+ count_1++;
+ } else if (reordered[i] == 0) {
+ count_0++;
+ } else {
+ fprintf(stderr, "odd read %d\n",
+ (int)reordered[i]);
+ ret = -1;
+ break;
+ }
+ }
+ if (labs(count_1 - count_0) > 1) {
+ fprintf(stderr, "inconsistent reads, got 0s:%d 1s:%d\n",
+ count_0, count_1);
+ ret = -1;
+ }
+ current = lseek(fd, 0, SEEK_CUR);
+ if (current != expected) {
+ fprintf(stderr, "f_pos incorrect, expected %ld have %ld\n",
+ (long) expected, (long) current);
+ ret = -1;
+ }
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+
+static int test_write(struct io_uring *ring, bool async, int blocksize)
+{
+ int ret, fd, i;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ bool fail = false;
+ loff_t current;
+ char data[blocksize+1];
+ char readbuff[QUEUE_SIZE*blocksize+1];
+
+ fd = open(".test_fpos_write", O_RDWR | O_CREAT, 0644);
+ unlink(".test_fpos_write");
+ assert(fd >= 0);
+
+ for (i = 0; i < blocksize; i++)
+ data[i] = 'A' + i;
+
+ data[blocksize] = '\0';
+
+ for (i = 0; i < QUEUE_SIZE; ++i) {
+ sqe = io_uring_get_sqe(ring);
+ if (!sqe) {
+ fprintf(stderr, "no sqe\n");
+ return -1;
+ }
+ io_uring_prep_write(sqe, fd, data + (i % blocksize), 1, -1);
+ sqe->user_data = 1;
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
+ if (i != QUEUE_SIZE - 1)
+ sqe->flags |= IOSQE_IO_LINK;
+ }
+ ret = io_uring_submit_and_wait(ring, QUEUE_SIZE);
+ if (ret != QUEUE_SIZE) {
+ fprintf(stderr, "submit failed: %d\n", ret);
+ return 1;
+ }
+ for (i = 0; i < QUEUE_SIZE; ++i) {
+ int res;
+
+ ret = io_uring_peek_cqe(ring, &cqe);
+ res = cqe->res;
+ if (ret) {
+ fprintf(stderr, "peek failed: %d\n", ret);
+ return ret;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ if (!fail && res != 1) {
+ fprintf(stderr, "bad result %d\n", res);
+ fail = true;
+ }
+ }
+ current = lseek(fd, 0, SEEK_CUR);
+ if (current != QUEUE_SIZE) {
+ fprintf(stderr, "f_pos incorrect, expected %ld have %d\n",
+ (long) current, QUEUE_SIZE);
+ fail = true;
+ }
+ current = lseek(fd, 0, SEEK_SET);
+ if (current != 0) {
+ perror("seek to start");
+ return -1;
+ }
+ ret = read(fd, readbuff, QUEUE_SIZE);
+ if (ret != QUEUE_SIZE) {
+ fprintf(stderr, "did not write enough: %d\n", ret);
+ return -1;
+ }
+ i = 0;
+ while (i < QUEUE_SIZE - blocksize) {
+ if (strncmp(readbuff + i, data, blocksize)) {
+ char bad[QUEUE_SIZE+1];
+
+ memcpy(bad, readbuff + i, blocksize);
+ bad[blocksize] = '\0';
+ fprintf(stderr, "unexpected data %s\n", bad);
+ fail = true;
+ }
+ i += blocksize;
+ }
+
+ return fail ? -1 : 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ int ret;
+
+ if (argc > 1)
+ return 0;
+
+ ret = io_uring_queue_init(QUEUE_SIZE, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed\n");
+ return 1;
+ }
+
+ for (int test = 0; test < 8; test++) {
+ int async = test & 0x01;
+ int write = test & 0x02;
+ int blocksize = test & 0x04 ? 1 : 7;
+
+ ret = write
+ ? test_write(&ring, !!async, blocksize)
+ : test_read(&ring, !!async, blocksize);
+ if (ret) {
+ fprintf(stderr, "failed %s async=%d blocksize=%d\n",
+ write ? "write" : "read",
+ async, blocksize);
+ return -1;
+ }
+ }
+ return 0;
+}