io_uring_prep_openat2(3)

πŸ’– io_uring_prep_openat2 β€” bestie's guide to prepping an openat2 request πŸ’–

okay so this is a page from the liburing manual, and honestly? it's giving "we open files but make it ✨async✨". grab a snack, we're doing this.


🌸 NAME 🌸

io_uring_prep_openat2 β€” prepare an openat2 request


✨ SYNOPSIS ✨

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/openat2.h>
#include <liburing.h>

void io_uring_prep_openat2(struct io_uring_sqe *sqe,
                           int dfd,
                           const char *path,
                           const struct open_how *how);

void io_uring_prep_openat2_direct(struct io_uring_sqe *sqe,
                                  int dfd,
                                  const char *path,
                                  const struct open_how *how,
                                  unsigned file_index);

πŸ¦‹ DESCRIPTION πŸ¦‹

So io_uring_prep_openat2(3) literally just preps an openat2 request. that's it, that's the job. it takes your submission queue entry sqe and sets it up so it uses the directory file descriptor dfd to start opening a file described by path, following the instructions on how to open it that you passed in how. cute, right? πŸŽ€

Now. if you're using the direct variant, there's a whole prerequisite arc: your app must have first registered a file table using io_uring_register_files(3) of the appropriate size. once that's done, a direct request can use any entry in that table β€” you point at it with file_index β€” as long as it's within the size of the registered table. πŸ’…

and listen, if the entry you picked already has a file in it? that file gets removed from the table and closed first. no cap. it's consistent with the behavior of updating an existing file with io_uring_register_files_update(3). πŸ‘‘

If you use IORING_FILE_INDEX_ALLOC as the file_index for a direct open, then io_uring will allocate a free direct descriptor in the existing table for you. the allocated descriptor gets returned in the CQE res field, just like it would be for a non-direct open request. and if there are no more entries available in the direct descriptor table? you get -ENFILE instead. sad but fair 😭

okay so what are direct descriptors? they're io_uring private file descriptors, bestie. they dodge some of the overhead that comes with thread shared file tables, and you can use them in any subsequent io_uring request that takes a file descriptor. to do that, you must set IOSQE_FIXED_FILE in the SQE flags member, and the SQE fd field should use the direct descriptor value rather than the regular file descriptor. direct descriptors are managed like registered files. slay. 🫢

one thing that does NOT change: the directory file descriptor dfd is always a regular file descriptor. periodt.

heads up 🚨 β€” old kernels don't check the SQE file_index field. that's not a problem for liburing helpers, but if you're using the raw io_uring interface you need to zero SQEs to avoid unexpected behavior. consider this your vibe check.

these functions prepare an async openat2(2) request. go read that man page for the deets, iykyk.


🌈 RETURN VALUE 🌈

None. literally nothing. it's a prep function, it doesn't return a thing. πŸ€·β™€οΈ


πŸ’€ ERRORS πŸ’€

the CQE res field will contain the result of the operation. check out the related man page for the possible values.

now here's the plot twist that trips people up: where synchronous system calls return -1 on failure and set errno to the actual error value, io_uring never uses errno. instead it returns the negated errno directly in the CQE res field. iconic behavior honestly. πŸ”₯


πŸ’œ NOTES πŸ’œ

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. 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 β€” different era, different rules. applications can test for this behavior by inspecting the IORING_FEAT_SUBMIT_STABLE flag passed back from io_uring_queue_init_params(3). ⭐


πŸ‘‘ SEE ALSO πŸ‘‘


and that's the whole page, bestie πŸ’– this was liburing-2.2, dated March 13, 2022 β€” go forth and open files asynchronously, you absolute main character πŸŒΈβœ¨πŸ¦‹

πŸ“¦ where this page comes from