From 1d06825b0ede541f63b5577435abd2fc649a9b5e Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 2 Dec 2011 11:56:25 -0800 Subject: net/hyperv: Fix the stop/wake queue mechanism The ring buffer is only used to pass meta data for outbound packets. The actual payload is accessed by DMA from the host. So the stop/wake queue mechanism based on counting and comparing number of pages sent v.s. number of pages in the ring buffer is wrong. Also, there is a race condition in the stop/wake queue calls, which can stop xmit queue forever. The new stop/wake queue mechanism is based on the actual bytes used by outbound packets in the ring buffer. The check for number of outstanding sends after stop queue prevents the race condition that can cause wake queue happening earlier than stop queue. Signed-off-by: Haiyang Zhang Signed-off-by: K. Y. Srinivasan Reported-by: Long Li Signed-off-by: Greg Kroah-Hartman --- drivers/net/hyperv/netvsc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/net/hyperv/netvsc.c') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 4a807e44ec60..b6ac152a9bd0 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -435,6 +435,9 @@ static void netvsc_send_completion(struct hv_device *device, nvsc_packet->completion.send.send_completion_ctx); atomic_dec(&net_device->num_outstanding_sends); + + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); } else { netdev_err(ndev, "Unknown send completion packet type- " "%d received!!\n", nvsp_packet->hdr.msg_type); @@ -485,11 +488,16 @@ int netvsc_send(struct hv_device *device, } - if (ret != 0) + if (ret == 0) { + atomic_inc(&net_device->num_outstanding_sends); + } else if (ret == -EAGAIN) { + netif_stop_queue(ndev); + if (atomic_read(&net_device->num_outstanding_sends) < 1) + netif_wake_queue(ndev); + } else { netdev_err(ndev, "Unable to send packet %p ret %d\n", packet, ret); - else - atomic_inc(&net_device->num_outstanding_sends); + } return ret; } -- cgit v1.2.3