mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Kent Overstreet <koverstreet@google.com>
To: linux-kernel@vger.kernel.org, linux-aio@kvack.org,
	linux-fsdevel@vger.kernel.org
Cc: zab@redhat.com, bcrl@kvack.org, jmoyer@redhat.com,
	axboe@kernel.dk, viro@zeniv.linux.org.uk,
	Kent Overstreet <koverstreet@google.com>
Subject: [PATCH 25/26] aio: use xchg() instead of completion_lock
Date: Mon,  3 Dec 2012 12:58:41 -0800	[thread overview]
Message-ID: <1354568322-29029-26-git-send-email-koverstreet@google.com> (raw)
In-Reply-To: <1354568322-29029-1-git-send-email-koverstreet@google.com>

So, for sticking kiocb completions on the kioctx ringbuffer, we need a
lock - it unfortunately can't be lockless.

When the kioctx is shared between threads on different cpus and the rate
of completions is high, this lock sees quite a bit of contention - in
terms of cacheline contention it's the hottest thing in the aio
subsystem.

That means, with a regular spinlock, we're going to take a cache miss
to grab the lock, then another cache miss when we touch the data the
lock protects - if it's on the same cacheline as the lock, other cpus
spinning on the lock are going to be pulling it out from under us as
we're using it.

So, we use an old trick to get rid of this second forced cache miss -
make the data the lock protects be the lock itself, so we grab them both
at once.

Signed-off-by: Kent Overstreet <koverstreet@google.com>
---
 fs/aio.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/fs/aio.c b/fs/aio.c
index 931606b..f44f21d 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -101,11 +101,11 @@ struct kioctx {
 
 	struct {
 		struct mutex	ring_lock;
+		unsigned	shadow_tail;
 	} ____cacheline_aligned;
 
 	struct {
 		unsigned	tail;
-		spinlock_t	completion_lock;
 	} ____cacheline_aligned;
 
 	struct {
@@ -311,9 +311,9 @@ static void free_ioctx(struct kioctx *ctx)
 	kunmap_atomic(ring);
 
 	while (atomic_read(&ctx->reqs_available) < ctx->nr) {
-		wait_event(ctx->wait, head != ctx->tail);
+		wait_event(ctx->wait, head != ctx->shadow_tail);
 
-		avail = (head < ctx->tail ? ctx->tail : ctx->nr) - head;
+		avail = (head < ctx->shadow_tail ? ctx->shadow_tail : ctx->nr) - head;
 
 		atomic_add(avail, &ctx->reqs_available);
 		head += avail;
@@ -378,7 +378,6 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
 	rcu_read_unlock();
 
 	spin_lock_init(&ctx->ctx_lock);
-	spin_lock_init(&ctx->completion_lock);
 	mutex_init(&ctx->ring_lock);
 	init_waitqueue_head(&ctx->wait);
 
@@ -686,9 +685,10 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
 	 * ctx->ctx_lock to prevent other code from messing with the tail
 	 * pointer since we might be called from irq context.
 	 */
-	spin_lock_irqsave(&ctx->completion_lock, flags);
+	local_irq_save(flags);
+	while ((tail = xchg(&ctx->tail, UINT_MAX)) == UINT_MAX)
+		cpu_relax();
 
-	tail = ctx->tail;
 	pos = tail + AIO_EVENTS_OFFSET;
 
 	if (++tail >= ctx->nr)
@@ -714,14 +714,16 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
 	 */
 	smp_wmb();	/* make event visible before updating tail */
 
-	ctx->tail = tail;
+	ctx->shadow_tail = tail;
 
 	ring = kmap_atomic(ctx->ring_pages[0]);
 	ring->tail = tail;
 	kunmap_atomic(ring);
 	flush_dcache_page(ctx->ring_pages[0]);
 
-	spin_unlock_irqrestore(&ctx->completion_lock, flags);
+	smp_wmb();
+	ctx->tail = tail;
+	local_irq_restore(flags);
 
 	pr_debug("added to ring %p at [%u]\n", iocb, tail);
 
@@ -766,11 +768,11 @@ static int aio_read_events(struct kioctx *ctx, struct io_event __user *event,
 	pr_debug("h%u t%u m%u\n", *head, ctx->tail, ctx->nr);
 
 	while (ret < nr) {
-		unsigned i = (*head < ctx->tail ? ctx->tail : ctx->nr) - *head;
+		unsigned i = (*head < ctx->shadow_tail ? ctx->shadow_tail : ctx->nr) - *head;
 		struct io_event *ev;
 		struct page *page;
 
-		if (*head == ctx->tail)
+		if (*head == ctx->shadow_tail)
 			break;
 
 		i = min_t(int, i, nr - ret);
@@ -860,7 +862,7 @@ retry:
 		prepare_to_wait_exclusive(&ctx->wait, &wait,
 					  TASK_INTERRUPTIBLE);
 
-		if (head != ctx->tail) {
+		if (head != ctx->shadow_tail) {
 			__set_current_state(TASK_RUNNING);
 			goto retry;
 		}
-- 
1.7.12


  parent reply	other threads:[~2012-12-03 21:00 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-03 20:58 [PATCH 00/26] AIO performance improvements/cleanups, v2 Kent Overstreet
2012-12-03 20:58 ` [PATCH 01/26] mm: remove old aio use_mm() comment Kent Overstreet
2012-12-03 20:58 ` [PATCH 02/26] aio: remove dead code from aio.h Kent Overstreet
2012-12-03 20:58 ` [PATCH 03/26] gadget: remove only user of aio retry Kent Overstreet
2012-12-03 20:58 ` [PATCH 04/26] aio: remove retry-based AIO Kent Overstreet
2012-12-27 10:11   ` Fubo Chen
2012-12-03 20:58 ` [PATCH 05/26] char: add aio_{read,write} to /dev/{null,zero} Kent Overstreet
2012-12-03 20:58 ` [PATCH 06/26] aio: Kill return value of aio_complete() Kent Overstreet
2012-12-03 20:58 ` [PATCH 07/26] aio: kiocb_cancel() Kent Overstreet
2012-12-03 20:58 ` [PATCH 08/26] aio: Move private stuff out of aio.h Kent Overstreet
2012-12-03 20:58 ` [PATCH 09/26] aio: dprintk() -> pr_debug() Kent Overstreet
2012-12-03 20:58 ` [PATCH 10/26] aio: do fget() after aio_get_req() Kent Overstreet
2012-12-03 20:58 ` [PATCH 11/26] aio: Make aio_put_req() lockless Kent Overstreet
2012-12-03 20:58 ` [PATCH 12/26] aio: Refcounting cleanup Kent Overstreet
2012-12-03 20:58 ` [PATCH 13/26] aio: Convert read_events() to hrtimers Kent Overstreet
2012-12-03 20:58 ` [PATCH 14/26] aio: Make aio_read_evt() more efficient Kent Overstreet
2012-12-03 20:58 ` [PATCH 15/26] aio: Use flush_dcache_page() Kent Overstreet
2012-12-03 20:58 ` [PATCH 16/26] aio: Use cancellation list lazily Kent Overstreet
2012-12-03 20:58 ` [PATCH 17/26] aio: Change reqs_active to include unreaped completions Kent Overstreet
2012-12-03 20:58 ` [PATCH 18/26] aio: Kill batch allocation Kent Overstreet
2012-12-03 20:58 ` [PATCH 19/26] aio: Kill struct aio_ring_info Kent Overstreet
2012-12-03 20:58 ` [PATCH 20/26] aio: Give shared kioctx fields their own cachelines Kent Overstreet
2012-12-03 20:58 ` [PATCH 21/26] aio: reqs_active -> reqs_available Kent Overstreet
2012-12-03 20:58 ` [PATCH 22/26] aio: percpu reqs_available Kent Overstreet
2012-12-03 20:58 ` [PATCH 23/26] Generic dynamic per cpu refcounting Kent Overstreet
2012-12-27 13:47   ` Fubo Chen
2012-12-03 20:58 ` [PATCH 24/26] aio: Percpu ioctx refcount Kent Overstreet
2012-12-03 20:58 ` Kent Overstreet [this message]
2012-12-03 20:58 ` [PATCH 26/26] aio: Don't include aio.h in sched.h Kent Overstreet
2012-12-13 21:18 ` [PATCH 00/26] AIO performance improvements/cleanups, v2 Jens Axboe
2012-12-14  2:26   ` Jack Wang
2012-12-14  7:35     ` Jens Axboe
2012-12-15  9:25       ` Kent Overstreet
2012-12-15  9:46         ` Jens Axboe
2012-12-15 10:36           ` Kent Overstreet
2012-12-15 12:59             ` Jens Axboe
2012-12-15 13:16             ` Jens Axboe
2012-12-18 19:16               ` Kent Overstreet
2012-12-19  6:45                 ` Kent Overstreet
2012-12-19 11:59 [PATCH 25/26] aio: use xchg() instead of completion_lock Hillf Danton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1354568322-29029-26-git-send-email-koverstreet@google.com \
    --to=koverstreet@google.com \
    --cc=axboe@kernel.dk \
    --cc=bcrl@kvack.org \
    --cc=jmoyer@redhat.com \
    --cc=linux-aio@kvack.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    --cc=zab@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®