From patchwork Tue Oct 6 17:29:33 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Gardner X-Patchwork-Id: 526851 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 8D04B140D8F; Wed, 7 Oct 2015 04:30:19 +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 1ZjW48-0002Sy-1h; Tue, 06 Oct 2015 17:30:16 +0000 Received: from mail-pa0-f54.google.com ([209.85.220.54]) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1ZjW3p-0002NC-P2 for kernel-team@lists.ubuntu.com; Tue, 06 Oct 2015 17:29:57 +0000 Received: by pacex6 with SMTP id ex6so216426676pac.0 for ; Tue, 06 Oct 2015 10:29:57 -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=mJlZndH2k9AL3sOsdawKY0//KfaSIL1TieVsg3Vwjik=; b=QEQ7Rgpe3jd17b3Gou4X7fr748OtahbwW/+1r4mGmMlc1TGn2taW9mMCmcvpJpwt0k un229yd/Xubd7BRYS2C1hDYggCCnqaSu2SKlb457jOHqXd4RvaxGqXJYlJVgazQSf1za 0Pnrjyhz3W6YvPzKplRnnThODmKvuWFwLCPXy2gJgc4QgSWgdbWGFbx/HJ6uG2fqw7ZY B8l+lZyxc4bKoOIfzvnGlMRbsJbC9/vD+zq6YzArWl6WPfGORTFGS+GQt1yF4fwa+g74 84mAw8ntIDSqY51sSGiBajuRCWYnwj37P+JBgFRanjlPbkL79VQp9fGMWd4VCVNmKaKS z+6w== X-Gm-Message-State: ALoCoQlDeYY7htcbH83qT/ss1nEI40JzOs36eeQVWtpOe6DYdAX+O81OIKhyiQKQVazaIoVR6mDt X-Received: by 10.68.94.99 with SMTP id db3mr48383527pbb.165.1444152597126; Tue, 06 Oct 2015 10:29:57 -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 es4sm4171537pbc.42.2015.10.06.10.29.56 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 06 Oct 2015 10:29:56 -0700 (PDT) From: tim.gardner@canonical.com To: kernel-team@lists.ubuntu.com Subject: [PATCH 3/3 Utopic LTS SRU v2] hv_netvsc: Add close of RNDIS filter into change mtu call Date: Tue, 6 Oct 2015 11:29:33 -0600 Message-Id: <1444152573-8655-4-git-send-email-tim.gardner@canonical.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1444152573-8655-1-git-send-email-tim.gardner@canonical.com> References: <20151006170754.GB35275@ubuntu-hedt> <1444152573-8655-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 a7a7fbd..c20a22f 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; }