mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Frederic Weisbecker <fweisbec@gmail.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: LKML <linux-kernel@vger.kernel.org>,
	Frederic Weisbecker <fweisbec@gmail.com>,
	Ingo Molnar <mingo@kernel.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	Andrew Morton <akpm@linux-foundation.org>,
	Steven Rostedt <rostedt@goodmis.org>,
	Paul Gortmaker <paul.gortmaker@windriver.com>
Subject: [PATCH 1/2] irq_work: Fix racy check on work pending flag
Date: Tue, 30 Oct 2012 16:35:00 +0100	[thread overview]
Message-ID: <1351611301-3520-2-git-send-email-fweisbec@gmail.com> (raw)
In-Reply-To: <1351611301-3520-1-git-send-email-fweisbec@gmail.com>

Work claiming semantics require this operation
to be SMP-safe.

So we want a strict ordering between the data we
want the work to handle and the flags that describe
the work state such that either we claim and we enqueue
the work that will see our data or we fail the claim
but the CPU where the work is still pending will
see the data we prepared when it executes the work:

CPU 0                   CPU 1

data = something        claim work
smp_mb()                smp_mb()
try claim work          execute work (data)

The early check for the pending flag in irq_work_claim()
fails to meet this ordering requirement. As a result,
when we fail to claim a work, it may have been processed
by CPU that were previously owning it already, leaving
our data unprocessed.

Discussing this with Steven Rostedt, we can use memory
barriers to fix this or we can rely on cmpxchg() that
implies full barrier already.

To fix this, we start by speculating about the value we
wish to be in the work->flags but we only make any conclusion
after the value returned by the cmpxchg() call that either
claims the work or does the ordering such that the CPU
where the work is pending handles our data.

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
---
 kernel/irq_work.c |   22 +++++++++++++++++-----
 1 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index 1588e3b..764240a 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -34,15 +34,27 @@ static DEFINE_PER_CPU(struct llist_head, irq_work_list);
  */
 static bool irq_work_claim(struct irq_work *work)
 {
-	unsigned long flags, nflags;
+	unsigned long flags, oflags, nflags;
 
+	/*
+	 * Can't check IRQ_WORK_PENDING bit right now because the work
+	 * can be running on another CPU and we need correct ordering
+	 * between work flags and data to compute in work execution
+	 * such that either we claim and we execute the work or the work
+	 * is still pending on another CPU but it's guaranteed it will see
+	 * our data when it executes the work.
+	 * Start with our best wish as a premise but only deal with
+	 * flags value for real after cmpxchg() ordering.
+	 */
+	flags = work->flags & ~IRQ_WORK_PENDING;
 	for (;;) {
-		flags = work->flags;
-		if (flags & IRQ_WORK_PENDING)
-			return false;
 		nflags = flags | IRQ_WORK_FLAGS;
-		if (cmpxchg(&work->flags, flags, nflags) == flags)
+		oflags = cmpxchg(&work->flags, flags, nflags);
+		if (oflags == flags)
 			break;
+		if (oflags & IRQ_WORK_PENDING)
+			return false;
+		flags = oflags;
 		cpu_relax();
 	}
 
-- 
1.7.5.4


  reply	other threads:[~2012-10-30 15:35 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-30 15:34 [PATCH 0/2] irq_work: A couple fixes Frederic Weisbecker
2012-10-30 15:35 ` Frederic Weisbecker [this message]
2012-10-30 15:53   ` [PATCH 1/2] irq_work: Fix racy check on work pending flag Steven Rostedt
2012-10-30 15:35 ` [PATCH 2/2] irq_work: Fix racy IRQ_WORK_BUSY flag setting Frederic Weisbecker
2012-10-30 16:26   ` Steven Rostedt
2012-10-30 18:33   ` anish kumar
2012-10-30 18:45     ` Steven Rostedt
2012-10-31 11:06       ` anish kumar
2012-10-31  0:36     ` Frederic Weisbecker
2012-10-31  2:23       ` Steven Rostedt
2012-10-31  2:54         ` Frederic Weisbecker
2012-10-31 11:04         ` anish kumar
2012-10-31 12:59           ` Steven Rostedt
2012-10-31 13:32             ` Frederic Weisbecker
2012-10-31 13:51           ` Steven Rostedt
2012-10-30 15:52 ` [PATCH 0/2] irq_work: A couple fixes Steven Rostedt
2012-10-30 16:25   ` Frederic Weisbecker
2012-10-30 17:13     ` Steven Rostedt
2012-10-30 17:17       ` Frederic Weisbecker

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=1351611301-3520-2-git-send-email-fweisbec@gmail.com \
    --to=fweisbec@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=paul.gortmaker@windriver.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=tglx@linutronix.de \
    /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

Powered by JetHome