mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	io_uring: remove struct io_tw_state::locked
ctx is always locked for task_work now, so get rid of struct io_tw_state::locked. Note I'm stopping one step before removing io_tw_state altogether, which is not empty, because it still serves the purpose of indicating which function is a tw callback and forcing users not to invoke them carelessly out of a wrong context. The removal can always be done later. Signed-off-by: Pavel Begunkov <asml.silence@gmail.com> Tested-by: Ming Lei <ming.lei@redhat.com> Link: https://lore.kernel.org/r/e95e1ea116d0bfa54b656076e6a977bc221392a4.1710799188.git.asml.silence@gmail.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
		
							parent
							
								
									92219afb98
								
							
						
					
					
						commit
						8e5b3b89ec
					
				
					 8 changed files with 17 additions and 47 deletions
				
			
		| 
						 | 
				
			
			@ -438,8 +438,6 @@ struct io_ring_ctx {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
struct io_tw_state {
 | 
			
		||||
	/* ->uring_lock is taken, callbacks can use io_tw_lock to lock it */
 | 
			
		||||
	bool locked;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -247,14 +247,12 @@ static __cold void io_fallback_req_func(struct work_struct *work)
 | 
			
		|||
						fallback_work.work);
 | 
			
		||||
	struct llist_node *node = llist_del_all(&ctx->fallback_llist);
 | 
			
		||||
	struct io_kiocb *req, *tmp;
 | 
			
		||||
	struct io_tw_state ts = { .locked = true, };
 | 
			
		||||
	struct io_tw_state ts = {};
 | 
			
		||||
 | 
			
		||||
	percpu_ref_get(&ctx->refs);
 | 
			
		||||
	mutex_lock(&ctx->uring_lock);
 | 
			
		||||
	llist_for_each_entry_safe(req, tmp, node, io_task_work.node)
 | 
			
		||||
		req->io_task_work.func(req, &ts);
 | 
			
		||||
	if (WARN_ON_ONCE(!ts.locked))
 | 
			
		||||
		return;
 | 
			
		||||
	io_submit_flush_completions(ctx);
 | 
			
		||||
	mutex_unlock(&ctx->uring_lock);
 | 
			
		||||
	percpu_ref_put(&ctx->refs);
 | 
			
		||||
| 
						 | 
				
			
			@ -1157,11 +1155,9 @@ static void ctx_flush_and_put(struct io_ring_ctx *ctx, struct io_tw_state *ts)
 | 
			
		|||
		return;
 | 
			
		||||
	if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
 | 
			
		||||
		atomic_andnot(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
 | 
			
		||||
	if (ts->locked) {
 | 
			
		||||
 | 
			
		||||
	io_submit_flush_completions(ctx);
 | 
			
		||||
	mutex_unlock(&ctx->uring_lock);
 | 
			
		||||
		ts->locked = false;
 | 
			
		||||
	}
 | 
			
		||||
	percpu_ref_put(&ctx->refs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1185,8 +1181,6 @@ struct llist_node *io_handle_tw_list(struct llist_node *node,
 | 
			
		|||
		if (req->ctx != ctx) {
 | 
			
		||||
			ctx_flush_and_put(ctx, &ts);
 | 
			
		||||
			ctx = req->ctx;
 | 
			
		||||
 | 
			
		||||
			ts.locked = true;
 | 
			
		||||
			mutex_lock(&ctx->uring_lock);
 | 
			
		||||
			percpu_ref_get(&ctx->refs);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -1459,22 +1453,16 @@ static int __io_run_local_work(struct io_ring_ctx *ctx, struct io_tw_state *ts,
 | 
			
		|||
static inline int io_run_local_work_locked(struct io_ring_ctx *ctx,
 | 
			
		||||
					   int min_events)
 | 
			
		||||
{
 | 
			
		||||
	struct io_tw_state ts = { .locked = true, };
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct io_tw_state ts = {};
 | 
			
		||||
 | 
			
		||||
	if (llist_empty(&ctx->work_llist))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	ret = __io_run_local_work(ctx, &ts, min_events);
 | 
			
		||||
	/* shouldn't happen! */
 | 
			
		||||
	if (WARN_ON_ONCE(!ts.locked))
 | 
			
		||||
		mutex_lock(&ctx->uring_lock);
 | 
			
		||||
	return ret;
 | 
			
		||||
	return __io_run_local_work(ctx, &ts, min_events);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int io_run_local_work(struct io_ring_ctx *ctx, int min_events)
 | 
			
		||||
{
 | 
			
		||||
	struct io_tw_state ts = { .locked = true };
 | 
			
		||||
	struct io_tw_state ts = {};
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&ctx->uring_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -1702,10 +1690,7 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
 | 
			
		|||
 | 
			
		||||
void io_req_task_complete(struct io_kiocb *req, struct io_tw_state *ts)
 | 
			
		||||
{
 | 
			
		||||
	if (ts->locked)
 | 
			
		||||
	io_req_complete_defer(req);
 | 
			
		||||
	else
 | 
			
		||||
		io_req_complete_post(req, IO_URING_F_UNLOCKED);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -351,10 +351,7 @@ static inline bool io_task_work_pending(struct io_ring_ctx *ctx)
 | 
			
		|||
 | 
			
		||||
static inline void io_tw_lock(struct io_ring_ctx *ctx, struct io_tw_state *ts)
 | 
			
		||||
{
 | 
			
		||||
	if (!ts->locked) {
 | 
			
		||||
		mutex_lock(&ctx->uring_lock);
 | 
			
		||||
		ts->locked = true;
 | 
			
		||||
	}
 | 
			
		||||
	lockdep_assert_held(&ctx->uring_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -322,7 +322,7 @@ static int io_poll_check_events(struct io_kiocb *req, struct io_tw_state *ts)
 | 
			
		|||
			__poll_t mask = mangle_poll(req->cqe.res &
 | 
			
		||||
						    req->apoll_events);
 | 
			
		||||
 | 
			
		||||
			if (!io_fill_cqe_req_aux(req, ts->locked, mask,
 | 
			
		||||
			if (!io_fill_cqe_req_aux(req, true, mask,
 | 
			
		||||
						 IORING_CQE_F_MORE)) {
 | 
			
		||||
				io_req_set_res(req, mask, 0);
 | 
			
		||||
				return IOU_POLL_REMOVE_POLL_USE_RES;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -305,11 +305,9 @@ void io_req_rw_complete(struct io_kiocb *req, struct io_tw_state *ts)
 | 
			
		|||
 | 
			
		||||
	io_req_io_end(req);
 | 
			
		||||
 | 
			
		||||
	if (req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING)) {
 | 
			
		||||
		unsigned issue_flags = ts->locked ? 0 : IO_URING_F_UNLOCKED;
 | 
			
		||||
	if (req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING))
 | 
			
		||||
		req->cqe.flags |= io_put_kbuf(req, 0);
 | 
			
		||||
 | 
			
		||||
		req->cqe.flags |= io_put_kbuf(req, issue_flags);
 | 
			
		||||
	}
 | 
			
		||||
	io_req_task_complete(req, ts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,10 +72,7 @@ static void io_timeout_complete(struct io_kiocb *req, struct io_tw_state *ts)
 | 
			
		|||
	struct io_ring_ctx *ctx = req->ctx;
 | 
			
		||||
 | 
			
		||||
	if (!io_timeout_finish(timeout, data)) {
 | 
			
		||||
		bool filled;
 | 
			
		||||
		filled = io_fill_cqe_req_aux(req, ts->locked, -ETIME,
 | 
			
		||||
					     IORING_CQE_F_MORE);
 | 
			
		||||
		if (filled) {
 | 
			
		||||
		if (io_fill_cqe_req_aux(req, true, -ETIME, IORING_CQE_F_MORE)) {
 | 
			
		||||
			/* re-arm timer */
 | 
			
		||||
			spin_lock_irq(&ctx->timeout_lock);
 | 
			
		||||
			list_add(&timeout->list, ctx->timeout_list.prev);
 | 
			
		||||
| 
						 | 
				
			
			@ -301,7 +298,6 @@ int io_timeout_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd)
 | 
			
		|||
 | 
			
		||||
static void io_req_task_link_timeout(struct io_kiocb *req, struct io_tw_state *ts)
 | 
			
		||||
{
 | 
			
		||||
	unsigned issue_flags = ts->locked ? 0 : IO_URING_F_UNLOCKED;
 | 
			
		||||
	struct io_timeout *timeout = io_kiocb_to_cmd(req, struct io_timeout);
 | 
			
		||||
	struct io_kiocb *prev = timeout->prev;
 | 
			
		||||
	int ret = -ENOENT;
 | 
			
		||||
| 
						 | 
				
			
			@ -313,7 +309,7 @@ static void io_req_task_link_timeout(struct io_kiocb *req, struct io_tw_state *t
 | 
			
		|||
				.data		= prev->cqe.user_data,
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			ret = io_try_cancel(req->task->io_uring, &cd, issue_flags);
 | 
			
		||||
			ret = io_try_cancel(req->task->io_uring, &cd, 0);
 | 
			
		||||
		}
 | 
			
		||||
		io_req_set_res(req, ret ?: -ETIME, 0);
 | 
			
		||||
		io_req_task_complete(req, ts);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,13 +87,9 @@ EXPORT_SYMBOL_GPL(io_uring_cmd_mark_cancelable);
 | 
			
		|||
static void io_uring_cmd_work(struct io_kiocb *req, struct io_tw_state *ts)
 | 
			
		||||
{
 | 
			
		||||
	struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
 | 
			
		||||
	unsigned issue_flags = IO_URING_F_UNLOCKED;
 | 
			
		||||
 | 
			
		||||
	/* locked task_work executor checks the deffered list completion */
 | 
			
		||||
	if (ts->locked)
 | 
			
		||||
		issue_flags = IO_URING_F_COMPLETE_DEFER;
 | 
			
		||||
 | 
			
		||||
	ioucmd->task_work_cb(ioucmd, issue_flags);
 | 
			
		||||
	/* task_work executor checks the deffered list completion */
 | 
			
		||||
	ioucmd->task_work_cb(ioucmd, IO_URING_F_COMPLETE_DEFER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __io_uring_cmd_do_in_task(struct io_uring_cmd *ioucmd,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,7 +118,7 @@ static int io_waitid_finish(struct io_kiocb *req, int ret)
 | 
			
		|||
static void io_waitid_complete(struct io_kiocb *req, int ret)
 | 
			
		||||
{
 | 
			
		||||
	struct io_waitid *iw = io_kiocb_to_cmd(req, struct io_waitid);
 | 
			
		||||
	struct io_tw_state ts = { .locked = true };
 | 
			
		||||
	struct io_tw_state ts = {};
 | 
			
		||||
 | 
			
		||||
	/* anyone completing better be holding a reference */
 | 
			
		||||
	WARN_ON_ONCE(!(atomic_read(&iw->refs) & IO_WAITID_REF_MASK));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue