The site pushes really hard that you shouldn't use the low-level system calls in your code and that you should (always?) be using a library (liburing).
What exactly is liburing bringing to the table that I shouldn't be using the uring syscalls directly?
This system call avoidance dogma exists because libraries generally have more convenient interfaces and are therefore easier to use. They're not strictly necessary though.
It should be noted that using certain system calls may cause problems with the libraries you're using. For example, glibc needs to maintain complete control over the threading model in order to implement thread-local storage. By issuing a clone system call directly, the glibc threading model is broken and even something simple like errno is likely to break.
In my opinion, libraries shouldn't contain thread-local or global variables in the first place. Unfortunately, the C language is old and these problems will never be fixed. It's possible to create better libraries in freestanding C or even freestanding Rust but replacing what already exists is a lifetime of work.
> What exactly is liburing bringing to the table that I shouldn't be using the uring syscalls directly?
It's easier to use compared to the kernel interface. For example, it handles submission queue polling automatically without any extra code.
The raw io_uring interface, once you ignore the boilerplate initialization code, is actually a super-simple interface to use. liburing is itself only a very thin wrapper on top of io_uring. I feel that if you ever used io_uring, after a while you'll end up with a bunch of convenience functions. liburing looks more like a collection of those functions to me today.
One place where a slightly high-level interface is provided by liburing is in the function io_uring_submit(). It determines among other things if there is a need to call the io_uring_enter() system call depending on whether you are in polling mode or not, for example. You can read more about it here:
io_uring requires userspace to access it using a well-defined load/store memory ordering. Care must be taken to make sure the compiler does not reorder instructions but also to use the correct load/store instructions so hardware doesn't reorder loads and stores. This is easier to (accidentally) get correct on x86 as it has stronger ordering guarantees. In other words, if you are not careful your code might be correct on x86 but fail on Arm, etc. Needless to say the library handles all of this correctly.
What exactly is liburing bringing to the table that I shouldn't be using the uring syscalls directly?