io_uring_prep_readv2(3)

πŸ’– io_uring_prep_readv2 πŸ’–

okay bestie, welcome to the liburing manual page for io_uring_prep_readv2(3) β€” yes she's a section 3 function, yes she's iconic, and yes we're gonna get you fluent in her by the end of this. grab a boba, let's go πŸ§‹βœ¨


✨ NAME ✨

io_uring_prep_readv2 β€” get a vectored I/O read request all prepped and cute, with flags πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

#include <sys/uio.h>
#include <liburing.h>

void io_uring_prep_readv2(struct io_uring_sqe *sqe,
                          int fd,
                          const struct iovec *iovecs,
                          unsigned nr_vecs,
                          __u64 offset,
                          int flags);

πŸ¦‹ DESCRIPTION πŸ¦‹

so basically, io_uring_prep_readv2(3) sets up a vectored IO read request. like, a read that scatters itself across a whole array of buffers instead of just one. main character energy fr fr 🌈

Here's the tea: the submission queue entry sqe gets set up to use the file descriptor fd, and it starts reading nr_vecs into the iovecs array β€” all at the specified offset. and if you wanna tweak how she behaves? that's what the flags parameter is for, bestie. she's flexible like that. πŸ’β€β™€οΈ

Supported values for flags are:

  • RWF_HIPRI β€” high priority request, poll if possible πŸ‘‘
  • RWF_DSYNC β€” per-IO O_DSYNC
  • RWF_SYNC β€” per-IO O_SYNC
  • RWF_NOWAIT β€” per-IO, return -EAGAIN if the operation would block 🚫
  • RWF_APPEND β€” per-IO O_APPEND

now, on files that support seeking: if you set offset to -1, the read operation commences at the file offset, and then the file offset gets incremented by however many bytes were read. (go peek at read(2) if you want the full lore πŸ“–)

⚠️ but bestie, listen β€” for an async API, reading and updating the current file offset can result in unpredictable behavior, unless access to the file is serialized. so like, it is not encouraged to use this feature if it's possible to just provide the desired IO offset straight from the application or library. do yourself a favor and pass the offset in. πŸ™ˆ

on files that are not capable of seeking? then offset must be 0 or -1. no in-between, no negotiating. βœ‹

after the read has been prepared, you can submit it with one of the submit functions. that's it, that's the moment. slay. 🫢


πŸ’œ RETURN VALUE πŸ’œ

None. she returns nothing. she prepares and dips. πŸ’…


🌸 ERRORS 🌸

the CQE res field will contain the result of the operation β€” check the related man page for the details on possible values, iykyk.

and here's the big one: where synchronous system calls will return -1 on failure and set errno to the actual error value, io_uring never uses errno. never ever. instead, it returns the negated errno directly in the CQE res field. so don't go checking errno like it's 2019, bestie. 😭


⭐ NOTES ⭐

okay so unless your application explicitly needs to pass in more than one iovec, it's more efficient to use io_uring_prep_read(3) instead of this function β€” because no state has to be maintained for a non-vectored IO request. less work, same vibes. lowkey the move. πŸ’–

And as with any request that passes in data in a struct: that data must remain valid until the request has been successfully submitted. πŸ“Œ it does not need to remain valid until completion, though. once a request has been submitted, the in-kernel state is stable.

πŸ’€ very early kernels (5.4 and earlier) required state to be stable until the completion occurred. ancient history, but know your roots.

Applications can test for this behavior by inspecting the IORING_FEAT_SUBMIT_STABLE flag passed back from io_uring_queue_init_params(3). go check it, she'll tell you everything ✨


πŸ‘‘ SEE ALSO πŸ‘‘


and that's the whole page, no cap 🫢 this lil' gem comes to you from liburing-2.2, dated November 15, 2021 β€” shoutout to the liburing Manual for keeping it real all this time. now go prep some reads and eat, bestie πŸ’…πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from