[PATCH 4/4] io_uring/futex: avoid ifd NULL check in io_futex_wait()

From: Caleb Sander Mateos

Date: Tue Nov 03 2026 - 16:14:32 EST


There are two paths that hit the done_unlock label in io_futex_wait():
the ENOMEM error path allocating ifd (via goto done_unlock) and the
futex_wait_setup() error path (via a fallthrough). In the ENOMEM path,
ifd is always NULL; in the futex_wait_setup() error path, it's always
non-NULL. Move the done_unlock label so the goto skips the ifd freeing
and the success path can free it unconditionally. This also avoids the
need to initialize ifd before the io_cache_alloc() call, as it's only
used if io_cache_alloc() succeeds.

Signed-off-by: Caleb Sander Mateos <csander@xxxxxxxxxxxxxxx>
---
io_uring/futex.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/io_uring/futex.c b/io_uring/futex.c
index 9c7d384bab9b..e0cb815fd37a 100644
--- a/io_uring/futex.c
+++ b/io_uring/futex.c
@@ -317,11 +317,11 @@ int io_futexv_wait(struct io_kiocb *req, unsigned int issue_flags)

int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
struct io_ring_ctx *ctx = req->ctx;
- struct io_futex_data *ifd = NULL;
+ struct io_futex_data *ifd;
int ret;

if (!iof->futex_mask) {
ret = -EINVAL;
goto done;
@@ -349,16 +349,14 @@ int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags)
io_ring_submit_unlock(ctx, issue_flags);

return IOU_ISSUE_SKIP_COMPLETE;
}

+ /* As in io_futex_complete(), or failed arms would drain it. */
+ io_cache_free(&ctx->futex_cache, ifd);
+ io_req_async_data_clear(req, 0);
done_unlock:
- if (ifd) {
- /* As in io_futex_complete(), or failed arms would drain it. */
- io_cache_free(&ctx->futex_cache, ifd);
- io_req_async_data_clear(req, 0);
- }
io_ring_submit_unlock(ctx, issue_flags);
done:
if (ret < 0)
req_set_fail(req);
io_req_set_res(req, ret, 0);
--
2.56.0