Date: Tue, 20 Nov 2012 15:18:33 +0400 From: Gleb Smirnoff <glebius@FreeBSD.org> To: Karim Fodil-Lemelin <fodillemlinkarim@gmail.com>, jfv@FreeBSD.org Cc: freebsd-net@FreeBSD.org Subject: Re: igb diver crashes in head@241037 Message-ID: <20121120111833.GC67660@FreeBSD.org> In-Reply-To: <50AA8F24.7080604@gmail.com>
index | next in thread | previous in thread | raw e-mail
[-- Attachment #1 --]
Karim,
On Mon, Nov 19, 2012 at 02:57:24PM -0500, Karim Fodil-Lemelin wrote:
K> While testing the latest igb driver in CURRENT I came across an issue
K> with igb_mq_start(). More specifically this code:
K>
K> ...
K>
K> struct mbuf *pm = NULL;
K> /*
K> ** Try to queue first to avoid
K> ** out-of-order delivery, but
K> ** settle for it if that fails
K> */
K> if (m && drbr_enqueue(ifp, txr->br, m))
K> pm = m;
K> err = igb_mq_start_locked(ifp, txr, pm);
K>
K> ...
K>
K>
K> The problem comes from the fact that drbr_enqueue() can return an error
K> and delete the mbuf as seen in drbr_enqueue():
K>
K> ...
K> error = buf_ring_enqueue(br, m);
K> if (error)
K> m_freem(m);
K> ...
Good catch!
K> diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
K> index 1318910..be1719a 100644
K> --- a/sys/dev/e1000/if_igb.c
K> +++ b/sys/dev/e1000/if_igb.c
K> @@ -961,15 +961,7 @@ igb_mq_start(struct ifnet *ifp, struct mbuf *m)
K> que = &adapter->queues[i];
K> if (((txr->queue_status & IGB_QUEUE_DEPLETED) == 0) &&
K> IGB_TX_TRYLOCK(txr)) {
K> - struct mbuf *pm = NULL;
K> - /*
K> - ** Try to queue first to avoid
K> - ** out-of-order delivery, but
K> - ** settle for it if that fails
K> - */
K> - if (m && drbr_enqueue(ifp, txr->br, m))
K> - pm = m;
K> - err = igb_mq_start_locked(ifp, txr, pm);
K> + err = igb_mq_start_locked(ifp, txr, m);
K> IGB_TX_UNLOCK(txr);
K> } else {
K> err = drbr_enqueue(ifp, txr->br, m);
Well, the idea to prevent out-of-order delivery is important. TCP
suffers a lot when this happens.
I'd suggest the following code:
if (m)
drbr_enqueue(ifp, txr->br, m);
err = igb_mq_start_locked(ifp, txr, NULL);
Which eventually leads us to all invocations of igb_mq_start_locked() called
with third argument as NULL. This allows us to simplify this function.
Patch for review attached.
--
Totus tuus, Glebius.
[-- Attachment #2 --]
Index: if_igb.c
===================================================================
--- if_igb.c (revision 243329)
+++ if_igb.c (working copy)
@@ -181,8 +181,7 @@
static int igb_resume(device_t);
#if __FreeBSD_version >= 800000
static int igb_mq_start(struct ifnet *, struct mbuf *);
-static int igb_mq_start_locked(struct ifnet *,
- struct tx_ring *, struct mbuf *);
+static int igb_mq_start_locked(struct ifnet *, struct tx_ring *);
static void igb_qflush(struct ifnet *);
static void igb_deferred_mq_start(void *, int);
#else
@@ -845,7 +844,7 @@
/* Process the stack queue only if not depleted */
if (((txr->queue_status & IGB_QUEUE_DEPLETED) == 0) &&
!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
+ igb_mq_start_locked(ifp, txr);
#else
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
igb_start_locked(txr, ifp);
@@ -961,15 +960,14 @@
que = &adapter->queues[i];
if (((txr->queue_status & IGB_QUEUE_DEPLETED) == 0) &&
IGB_TX_TRYLOCK(txr)) {
- struct mbuf *pm = NULL;
/*
** Try to queue first to avoid
** out-of-order delivery, but
** settle for it if that fails
*/
- if (m && drbr_enqueue(ifp, txr->br, m))
- pm = m;
- err = igb_mq_start_locked(ifp, txr, pm);
+ if (m)
+ drbr_enqueue(ifp, txr->br, m);
+ err = igb_mq_start_locked(ifp, txr);
IGB_TX_UNLOCK(txr);
} else {
err = drbr_enqueue(ifp, txr->br, m);
@@ -980,7 +978,7 @@
}
static int
-igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
+igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr)
{
struct adapter *adapter = txr->adapter;
struct mbuf *next;
@@ -990,24 +988,13 @@
if (((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) ||
(txr->queue_status & IGB_QUEUE_DEPLETED) ||
- adapter->link_active == 0) {
- if (m != NULL)
- err = drbr_enqueue(ifp, txr->br, m);
+ adapter->link_active == 0)
return (err);
- }
enq = 0;
- if (m == NULL) {
- next = drbr_dequeue(ifp, txr->br);
- } else if (drbr_needs_enqueue(ifp, txr->br)) {
- if ((err = drbr_enqueue(ifp, txr->br, m)) != 0)
- return (err);
- next = drbr_dequeue(ifp, txr->br);
- } else
- next = m;
/* Process the queue */
- while (next != NULL) {
+ while ((next = drbr_dequeue(ifp, txr->br)) != NULL) {
if ((err = igb_xmit(txr, &next)) != 0) {
if (next != NULL)
err = drbr_enqueue(ifp, txr->br, next);
@@ -1020,7 +1007,6 @@
ETHER_BPF_MTAP(ifp, next);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
break;
- next = drbr_dequeue(ifp, txr->br);
}
if (enq > 0) {
/* Set the watchdog */
@@ -1046,7 +1032,7 @@
IGB_TX_LOCK(txr);
if (!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
+ igb_mq_start_locked(ifp, txr);
IGB_TX_UNLOCK(txr);
}
@@ -1398,7 +1384,7 @@
/* Process the stack queue only if not depleted */
if (((txr->queue_status & IGB_QUEUE_DEPLETED) == 0) &&
!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
+ igb_mq_start_locked(ifp, txr);
#else
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
igb_start_locked(txr, ifp);
@@ -1449,7 +1435,7 @@
/* Process the stack queue only if not depleted */
if (((txr->queue_status & IGB_QUEUE_DEPLETED) == 0) &&
!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
+ igb_mq_start_locked(ifp, txr);
#else
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
igb_start_locked(txr, ifp);
@@ -1549,7 +1535,7 @@
} while (loop-- && more);
#if __FreeBSD_version >= 800000
if (!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
+ igb_mq_start_locked(ifp, txr);
#else
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
igb_start_locked(txr, ifp);
@@ -1586,7 +1572,7 @@
/* Process the stack queue only if not depleted */
if (((txr->queue_status & IGB_QUEUE_DEPLETED) == 0) &&
!drbr_empty(ifp, txr->br))
- igb_mq_start_locked(ifp, txr, NULL);
+ igb_mq_start_locked(ifp, txr);
#else
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
igb_start_locked(txr, ifp);
home |
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20121120111833.GC67660>
