We try to avoid the event channel notification when sending finish
messages, for performance reasons, but that can lead to a deadlock if
you have a lot of packets going in one direction and nothing coming
the other way. Fix it by just polling for messages every second when
there are unfinished packets outstanding.
Signed-off-by: Steven Smith <steven.smith@xxxxxxxxxx>
---
drivers/net/xen-netchannel2/Makefile | 2 +-
drivers/net/xen-netchannel2/chan.c | 4 ++
drivers/net/xen-netchannel2/netchannel2_core.h | 10 ++++
drivers/net/xen-netchannel2/poll.c | 59 ++++++++++++++++++++++++
drivers/net/xen-netchannel2/xmit_packet.c | 3 +
5 files changed, 77 insertions(+), 1 deletions(-)
create mode 100644 drivers/net/xen-netchannel2/poll.c
diff --git a/drivers/net/xen-netchannel2/Makefile
b/drivers/net/xen-netchannel2/Makefile
index bdad6da..d6641a1 100644
--- a/drivers/net/xen-netchannel2/Makefile
+++ b/drivers/net/xen-netchannel2/Makefile
@@ -1,7 +1,7 @@
obj-$(CONFIG_XEN_NETCHANNEL2) += netchannel2.o
netchannel2-objs := chan.o netchan2.o rscb.o util.o \
- xmit_packet.o recv_packet.o
+ xmit_packet.o recv_packet.o poll.o
ifeq ($(CONFIG_XEN_NETDEV2_BACKEND),y)
netchannel2-objs += netback2.o
diff --git a/drivers/net/xen-netchannel2/chan.c
b/drivers/net/xen-netchannel2/chan.c
index 328b2f1..bd64e53 100644
--- a/drivers/net/xen-netchannel2/chan.c
+++ b/drivers/net/xen-netchannel2/chan.c
@@ -24,6 +24,7 @@ static irqreturn_t nc2_int(int irq, void *dev_id)
if (ncr->irq == -1)
return IRQ_HANDLED;
+ ncr->last_event = jiffies;
if (ncr->cons_ring.sring->prod != ncr->cons_ring.cons_pvt ||
ncr->interface->is_stopped)
nc2_kick(ncr);
@@ -294,6 +295,8 @@ int init_ring_pair(struct netchannel2_ring_pair *ncrp,
&ncrp->gref_pool) < 0)
return -1;
+ nc2_init_poller(ncrp);
+
netif_napi_add(ncrp->interface->net_device, &ncrp->napi,
process_ring, 64);
napi_enable(&ncrp->napi);
@@ -514,6 +517,7 @@ static void nc2_detach_ring(struct netchannel2_ring_pair
*ncrp)
{
if (!ncrp->is_attached)
return;
+ nc2_stop_polling(ncrp);
napi_disable(&ncrp->napi);
_detach_rings(ncrp);
}
diff --git a/drivers/net/xen-netchannel2/netchannel2_core.h
b/drivers/net/xen-netchannel2/netchannel2_core.h
index 4b324fc..429dd0c 100644
--- a/drivers/net/xen-netchannel2/netchannel2_core.h
+++ b/drivers/net/xen-netchannel2/netchannel2_core.h
@@ -131,6 +131,11 @@ struct netchannel2_ring_pair {
struct napi_struct napi;
+ /* jiffies the last time the interrupt fired. Not
+ synchronised at all, because it doesn't usually matter if
+ it's a bit off. */
+ unsigned last_event;
+
/* Protected by the lock. Initialised at attach_ring() time
and de-initialised at detach_ring() time. */
struct netchannel2_prod_ring prod_ring;
@@ -140,6 +145,7 @@ struct netchannel2_ring_pair {
unsigned max_count_frags_no_event;
unsigned expected_finish_messages;
+ struct timer_list polling_timer;
domid_t otherend_id;
@@ -349,4 +355,8 @@ void receive_pending_skbs(struct sk_buff_head *rx_queue);
void nc2_queue_purge(struct netchannel2_ring_pair *ncrp,
struct sk_buff_head *queue);
+void nc2_init_poller(struct netchannel2_ring_pair *ncrp);
+void nc2_start_polling(struct netchannel2_ring_pair *ncrp);
+void nc2_stop_polling(struct netchannel2_ring_pair *ncrp);
+
#endif /* !NETCHANNEL2_CORE_H__ */
diff --git a/drivers/net/xen-netchannel2/poll.c
b/drivers/net/xen-netchannel2/poll.c
new file mode 100644
index 0000000..42ca0d5
--- /dev/null
+++ b/drivers/net/xen-netchannel2/poll.c
@@ -0,0 +1,59 @@
+/* There are a couple of places where we try to minimise wakeups in
+ ways which work in the vast majority of cases, but occasionally
+ cause a needed event to be lost. Compensate for those with a 1Hz
+ ticker. The ticker runs whenever we have outstanding TX packets.
+ Once it's running, we never try to modify it, and instead just let
+ it run out. */
+/* If we're relying on this timer for correctness then performance is
+ going to be absolutely dire, but it should be sufficient to avoid
+ outright deadlocks. */
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include "netchannel2_core.h"
+
+#define TICKER_INTERVAL (HZ)
+
+static void poll_timer(unsigned long arg)
+{
+ struct netchannel2_ring_pair *ncrp =
+ (struct netchannel2_ring_pair *)arg;
+
+ /* If the ring appears to be behaving ``normally'', increase
+ the number of messages which we're allowed to have
+ outstanding by some small amount. If it looks like we've
+ deadlocked, halve it. */
+ /* Arbitrarily define ``normal'' to be at least one interrupt
+ every 100ms, and a small amount to be 10. */
+ /* We don't synchronise against concurrent readers of
+ max_count_frags_no_event, because it doesn't matter too
+ much if it's slightly wrong. We don't need to worry about
+ concurrent writers, because this timer is the only thing
+ which can change it, and it's only ever run on one cpu at a
+ time. */
+ if (jiffies - ncrp->last_event > HZ/10)
+ ncrp->max_count_frags_no_event /= 2;
+ else if (ncrp->max_count_frags_no_event + 10 <=
+ MAX_MAX_COUNT_FRAGS_NO_EVENT)
+ ncrp->max_count_frags_no_event += 10;
+
+ if (ncrp->expected_finish_messages == 0)
+ return;
+ if (ncrp->cons_ring.sring->prod != ncrp->cons_ring.cons_pvt)
+ nc2_kick(ncrp);
+ nc2_start_polling(ncrp);
+}
+
+void nc2_init_poller(struct netchannel2_ring_pair *ncrp)
+{
+ setup_timer(&ncrp->polling_timer, poll_timer, (unsigned long)ncrp);
+}
+
+void nc2_start_polling(struct netchannel2_ring_pair *ncrp)
+{
+ mod_timer(&ncrp->polling_timer, jiffies + TICKER_INTERVAL);
+}
+
+void nc2_stop_polling(struct netchannel2_ring_pair *ncrp)
+{
+ del_timer_sync(&ncrp->polling_timer);
+}
diff --git a/drivers/net/xen-netchannel2/xmit_packet.c
b/drivers/net/xen-netchannel2/xmit_packet.c
index 92fbabf..a693a75 100644
--- a/drivers/net/xen-netchannel2/xmit_packet.c
+++ b/drivers/net/xen-netchannel2/xmit_packet.c
@@ -165,6 +165,9 @@ int nc2_really_start_xmit(struct netchannel2_ring_pair
*ncrp,
if (skb_co->tp) {
ncrp->expected_finish_messages++;
+ if (ncrp->expected_finish_messages == 1 &&
+ !timer_pending(&ncrp->polling_timer))
+ nc2_start_polling(ncrp);
/* We're now ready to accept a FINISH message for this
packet. */
skb_co->expecting_finish = 1;
--
1.6.3.1
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|