Search code examples
clinuxio-uring

Trouble compiling io_uring


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.


Solution

  • (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.