diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-06-03 05:46:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-07 19:26:34 -0400 |
commit | c05cdb1b864f548c0c3d8ae3b51264e6739a69b1 (patch) | |
tree | 47eea1f60be0c0f7cfe57a0a594e6a606c37eea9 /net/netlink | |
parent | 1b5acd292336da029535de010af568533df9b665 (diff) |
netlink: allow large data transfers from user-space
I can hit ENOBUFS in the sendmsg() path with a large batch that is
composed of many netlink messages. Here that limit is 8 MBytes of
skbuff data area as kmalloc does not manage to get more than that.
While discussing atomic rule-set for nftables with Patrick McHardy,
we decided to put all rule-set updates that need to be applied
atomically in one single batch to simplify the existing approach.
However, as explained above, the existing netlink code limits us
to a maximum of ~20000 rules that fit in one single batch without
hitting ENOBUFS. iptables does not have such limitation as it is
using vmalloc.
This patch adds netlink_alloc_large_skb() which is only used in
the netlink_sendmsg() path. It uses alloc_skb if the memory
requested is <= one memory page, that should be the common case
for most subsystems, else vmalloc for higher memory allocations.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d0b3dd60d386..68c167374394 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -750,6 +750,10 @@ static void netlink_skb_destructor(struct sk_buff *skb) | |||
750 | skb->head = NULL; | 750 | skb->head = NULL; |
751 | } | 751 | } |
752 | #endif | 752 | #endif |
753 | if (is_vmalloc_addr(skb->head)) { | ||
754 | vfree(skb->head); | ||
755 | skb->head = NULL; | ||
756 | } | ||
753 | if (skb->sk != NULL) | 757 | if (skb->sk != NULL) |
754 | sock_rfree(skb); | 758 | sock_rfree(skb); |
755 | } | 759 | } |
@@ -1420,6 +1424,35 @@ struct sock *netlink_getsockbyfilp(struct file *filp) | |||
1420 | return sock; | 1424 | return sock; |
1421 | } | 1425 | } |
1422 | 1426 | ||
1427 | static struct sk_buff *netlink_alloc_large_skb(unsigned int size) | ||
1428 | { | ||
1429 | struct sk_buff *skb; | ||
1430 | void *data; | ||
1431 | |||
1432 | if (size <= NLMSG_GOODSIZE) | ||
1433 | return alloc_skb(size, GFP_KERNEL); | ||
1434 | |||
1435 | skb = alloc_skb_head(GFP_KERNEL); | ||
1436 | if (skb == NULL) | ||
1437 | return NULL; | ||
1438 | |||
1439 | data = vmalloc(size); | ||
1440 | if (data == NULL) | ||
1441 | goto err; | ||
1442 | |||
1443 | skb->head = data; | ||
1444 | skb->data = data; | ||
1445 | skb_reset_tail_pointer(skb); | ||
1446 | skb->end = skb->tail + size; | ||
1447 | skb->len = 0; | ||
1448 | skb->destructor = netlink_skb_destructor; | ||
1449 | |||
1450 | return skb; | ||
1451 | err: | ||
1452 | kfree_skb(skb); | ||
1453 | return NULL; | ||
1454 | } | ||
1455 | |||
1423 | /* | 1456 | /* |
1424 | * Attach a skb to a netlink socket. | 1457 | * Attach a skb to a netlink socket. |
1425 | * The caller must hold a reference to the destination socket. On error, the | 1458 | * The caller must hold a reference to the destination socket. On error, the |
@@ -1510,7 +1543,7 @@ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation) | |||
1510 | return skb; | 1543 | return skb; |
1511 | 1544 | ||
1512 | delta = skb->end - skb->tail; | 1545 | delta = skb->end - skb->tail; |
1513 | if (delta * 2 < skb->truesize) | 1546 | if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize) |
1514 | return skb; | 1547 | return skb; |
1515 | 1548 | ||
1516 | if (skb_shared(skb)) { | 1549 | if (skb_shared(skb)) { |
@@ -2096,7 +2129,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
2096 | if (len > sk->sk_sndbuf - 32) | 2129 | if (len > sk->sk_sndbuf - 32) |
2097 | goto out; | 2130 | goto out; |
2098 | err = -ENOBUFS; | 2131 | err = -ENOBUFS; |
2099 | skb = alloc_skb(len, GFP_KERNEL); | 2132 | skb = netlink_alloc_large_skb(len); |
2100 | if (skb == NULL) | 2133 | if (skb == NULL) |
2101 | goto out; | 2134 | goto out; |
2102 | 2135 | ||