4

I have been reading https://kernel.dk/io_uring.pdf and I would like to experiment with the actual syscalls (io_uring_setup, io_uring_enter) to check my understanding, but I am not able to compile the following simple program:

#include <kernel/io_uring.h>
#include <stdint.h>

int main() {
    struct io_uring_params p;
    int ring = io_uring_setup((__u32) 512, &p);
    return 0;
}

I get an implicit declaration error for the io_uring_setup function. The man page https://manpages.debian.org/unstable/liburing-dev/io_uring_setup.2.en.html suggests that the only file to include is linux/io_uring.h, but when I look at the source code, I do not see the definition of io_uring_setup.

sc46
  • 57
  • 4
  • 1
    It may be the same case as with `futex` syscall: that is, it must be invoked directly using `syscall`. The idea is to prevent users from trying to use this feature directly unless they really know what they are doing. – oakad May 16 '21 at 07:28
  • Indeed: https://github.com/axboe/liburing/blob/master/src/syscall.c – oakad May 16 '21 at 07:31
  • Thanks, I was able to get it working using __sys_io_uring_setup. I'm working in the examples/ directory of liburing/ and all I had to do was copy src/syscall.h into src/include/ and "#include syscall.h" in my file. – sc46 May 16 '21 at 16:13

1 Answers1

3

(Mid-2021) As @oakad stated in the comments the io_uring syscalls are not currently wrapped by libc. If a user wants to invoke raw io_uring syscalls (e.g. as described in io_uring_setup(2)) it is up to them to provide the additional boilerplate to do so and ensure they obey all the expected rules... Rather than doing everything by hand it looks easier to use liburing (the io_uring wrapper library).

I'm unclear on why you chose to use

#include <kernel/io_uring.h>

-- this looks wrong. The header on my system is found by

#include <linux/io_uring.h>

and the following compiles without error on my system:

/* Needed for memset */
#include <stdio.h>
/* Needed for perror */
#include <string.h>
/* Needed to invoke the syscall */
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
/* Needed for io_uring data structures. Compilation will error with a "No such
 * file or directory" on the following include line if your kernel headers are
 * too old/don't know about io_uring. If this happens you have to manually 
 * declare all the io_uring structures/defines yourself. */
#include <linux/io_uring.h>
/* C libraries don't (yet) provide a pretty wrapper for the io_uring syscalls 
 * so create an io_uring_setup syscall wrapper ourselves */
int io_uring_setup(unsigned int entries, struct io_uring_params *p) {
    return syscall(__NR_io_uring_setup, entries, p);
}

int main() {
    int fd;
    struct io_uring_params p;

    memset(&p, 0, sizeof(p));
    fd = io_uring_setup(512, &p);

    if (fd < 0)
        perror("io_uring_setup");

    return 0;
}

However as mentioned in Efficient IO with io_uring PDF this is just the tip of the iceberg when using io_uring via direct syscalls. The Lord of the io_uring tutorial has a section titled The Low-level io_uring Interface which describes the usage in more detail but using io_uring looks both easier and safer.

Anon
  • 6,306
  • 2
  • 38
  • 56
  • Thank you. I am surprised this may be an issue, as I am using the most current release of the Oracle UEK (available here: https://yum.oracle.com/repo/OracleLinux/OL8/UEKR6/x86_64/). I ended up just looking at the liburing source code and I realized there really is no need to use the syscalls directly. – sc46 Jun 20 '21 at 07:01
  • Yes, I had a typo in my original question but the code does not compile in either case so I see the need for a wrapper. And I agree that from what I can tell liburing encompasses all the functionality of io_uring. – sc46 Jun 20 '21 at 16:16