diff options
author | Octavian Purdila <opurdila@ixiacom.com> | 2009-12-26 06:51:03 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-26 23:42:29 -0500 |
commit | 0f7b67dd9e1192976f5e5a78934c7a339ff7c45f (patch) | |
tree | 123fd1196cea045dcd2b0e2870381f4949cd62db | |
parent | b76f5a8427ac2928c07fa4ff2144bb8db072c240 (diff) |
llc: optimize multicast delivery
Optimize multicast delivery by doing the actual delivery without
holding the lock. Based on the same approach used in UDP code.
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/llc/llc_sap.c | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 39760d013ce2..94790e60d072 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c | |||
@@ -355,6 +355,24 @@ static inline bool llc_mcast_match(const struct llc_sap *sap, | |||
355 | llc->dev == skb->dev; | 355 | llc->dev == skb->dev; |
356 | } | 356 | } |
357 | 357 | ||
358 | static void llc_do_mcast(struct llc_sap *sap, struct sk_buff *skb, | ||
359 | struct sock **stack, int count) | ||
360 | { | ||
361 | struct sk_buff *skb1; | ||
362 | int i; | ||
363 | |||
364 | for (i = 0; i < count; i++) { | ||
365 | skb1 = skb_clone(skb, GFP_ATOMIC); | ||
366 | if (!skb1) { | ||
367 | sock_put(stack[i]); | ||
368 | continue; | ||
369 | } | ||
370 | |||
371 | llc_sap_rcv(sap, skb1, stack[i]); | ||
372 | sock_put(stack[i]); | ||
373 | } | ||
374 | } | ||
375 | |||
358 | /** | 376 | /** |
359 | * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. | 377 | * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. |
360 | * @sap: SAP | 378 | * @sap: SAP |
@@ -367,25 +385,27 @@ static void llc_sap_mcast(struct llc_sap *sap, | |||
367 | const struct llc_addr *laddr, | 385 | const struct llc_addr *laddr, |
368 | struct sk_buff *skb) | 386 | struct sk_buff *skb) |
369 | { | 387 | { |
370 | struct sock *sk; | 388 | int i = 0, count = 256 / sizeof(struct sock *); |
389 | struct sock *sk, *stack[count]; | ||
371 | struct hlist_nulls_node *node; | 390 | struct hlist_nulls_node *node; |
372 | 391 | ||
373 | spin_lock_bh(&sap->sk_lock); | 392 | spin_lock_bh(&sap->sk_lock); |
374 | sk_nulls_for_each_rcu(sk, node, &sap->sk_list) { | 393 | sk_nulls_for_each_rcu(sk, node, &sap->sk_list) { |
375 | struct sk_buff *skb1; | ||
376 | 394 | ||
377 | if (!llc_mcast_match(sap, laddr, skb, sk)) | 395 | if (!llc_mcast_match(sap, laddr, skb, sk)) |
378 | continue; | 396 | continue; |
379 | 397 | ||
380 | skb1 = skb_clone(skb, GFP_ATOMIC); | ||
381 | if (!skb1) | ||
382 | break; | ||
383 | |||
384 | sock_hold(sk); | 398 | sock_hold(sk); |
385 | llc_sap_rcv(sap, skb1, sk); | 399 | if (i < count) |
386 | sock_put(sk); | 400 | stack[i++] = sk; |
401 | else { | ||
402 | llc_do_mcast(sap, skb, stack, i); | ||
403 | i = 0; | ||
404 | } | ||
387 | } | 405 | } |
388 | spin_unlock_bh(&sap->sk_lock); | 406 | spin_unlock_bh(&sap->sk_lock); |
407 | |||
408 | llc_do_mcast(sap, skb, stack, i); | ||
389 | } | 409 | } |
390 | 410 | ||
391 | 411 | ||