diff options
author | Jason Wang <jasowang@redhat.com> | 2013-11-13 01:00:40 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-11-14 16:05:27 -0500 |
commit | 16a3fa28630331e28208872fa5341ce210b901c7 (patch) | |
tree | 2c87d8d0b55f26c9fcc723f2f7760a455a09d4da | |
parent | 96f8d9ecf227638c89f98ccdcdd50b569891976c (diff) |
macvtap: limit head length of skb allocated
We currently use hdr_len as a hint of head length which is advertised by
guest. But when guest advertise a very big value, it can lead to an 64K+
allocating of kmalloc() which has a very high possibility of failure when host
memory is fragmented or under heavy stress. The huge hdr_len also reduce the
effect of zerocopy or even disable if a gso skb is linearized in guest.
To solves those issues, this patch introduces an upper limit (PAGE_SIZE) of the
head, which guarantees an order 0 allocation each time.
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/macvtap.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 9dccb1edfd2a..dc76670c2f2a 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c | |||
@@ -628,6 +628,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, | |||
628 | const struct iovec *iv, unsigned long total_len, | 628 | const struct iovec *iv, unsigned long total_len, |
629 | size_t count, int noblock) | 629 | size_t count, int noblock) |
630 | { | 630 | { |
631 | int good_linear = SKB_MAX_HEAD(NET_IP_ALIGN); | ||
631 | struct sk_buff *skb; | 632 | struct sk_buff *skb; |
632 | struct macvlan_dev *vlan; | 633 | struct macvlan_dev *vlan; |
633 | unsigned long len = total_len; | 634 | unsigned long len = total_len; |
@@ -670,6 +671,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, | |||
670 | 671 | ||
671 | if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) { | 672 | if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) { |
672 | copylen = vnet_hdr.hdr_len ? vnet_hdr.hdr_len : GOODCOPY_LEN; | 673 | copylen = vnet_hdr.hdr_len ? vnet_hdr.hdr_len : GOODCOPY_LEN; |
674 | if (copylen > good_linear) | ||
675 | copylen = good_linear; | ||
673 | linear = copylen; | 676 | linear = copylen; |
674 | if (iov_pages(iv, vnet_hdr_len + copylen, count) | 677 | if (iov_pages(iv, vnet_hdr_len + copylen, count) |
675 | <= MAX_SKB_FRAGS) | 678 | <= MAX_SKB_FRAGS) |
@@ -678,7 +681,10 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, | |||
678 | 681 | ||
679 | if (!zerocopy) { | 682 | if (!zerocopy) { |
680 | copylen = len; | 683 | copylen = len; |
681 | linear = vnet_hdr.hdr_len; | 684 | if (vnet_hdr.hdr_len > good_linear) |
685 | linear = good_linear; | ||
686 | else | ||
687 | linear = vnet_hdr.hdr_len; | ||
682 | } | 688 | } |
683 | 689 | ||
684 | skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen, | 690 | skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen, |