Commit b56fc3c5 authored by KY Srinivasan's avatar KY Srinivasan Committed by David S. Miller

hv_netvsc: Fix a bug in netvsc_start_xmit()

Commit b08cc791 eliminated memory
allocation in the packet send path:

    "hv_netvsc: Eliminate memory allocation in the packet send path

    The network protocol used to communicate with the host is the remote ndis (rndis)
    protocol. We need to decorate each outgoing packet with a rndis header and
    additional rndis state (rndis per-packet state). To manage this state, we
    currently allocate memory in the transmit path. Eliminate this allocation by
    requesting additional head room in the skb."

This commit introduced a bug since it did not account for the case if the skb
was cloned. Fix this bug.
Signed-off-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Tested-by: default avatarDexuan Cui <decui@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 48734994
...@@ -128,7 +128,6 @@ struct ndis_tcp_ip_checksum_info; ...@@ -128,7 +128,6 @@ struct ndis_tcp_ip_checksum_info;
struct hv_netvsc_packet { struct hv_netvsc_packet {
/* Bookkeeping stuff */ /* Bookkeeping stuff */
u32 status; u32 status;
bool part_of_skb;
bool is_data_pkt; bool is_data_pkt;
bool xmit_more; /* from skb */ bool xmit_more; /* from skb */
......
...@@ -889,11 +889,6 @@ int netvsc_send(struct hv_device *device, ...@@ -889,11 +889,6 @@ int netvsc_send(struct hv_device *device,
} else { } else {
packet->page_buf_cnt = 0; packet->page_buf_cnt = 0;
packet->total_data_buflen += msd_len; packet->total_data_buflen += msd_len;
if (!packet->part_of_skb) {
skb = (struct sk_buff *)(unsigned long)packet->
send_completion_tid;
packet->send_completion_tid = 0;
}
} }
if (msdp->pkt) if (msdp->pkt)
......
...@@ -238,9 +238,6 @@ void netvsc_xmit_completion(void *context) ...@@ -238,9 +238,6 @@ void netvsc_xmit_completion(void *context)
struct sk_buff *skb = (struct sk_buff *) struct sk_buff *skb = (struct sk_buff *)
(unsigned long)packet->send_completion_tid; (unsigned long)packet->send_completion_tid;
if (!packet->part_of_skb)
kfree(packet);
if (skb) if (skb)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
...@@ -392,7 +389,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -392,7 +389,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
u32 net_trans_info; u32 net_trans_info;
u32 hash; u32 hash;
u32 skb_length; u32 skb_length;
u32 head_room;
u32 pkt_sz; u32 pkt_sz;
struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT]; struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
...@@ -405,7 +401,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -405,7 +401,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
check_size: check_size:
skb_length = skb->len; skb_length = skb->len;
head_room = skb_headroom(skb);
num_data_pgs = netvsc_get_slots(skb) + 2; num_data_pgs = netvsc_get_slots(skb) + 2;
if (num_data_pgs > MAX_PAGE_BUFFER_COUNT && linear) { if (num_data_pgs > MAX_PAGE_BUFFER_COUNT && linear) {
net_alert_ratelimited("packet too big: %u pages (%u bytes)\n", net_alert_ratelimited("packet too big: %u pages (%u bytes)\n",
...@@ -424,20 +419,14 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -424,20 +419,14 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
pkt_sz = sizeof(struct hv_netvsc_packet) + RNDIS_AND_PPI_SIZE; pkt_sz = sizeof(struct hv_netvsc_packet) + RNDIS_AND_PPI_SIZE;
if (head_room < pkt_sz) { ret = skb_cow_head(skb, pkt_sz);
packet = kmalloc(pkt_sz, GFP_ATOMIC); if (ret) {
if (!packet) { netdev_err(net, "unable to alloc hv_netvsc_packet\n");
/* out of memory, drop packet */ ret = -ENOMEM;
netdev_err(net, "unable to alloc hv_netvsc_packet\n"); goto drop;
ret = -ENOMEM;
goto drop;
}
packet->part_of_skb = false;
} else {
/* Use the headroom for building up the packet */
packet = (struct hv_netvsc_packet *)skb->head;
packet->part_of_skb = true;
} }
/* Use the headroom for building up the packet */
packet = (struct hv_netvsc_packet *)skb->head;
packet->status = 0; packet->status = 0;
packet->xmit_more = skb->xmit_more; packet->xmit_more = skb->xmit_more;
...@@ -594,8 +583,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -594,8 +583,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
net->stats.tx_bytes += skb_length; net->stats.tx_bytes += skb_length;
net->stats.tx_packets++; net->stats.tx_packets++;
} else { } else {
if (packet && !packet->part_of_skb)
kfree(packet);
if (ret != -EAGAIN) { if (ret != -EAGAIN) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
net->stats.tx_dropped++; net->stats.tx_dropped++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment