Commit 9063e21f authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

netlink: autosize skb lengthes

One known problem with netlink is the fact that NLMSG_GOODSIZE is
really small on PAGE_SIZE==4096 architectures, and it is difficult
to know in advance what buffer size is used by the application.

This patch adds an automatic learning of the size.

First netlink message will still be limited to ~4K, but if user used
bigger buffers, then following messages will be able to use up to 16KB.

This speedups dump() operations by a large factor and should be safe
for legacy applications.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Thomas Graf <tgraf@suug.ch>
Acked-by: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cd84ff4d
...@@ -2343,6 +2343,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, ...@@ -2343,6 +2343,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
} }
#endif #endif
/* Record the max length of recvmsg() calls for future allocations */
nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len);
nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len,
16384);
copied = data_skb->len; copied = data_skb->len;
if (len < copied) { if (len < copied) {
msg->msg_flags |= MSG_TRUNC; msg->msg_flags |= MSG_TRUNC;
...@@ -2587,7 +2592,27 @@ static int netlink_dump(struct sock *sk) ...@@ -2587,7 +2592,27 @@ static int netlink_dump(struct sock *sk)
if (!netlink_rx_is_mmaped(sk) && if (!netlink_rx_is_mmaped(sk) &&
atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
goto errout_skb; goto errout_skb;
skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, GFP_KERNEL);
/* NLMSG_GOODSIZE is small to avoid high order allocations being
* required, but it makes sense to _attempt_ a 16K bytes allocation
* to reduce number of system calls on dump operations, if user
* ever provided a big enough buffer.
*/
if (alloc_size < nlk->max_recvmsg_len) {
skb = netlink_alloc_skb(sk,
nlk->max_recvmsg_len,
nlk->portid,
GFP_KERNEL |
__GFP_NOWARN |
__GFP_NORETRY);
/* available room should be exact amount to avoid MSG_TRUNC */
if (skb)
skb_reserve(skb, skb_tailroom(skb) -
nlk->max_recvmsg_len);
}
if (!skb)
skb = netlink_alloc_skb(sk, alloc_size, nlk->portid,
GFP_KERNEL);
if (!skb) if (!skb)
goto errout_skb; goto errout_skb;
netlink_skb_set_owner_r(skb, sk); netlink_skb_set_owner_r(skb, sk);
......
...@@ -31,6 +31,7 @@ struct netlink_sock { ...@@ -31,6 +31,7 @@ struct netlink_sock {
u32 ngroups; u32 ngroups;
unsigned long *groups; unsigned long *groups;
unsigned long state; unsigned long state;
size_t max_recvmsg_len;
wait_queue_head_t wait; wait_queue_head_t wait;
bool cb_running; bool cb_running;
struct netlink_callback cb; struct netlink_callback cb;
......
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