: 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