diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/netlink/af_netlink.c | 27 | ||||
| -rw-r--r-- | net/netlink/af_netlink.h | 1 |
2 files changed, 27 insertions, 1 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 9db8bab27fa2..c2d585c4f7c5 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -2343,6 +2343,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 2343 | } | 2343 | } |
| 2344 | #endif | 2344 | #endif |
| 2345 | 2345 | ||
| 2346 | /* Record the max length of recvmsg() calls for future allocations */ | ||
| 2347 | nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len); | ||
| 2348 | nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len, | ||
| 2349 | 16384); | ||
| 2350 | |||
| 2346 | copied = data_skb->len; | 2351 | copied = data_skb->len; |
| 2347 | if (len < copied) { | 2352 | if (len < copied) { |
| 2348 | msg->msg_flags |= MSG_TRUNC; | 2353 | msg->msg_flags |= MSG_TRUNC; |
| @@ -2587,7 +2592,27 @@ static int netlink_dump(struct sock *sk) | |||
| 2587 | if (!netlink_rx_is_mmaped(sk) && | 2592 | if (!netlink_rx_is_mmaped(sk) && |
| 2588 | atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) | 2593 | atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) |
| 2589 | goto errout_skb; | 2594 | goto errout_skb; |
| 2590 | skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, GFP_KERNEL); | 2595 | |
| 2596 | /* NLMSG_GOODSIZE is small to avoid high order allocations being | ||
| 2597 | * required, but it makes sense to _attempt_ a 16K bytes allocation | ||
| 2598 | * to reduce number of system calls on dump operations, if user | ||
| 2599 | * ever provided a big enough buffer. | ||
| 2600 | */ | ||
| 2601 | if (alloc_size < nlk->max_recvmsg_len) { | ||
| 2602 | skb = netlink_alloc_skb(sk, | ||
| 2603 | nlk->max_recvmsg_len, | ||
| 2604 | nlk->portid, | ||
| 2605 | GFP_KERNEL | | ||
| 2606 | __GFP_NOWARN | | ||
| 2607 | __GFP_NORETRY); | ||
| 2608 | /* available room should be exact amount to avoid MSG_TRUNC */ | ||
| 2609 | if (skb) | ||
| 2610 | skb_reserve(skb, skb_tailroom(skb) - | ||
| 2611 | nlk->max_recvmsg_len); | ||
| 2612 | } | ||
| 2613 | if (!skb) | ||
| 2614 | skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, | ||
| 2615 | GFP_KERNEL); | ||
| 2591 | if (!skb) | 2616 | if (!skb) |
| 2592 | goto errout_skb; | 2617 | goto errout_skb; |
| 2593 | netlink_skb_set_owner_r(skb, sk); | 2618 | netlink_skb_set_owner_r(skb, sk); |
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index acbd774eeb7c..ed13a790b00e 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h | |||
| @@ -31,6 +31,7 @@ struct netlink_sock { | |||
| 31 | u32 ngroups; | 31 | u32 ngroups; |
| 32 | unsigned long *groups; | 32 | unsigned long *groups; |
| 33 | unsigned long state; | 33 | unsigned long state; |
| 34 | size_t max_recvmsg_len; | ||
| 34 | wait_queue_head_t wait; | 35 | wait_queue_head_t wait; |
| 35 | bool cb_running; | 36 | bool cb_running; |
| 36 | struct netlink_callback cb; | 37 | struct netlink_callback cb; |
