xref: /linux/io_uring/futex.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
1194bb58cSJens Axboe // SPDX-License-Identifier: GPL-2.0
2194bb58cSJens Axboe #include <linux/kernel.h>
3194bb58cSJens Axboe #include <linux/errno.h>
4194bb58cSJens Axboe #include <linux/fs.h>
5194bb58cSJens Axboe #include <linux/file.h>
6194bb58cSJens Axboe #include <linux/io_uring.h>
7194bb58cSJens Axboe 
8194bb58cSJens Axboe #include <uapi/linux/io_uring.h>
9194bb58cSJens Axboe 
10194bb58cSJens Axboe #include "../kernel/futex/futex.h"
11194bb58cSJens Axboe #include "io_uring.h"
12*414d0f45SJens Axboe #include "alloc_cache.h"
13194bb58cSJens Axboe #include "futex.h"
14194bb58cSJens Axboe 
15194bb58cSJens Axboe struct io_futex {
16194bb58cSJens Axboe 	struct file	*file;
178f350194SJens Axboe 	union {
18194bb58cSJens Axboe 		u32 __user			*uaddr;
198f350194SJens Axboe 		struct futex_waitv __user	*uwaitv;
208f350194SJens Axboe 	};
21194bb58cSJens Axboe 	unsigned long	futex_val;
22194bb58cSJens Axboe 	unsigned long	futex_mask;
238f350194SJens Axboe 	unsigned long	futexv_owned;
24194bb58cSJens Axboe 	u32		futex_flags;
258f350194SJens Axboe 	unsigned int	futex_nr;
268f350194SJens Axboe 	bool		futexv_unqueued;
27194bb58cSJens Axboe };
28194bb58cSJens Axboe 
29194bb58cSJens Axboe struct io_futex_data {
30194bb58cSJens Axboe 	struct futex_q	q;
31194bb58cSJens Axboe 	struct io_kiocb	*req;
32194bb58cSJens Axboe };
33194bb58cSJens Axboe 
34*414d0f45SJens Axboe #define IO_FUTEX_ALLOC_CACHE_MAX	32
35194bb58cSJens Axboe 
io_futex_cache_init(struct io_ring_ctx * ctx)36*414d0f45SJens Axboe bool io_futex_cache_init(struct io_ring_ctx *ctx)
37194bb58cSJens Axboe {
38*414d0f45SJens Axboe 	return io_alloc_cache_init(&ctx->futex_cache, IO_FUTEX_ALLOC_CACHE_MAX,
39*414d0f45SJens Axboe 				sizeof(struct io_futex_data));
40194bb58cSJens Axboe }
41194bb58cSJens Axboe 
io_futex_cache_free(struct io_ring_ctx * ctx)42194bb58cSJens Axboe void io_futex_cache_free(struct io_ring_ctx *ctx)
43194bb58cSJens Axboe {
44*414d0f45SJens Axboe 	io_alloc_cache_free(&ctx->futex_cache, kfree);
45194bb58cSJens Axboe }
46194bb58cSJens Axboe 
__io_futex_complete(struct io_kiocb * req,struct io_tw_state * ts)478f350194SJens Axboe static void __io_futex_complete(struct io_kiocb *req, struct io_tw_state *ts)
488f350194SJens Axboe {
498f350194SJens Axboe 	req->async_data = NULL;
508f350194SJens Axboe 	hlist_del_init(&req->hash_node);
518f350194SJens Axboe 	io_req_task_complete(req, ts);
528f350194SJens Axboe }
538f350194SJens Axboe 
io_futex_complete(struct io_kiocb * req,struct io_tw_state * ts)54194bb58cSJens Axboe static void io_futex_complete(struct io_kiocb *req, struct io_tw_state *ts)
55194bb58cSJens Axboe {
56194bb58cSJens Axboe 	struct io_futex_data *ifd = req->async_data;
57194bb58cSJens Axboe 	struct io_ring_ctx *ctx = req->ctx;
58194bb58cSJens Axboe 
59194bb58cSJens Axboe 	io_tw_lock(ctx, ts);
60*414d0f45SJens Axboe 	if (!io_alloc_cache_put(&ctx->futex_cache, ifd))
61194bb58cSJens Axboe 		kfree(ifd);
628f350194SJens Axboe 	__io_futex_complete(req, ts);
638f350194SJens Axboe }
648f350194SJens Axboe 
io_futexv_complete(struct io_kiocb * req,struct io_tw_state * ts)658f350194SJens Axboe static void io_futexv_complete(struct io_kiocb *req, struct io_tw_state *ts)
668f350194SJens Axboe {
678f350194SJens Axboe 	struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
688f350194SJens Axboe 	struct futex_vector *futexv = req->async_data;
698f350194SJens Axboe 
708f350194SJens Axboe 	io_tw_lock(req->ctx, ts);
718f350194SJens Axboe 
728f350194SJens Axboe 	if (!iof->futexv_unqueued) {
738f350194SJens Axboe 		int res;
748f350194SJens Axboe 
758f350194SJens Axboe 		res = futex_unqueue_multiple(futexv, iof->futex_nr);
768f350194SJens Axboe 		if (res != -1)
778f350194SJens Axboe 			io_req_set_res(req, res, 0);
788f350194SJens Axboe 	}
798f350194SJens Axboe 
808f350194SJens Axboe 	kfree(req->async_data);
818f350194SJens Axboe 	req->flags &= ~REQ_F_ASYNC_DATA;
828f350194SJens Axboe 	__io_futex_complete(req, ts);
838f350194SJens Axboe }
848f350194SJens Axboe 
io_futexv_claim(struct io_futex * iof)858f350194SJens Axboe static bool io_futexv_claim(struct io_futex *iof)
868f350194SJens Axboe {
878f350194SJens Axboe 	if (test_bit(0, &iof->futexv_owned) ||
888f350194SJens Axboe 	    test_and_set_bit_lock(0, &iof->futexv_owned))
898f350194SJens Axboe 		return false;
908f350194SJens Axboe 	return true;
91194bb58cSJens Axboe }
92194bb58cSJens Axboe 
__io_futex_cancel(struct io_ring_ctx * ctx,struct io_kiocb * req)93194bb58cSJens Axboe static bool __io_futex_cancel(struct io_ring_ctx *ctx, struct io_kiocb *req)
94194bb58cSJens Axboe {
958f350194SJens Axboe 	/* futex wake already done or in progress */
968f350194SJens Axboe 	if (req->opcode == IORING_OP_FUTEX_WAIT) {
97194bb58cSJens Axboe 		struct io_futex_data *ifd = req->async_data;
98194bb58cSJens Axboe 
99194bb58cSJens Axboe 		if (!futex_unqueue(&ifd->q))
100194bb58cSJens Axboe 			return false;
1018f350194SJens Axboe 		req->io_task_work.func = io_futex_complete;
1028f350194SJens Axboe 	} else {
1038f350194SJens Axboe 		struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
1048f350194SJens Axboe 
1058f350194SJens Axboe 		if (!io_futexv_claim(iof))
1068f350194SJens Axboe 			return false;
1078f350194SJens Axboe 		req->io_task_work.func = io_futexv_complete;
1088f350194SJens Axboe 	}
109194bb58cSJens Axboe 
110194bb58cSJens Axboe 	hlist_del_init(&req->hash_node);
111194bb58cSJens Axboe 	io_req_set_res(req, -ECANCELED, 0);
112194bb58cSJens Axboe 	io_req_task_work_add(req);
113194bb58cSJens Axboe 	return true;
114194bb58cSJens Axboe }
115194bb58cSJens Axboe 
io_futex_cancel(struct io_ring_ctx * ctx,struct io_cancel_data * cd,unsigned int issue_flags)116194bb58cSJens Axboe int io_futex_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
117194bb58cSJens Axboe 		    unsigned int issue_flags)
118194bb58cSJens Axboe {
119194bb58cSJens Axboe 	struct hlist_node *tmp;
120194bb58cSJens Axboe 	struct io_kiocb *req;
121194bb58cSJens Axboe 	int nr = 0;
122194bb58cSJens Axboe 
123194bb58cSJens Axboe 	if (cd->flags & (IORING_ASYNC_CANCEL_FD|IORING_ASYNC_CANCEL_FD_FIXED))
124194bb58cSJens Axboe 		return -ENOENT;
125194bb58cSJens Axboe 
126194bb58cSJens Axboe 	io_ring_submit_lock(ctx, issue_flags);
127194bb58cSJens Axboe 	hlist_for_each_entry_safe(req, tmp, &ctx->futex_list, hash_node) {
128194bb58cSJens Axboe 		if (req->cqe.user_data != cd->data &&
129194bb58cSJens Axboe 		    !(cd->flags & IORING_ASYNC_CANCEL_ANY))
130194bb58cSJens Axboe 			continue;
131194bb58cSJens Axboe 		if (__io_futex_cancel(ctx, req))
132194bb58cSJens Axboe 			nr++;
133194bb58cSJens Axboe 		if (!(cd->flags & IORING_ASYNC_CANCEL_ALL))
134194bb58cSJens Axboe 			break;
135194bb58cSJens Axboe 	}
136194bb58cSJens Axboe 	io_ring_submit_unlock(ctx, issue_flags);
137194bb58cSJens Axboe 
138194bb58cSJens Axboe 	if (nr)
139194bb58cSJens Axboe 		return nr;
140194bb58cSJens Axboe 
141194bb58cSJens Axboe 	return -ENOENT;
142194bb58cSJens Axboe }
143194bb58cSJens Axboe 
io_futex_remove_all(struct io_ring_ctx * ctx,struct task_struct * task,bool cancel_all)144194bb58cSJens Axboe bool io_futex_remove_all(struct io_ring_ctx *ctx, struct task_struct *task,
145194bb58cSJens Axboe 			 bool cancel_all)
146194bb58cSJens Axboe {
147194bb58cSJens Axboe 	struct hlist_node *tmp;
148194bb58cSJens Axboe 	struct io_kiocb *req;
149194bb58cSJens Axboe 	bool found = false;
150194bb58cSJens Axboe 
151194bb58cSJens Axboe 	lockdep_assert_held(&ctx->uring_lock);
152194bb58cSJens Axboe 
153194bb58cSJens Axboe 	hlist_for_each_entry_safe(req, tmp, &ctx->futex_list, hash_node) {
154194bb58cSJens Axboe 		if (!io_match_task_safe(req, task, cancel_all))
155194bb58cSJens Axboe 			continue;
15630dab608SJens Axboe 		hlist_del_init(&req->hash_node);
157194bb58cSJens Axboe 		__io_futex_cancel(ctx, req);
158194bb58cSJens Axboe 		found = true;
159194bb58cSJens Axboe 	}
160194bb58cSJens Axboe 
161194bb58cSJens Axboe 	return found;
162194bb58cSJens Axboe }
163194bb58cSJens Axboe 
io_futex_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)164194bb58cSJens Axboe int io_futex_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
165194bb58cSJens Axboe {
166194bb58cSJens Axboe 	struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
167194bb58cSJens Axboe 	u32 flags;
168194bb58cSJens Axboe 
169194bb58cSJens Axboe 	if (unlikely(sqe->len || sqe->futex_flags || sqe->buf_index ||
170194bb58cSJens Axboe 		     sqe->file_index))
171194bb58cSJens Axboe 		return -EINVAL;
172194bb58cSJens Axboe 
173194bb58cSJens Axboe 	iof->uaddr = u64_to_user_ptr(READ_ONCE(sqe->addr));
174194bb58cSJens Axboe 	iof->futex_val = READ_ONCE(sqe->addr2);
175194bb58cSJens Axboe 	iof->futex_mask = READ_ONCE(sqe->addr3);
176194bb58cSJens Axboe 	flags = READ_ONCE(sqe->fd);
177194bb58cSJens Axboe 
178194bb58cSJens Axboe 	if (flags & ~FUTEX2_VALID_MASK)
179194bb58cSJens Axboe 		return -EINVAL;
180194bb58cSJens Axboe 
181194bb58cSJens Axboe 	iof->futex_flags = futex2_to_flags(flags);
182194bb58cSJens Axboe 	if (!futex_flags_valid(iof->futex_flags))
183194bb58cSJens Axboe 		return -EINVAL;
184194bb58cSJens Axboe 
185194bb58cSJens Axboe 	if (!futex_validate_input(iof->futex_flags, iof->futex_val) ||
186194bb58cSJens Axboe 	    !futex_validate_input(iof->futex_flags, iof->futex_mask))
187194bb58cSJens Axboe 		return -EINVAL;
188194bb58cSJens Axboe 
189194bb58cSJens Axboe 	return 0;
190194bb58cSJens Axboe }
191194bb58cSJens Axboe 
io_futex_wakev_fn(struct wake_q_head * wake_q,struct futex_q * q)1928f350194SJens Axboe static void io_futex_wakev_fn(struct wake_q_head *wake_q, struct futex_q *q)
1938f350194SJens Axboe {
1948f350194SJens Axboe 	struct io_kiocb *req = q->wake_data;
1958f350194SJens Axboe 	struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
1968f350194SJens Axboe 
1978f350194SJens Axboe 	if (!io_futexv_claim(iof))
1988f350194SJens Axboe 		return;
1998f350194SJens Axboe 	if (unlikely(!__futex_wake_mark(q)))
2008f350194SJens Axboe 		return;
2018f350194SJens Axboe 
2028f350194SJens Axboe 	io_req_set_res(req, 0, 0);
2038f350194SJens Axboe 	req->io_task_work.func = io_futexv_complete;
2048f350194SJens Axboe 	io_req_task_work_add(req);
2058f350194SJens Axboe }
2068f350194SJens Axboe 
io_futexv_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)2078f350194SJens Axboe int io_futexv_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
2088f350194SJens Axboe {
2098f350194SJens Axboe 	struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
2108f350194SJens Axboe 	struct futex_vector *futexv;
2118f350194SJens Axboe 	int ret;
2128f350194SJens Axboe 
2138f350194SJens Axboe 	/* No flags or mask supported for waitv */
2148f350194SJens Axboe 	if (unlikely(sqe->fd || sqe->buf_index || sqe->file_index ||
2158f350194SJens Axboe 		     sqe->addr2 || sqe->futex_flags || sqe->addr3))
2168f350194SJens Axboe 		return -EINVAL;
2178f350194SJens Axboe 
2188f350194SJens Axboe 	iof->uaddr = u64_to_user_ptr(READ_ONCE(sqe->addr));
2198f350194SJens Axboe 	iof->futex_nr = READ_ONCE(sqe->len);
2208f350194SJens Axboe 	if (!iof->futex_nr || iof->futex_nr > FUTEX_WAITV_MAX)
2218f350194SJens Axboe 		return -EINVAL;
2228f350194SJens Axboe 
2238f350194SJens Axboe 	futexv = kcalloc(iof->futex_nr, sizeof(*futexv), GFP_KERNEL);
2248f350194SJens Axboe 	if (!futexv)
2258f350194SJens Axboe 		return -ENOMEM;
2268f350194SJens Axboe 
2278f350194SJens Axboe 	ret = futex_parse_waitv(futexv, iof->uwaitv, iof->futex_nr,
2288f350194SJens Axboe 				io_futex_wakev_fn, req);
2298f350194SJens Axboe 	if (ret) {
2308f350194SJens Axboe 		kfree(futexv);
2318f350194SJens Axboe 		return ret;
2328f350194SJens Axboe 	}
2338f350194SJens Axboe 
2348f350194SJens Axboe 	iof->futexv_owned = 0;
2358f350194SJens Axboe 	iof->futexv_unqueued = 0;
2368f350194SJens Axboe 	req->flags |= REQ_F_ASYNC_DATA;
2378f350194SJens Axboe 	req->async_data = futexv;
2388f350194SJens Axboe 	return 0;
2398f350194SJens Axboe }
2408f350194SJens Axboe 
io_futex_wake_fn(struct wake_q_head * wake_q,struct futex_q * q)241194bb58cSJens Axboe static void io_futex_wake_fn(struct wake_q_head *wake_q, struct futex_q *q)
242194bb58cSJens Axboe {
243194bb58cSJens Axboe 	struct io_futex_data *ifd = container_of(q, struct io_futex_data, q);
244194bb58cSJens Axboe 	struct io_kiocb *req = ifd->req;
245194bb58cSJens Axboe 
246194bb58cSJens Axboe 	if (unlikely(!__futex_wake_mark(q)))
247194bb58cSJens Axboe 		return;
248194bb58cSJens Axboe 
249194bb58cSJens Axboe 	io_req_set_res(req, 0, 0);
250194bb58cSJens Axboe 	req->io_task_work.func = io_futex_complete;
251194bb58cSJens Axboe 	io_req_task_work_add(req);
252194bb58cSJens Axboe }
253194bb58cSJens Axboe 
io_alloc_ifd(struct io_ring_ctx * ctx)254194bb58cSJens Axboe static struct io_futex_data *io_alloc_ifd(struct io_ring_ctx *ctx)
255194bb58cSJens Axboe {
256*414d0f45SJens Axboe 	struct io_futex_data *ifd;
257194bb58cSJens Axboe 
258*414d0f45SJens Axboe 	ifd = io_alloc_cache_get(&ctx->futex_cache);
259*414d0f45SJens Axboe 	if (ifd)
260*414d0f45SJens Axboe 		return ifd;
261194bb58cSJens Axboe 
262194bb58cSJens Axboe 	return kmalloc(sizeof(struct io_futex_data), GFP_NOWAIT);
263194bb58cSJens Axboe }
264194bb58cSJens Axboe 
io_futexv_wait(struct io_kiocb * req,unsigned int issue_flags)2658f350194SJens Axboe int io_futexv_wait(struct io_kiocb *req, unsigned int issue_flags)
2668f350194SJens Axboe {
2678f350194SJens Axboe 	struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
2688f350194SJens Axboe 	struct futex_vector *futexv = req->async_data;
2698f350194SJens Axboe 	struct io_ring_ctx *ctx = req->ctx;
2708f350194SJens Axboe 	int ret, woken = -1;
2718f350194SJens Axboe 
2728f350194SJens Axboe 	io_ring_submit_lock(ctx, issue_flags);
2738f350194SJens Axboe 
2748f350194SJens Axboe 	ret = futex_wait_multiple_setup(futexv, iof->futex_nr, &woken);
2758f350194SJens Axboe 
2768f350194SJens Axboe 	/*
2778f350194SJens Axboe 	 * Error case, ret is < 0. Mark the request as failed.
2788f350194SJens Axboe 	 */
2798f350194SJens Axboe 	if (unlikely(ret < 0)) {
2808f350194SJens Axboe 		io_ring_submit_unlock(ctx, issue_flags);
2818f350194SJens Axboe 		req_set_fail(req);
2828f350194SJens Axboe 		io_req_set_res(req, ret, 0);
2838f350194SJens Axboe 		kfree(futexv);
2848f350194SJens Axboe 		req->async_data = NULL;
2858f350194SJens Axboe 		req->flags &= ~REQ_F_ASYNC_DATA;
2868f350194SJens Axboe 		return IOU_OK;
2878f350194SJens Axboe 	}
2888f350194SJens Axboe 
2898f350194SJens Axboe 	/*
2908f350194SJens Axboe 	 * 0 return means that we successfully setup the waiters, and that
2918f350194SJens Axboe 	 * nobody triggered a wakeup while we were doing so. If the wakeup
2928f350194SJens Axboe 	 * happened post setup, the task_work will be run post this issue and
2938f350194SJens Axboe 	 * under the submission lock. 1 means We got woken while setting up,
2948f350194SJens Axboe 	 * let that side do the completion. Note that
2958f350194SJens Axboe 	 * futex_wait_multiple_setup() will have unqueued all the futexes in
2968f350194SJens Axboe 	 * this case. Mark us as having done that already, since this is
2978f350194SJens Axboe 	 * different from normal wakeup.
2988f350194SJens Axboe 	 */
2998f350194SJens Axboe 	if (!ret) {
3008f350194SJens Axboe 		/*
3018f350194SJens Axboe 		 * If futex_wait_multiple_setup() returns 0 for a
3028f350194SJens Axboe 		 * successful setup, then the task state will not be
3038f350194SJens Axboe 		 * runnable. This is fine for the sync syscall, as
3048f350194SJens Axboe 		 * it'll be blocking unless we already got one of the
3058f350194SJens Axboe 		 * futexes woken, but it obviously won't work for an
3068f350194SJens Axboe 		 * async invocation. Mark us runnable again.
3078f350194SJens Axboe 		 */
3088f350194SJens Axboe 		__set_current_state(TASK_RUNNING);
3098f350194SJens Axboe 		hlist_add_head(&req->hash_node, &ctx->futex_list);
3108f350194SJens Axboe 	} else {
3118f350194SJens Axboe 		iof->futexv_unqueued = 1;
3128f350194SJens Axboe 		if (woken != -1)
3138f350194SJens Axboe 			io_req_set_res(req, woken, 0);
3148f350194SJens Axboe 	}
3158f350194SJens Axboe 
3168f350194SJens Axboe 	io_ring_submit_unlock(ctx, issue_flags);
3178f350194SJens Axboe 	return IOU_ISSUE_SKIP_COMPLETE;
3188f350194SJens Axboe }
3198f350194SJens Axboe 
io_futex_wait(struct io_kiocb * req,unsigned int issue_flags)320194bb58cSJens Axboe int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags)
321194bb58cSJens Axboe {
322194bb58cSJens Axboe 	struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
323194bb58cSJens Axboe 	struct io_ring_ctx *ctx = req->ctx;
324194bb58cSJens Axboe 	struct io_futex_data *ifd = NULL;
325194bb58cSJens Axboe 	struct futex_hash_bucket *hb;
326194bb58cSJens Axboe 	int ret;
327194bb58cSJens Axboe 
328194bb58cSJens Axboe 	if (!iof->futex_mask) {
329194bb58cSJens Axboe 		ret = -EINVAL;
330194bb58cSJens Axboe 		goto done;
331194bb58cSJens Axboe 	}
332194bb58cSJens Axboe 
333194bb58cSJens Axboe 	io_ring_submit_lock(ctx, issue_flags);
334194bb58cSJens Axboe 	ifd = io_alloc_ifd(ctx);
335194bb58cSJens Axboe 	if (!ifd) {
336194bb58cSJens Axboe 		ret = -ENOMEM;
337194bb58cSJens Axboe 		goto done_unlock;
338194bb58cSJens Axboe 	}
339194bb58cSJens Axboe 
340194bb58cSJens Axboe 	req->async_data = ifd;
341194bb58cSJens Axboe 	ifd->q = futex_q_init;
342194bb58cSJens Axboe 	ifd->q.bitset = iof->futex_mask;
343194bb58cSJens Axboe 	ifd->q.wake = io_futex_wake_fn;
344194bb58cSJens Axboe 	ifd->req = req;
345194bb58cSJens Axboe 
346194bb58cSJens Axboe 	ret = futex_wait_setup(iof->uaddr, iof->futex_val, iof->futex_flags,
347194bb58cSJens Axboe 			       &ifd->q, &hb);
348194bb58cSJens Axboe 	if (!ret) {
349194bb58cSJens Axboe 		hlist_add_head(&req->hash_node, &ctx->futex_list);
350194bb58cSJens Axboe 		io_ring_submit_unlock(ctx, issue_flags);
351194bb58cSJens Axboe 
352194bb58cSJens Axboe 		futex_queue(&ifd->q, hb);
353194bb58cSJens Axboe 		return IOU_ISSUE_SKIP_COMPLETE;
354194bb58cSJens Axboe 	}
355194bb58cSJens Axboe 
356194bb58cSJens Axboe done_unlock:
357194bb58cSJens Axboe 	io_ring_submit_unlock(ctx, issue_flags);
358194bb58cSJens Axboe done:
359194bb58cSJens Axboe 	if (ret < 0)
360194bb58cSJens Axboe 		req_set_fail(req);
361194bb58cSJens Axboe 	io_req_set_res(req, ret, 0);
362194bb58cSJens Axboe 	kfree(ifd);
363194bb58cSJens Axboe 	return IOU_OK;
364194bb58cSJens Axboe }
365194bb58cSJens Axboe 
io_futex_wake(struct io_kiocb * req,unsigned int issue_flags)366194bb58cSJens Axboe int io_futex_wake(struct io_kiocb *req, unsigned int issue_flags)
367194bb58cSJens Axboe {
368194bb58cSJens Axboe 	struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
369194bb58cSJens Axboe 	int ret;
370194bb58cSJens Axboe 
371194bb58cSJens Axboe 	/*
372194bb58cSJens Axboe 	 * Strict flags - ensure that waking 0 futexes yields a 0 result.
373194bb58cSJens Axboe 	 * See commit 43adf8449510 ("futex: FLAGS_STRICT") for details.
374194bb58cSJens Axboe 	 */
375194bb58cSJens Axboe 	ret = futex_wake(iof->uaddr, FLAGS_STRICT | iof->futex_flags,
376194bb58cSJens Axboe 			 iof->futex_val, iof->futex_mask);
377194bb58cSJens Axboe 	if (ret < 0)
378194bb58cSJens Axboe 		req_set_fail(req);
379194bb58cSJens Axboe 	io_req_set_res(req, ret, 0);
380194bb58cSJens Axboe 	return IOU_OK;
381194bb58cSJens Axboe }
382