Date: Fri, 5 Feb 2010 03:51:12 +0100 From: Max Laier <max@love2party.net> To: freebsd-stable@freebsd.org Cc: pyunyh@gmail.com, Nick Rogers <ncrogers@gmail.com>, jfv@freebsd.org, Jack Vogel <jfvogel@gmail.com> Subject: Re: em(4) + ALTQ broken Message-ID: <201002050351.12270.max@love2party.net> In-Reply-To: <2a41acea1002021447t1067ee42gc59b25216270459b@mail.gmail.com> References: <147432021001310037n1b67f01bx4b4e8781321cea8@mail.gmail.com> <2a41acea1002021443t1c298528i2df3cf40269c733@mail.gmail.com> <2a41acea1002021447t1067ee42gc59b25216270459b@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Okay ... attached is a patch to fix this for em(4) (and lay the groundwork to
fix it for other drbr_* consumer as well). I have tested it in VirtualBox,
but don't have real hardware to check for non-ALTQ performance or other
regressions.
Test, comments and review appreciated.
--
Max
[-- Attachment #2 --]
Index: sys/dev/e1000/if_em.c
===================================================================
--- sys/dev/e1000/if_em.c (revision 203362)
+++ sys/dev/e1000/if_em.c (working copy)
@@ -943,7 +943,7 @@
{
struct adapter *adapter = ifp->if_softc;
struct mbuf *next;
- int error = E1000_SUCCESS;
+ int ret, error = E1000_SUCCESS;
EM_TX_LOCK_ASSERT(adapter);
/* To allow being called from a tasklet */
@@ -955,28 +955,34 @@
|| (!adapter->link_active)) {
error = drbr_enqueue(ifp, adapter->br, m);
return (error);
- } else if (drbr_empty(ifp, adapter->br) &&
- (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) {
- if ((error = em_xmit(adapter, &m)) != 0) {
- if (m)
- error = drbr_enqueue(ifp, adapter->br, m);
+ }
+ ret = drbr_maybe_enqueue(ifp, adapter->br, m);
+ if (ret == 0) {
+ if (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD) {
+ if ((error = em_xmit(adapter, &m)) != 0) {
+ if (m)
+ error = drbr_enqueue(ifp, adapter->br,
+ m);
+ return (error);
+ } else {
+ /*
+ * We've bypassed the buf ring so we need to
+ * update ifp directly
+ */
+ drbr_stats_update(ifp, m->m_pkthdr.len,
+ m->m_flags);
+ /*
+ ** Send a copy of the frame to the BPF
+ ** listener and set the watchdog on.
+ */
+ ETHER_BPF_MTAP(ifp, m);
+ adapter->watchdog_check = TRUE;
+ }
+ } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
return (error);
- } else {
- /*
- * We've bypassed the buf ring so we need to update
- * ifp directly
- */
- drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags);
- /*
- ** Send a copy of the frame to the BPF
- ** listener and set the watchdog on.
- */
- ETHER_BPF_MTAP(ifp, m);
- adapter->watchdog_check = TRUE;
- }
- } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
- return (error);
-
+ } else if (ret < 0)
+ return (-ret);
+
process:
if (drbr_empty(ifp, adapter->br))
return(error);
@@ -989,7 +995,7 @@
break;
if ((error = em_xmit(adapter, &next)) != 0) {
if (next != NULL)
- error = drbr_enqueue(ifp, adapter->br, next);
+ error = drbr_requeue(ifp, adapter->br, next);
break;
}
drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
Index: sys/net/if_var.h
===================================================================
--- sys/net/if_var.h (revision 203362)
+++ sys/net/if_var.h (working copy)
@@ -597,18 +597,26 @@
return (error);
}
+static __inline int
+drbr_requeue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+#ifdef ALTQ
+ if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ return (0);
+ }
+#endif
+ return drbr_enqueue(ifp, br, m);
+}
+
static __inline void
drbr_flush(struct ifnet *ifp, struct buf_ring *br)
{
struct mbuf *m;
#ifdef ALTQ
- if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
- while (!IFQ_IS_EMPTY(&ifp->if_snd)) {
- IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
- m_freem(m);
- }
- }
+ if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd))
+ IFQ_DRV_PURGE(&ifp->if_snd);
#endif
while ((m = buf_ring_dequeue_sc(br)) != NULL)
m_freem(m);
@@ -642,11 +650,12 @@
{
struct mbuf *m;
#ifdef ALTQ
- /*
- * XXX need to evaluate / requeue
- */
if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m != NULL && func(m, arg) == 0) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ return (NULL);
+ }
return (m);
}
#endif
@@ -668,6 +677,24 @@
}
static __inline int
+drbr_maybe_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+ int error;
+
+#ifdef ALTQ
+ if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+ IFQ_ENQUEUE(&ifp->if_snd, m, error);
+ return error ? -error : 1;
+ }
+#endif
+ if (drbr_empty(ifp, br))
+ return 0;
+
+ error = drbr_enqueue(ifp, br, m);
+ return error ? -error : 1;
+}
+
+static __inline int
drbr_inuse(struct ifnet *ifp, struct buf_ring *br)
{
#ifdef ALTQ
[-- Attachment #3 --]
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 7a2dbad..94ad229 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -1020,7 +1020,7 @@ em_mq_start_locked(struct ifnet *ifp, struct mbuf *m)
{
struct adapter *adapter = ifp->if_softc;
struct mbuf *next;
- int error = E1000_SUCCESS;
+ int ret, error = E1000_SUCCESS;
EM_TX_LOCK_ASSERT(adapter);
/* To allow being called from a tasklet */
@@ -1032,28 +1032,34 @@ em_mq_start_locked(struct ifnet *ifp, struct mbuf *m)
|| (!adapter->link_active)) {
error = drbr_enqueue(ifp, adapter->br, m);
return (error);
- } else if (drbr_empty(ifp, adapter->br) &&
- (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) {
- if ((error = em_xmit(adapter, &m)) != 0) {
- if (m != NULL)
- error = drbr_enqueue(ifp, adapter->br, m);
- return (error);
- } else {
- /*
- * We've bypassed the buf ring so we need to update
- * ifp directly
- */
- drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags);
- /*
- ** Send a copy of the frame to the BPF
- ** listener and set the watchdog on.
- */
- ETHER_BPF_MTAP(ifp, m);
- adapter->watchdog_timer = EM_TX_TIMEOUT;
- }
- } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
- return (error);
-
+ }
+ ret = drbr_maybe_enqueue(ifp, adapter->br, m);
+ if (ret == 0) {
+ if (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD) {
+ if ((error = em_xmit(adapter, &m)) != 0) {
+ if (m)
+ error = drbr_enqueue(ifp, adapter->br,
+ m);
+ return (error);
+ } else {
+ /*
+ * We've bypassed the buf ring so we need to
+ * update ifp directly
+ */
+ drbr_stats_update(ifp, m->m_pkthdr.len,
+ m->m_flags);
+ /*
+ ** Send a copy of the frame to the BPF
+ ** listener and set the watchdog on.
+ */
+ ETHER_BPF_MTAP(ifp, m);
+ adapter->watchdog_timer = EM_TX_TIMEOUT;
+ }
+ } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
+ return (error);
+ } else if (ret < 0)
+ return (-ret);
+
process:
if (drbr_empty(ifp, adapter->br))
return(error);
@@ -1066,7 +1072,7 @@ process:
break;
if ((error = em_xmit(adapter, &next)) != 0) {
if (next != NULL)
- error = drbr_enqueue(ifp, adapter->br, next);
+ error = drbr_requeue(ifp, adapter->br, next);
break;
}
drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index eac7dbf..1d59402 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -595,18 +595,26 @@ drbr_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
return (error);
}
+static __inline int
+drbr_requeue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+#ifdef ALTQ
+ if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ return (0);
+ }
+#endif
+ return drbr_enqueue(ifp, br, m);
+}
+
static __inline void
drbr_flush(struct ifnet *ifp, struct buf_ring *br)
{
struct mbuf *m;
#ifdef ALTQ
- if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
- while (!IFQ_IS_EMPTY(&ifp->if_snd)) {
- IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
- m_freem(m);
- }
- }
+ if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd))
+ IFQ_DRV_PURGE(&ifp->if_snd);
#endif
while ((m = buf_ring_dequeue_sc(br)) != NULL)
m_freem(m);
@@ -640,11 +648,12 @@ drbr_dequeue_cond(struct ifnet *ifp, struct buf_ring *br,
{
struct mbuf *m;
#ifdef ALTQ
- /*
- * XXX need to evaluate / requeue
- */
if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m != NULL && func(m, arg) == 0) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ return (NULL);
+ }
return (m);
}
#endif
@@ -666,6 +675,24 @@ drbr_empty(struct ifnet *ifp, struct buf_ring *br)
}
static __inline int
+drbr_maybe_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+ int error;
+
+#ifdef ALTQ
+ if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+ IFQ_ENQUEUE(&ifp->if_snd, m, error);
+ return error ? -error : 1;
+ }
+#endif
+ if (drbr_empty(ifp, br))
+ return 0;
+
+ error = drbr_enqueue(ifp, br, m);
+ return error ? -error : 1;
+}
+
+static __inline int
drbr_inuse(struct ifnet *ifp, struct buf_ring *br)
{
#ifdef ALTQ
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002050351.12270.max>
