diff options
Diffstat (limited to 'net/netlink/af_netlink.c')
| -rw-r--r-- | net/netlink/af_netlink.c | 20 | 
1 files changed, 13 insertions, 7 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 6ef64adf736..0a4db0211da 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1659,13 +1659,10 @@ static int netlink_dump(struct sock *sk)  {  	struct netlink_sock *nlk = nlk_sk(sk);  	struct netlink_callback *cb; -	struct sk_buff *skb; +	struct sk_buff *skb = NULL;  	struct nlmsghdr *nlh;  	int len, err = -ENOBUFS; - -	skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); -	if (!skb) -		goto errout; +	int alloc_size;  	mutex_lock(nlk->cb_mutex); @@ -1675,6 +1672,12 @@ static int netlink_dump(struct sock *sk)  		goto errout_skb;  	} +	alloc_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE); + +	skb = sock_rmalloc(sk, alloc_size, 0, GFP_KERNEL); +	if (!skb) +		goto errout_skb; +  	len = cb->dump(skb, cb);  	if (len > 0) { @@ -1693,6 +1696,8 @@ static int netlink_dump(struct sock *sk)  	if (!nlh)  		goto errout_skb; +	nl_dump_check_consistent(cb, nlh); +  	memcpy(nlmsg_data(nlh), &len, sizeof(len));  	if (sk_filter(sk, skb)) @@ -1713,7 +1718,6 @@ static int netlink_dump(struct sock *sk)  errout_skb:  	mutex_unlock(nlk->cb_mutex);  	kfree_skb(skb); -errout:  	return err;  } @@ -1721,7 +1725,8 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,  		       const struct nlmsghdr *nlh,  		       int (*dump)(struct sk_buff *skb,  				   struct netlink_callback *), -		       int (*done)(struct netlink_callback *)) +		       int (*done)(struct netlink_callback *), +		       u16 min_dump_alloc)  {  	struct netlink_callback *cb;  	struct sock *sk; @@ -1735,6 +1740,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,  	cb->dump = dump;  	cb->done = done;  	cb->nlh = nlh; +	cb->min_dump_alloc = min_dump_alloc;  	atomic_inc(&skb->users);  	cb->skb = skb;  |