netvsc: fix calculation of available send sections
authorstephen hemminger <stephen@networkplumber.org>
Tue, 25 Apr 2017 01:33:38 +0000 (18:33 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 25 Apr 2017 15:56:59 +0000 (11:56 -0400)
My change (introduced in 4.11) to use find_first_clear_bit
incorrectly assumed that the size argument was words, not bits.
The effect was only a small limited number of the available send
sections were being actually used. This can cause performance loss
with some workloads.

Since map_words is now used only during initialization, it can
be on stack instead of in per-device data.

Fixes: b58a185801da ("netvsc: simplify get next send section")
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

index f9f3dba..db23cb3 100644 (file)
@@ -751,7 +751,6 @@ struct netvsc_device {
        u32 send_section_cnt;
        u32 send_section_size;
        unsigned long *send_section_map;
-       int map_words;
 
        /* Used for NetVSP initialization protocol */
        struct completion channel_init_wait;
index 8dd0b87..15ef713 100644 (file)
@@ -236,6 +236,7 @@ static int netvsc_init_buf(struct hv_device *device)
        struct netvsc_device *net_device;
        struct nvsp_message *init_packet;
        struct net_device *ndev;
+       size_t map_words;
        int node;
 
        net_device = get_outbound_net_device(device);
@@ -401,11 +402,9 @@ static int netvsc_init_buf(struct hv_device *device)
                   net_device->send_section_size, net_device->send_section_cnt);
 
        /* Setup state for managing the send buffer. */
-       net_device->map_words = DIV_ROUND_UP(net_device->send_section_cnt,
-                                            BITS_PER_LONG);
+       map_words = DIV_ROUND_UP(net_device->send_section_cnt, BITS_PER_LONG);
 
-       net_device->send_section_map = kcalloc(net_device->map_words,
-                                              sizeof(ulong), GFP_KERNEL);
+       net_device->send_section_map = kcalloc(map_words, sizeof(ulong), GFP_KERNEL);
        if (net_device->send_section_map == NULL) {
                ret = -ENOMEM;
                goto cleanup;
@@ -683,7 +682,7 @@ static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
        unsigned long *map_addr = net_device->send_section_map;
        unsigned int i;
 
-       for_each_clear_bit(i, map_addr, net_device->map_words) {
+       for_each_clear_bit(i, map_addr, net_device->send_section_cnt) {
                if (sync_test_and_set_bit(i, map_addr) == 0)
                        return i;
        }