All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] bunch of random cleanup for-next
@ 2021-10-06 15:06 Pavel Begunkov
  2021-10-06 15:06 ` [PATCH 1/5] io_uring: optimise plugging Pavel Begunkov
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Pavel Begunkov @ 2021-10-06 15:06 UTC (permalink / raw)
  To: io-uring; +Cc: Jens Axboe, asml.silence

Mix of small optimisations and some additions for safety

Pavel Begunkov (5):
  io_uring: optimise plugging
  io_uring: safer fallback_work free
  io_uring: reshuffle io_submit_state bits
  io_uring: optimise out req->opcode reloading
  io_uring: remove extra io_ring_exit_work wake up

 fs/io_uring.c | 72 +++++++++++++++++++++++++--------------------------
 1 file changed, 35 insertions(+), 37 deletions(-)

-- 
2.33.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/5] io_uring: optimise plugging
  2021-10-06 15:06 [PATCH 0/5] bunch of random cleanup for-next Pavel Begunkov
@ 2021-10-06 15:06 ` Pavel Begunkov
  2021-10-06 15:06 ` [PATCH 2/5] io_uring: safer fallback_work free Pavel Begunkov
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Pavel Begunkov @ 2021-10-06 15:06 UTC (permalink / raw)
  To: io-uring; +Cc: Jens Axboe, asml.silence

Plugging is only needed with requests that also need a file, so hide
plugging under a ->needs_file check. Also, place ->needs_file and ->plug
bits into the same byte of io_op_defs, it may matter for compilers, e.g.
only with the change a tested one decided to optimise two memory testb
into a more with two register testb.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 fs/io_uring.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index 62dc128e9b6b..fabb3580e27c 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -894,12 +894,12 @@ struct io_defer_entry {
 struct io_op_def {
 	/* needs req->file assigned */
 	unsigned		needs_file : 1;
+	/* should block plug */
+	unsigned		plug : 1;
 	/* hash wq insertion if file is a regular file */
 	unsigned		hash_reg_file : 1;
 	/* unbound wq insertion if file is a non-regular file */
 	unsigned		unbound_nonreg_file : 1;
-	/* opcode is not supported by this kernel */
-	unsigned		not_supported : 1;
 	/* set if opcode supports polled "wait" */
 	unsigned		pollin : 1;
 	unsigned		pollout : 1;
@@ -907,8 +907,8 @@ struct io_op_def {
 	unsigned		buffer_select : 1;
 	/* do prep async if is going to be punted */
 	unsigned		needs_async_setup : 1;
-	/* should block plug */
-	unsigned		plug : 1;
+	/* opcode is not supported by this kernel */
+	unsigned		not_supported : 1;
 	/* size of async data needed, if any */
 	unsigned short		async_size;
 };
@@ -6981,7 +6981,6 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 		       const struct io_uring_sqe *sqe)
 	__must_hold(&ctx->uring_lock)
 {
-	struct io_submit_state *state;
 	unsigned int sqe_flags;
 	int personality;
 
@@ -7028,19 +7027,20 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 		get_cred(req->creds);
 		req->flags |= REQ_F_CREDS;
 	}
-	state = &ctx->submit_state;
-
-	/*
-	 * Plug now if we have more than 1 IO left after this, and the target
-	 * is potentially a read/write to block based storage.
-	 */
-	if (state->need_plug && io_op_defs[req->opcode].plug) {
-		blk_start_plug(&state->plug);
-		state->plug_started = true;
-		state->need_plug = false;
-	}
 
 	if (io_op_defs[req->opcode].needs_file) {
+		struct io_submit_state *state = &ctx->submit_state;
+
+		/*
+		 * Plug now if we have more than 2 IO left after this, and the
+		 * target is potentially a read/write to block based storage.
+		 */
+		if (state->need_plug && io_op_defs[req->opcode].plug) {
+			state->plug_started = true;
+			state->need_plug = false;
+			blk_start_plug(&state->plug);
+		}
+
 		req->file = io_file_get(ctx, req, READ_ONCE(sqe->fd),
 					(sqe_flags & IOSQE_FIXED_FILE));
 		if (unlikely(!req->file))
-- 
2.33.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/5] io_uring: safer fallback_work free
  2021-10-06 15:06 [PATCH 0/5] bunch of random cleanup for-next Pavel Begunkov
  2021-10-06 15:06 ` [PATCH 1/5] io_uring: optimise plugging Pavel Begunkov
@ 2021-10-06 15:06 ` Pavel Begunkov
  2021-10-06 15:06 ` [PATCH 3/5] io_uring: reshuffle io_submit_state bits Pavel Begunkov
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Pavel Begunkov @ 2021-10-06 15:06 UTC (permalink / raw)
  To: io-uring; +Cc: Jens Axboe, asml.silence

