]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/llc/llc_sap.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
[mv-sheeva.git] / net / llc / llc_sap.c
index 39760d013ce205ce7fb4bdb1c454e1728e769294..ad6e6e1cf22fce1eefa43d1726537d3b5bf644dc 100644 (file)
@@ -321,10 +321,12 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
 {
        struct sock *rc;
        struct hlist_nulls_node *node;
+       int slot = llc_sk_laddr_hashfn(sap, laddr);
+       struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
 
        rcu_read_lock_bh();
 again:
-       sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
+       sk_nulls_for_each_rcu(rc, node, laddr_hb) {
                if (llc_dgram_match(sap, laddr, rc)) {
                        /* Extra checks required by SLAB_DESTROY_BY_RCU */
                        if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
@@ -338,6 +340,13 @@ again:
                }
        }
        rc = NULL;
+       /*
+        * if the nulls value we got at the end of this lookup is
+        * not the expected one, we must restart lookup.
+        * We probably met an item that was moved to another chain.
+        */
+       if (unlikely(get_nulls_value(node) != slot))
+               goto again;
 found:
        rcu_read_unlock_bh();
        return rc;
@@ -355,6 +364,24 @@ static inline bool llc_mcast_match(const struct llc_sap *sap,
          llc->dev == skb->dev;
 }
 
+static void llc_do_mcast(struct llc_sap *sap, struct sk_buff *skb,
+                        struct sock **stack, int count)
+{
+       struct sk_buff *skb1;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               skb1 = skb_clone(skb, GFP_ATOMIC);
+               if (!skb1) {
+                       sock_put(stack[i]);
+                       continue;
+               }
+
+               llc_sap_rcv(sap, skb1, stack[i]);
+               sock_put(stack[i]);
+       }
+}
+
 /**
  *     llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
  *     @sap: SAP
@@ -367,25 +394,31 @@ static void llc_sap_mcast(struct llc_sap *sap,
                          const struct llc_addr *laddr,
                          struct sk_buff *skb)
 {
-       struct sock *sk;
-       struct hlist_nulls_node *node;
+       int i = 0, count = 256 / sizeof(struct sock *);
+       struct sock *sk, *stack[count];
+       struct hlist_node *node;
+       struct llc_sock *llc;
+       struct hlist_head *dev_hb = llc_sk_dev_hash(sap, skb->dev->ifindex);
 
        spin_lock_bh(&sap->sk_lock);
-       sk_nulls_for_each_rcu(sk, node, &sap->sk_list) {
-               struct sk_buff *skb1;
+       hlist_for_each_entry(llc, node, dev_hb, dev_hash_node) {
+
+               sk = &llc->sk;
 
                if (!llc_mcast_match(sap, laddr, skb, sk))
                        continue;
 
-               skb1 = skb_clone(skb, GFP_ATOMIC);
-               if (!skb1)
-                       break;
-
                sock_hold(sk);
-               llc_sap_rcv(sap, skb1, sk);
-               sock_put(sk);
+               if (i < count)
+                       stack[i++] = sk;
+               else {
+                       llc_do_mcast(sap, skb, stack, i);
+                       i = 0;
+               }
        }
        spin_unlock_bh(&sap->sk_lock);
+
+       llc_do_mcast(sap, skb, stack, i);
 }