diff mbox

netpoll: use non-BH variant of RCU

Message ID 20100811112706.GA6772@gondor.apana.org.au
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Herbert Xu Aug. 11, 2010, 11:27 a.m. UTC
On Wed, Aug 11, 2010 at 07:03:30AM -0400, Herbert Xu wrote:
>
> To use rcu_read_lock safely we'd also need to add do synchronize_rcu
> in addition of synchronize_rcu_bh, right Paul?
> 
> Of course as we were doing this unsafely prior to my patch anyway
> I'm also fine with just reverting it.

Actually, we could just disable IRQs for stable.  How about this
patch (untested)?

netpoll: Disable IRQ around RCU dereference in netpoll_rx

We cannot use rcu_dereference_bh safely in netpoll_rx as we may
be called with IRQs disabled.  We could however simply disable
IRQs as that too causes BH to be disabled and is safe in either
case.

Thanks to John Linville for discovering this bug and providing
a patch.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Cheers,

Comments

John W. Linville Aug. 11, 2010, 3:37 p.m. UTC | #1
On Wed, Aug 11, 2010 at 07:27:06AM -0400, Herbert Xu wrote:
> On Wed, Aug 11, 2010 at 07:03:30AM -0400, Herbert Xu wrote:
> >
> > To use rcu_read_lock safely we'd also need to add do synchronize_rcu
> > in addition of synchronize_rcu_bh, right Paul?
> > 
> > Of course as we were doing this unsafely prior to my patch anyway
> > I'm also fine with just reverting it.
> 
> Actually, we could just disable IRQs for stable.  How about this
> patch (untested)?
> 
> netpoll: Disable IRQ around RCU dereference in netpoll_rx
> 
> We cannot use rcu_dereference_bh safely in netpoll_rx as we may
> be called with IRQs disabled.  We could however simply disable
> IRQs as that too causes BH to be disabled and is safe in either
> case.
> 
> Thanks to John Linville for discovering this bug and providing
> a patch.
> 
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

This also seems to work for me.

John

P.S.  As pointed-out elsewhere, my patch neglected to change
synchronize_rcu_bh to synchronize_rcu in netpoll.c.  If some fault
is found w/ Herbert's patch then I can post a modified version of mine.
David Miller Aug. 12, 2010, 6:16 a.m. UTC | #2
From: "John W. Linville" <linville@tuxdriver.com>
Date: Wed, 11 Aug 2010 11:37:36 -0400

> On Wed, Aug 11, 2010 at 07:27:06AM -0400, Herbert Xu wrote:
>> On Wed, Aug 11, 2010 at 07:03:30AM -0400, Herbert Xu wrote:
>> >
>> > To use rcu_read_lock safely we'd also need to add do synchronize_rcu
>> > in addition of synchronize_rcu_bh, right Paul?
>> > 
>> > Of course as we were doing this unsafely prior to my patch anyway
>> > I'm also fine with just reverting it.
>> 
>> Actually, we could just disable IRQs for stable.  How about this
>> patch (untested)?
>> 
>> netpoll: Disable IRQ around RCU dereference in netpoll_rx
>> 
>> We cannot use rcu_dereference_bh safely in netpoll_rx as we may
>> be called with IRQs disabled.  We could however simply disable
>> IRQs as that too causes BH to be disabled and is safe in either
>> case.
>> 
>> Thanks to John Linville for discovering this bug and providing
>> a patch.
>> 
>> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
> 
> This also seems to work for me.

I'll queue up this variant for -stable.

And we'll go with making use of Paul's new RCU irqsoff interface
approach for Linus's tree.

Thanks.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 413742c..54f286b 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -63,20 +63,20 @@  static inline bool netpoll_rx(struct sk_buff *skb)
 	unsigned long flags;
 	bool ret = false;
 
-	rcu_read_lock_bh();
+	local_irq_save(flags);
 	npinfo = rcu_dereference_bh(skb->dev->npinfo);
 
 	if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
 		goto out;
 
-	spin_lock_irqsave(&npinfo->rx_lock, flags);
+	spin_lock(&npinfo->rx_lock);
 	/* check rx_flags again with the lock held */
 	if (npinfo->rx_flags && __netpoll_rx(skb))
 		ret = true;
-	spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+	spin_unlock(&npinfo->rx_lock);
 
 out:
-	rcu_read_unlock_bh();
+	local_irq_restore(flags);
 	return ret;
 }