Skip to contentSkip to conversation

IPoIB: Fix unregister_netdev hang

PATCH In review Krishna Kumar 3 participants 12 messages Sep 18, 2007 – Sep 19, 2007

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/2 IPoIB: Fix unregister_netdev hang

While using IPoIB over EHCA (rc6 bits), unregister_netdev hangs with the message: "waiting for ib2 to become free. Usage count = -515276", etc.

The problem is that the poll handler does netif_rx_complete (which does a dev_put) followed by netif_rx_reschedule() to schedule for more receives (which again does a dev_put). This reduces refcount to < 0 (depending on how many times netif_rx_complete followed by netif_rx_reschedule was called).

The following patch fixes the bug, but I don't know if there is some specific IB issue that prevents this approach.

---
 ipoib_ib.c |   11 ++++-------
 1 files changed, 4 insertions(+), 7 deletions(-)
drivers/infiniband/ulp/ipoib/ipoib_ib.c +4 -7
diff -ruNp org/drivers/infiniband/ulp/ipoib/ipoib_ib.c new1/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -291,7 +291,6 @@ int ipoib_poll(struct napi_struct *napi,
 
 	done  = 0;
 
-poll_more:
 	while (done < budget) {
 		int max = (budget - done);
 
@@ -316,12 +315,10 @@ poll_more:
 	}
 
 	if (done < budget) {
-		netif_rx_complete(dev, napi);
-		if (unlikely(ib_req_notify_cq(priv->cq,
-					      IB_CQ_NEXT_COMP |
-					      IB_CQ_REPORT_MISSED_EVENTS)) &&
-		    netif_rx_reschedule(napi))
-			goto poll_more;
+		if (likely(!ib_req_notify_cq(priv->cq,
+					     IB_CQ_NEXT_COMP |
+					     IB_CQ_REPORT_MISSED_EVENTS)))
+			netif_rx_complete(dev, napi);
 	}
 
 	return done;
#1 lore raw

PATCH 2/2 IPoIB: Code cleanup

Follow-up cleanup and "while loop" optimization in the poll handler. net_rx_action guarantees that 'budget' is atleast 1.

Note: This could also be done for poll handlers of other drivers.

---
 ipoib_ib.c |   22 ++++++++--------------
 1 files changed, 8 insertions(+), 14 deletions(-)
drivers/infiniband/ulp/ipoib/ipoib_ib.c +8 -14
diff -ruNp new1/drivers/infiniband/ulp/ipoib/ipoib_ib.c new2/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -285,19 +285,16 @@ int ipoib_poll(struct napi_struct *napi,
 {
 	struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi);
 	struct net_device *dev = priv->dev;
-	int done;
-	int t;
-	int n, i;
+	int num_wc, max_wc;
+	int done = 0;
 
-	done  = 0;
-
-	while (done < budget) {
-		int max = (budget - done);
+	do {
+		int i;
 
-		t = min(IPOIB_NUM_WC, max);
-		n = ib_poll_cq(priv->cq, t, priv->ibwc);
+		max_wc = min(IPOIB_NUM_WC, budget - done);
+		num_wc = ib_poll_cq(priv->cq, max_wc, priv->ibwc);
 
-		for (i = 0; i < n; i++) {
+		for (i = 0; i < num_wc; i++) {
 			struct ib_wc *wc = priv->ibwc + i;
 
 			if (wc->wr_id & IPOIB_CM_OP_SRQ) {
@@ -309,10 +306,7 @@ int ipoib_poll(struct napi_struct *napi,
 			} else
 				ipoib_ib_handle_tx_wc(dev, wc);
 		}
-
-		if (n != t)
-			break;
-	}
+	} while (num_wc == max_wc && done < budget);
 
 	if (done < budget) {
 		if (likely(!ib_req_notify_cq(priv->cq,
#2 lore raw
In reply to Krishna Kumar

Thanks for testing on ehca...

Quoted 1 line

While using IPoIB over EHCA (rc6 bits), unregister_netdev hangs with

I don't think you're actually using rc6 bits, since in your patch you have:

Quoted 1 line

-poll_more:

and I think that is only in Dave's net-2.6.24 tree now, right?

Quoted 5 lines

The problem is that the poll handler does netif_rx_complete (which does a dev_put) followed by netif_rx_reschedule() to schedule for more receives (which again does a dev_put). This reduces refcount to < 0 (depending on how many times netif_rx_complete followed by netif_rx_reschedule was called).

Dave, the real problem seems to be that netif_rx_recschedule() calls __napi_schedule() rather than __netif_rx_schedule(), so it misses the call to dev_hold() that is needed to balance the dev_put() in netif_rx_complete(). The current netif_rx_reschedule() looks like it really should be napi_reschedule(), and we need a new function that takes a netdev too. Or am I misunderstanding the refcounting?

I'll send a patch once I've had some breakfast and had a chance to at least compile it...

Krishna, unfortunately your proposed fix has a race:

drivers/infiniband/ulp/ipoib/ipoib_ib.c poll_more: · line 320

Quoted 9 lines
drivers/infiniband/ulp/ipoib/ipoib_ib.c +3 -6
-		netif_rx_complete(dev, napi);
-		if (unlikely(ib_req_notify_cq(priv->cq,
-					      IB_CQ_NEXT_COMP |
-					      IB_CQ_REPORT_MISSED_EVENTS)) &&
-		    netif_rx_reschedule(napi))
-			goto poll_more;
+		if (likely(!ib_req_notify_cq(priv->cq,
+					     IB_CQ_NEXT_COMP |
+					     IB_CQ_REPORT_MISSED_EVENTS)))

It is possible for an interrupt to happen immediately right here, before the netif_rx_complete(), so that netif_rx_schedule() gets called while we are still on the poll list.

drivers/infiniband/ulp/ipoib/ipoib_ib.c poll_more: · line 321

Quoted 1 line
drivers/infiniband/ulp/ipoib/ipoib_ib.c +1 -0
+			netif_rx_complete(dev, napi);

- R.

#3 lore raw

Hi Roland,

Roland Dreier <[email protected]> wrote on 09/18/2007 07:57:24 PM:

Quoted 3 lines
Quoted 1 line

While using IPoIB over EHCA (rc6 bits), unregister_netdev hangs with

I don't think you're actually using rc6 bits, since in your patch you

have:

Quoted 4 lines
Quoted 2 lines

-poll_more:

and I think that is only in Dave's net-2.6.24 tree now, right?

Nope, that was what I downloaded yesterday:

VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 23
EXTRAVERSION =-rc6
NAME = Pink Farting Weasel

Quoted 2 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+                    if (likely(!ib_req_notify_cq(priv->cq,
+

IB_CQ_NEXT_COMP |

Quoted 1 line
Quoted 1 line

+

IB_CQ_REPORT_MISSED_EVENTS)))

Quoted 6 lines

It is possible for an interrupt to happen immediately right here, before the netif_rx_complete(), so that netif_rx_schedule() gets called while we are still on the poll list.

Quoted 1 line

+ netif_rx_complete(dev, napi);

To be clear, netif_rx_schedule while we are still in the poll list will not do any harm as it does nothing since NAPI_STATE_SCHED is still set (cleared by netif_rx_complete which has not yet run). Effectively we lost/delayed processing an interrupt, if I understood the code right.

I agree with you on the new patch.

thanks,

- KK

#4 lore raw
Quoted 9 lines
Quoted 1 line

and I think that is only in Dave's net-2.6.24 tree now, right?

Nope, that was what I downloaded yesterday:

VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 23
EXTRAVERSION =-rc6
NAME = Pink Farting Weasel

Please double check your tree. I just very carefully looked at my trees, and the poll_more: label is added in commit 6b460a71 ("[NET]:
Make NAPI polling independent of struct net_device objects.") which is only in the net-2.6.24 tree. Of course Dave did not change the version information in the Makefile since he wouldn't want Linus to pick up any extra strange changes when he pulls, so a net-2.6.24 tree will look like 2.6.23-rc6 as you quoted.

And the refcounting bug I fixed is only in net-2.6.24.

Quoted 4 lines

To be clear, netif_rx_schedule while we are still in the poll list will not do any harm as it does nothing since NAPI_STATE_SCHED is still set (cleared by netif_rx_complete which has not yet run). Effectively we lost/delayed processing an interrupt, if I understood the code right.

Right, we lose an interrupt, and since the CQ events are one-shot, we never get another one, and the interface is effectively dead.

- R.

#5 lore raw

Hi Roland,

Quoted 9 lines

Please double check your tree. I just very carefully looked at my trees, and the poll_more: label is added in commit 6b460a71 ("[NET]:
Make NAPI polling independent of struct net_device objects.") which is only in the net-2.6.24 tree. Of course Dave did not change the version information in the Makefile since he wouldn't want Linus to pick up any extra strange changes when he pulls, so a net-2.6.24 tree will look like 2.6.23-rc6 as you quoted.

And the refcounting bug I fixed is only in net-2.6.24.

You are absolutely right. My wording was incorrect, I should have said net-2.6.24 (which is *at* rev rc6).

Quoted 1 line
Quoted 1 line

To be clear, netif_rx_schedule while we are still in the poll list

will not

Quoted 1 line
Quoted 1 line

do any harm as it does nothing since NAPI_STATE_SCHED is still set

(cleared

Quoted 1 line
Quoted 1 line

by netif_rx_complete which has not yet run). Effectively we

lost/delayed

Quoted 4 lines
Quoted 1 line

processing an interrupt, if I understood the code right.

Right, we lose an interrupt, and since the CQ events are one-shot, we never get another one, and the interface is effectively dead.

Thanks,

- KK

#6 lore raw

PATCH 1/1 Fix refcounting problem with netif_rx_reschedule()

In reply to Krishna Kumar

netif_rx_complete() takes a netdev parameter and does dev_put() on that netdev, so netif_rx_reschedule() needs to also take a netdev parameter and do dev_hold() on it to avoid reference counts from getting becoming negative because of unbalanced dev_put()s.

This should fix the problem reported by Krishna Kumar <[email protected]> with IPoIB waiting forever for netdev refcounts to become 0 during module unload.

---
Dave, feel free to roll this up into earlier NAPI conversion patches (assuming I'm understanding things correctly and this patch actually makes sense!).

BTW, it looks like drivers/net/ibm_emac/ibm_emac_mal.c would not have built in the current net-2.6.24 tree, since its call to netif_rx_reschedule() was left with the netdev parameter. So that file does not need to be touched in this patch.

 drivers/infiniband/ulp/ipoib/ipoib_ib.c |    2 +-
 drivers/net/arm/ep93xx_eth.c            |    2 +-
 drivers/net/ehea/ehea_main.c            |    2 +-
 drivers/net/ibmveth.c                   |    2 +-
 include/linux/netdevice.h               |   21 +++++++++++----------
 5 files changed, 15 insertions(+), 14 deletions(-)
drivers/infiniband/ulp/ipoib/ipoib_ib.c +1 -1
index 6a2bff4..481e4b6 100644
@@ -320,7 +320,7 @@ poll_more:
 		if (unlikely(ib_req_notify_cq(priv->cq,
 					      IB_CQ_NEXT_COMP |
 					      IB_CQ_REPORT_MISSED_EVENTS)) &&
-		    netif_rx_reschedule(napi))
+		    netif_rx_reschedule(dev, napi))
 			goto poll_more;
 	}
 
drivers/net/arm/ep93xx_eth.c +1 -1
index f3858d1..7f016f3 100644
@@ -309,7 +309,7 @@ poll_some_more:
 		}
 		spin_unlock_irq(&ep->rx_lock);
 
-		if (more && netif_rx_reschedule(napi))
+		if (more && netif_rx_reschedule(dev, napi))
 			goto poll_some_more;
 	}
 
drivers/net/ehea/ehea_main.c +1 -1
index 4a5ab4a..9a499f4 100644
@@ -636,7 +636,7 @@ static int ehea_poll(struct napi_struct *napi, int budget)
 		if (!cqe && !cqe_skb)
 			return 0;
 
-		if (!netif_rx_reschedule(napi))
+		if (!netif_rx_reschedule(dev, napi))
 			return 0;
 	}
 
drivers/net/ibmveth.c +1 -1
index b8d7cec..b94f266 100644
@@ -973,7 +973,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
 		netif_rx_complete(netdev, napi);
 
 		if (ibmveth_rxq_pending_buffer(adapter) &&
-		    netif_rx_reschedule(napi)) {
+		    netif_rx_reschedule(netdev, napi)) {
 			lpar_rc = h_vio_signal(adapter->vdev->unit_address,
 					       VIO_IRQ_DISABLE);
 			goto restart_poll;
include/linux/netdevice.h +11 -10
index be5fe05..0dbf185 100644
@@ -1198,16 +1198,6 @@ static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits)
 	return (1 << debug_value) - 1;
 }
 
-/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete().  */
-static inline int netif_rx_reschedule(struct napi_struct *n)
-{
-	if (napi_schedule_prep(n)) {
-		__napi_schedule(n);
-		return 1;
-	}
-	return 0;
-}
-
 /* Test if receive needs to be scheduled but only if up */
 static inline int netif_rx_schedule_prep(struct net_device *dev,
 					 struct napi_struct *napi)
@@ -1234,6 +1224,17 @@ static inline void netif_rx_schedule(struct net_device *dev,
 		__netif_rx_schedule(dev, napi);
 }
 
+/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete().  */
+static inline int netif_rx_reschedule(struct net_device *dev,
+				      struct napi_struct *napi)
+{
+	if (napi_schedule_prep(napi)) {
+		__netif_rx_schedule(dev, napi);
+		return 1;
+	}
+	return 0;
+}
+
 /* same as netif_rx_complete, except that local_irq_save(flags)
  * has already been issued
  */
#7 lore raw

PATCH 1/1 Fix documentation for dev_put()/dev_hold()

It looks like the comments for dev_put() and dev_hold() got reversed somehow.

---
 include/linux/netdevice.h |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
include/linux/netdevice.h +2 -2
index be5fe05..239ae68 100644
@@ -1030,7 +1030,7 @@ extern int		netdev_budget;
 extern void netdev_run_todo(void);
 
 /**
- *	dev_put - get reference to device
+ *	dev_put - release reference to device
  *	@dev: network device
  *
  * Hold reference to device to keep it from being freed.
@@ -1041,7 +1041,7 @@ static inline void dev_put(struct net_device *dev)
 }
 
 /**
- *	dev_hold - release reference to device
+ *	dev_hold - get reference to device
  *	@dev: network device
  *
  * Release reference to device to allow it to be freed.
maintainer Applied
#8 lore raw

Re: [PATCH net-2.6.24] Fix documentation for dev_put()/dev_hold()

From: Roland Dreier <[email protected]>
Date: Tue, 18 Sep 2007 11:04:22 -0700

Quoted 3 lines

It looks like the comments for dev_put() and dev_hold() got reversed somehow.

Applied, thanks Roland.

maintainer Applied
#9 lore raw

[ofa-general] Re: [PATCH net-2.6.24] Fix refcounting problem with netif_rx_reschedule()

In reply to Roland Dreier

From: Roland Dreier <[email protected]>
Date: Tue, 18 Sep 2007 10:58:37 -0700

Quoted 10 lines

netif_rx_complete() takes a netdev parameter and does dev_put() on that netdev, so netif_rx_reschedule() needs to also take a netdev parameter and do dev_hold() on it to avoid reference counts from getting becoming negative because of unbalanced dev_put()s.

This should fix the problem reported by Krishna Kumar <[email protected]> with IPoIB waiting forever for netdev refcounts to become 0 during module unload.

Applied to net-2.6.24, thanks Roland.

Quoted 4 lines

BTW, it looks like drivers/net/ibm_emac/ibm_emac_mal.c would not have built in the current net-2.6.24 tree, since its call to netif_rx_reschedule() was left with the netdev parameter. So that file does not need to be touched in this patch.

Yes, I know, this is the one NAPI driver that hasn't been converted.

It's a complicated conversion because of how the driver and the data structures have been arranged (in short, a mess) which makes it insanely difficult to get from a queue instance back up to a network device or similar.

Further complicating things is that you need to setup a ppc32 cross-build environment to even build test a conversion, and I'm not comfortable doing the surgery until I can test build the thing.

And this may be hard to believe, but other things have been more pressing than setting up a ppc32 cross-build environment :-)

This is a hint of anyone looking for something to do that it'd be much appreciated for someone to tackle the ibm_emac conversion.

Thanks.

#10 lore raw

[ofa-general] Re: [PATCH net-2.6.24] Fix refcounting problem with netif_rx_reschedule()

Quoted 3 lines

Further complicating things is that you need to setup a ppc32 cross-build environment to even build test a conversion, and I'm not comfortable doing the surgery until I can test build the thing.

OK, I actually have a system with a ppc 440 SoC that uses this driver, so I'll try to get things to the stage where I can boot net-2.6.24 on it and see if I can get the driver working...

maintainer
#11 lore raw

[ofa-general] Re: [PATCH net-2.6.24] Fix refcounting problem with netif_rx_reschedule()

From: Roland Dreier <[email protected]>
Date: Tue, 18 Sep 2007 15:46:36 -0700

Quoted 3 lines

OK, I actually have a system with a ppc 440 SoC that uses this driver, so I'll try to get things to the stage where I can boot net-2.6.24 on it and see if I can get the driver working...

Thanks a lot Roland.