Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hv_netvsc: fix send buffer failure on MTU change

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>

authored by

Alex Ng and committed by
David S. Miller
0ab09bef fe2502e4

+12 -5
+2
drivers/net/hyperv/hyperv_net.h
··· 150 150 u32 num_chn; 151 151 u32 send_sections; 152 152 u32 recv_sections; 153 + u32 send_section_size; 154 + u32 recv_section_size; 153 155 }; 154 156 155 157 enum rndis_device_state {
+2 -5
drivers/net/hyperv/netvsc.c
··· 76 76 net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT; 77 77 net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT; 78 78 79 - net_device->recv_section_size = NETVSC_RECV_SECTION_SIZE; 80 - net_device->send_section_size = NETVSC_SEND_SECTION_SIZE; 81 - 82 79 init_completion(&net_device->channel_init_wait); 83 80 init_waitqueue_head(&net_device->subchan_open); 84 81 INIT_WORK(&net_device->subchan_work, rndis_set_subchannel); ··· 259 262 int ret = 0; 260 263 261 264 /* Get receive buffer area. */ 262 - buf_size = device_info->recv_sections * net_device->recv_section_size; 265 + buf_size = device_info->recv_sections * device_info->recv_section_size; 263 266 buf_size = roundup(buf_size, PAGE_SIZE); 264 267 265 268 net_device->recv_buf = vzalloc(buf_size); ··· 341 344 goto cleanup; 342 345 343 346 /* Now setup the send buffer. */ 344 - buf_size = device_info->send_sections * net_device->send_section_size; 347 + buf_size = device_info->send_sections * device_info->send_section_size; 345 348 buf_size = round_up(buf_size, PAGE_SIZE); 346 349 347 350 net_device->send_buf = vzalloc(buf_size);
+8
drivers/net/hyperv/netvsc_drv.c
··· 848 848 device_info.num_chn = count; 849 849 device_info.ring_size = ring_size; 850 850 device_info.send_sections = nvdev->send_section_cnt; 851 + device_info.send_section_size = nvdev->send_section_size; 851 852 device_info.recv_sections = nvdev->recv_section_cnt; 853 + device_info.recv_section_size = nvdev->recv_section_size; 852 854 853 855 rndis_filter_device_remove(dev, nvdev); 854 856 ··· 965 963 device_info.ring_size = ring_size; 966 964 device_info.num_chn = nvdev->num_chn; 967 965 device_info.send_sections = nvdev->send_section_cnt; 966 + device_info.send_section_size = nvdev->send_section_size; 968 967 device_info.recv_sections = nvdev->recv_section_cnt; 968 + device_info.recv_section_size = nvdev->recv_section_size; 969 969 970 970 rndis_filter_device_remove(hdev, nvdev); 971 971 ··· 1489 1485 device_info.num_chn = nvdev->num_chn; 1490 1486 device_info.ring_size = ring_size; 1491 1487 device_info.send_sections = new_tx; 1488 + device_info.send_section_size = nvdev->send_section_size; 1492 1489 device_info.recv_sections = new_rx; 1490 + device_info.recv_section_size = nvdev->recv_section_size; 1493 1491 1494 1492 netif_device_detach(ndev); 1495 1493 was_opened = rndis_filter_opened(nvdev); ··· 1940 1934 device_info.ring_size = ring_size; 1941 1935 device_info.num_chn = VRSS_CHANNEL_DEFAULT; 1942 1936 device_info.send_sections = NETVSC_DEFAULT_TX; 1937 + device_info.send_section_size = NETVSC_SEND_SECTION_SIZE; 1943 1938 device_info.recv_sections = NETVSC_DEFAULT_RX; 1939 + device_info.recv_section_size = NETVSC_RECV_SECTION_SIZE; 1944 1940 1945 1941 nvdev = rndis_filter_device_add(dev, &device_info); 1946 1942 if (IS_ERR(nvdev)) {