@@ -5,7 +5,7 @@ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda
SRC_URI = "file://io-uring-writev.c"
-S = "${WORKDIR}"
+S = "${UNPACKDIR}"
do_compile() {
${BUILD_CC} io-uring-writev.c -o io-uring-writev
@@ -20,10 +20,13 @@
/* If your compilation fails because the header file below is missing,
* your kernel is probably too old to support io_uring.
* */
+#include <errno.h>
+#include <stdbool.h>
#include <linux/io_uring.h>
#define QUEUE_DEPTH 1
#define BLOCK_SZ 1024
+#define OPEN_TAG 1
/* This is x86 specific */
#define read_barrier() __asm__ __volatile__("":::"memory")
@@ -101,6 +104,79 @@ off_t get_file_size(int fd) {
return -1;
}
+int open_with_uring(const char* path, struct submitter *s) {
+ struct app_io_sq_ring *sring = &s->sq_ring;
+ struct app_io_cq_ring *cring = &s->cq_ring;
+
+ // Get position of the next SQE
+ unsigned tail = *sring->tail;
+ read_barrier();
+ unsigned index = tail & *sring->ring_mask;
+ unsigned next_tail = tail + 1;
+ struct io_uring_sqe *sqe = &s->sqes[index];
+
+ // Prepare SQE
+ memset(sqe, 0, sizeof(*sqe));
+ sqe->opcode = IORING_OP_OPENAT;
+ sqe->fd = AT_FDCWD;
+ sqe->addr = (unsigned long)path;
+ sqe->open_flags = O_WRONLY | O_CREAT;
+ sqe->len = 0666;
+ sqe->user_data = OPEN_TAG;
+
+ // Add prepared sqe to the submission queue
+ sring->array[index] = index;
+
+ // Update the tail so the kernel can see it
+ tail = next_tail;
+ if(*sring->tail != tail) {
+ write_barrier();
+ *sring->tail = tail;
+ }
+
+ //Tell the kernel to process events in SQ
+ int ret = io_uring_enter(s->ring_fd, 1,1,
+ IORING_ENTER_GETEVENTS);
+ if(ret < 0) {
+ perror("io_uring_enter");
+ return -1;
+ }
+
+ //Now we need to read the output from kernel from the CQ
+ while (true) {
+ unsigned head = *cring->head;
+ tail = *cring->tail;
+ read_barrier();
+
+ if (head == tail) {
+ /* It means the buffer is empty.
+ * If we are here, then something went wrong and
+ * kernel didn't return CQE with user_data == OPEN_TAG for some reason
+ */
+ fprintf(stderr, "open_with_uring error: kernel didn't return fd");
+ return -1;
+ }
+
+ index = head & *cring->ring_mask;
+ struct io_uring_cqe *cqe = &cring->cqes[index];
+
+ unsigned long long tag = cqe->user_data;
+ int res = cqe->res;
+
+ write_barrier();
+ *cring->head = head + 1;
+
+ if (tag == OPEN_TAG) {
+ if (res < 0) {
+ errno = -res;
+ perror("IORING_OP_OPENAT");
+ return -1;
+ }
+ return res;
+ }
+ }
+}
+
/*
* io_uring requires a lot of setup which looks pretty hairy, but isn't all
* that difficult to understand. Because of all this boilerplate code,
@@ -155,7 +231,7 @@ int app_setup_uring(struct submitter *s) {
/* Map in the submission and completion queue ring buffers.
* Older kernels only map in the submission queue, though.
* */
- sq_ptr = mmap(0, sring_sz, PROT_READ | PROT_WRITE,
+ sq_ptr = mmap(0, sring_sz, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_POPULATE,
s->ring_fd, IORING_OFF_SQ_RING);
if (sq_ptr == MAP_FAILED) {
@@ -167,7 +243,7 @@ int app_setup_uring(struct submitter *s) {
cq_ptr = sq_ptr;
} else {
/* Map in the completion queue ring buffer in older kernels separately */
- cq_ptr = mmap(0, cring_sz, PROT_READ | PROT_WRITE,
+ cq_ptr = mmap(0, cring_sz, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_POPULATE,
s->ring_fd, IORING_OFF_CQ_RING);
if (cq_ptr == MAP_FAILED) {
@@ -266,8 +342,8 @@ void read_from_cq(struct submitter *s) {
int submit_to_sq(char *file_path, struct submitter *s) {
struct file_info *fi;
- int file_fd = open(file_path, O_WRONLY|O_CREAT, 0666);
- if (file_fd < 0 ) {
+ int file_fd = open_with_uring(file_path, s);
+ if (file_fd < 0) {
perror("open");
return 1;
}
@@ -317,7 +393,7 @@ int submit_to_sq(char *file_path, struct submitter *s) {
*/
fi->iovecs[current_block].iov_len = bytes_remaining;
fi->iovecs[current_block].iov_base = bark;
-
+
/* Add our submission queue entry to the tail of the SQE ring buffer */
next_tail = tail = *sring->tail;
@@ -336,7 +412,7 @@ int submit_to_sq(char *file_path, struct submitter *s) {
tail = next_tail;
/* Update the tail so the kernel can see it. */
- if(*sring->tail != tail) {
+ if (*sring->tail != tail) {
*sring->tail = tail;
write_barrier();
}
@@ -347,9 +423,9 @@ int submit_to_sq(char *file_path, struct submitter *s) {
* io_uring_enter() call to wait until min_complete events (the 3rd param)
* complete.
* */
- int ret = io_uring_enter(s->ring_fd, 1,1,
- IORING_ENTER_GETEVENTS);
- if(ret < 0) {
+ int ret = io_uring_enter(s->ring_fd, 1, 1,
+ IORING_ENTER_GETEVENTS);
+ if (ret < 0) {
perror("io_uring_enter");
return 1;
}
@@ -372,13 +448,13 @@ int main(int argc, char *argv[]) {
}
memset(s, 0, sizeof(*s));
- if(app_setup_uring(s)) {
+ if (app_setup_uring(s)) {
fprintf(stderr, "Unable to setup uring!\n");
return 1;
}
for (int i = 1; i < argc; i++) {
- if(submit_to_sq(argv[i], s)) {
+ if (submit_to_sq(argv[i], s)) {
fprintf(stderr, "Error writting file\n");
return 1;
}