[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 09/17] Add a fall-back poller, in case finish messages get stuck somewhere.
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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |