[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2AD939572F25A448A3AE3CAEA61328C237A41FCA@BC-MAIL-M30.internal.baidu.com>
Date: Fri, 21 Sep 2018 03:27:47 +0000
From: "Li,Rongqing" <lirongqing@...du.com>
To: Eric Dumazet <eric.dumazet@...il.com>,
"netdev@...r.kernel.org" <netdev@...r.kernel.org>
Subject: 答复: [PATCH][next-next][v2] netlink: avoid to allocate full skb when sending to many devices
: Re: [PATCH][next-next][v2] netlink: avoid to allocate full skb when
> sending to many devices
>
>
>
> On 09/20/2018 06:43 AM, Eric Dumazet wrote:
> >
>
Sorry, I should cc to you.
> > And lastly this patch looks way too complicated to me.
> > You probably can write something much simpler.
>
But it should not increase the negative performance
> Something like :
>
> diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index
> 930d17fa906c9ebf1cf7b6031ce0a22f9f66c0e4..e0a81beb4f37751421dbbe794c
> cf3d5a46bdf900 100644
> --- a/net/netlink/af_netlink.c
> +++ b/net/netlink/af_netlink.c
> @@ -278,22 +278,26 @@ static bool netlink_filter_tap(const struct sk_buff
> *skb)
> return false;
> }
>
> -static int __netlink_deliver_tap_skb(struct sk_buff *skb,
> +static int __netlink_deliver_tap_skb(struct sk_buff **pskb,
> struct net_device *dev) {
> - struct sk_buff *nskb;
> + struct sk_buff *nskb, *skb = *pskb;
> struct sock *sk = skb->sk;
> int ret = -ENOMEM;
>
> if (!net_eq(dev_net(dev), sock_net(sk)))
> return 0;
>
> - dev_hold(dev);
> -
> - if (is_vmalloc_addr(skb->head))
> + if (is_vmalloc_addr(skb->head)) {
> nskb = netlink_to_full_skb(skb, GFP_ATOMIC);
> - else
> - nskb = skb_clone(skb, GFP_ATOMIC);
> + if (!nskb)
> + return -ENOMEM;
> + consume_skb(skb);
The original skb can not be freed, since it will be used after send to tap in __netlink_sendskb
> + skb = nskb;
> + *pskb = skb;
> + }
> + dev_hold(dev);
> + nskb = skb_clone(skb, GFP_ATOMIC);
since original skb can not be freed, skb_clone will lead to a leak.
> if (nskb) {
> nskb->dev = dev;
> nskb->protocol = htons((u16) sk->sk_protocol); @@ -318,7 +322,7
> @@ static void __netlink_deliver_tap(struct sk_buff *skb, struct
> netlink_tap_net *n
> return;
>
> list_for_each_entry_rcu(tmp, &nn->netlink_tap_all, list) {
> - ret = __netlink_deliver_tap_skb(skb, tmp->dev);
> + ret = __netlink_deliver_tap_skb(&skb, tmp->dev);
> if (unlikely(ret))
> break;
> }
>
The below change seems simple, but it increase skb allocation and
free one time,
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index e3a0538ec0be..b9631137f0fe 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -290,10 +290,8 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb,
dev_hold(dev);
- if (is_vmalloc_addr(skb->head))
- nskb = netlink_to_full_skb(skb, GFP_ATOMIC);
- else
- nskb = skb_clone(skb, GFP_ATOMIC);
+ nskb = skb_clone(skb GFP_ATOMIC);
+
if (nskb) {
nskb->dev = dev;
nskb->protocol = htons((u16) sk->sk_protocol);
@@ -317,11 +315,20 @@ static void __netlink_deliver_tap(struct sk_buff *skb, struct netlink_tap_net *n
if (!netlink_filter_tap(skb))
return;
+ if (is_vmalloc_addr(skb->head)) {
+ skb = netlink_to_full_skb(skb, GFP_ATOMIC);
+ if (!skb)
+ return;
+ alloc = true;
+ }
+
list_for_each_entry_rcu(tmp, &nn->netlink_tap_all, list) {
+
ret = __netlink_deliver_tap_skb(skb, tmp->dev);
if (unlikely(ret))
break;
}
+
+ if (alloc)
+ consume_skb(skb);
}
-Q
Powered by blists - more mailing lists