Add extra wq flushing for fallback_work, that's not necessary but safer
if invariants of io_fallback_req_func() change.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 fs/io_uring.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index fabb3580e27c..b61ffb1e7990 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -1262,7 +1262,6 @@ static __cold void io_fallback_req_func(struct work_struct *work)
 		mutex_unlock(&ctx->uring_lock);
 	}
 	percpu_ref_put(&ctx->refs);
-
 }
 
 static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
@@ -9215,6 +9214,7 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
 	if (ctx->rsrc_backup_node)
 		io_rsrc_node_destroy(ctx->rsrc_backup_node);
 	flush_delayed_work(&ctx->rsrc_put_work);
+	flush_delayed_work(&ctx->fallback_work);
 
 	WARN_ON_ONCE(!list_empty(&ctx->rsrc_ref_list));
 	WARN_ON_ONCE(!llist_empty(&ctx->rsrc_put_llist));
-- 
2.33.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/5] io_uring: reshuffle io_submit_state bits
  2021-10-06 15:06 [PATCH 0/5] bunch of random cleanup for-next Pavel Begunkov
  2021-10-06 15:06 ` [PATCH 1/5] io_uring: optimise plugging Pavel Begunkov
  2021-10-06 15:06 ` [PATCH 2/5] io_uring: safer fallback_work free Pavel Begunkov
@ 2021-10-06 15:06 ` Pavel Begunkov
  2021-10-06 15:06 ` [PATCH 4/5] io_uring: optimise out req->opcode reloading Pavel Begunkov
  2021-10-06 15:06 ` [PATCH 5/5] io_uring: remove extra io_ring_exit_work wake up Pavel Begunkov
  4 siblings, 0 replies; 7+ messages in thread
From: Pavel Begunkov @ 2021-10-06 15:06 UTC (permalink / raw)
  To: io-uring; +Cc: Jens Axboe, asml.silence

struct io_submit_state's ->free_list and ->link are hotter and smaller
than ->plug, place them first.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 fs/io_uring.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index b61ffb1e7990..3f8bfa309b16 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -308,19 +308,15 @@ struct io_submit_link {
 };
 
 struct io_submit_state {
-	struct blk_plug		plug;
+	/* inline/task_work completion list, under ->uring_lock */
+	struct io_wq_work_node	free_list;
+	/* batch completion logic */
+	struct io_wq_work_list	compl_reqs;
 	struct io_submit_link	link;
 
 	bool			plug_started;
 	bool			need_plug;
-
-	/*
-	 * Batch completion logic
-	 */
-	struct io_wq_work_list	compl_reqs;
-
-	/* inline/task_work completion list, under ->uring_lock */
-	struct io_wq_work_node	free_list;
+	struct blk_plug		plug;
 };
 
 struct io_ring_ctx {
-- 
2.33.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/5] io_uring: optimise out req->opcode reloading
  2021-10-06 15:06 [PATCH 0/5] bunch of random cleanup for-next Pavel Begunkov
                   ` (2 preceding siblings ...)
  2021-10-06 15:06 ` [PATCH 3/5] io_uring: reshuffle io_submit_state bits Pavel Begunkov
@ 2021-10-06 15:06 ` Pavel Begunkov
  2021-10-06 16:48   ` Jens Axboe
  2021-10-06 15:06 ` [PATCH 5/5] io_uring: remove extra io_ring_exit_work wake up Pavel Begunkov
  4 siblings, 1 reply; 7+ messages in thread
From: Pavel Begunkov @ 2021-10-06 15:06 UTC (permalink / raw)
  To: io-uring; +Cc: Jens Axboe, asml.silence

Looking at the assembly, the compiler decided to reload req->opcode in
io_op_defs[opcode].needs_file instead of one it had in a register, so
store it in a temp variable so it can be optimised out. Also move the
personality block later, it's better for spilling/etc. as it only
depends on @sqe, which we're keeping anyway.

By the way, zero req->opcode if it over IORING_OP_LAST, not a problem,
at the moment but is safer.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 fs/io_uring.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index 3f8bfa309b16..1f4aa2cdaaa2 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -6978,9 +6978,10 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 {
 	unsigned int sqe_flags;
 	int personality;
+	u8 opcode;
 
 	/* req is partially pre-initialised, see io_preinit_req() */
-	req->opcode = READ_ONCE(sqe->opcode);
+	req->opcode = opcode = READ_ONCE(sqe->opcode);
 	/* same numerical values with corresponding REQ_F_*, safe to copy */
 	req->flags = sqe_flags = READ_ONCE(sqe->flags);
 	req->user_data = READ_ONCE(sqe->user_data);
@@ -6988,14 +6989,16 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 	req->fixed_rsrc_refs = NULL;
 	req->task = current;
 
-	if (unlikely(req->opcode >= IORING_OP_LAST))
+	if (unlikely(opcode >= IORING_OP_LAST)) {
+		req->opcode = 0;
 		return -EINVAL;
+	}
 	if (unlikely(sqe_flags & ~SQE_COMMON_FLAGS)) {
 		/* enforce forwards compatibility on users */
 		if (sqe_flags & ~SQE_VALID_FLAGS)
 			return -EINVAL;
 		if ((sqe_flags & IOSQE_BUFFER_SELECT) &&
-		    !io_op_defs[req->opcode].buffer_select)
+		    !io_op_defs[opcode].buffer_select)
 			return -EOPNOTSUPP;
 		if (sqe_flags & IOSQE_IO_DRAIN)
 			io_init_req_drain(req);
@@ -7014,23 +7017,14 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 		}
 	}
 
