From patchwork Mon Oct 5 18:28:01 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Gardner X-Patchwork-Id: 526473 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 1B613140D84; Tue, 6 Oct 2015 05:28:20 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1ZjAUf-0008N8-9u; Mon, 05 Oct 2015 18:28:13 +0000 Received: from mail-pa0-f44.google.com ([209.85.220.44]) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1ZjAUZ-0008Mt-Va for kernel-team@lists.ubuntu.com; Mon, 05 Oct 2015 18:28:08 +0000 Received: by pacfv12 with SMTP id fv12so187579009pac.2 for ; Mon, 05 Oct 2015 11:28:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=fMLUKNjUpicRkM0VzhrkkC18xKjhmSyJx8Sm0b+oNl8=; b=AH+yM1/ydSkOpLJFJIL5FbIO6Who1/lCdpWIJS9zvD04sc31NFh/aOdze3vYDDcHHL ErWtblZ4eDJ2XHELv7kqIsMume22aXkUdTcLrKaLxNz4BfLrDDvs9lB3sH5yeflkGl51 dEbyKN8uqQCQfXLWub54eRm5t3yH0BwUG6r/H9S7DNLOJcCZQBuTCVtMHBgMTbgmMjLu t7CgOIHCrRcdZxYYfEDZcB5ZGuGr2z20j3X4Rxg8Cbh96rkYJr7Q/KQRUtOBTDtLPINl 80VTC0udFNvMLKjPkg32luEjjwv2jx5lXjbetKdGxYA5rBPFML+B7OEiEVab7cT7y27j kQuw== X-Gm-Message-State: ALoCoQlUPNnHcl3KNkFgHGBQXfaFX7CKSUYXsfhDbIyOzBSNHcasTpGd7HH0wNl7gljLAQvJ470z X-Received: by 10.66.65.228 with SMTP id a4mr41933766pat.19.1444069687319; Mon, 05 Oct 2015 11:28:07 -0700 (PDT) Received: from localhost.localdomain (host-174-45-38-91.hln-mt.client.bresnan.net. [174.45.38.91]) by smtp.gmail.com with ESMTPSA id xg2sm28950081pbb.2.2015.10.05.11.28.06 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 05 Oct 2015 11:28:06 -0700 (PDT) From: tim.gardner@canonical.com To: kernel-team@lists.ubuntu.com Subject: [PATCH 2/2 Utopic LTS SRU] hv_netvsc: Add close of RNDIS filter into change mtu call Date: Mon, 5 Oct 2015 12:28:01 -0600 Message-Id: <1444069681-23064-2-git-send-email-tim.gardner@canonical.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1444069681-23064-1-git-send-email-tim.gardner@canonical.com> References: <1444069681-23064-1-git-send-email-tim.gardner@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: kernel-team-bounces@lists.ubuntu.com From: Haiyang Zhang BugLink: http://bugs.launchpad.net/bugs/1494431 The current change mtu call only stops tx before removing RNDIS filter. In case ringbufer is not empty, the rndis_filter_device_remove() may hang on removing the buffers. This patch adds close of RNDIS filter before removing it, also a gradual waiting loop until the ring is empty. The change_mtu hang issue under heavy traffic is solved by this patch. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller (cherry picked from commit 2de8530ba0c71a2fba02590681af0f3a2a187a9b) Signed-off-by: Tim Gardner --- drivers/net/hyperv/netvsc_drv.c | 58 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 74266e9..3e5e6e5 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -101,7 +101,7 @@ static int netvsc_open(struct net_device *net) return ret; } - netif_tx_start_all_queues(net); + netif_tx_wake_all_queues(net); nvdev = hv_get_drvdata(device_obj); rdev = nvdev->extension; @@ -115,15 +115,56 @@ static int netvsc_close(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_device *device_obj = net_device_ctx->device_ctx; + struct netvsc_device *nvdev = hv_get_drvdata(device_obj); int ret; + u32 aread, awrite, i, msec = 10, retry = 0, retry_max = 20; + struct vmbus_channel *chn; netif_tx_disable(net); /* Make sure netvsc_set_multicast_list doesn't re-enable filter! */ cancel_work_sync(&net_device_ctx->work); ret = rndis_filter_close(device_obj); - if (ret != 0) + if (ret != 0) { netdev_err(net, "unable to close device (ret %d).\n", ret); + return ret; + } + + /* Ensure pending bytes in ring are read */ + while (true) { + aread = 0; + for (i = 0; i < nvdev->num_chn; i++) { + chn = nvdev->chn_table[i]; + if (!chn) + continue; + + hv_get_ringbuffer_availbytes(&chn->inbound, &aread, + &awrite); + + if (aread) + break; + + hv_get_ringbuffer_availbytes(&chn->outbound, &aread, + &awrite); + + if (aread) + break; + } + + retry++; + if (retry > retry_max || aread == 0) + break; + + msleep(msec); + + if (msec < 1000) + msec *= 2; + } + + if (aread) { + netdev_err(net, "Ring buffer not empty after closing rndis\n"); + ret = -ETIMEDOUT; + } return ret; } @@ -685,6 +726,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) struct netvsc_device *nvdev = hv_get_drvdata(hdev); struct netvsc_device_info device_info; int limit = ETH_DATA_LEN; + int ret = 0; if (nvdev == NULL || nvdev->destroy) return -ENODEV; @@ -695,9 +737,11 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) if (mtu < NETVSC_MTU_MIN || mtu > limit) return -EINVAL; + ret = netvsc_close(ndev); + if (ret) + goto out; + nvdev->start_remove = true; - cancel_work_sync(&ndevctx->work); - netif_tx_disable(ndev); rndis_filter_device_remove(hdev); ndev->mtu = mtu; @@ -706,9 +750,11 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) hv_set_drvdata(hdev, ndev); device_info.ring_size = ring_size; rndis_filter_device_add(hdev, &device_info); - netif_tx_wake_all_queues(ndev); - return 0; +out: + netvsc_open(ndev); + + return ret; }