Is there really no asynchronous block I/O on Linux?

(2020) If you’re using a 5.1 or above Linux kernel you can use the io_uring interface for file-like I/O and obtain excellent asynchronous operation.

Compared to the existing libaio/KAIO interface, io_uring has the following advantages:

  • Retains asynchronous behaviour when doing buffered I/O (and not just when doing direct I/O)
  • Easier to use (especially when using the liburing helper library)
  • Can optionally work in a polled manner (but you’ll need higher privileges to enable this mode)
  • Less bookkeeping space overhead per I/O
  • Lower CPU overhead due to fewer userspace/kernel syscall mode switches (a big deal these days due to the impact of spectre/meltdown mitigations)
  • File descriptors and buffers can be pre-registered to save mapping/unmapping time
  • Faster (can achieve higher aggregate throughput, I/Os have a lower latency)
  • “Linked mode” can express dependencies between I/Os (>=5.3 kernel)
  • Can work with socket based I/O (recvmsg()/sendmsg() are supported from >=5.3, see messages mentioning the word support in io_uring.c’s git history)
  • Supports attempted cancellation of queued I/O (>=5.5)
  • Can request that I/O always be performed from asynchronous context rather than the default of only falling back to punting I/O to an asynchronous context when the inline submission path triggers blocking (>=5.6 kernel)
  • Growing support for performing asynchronous operations beyond read/write (e.g. fsync (>=5.1), fallocate (>=5.6), splice (>=5.7) and more)
  • Higher development momentum
  • Doesn’t become blocking each time the stars aren’t perfectly aligned

Compared to glibc’s POSIX AIO, io_uring has the following advantages:

The Efficient IO with io_uring document goes into far more detail as to io_uring‘s benefits and usage. The What’s new with io_uring document describes new features added to io_uring between the 5.2 – 5.5 kernels, while The rapid growth of io_uring
LWN article
describes which features were available in each of the 5.1 – 5.5 kernels with a forward glance to what was going to be in 5.6 (also see LWN’s list of io_uring articles). There’s also a Faster IO through io_uring Kernel Recipes videoed presentation (slides) from late 2019 and What’s new with io_uring Kernel Recipes videoed presentation (slides) from mid 2022 by io_uring author Jens Axboe. Finally, the Lord of the io_uring tutorial gives an introduction to io_uring usage.

The io_uring community can be reached via the io_uring mailing list and the io_uring mailing list archives show daily traffic at the start of 2021.

Re “support partial I/O in the sense of recv() vs read()“: a patch went into the 5.3 kernel that will automatically retry io_uring short reads and a further commit went into the 5.4 kernel that tweaks the behaviour to only automatically take care of short reads when working with “regular” files on requests that haven’t set the REQ_F_NOWAIT flag (it looks like you can request REQ_F_NOWAIT via IOCB_NOWAIT or by opening the file with O_NONBLOCK). Thus you can get recv() style- “short” I/O behaviour from io_uring too.

Software/projects using io_uring

Though the interface is young (its first incarnation arrived in May 2019), some open-source software is using io_uring “in the wild”:

Software investigating using io_uring

Linux distribution support for io_uring

  • (Late 2020) Ubuntu 18.04’s latest HWE enablement kernel is 5.4 so io_uring syscalls can be used. This distro doesn’t pre-package the liburing helper library but you can build it for yourself.
  • Ubuntu 20.04’s initial kernel is 5.4 so io_uring syscalls can be used. As above, the distro doesn’t pre-package liburing.
  • Fedora 32’s initial kernel is 5.6 and it has a packaged liburing so io_uring is usable.
  • SLES 15 SP2 has a 5.3 kernel so io_uring syscalls can be used. This distro doesn’t pre-package the liburing helper library but you can build it for yourself.
  • (Mid 2021) RHEL 8’s default kernel does not support io_uring (a previous version of this answer mistakenly said it did). There is an Add io_uring support Red Hat knowledge base article (contents is behind a subscriber paywall) that is “in progress”.
  • (Mid 2022) RHEL 9’s default kernel does not support io_uring. The kernel is new enough (5.14) but support for io_uring is explicitly disabled.

Hopefully io_uring will usher in a better asynchronous file-like I/O story for Linux.

(To add a thin veneer of credibility to this answer, at some point in the past Jens Axboe (Linux kernel block layer maintainer and inventor of io_uring) thought this answer might be worth upvoting 🙂

Leave a Comment