-	personality = READ_ONCE(sqe->personality);
-	if (personality) {
-		req->creds = xa_load(&ctx->personalities, personality);
-		if (!req->creds)
-			return -EINVAL;
-		get_cred(req->creds);
-		req->flags |= REQ_F_CREDS;
-	}
-
-	if (io_op_defs[req->opcode].needs_file) {
+	if (io_op_defs[opcode].needs_file) {
 		struct io_submit_state *state = &ctx->submit_state;
 
 		/*
 		 * Plug now if we have more than 2 IO left after this, and the
 		 * target is potentially a read/write to block based storage.
 		 */
-		if (state->need_plug && io_op_defs[req->opcode].plug) {
+		if (state->need_plug && io_op_defs[opcode].plug) {
 			state->plug_started = true;
 			state->need_plug = false;
 			blk_start_plug(&state->plug);
@@ -7042,6 +7036,15 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 			return -EBADF;
 	}
 
+	personality = READ_ONCE(sqe->personality);
+	if (personality) {
+		req->creds = xa_load(&ctx->personalities, personality);
+		if (!req->creds)
+			return -EINVAL;
+		get_cred(req->creds);
+		req->flags |= REQ_F_CREDS;
+	}
+
 	return io_req_prep(req, sqe);
 }
 
-- 
2.33.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/5] io_uring: remove extra io_ring_exit_work wake up
  2021-10-06 15:06 [PATCH 0/5] bunch of random cleanup for-next Pavel Begunkov
                   ` (3 preceding siblings ...)
  2021-10-06 15:06 ` [PATCH 4/5] io_uring: optimise out req->opcode reloading Pavel Begunkov
@ 2021-10-06 15:06 ` Pavel Begunkov
  4 siblings, 0 replies; 7+ messages in thread
From: Pavel Begunkov @ 2021-10-06 15:06 UTC (permalink / raw)
  To: io-uring; +Cc: Jens Axboe, asml.silence

task_work_add() takes care of waking up the thread, remove useless
wake_up_process().

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 fs/io_uring.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index 1f4aa2cdaaa2..73135c5c6168 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -9370,7 +9370,6 @@ static __cold void io_ring_exit_work(struct work_struct *work)
 		ret = task_work_add(node->task, &exit.task_work, TWA_SIGNAL);
 		if (WARN_ON_ONCE(ret))
 			continue;
-		wake_up_process(node->task);
 
 		mutex_unlock(&ctx->uring_lock);
 		wait_for_completion(&exit.completion);
-- 
2.33.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 4/5] io_uring: optimise out req->opcode reloading
  2021-10-06 15:06 ` [PATCH 4/5] io_uring: optimise out req->opcode reloading Pavel Begunkov
@ 2021-10-06 16:48   ` Jens Axboe
  0 siblings, 0 replies; 7+ messages in thread
From: Jens Axboe @ 2021-10-06 16:48 UTC (permalink / raw)
  To: Pavel Begunkov, io-uring

On 10/6/21 9:06 AM, Pavel Begunkov wrote:
> Looking at the assembly, the compiler decided to reload req->opcode in
> io_op_defs[opcode].needs_file instead of one it had in a register, so
> store it in a temp variable so it can be optimised out. Also move the
> personality block later, it's better for spilling/etc. as it only
> depends on @sqe, which we're keeping anyway.
> 
> By the way, zero req->opcode if it over IORING_OP_LAST, not a problem,
> at the moment but is safer.

That had me a bit worried, but you mean it's reloading req->opcode,
not sqe->opcode. Phew.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-10-06 16:48 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-10-06 15:06 [PATCH 0/5] bunch of random cleanup for-next Pavel Begunkov
2021-10-06 15:06 ` [PATCH 1/5] io_uring: optimise plugging Pavel Begunkov
2021-10-06 15:06 ` [PATCH 2/5] io_uring: safer fallback_work free Pavel Begunkov
2021-10-06 15:06 ` [PATCH 3/5] io_uring: reshuffle io_submit_state bits Pavel Begunkov
2021-10-06 15:06 ` [PATCH 4/5] io_uring: optimise out req->opcode reloading Pavel Begunkov
2021-10-06 16:48   ` Jens Axboe
2021-10-06 15:06 ` [PATCH 5/5] io_uring: remove extra io_ring_exit_work wake up Pavel Begunkov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.