From 7204d9d13415769d4b43191cd076f6d026646c1b Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Tue, 7 Jun 2016 14:28:35 -0700 Subject: [PATCH] lkl: Fix netperf TCP_STREAM server hangs The netserver hangs after haijacking in TCP_STREAM test. To reproduce: $ LKL_HIJACK_NET_TAP=lkl_ptt1 LKL_HIJACK_NET_IP=192.168.20.2 LKL_HIJACK_NET_NETMASK_LEN=24 LKL_HIJACK_DEBUG=1 ./bin/lkl-hijack.sh netserver -D -f $ echo "set -e && for i in \`seq 1000\`;do echo Test:\$i; netperf -L 192.168.20.1 -H 192.168.20.2 ; done" > /tmp/test.sh $ sh /tmp/test.sh The netperf may fail with error "recv_response_timed_n: no response received. errno 113 counter 0" after hundreds of runs. This fix make virtio trigger an irq whenever the avail queue is empty. Signed-off-by: Yuan Liu --- tools/lkl/lib/virtio.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/lkl/lib/virtio.c b/tools/lkl/lib/virtio.c index 695cacc9e54bf4..a5c041f85d8be2 100644 --- a/tools/lkl/lib/virtio.c +++ b/tools/lkl/lib/virtio.c @@ -71,6 +71,7 @@ void virtio_req_complete(struct virtio_req *req, uint32_t len) struct virtio_dev *dev = req->dev; uint16_t idx = le16toh(q->used->idx) & (q->num - 1); uint16_t new = le16toh(q->used->idx) + 1; + int send_irq = 0; q->used->ring[idx].id = htole16(req->idx); q->used->ring[idx].len = htole16(len); @@ -83,6 +84,13 @@ void virtio_req_complete(struct virtio_req *req, uint32_t len) __sync_synchronize(); q->used->idx = htole16(new); + /* Triggers the irq whenever there is no available buffer. + * q->last_avail_idx is incremented after calling virtio_req_complete(), + * so here we need to add one to it. + */ + if (q->last_avail_idx + 1 == q->avail->idx) + send_irq = 1; + /* There are two rings: q->avail and q->used for each of the rx and tx * queues that are used to pass buffers between kernel driver and the * virtio device implementation. @@ -105,16 +113,16 @@ void virtio_req_complete(struct virtio_req *req, uint32_t len) * increased to a larger one. So we need to trigger the irq when * virtio_get_used_event(q) < q->used->idx. * - * To avoid unnessary irqs for each packet after + * To avoid unnessary irqs for each packet after * virtio_get_used_event(q) < q->used->idx, last_used_idx_signaled is - * stored and irq is only triggered if + * stored and irq is only triggered if * last_used_idx_signaled <= virtio_get_used_event(q) < q->used->idx * * This is what lkl_vring_need_event() checks and it evens covers the - * case when those numbers round up. + * case when those numbers wrap up. */ - if (lkl_vring_need_event(le16toh(virtio_get_used_event(q)), new, - q->last_used_idx_signaled)) { + if (send_irq || lkl_vring_need_event(le16toh(virtio_get_used_event(q)), + new, q->last_used_idx_signaled)) { q->last_used_idx_signaled = new; virtio_deliver_irq(dev); }