hv_netvsc: fix send buffer failure on MTU change
authorAlex Ng <alexng@microsoft.com>
Wed, 20 Sep 2017 18:17:35 +0000 (11:17 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 21 Sep 2017 22:17:16 +0000 (15:17 -0700)
If MTU is changed the host would reject the send buffer change.
This problem is result of recent change to allow changing send
buffer size.

Every time we change the MTU, we store the previous net_device section
count before destroying the buffer, but we don’t store the previous
section size. When we reinitialize the buffer, its size is calculated
by multiplying the previous count and previous size. Since we
continuously increase the MTU, the host returns us a decreasing count
value while the section size is reinitialized to 1728 bytes every
time.

This eventually leads to a condition where the calculated buf_size is
so small that the host rejects it.

Fixes: 8b5327975ae1 ("netvsc: allow controlling send/recv buffer size")
Signed-off-by: Alex Ng <alexng@microsoft.com>
Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c

index d98cdfb1536b5600c0b2e962a2e5e003496ad129..5176be76ca7d57771d82829f8bd08b64dbdc7773 100644 (file)
@@ -150,6 +150,8 @@ struct netvsc_device_info {
        u32  num_chn;
        u32  send_sections;
        u32  recv_sections;
+       u32  send_section_size;
+       u32  recv_section_size;
 };
 
 enum rndis_device_state {
index a5511b7326af646618658060c8d289b60fb4883b..8d5077fb04929cb362e7266b45b04c1369ed1284 100644 (file)
@@ -76,9 +76,6 @@ static struct netvsc_device *alloc_net_device(void)
        net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
        net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
 
-       net_device->recv_section_size = NETVSC_RECV_SECTION_SIZE;
-       net_device->send_section_size = NETVSC_SEND_SECTION_SIZE;
-
        init_completion(&net_device->channel_init_wait);
        init_waitqueue_head(&net_device->subchan_open);
        INIT_WORK(&net_device->subchan_work, rndis_set_subchannel);
@@ -262,7 +259,7 @@ static int netvsc_init_buf(struct hv_device *device,
        int ret = 0;
 
        /* Get receive buffer area. */
-       buf_size = device_info->recv_sections * net_device->recv_section_size;
+       buf_size = device_info->recv_sections * device_info->recv_section_size;
        buf_size = roundup(buf_size, PAGE_SIZE);
 
        net_device->recv_buf = vzalloc(buf_size);
@@ -344,7 +341,7 @@ static int netvsc_init_buf(struct hv_device *device,
                goto cleanup;
 
        /* Now setup the send buffer. */
-       buf_size = device_info->send_sections * net_device->send_section_size;
+       buf_size = device_info->send_sections * device_info->send_section_size;
        buf_size = round_up(buf_size, PAGE_SIZE);
 
        net_device->send_buf = vzalloc(buf_size);
index d4902ee5f260f2df2fa03d680c3c7ea0d79e5dc8..a32ae02e1b6cb6fc2975b0e124aacb42370c0c5d 100644 (file)
@@ -848,7 +848,9 @@ static int netvsc_set_channels(struct net_device *net,
        device_info.num_chn = count;
        device_info.ring_size = ring_size;
        device_info.send_sections = nvdev->send_section_cnt;
+       device_info.send_section_size = nvdev->send_section_size;
        device_info.recv_sections = nvdev->recv_section_cnt;
+       device_info.recv_section_size = nvdev->recv_section_size;
 
        rndis_filter_device_remove(dev, nvdev);
 
@@ -963,7 +965,9 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        device_info.ring_size = ring_size;
        device_info.num_chn = nvdev->num_chn;
        device_info.send_sections = nvdev->send_section_cnt;
+       device_info.send_section_size = nvdev->send_section_size;
        device_info.recv_sections = nvdev->recv_section_cnt;
+       device_info.recv_section_size = nvdev->recv_section_size;
 
        rndis_filter_device_remove(hdev, nvdev);
 
@@ -1485,7 +1489,9 @@ static int netvsc_set_ringparam(struct net_device *ndev,
        device_info.num_chn = nvdev->num_chn;
        device_info.ring_size = ring_size;
        device_info.send_sections = new_tx;
+       device_info.send_section_size = nvdev->send_section_size;
        device_info.recv_sections = new_rx;
+       device_info.recv_section_size = nvdev->recv_section_size;
 
        netif_device_detach(ndev);
        was_opened = rndis_filter_opened(nvdev);
@@ -1934,7 +1940,9 @@ static int netvsc_probe(struct hv_device *dev,
        device_info.ring_size = ring_size;
        device_info.num_chn = VRSS_CHANNEL_DEFAULT;
        device_info.send_sections = NETVSC_DEFAULT_TX;
+       device_info.send_section_size = NETVSC_SEND_SECTION_SIZE;
        device_info.recv_sections = NETVSC_DEFAULT_RX;
+       device_info.recv_section_size = NETVSC_RECV_SECTION_SIZE;
 
        nvdev = rndis_filter_device_add(dev, &device_info);
        if (IS_ERR(nvdev)) {