|
@@ -1619,6 +1619,8 @@ static void flush_stack(struct sock **stack, unsigned int count,
|
|
|
|
|
|
if (skb1 && udp_queue_rcv_skb(sk, skb1) <= 0)
|
|
|
skb1 = NULL;
|
|
|
+
|
|
|
+ sock_put(sk);
|
|
|
}
|
|
|
if (unlikely(skb1))
|
|
|
kfree_skb(skb1);
|
|
@@ -1651,10 +1653,20 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
|
|
|
unsigned short hnum = ntohs(uh->dest);
|
|
|
struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum);
|
|
|
int dif = skb->dev->ifindex;
|
|
|
- unsigned int i, count = 0;
|
|
|
+ unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node);
|
|
|
+ unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10);
|
|
|
+
|
|
|
+ if (use_hash2) {
|
|
|
+ hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) &
|
|
|
+ udp_table.mask;
|
|
|
+ hash2 = udp4_portaddr_hash(net, daddr, hnum) & udp_table.mask;
|
|
|
+start_lookup:
|
|
|
+ hslot = &udp_table.hash2[hash2];
|
|
|
+ offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node);
|
|
|
+ }
|
|
|
|
|
|
spin_lock(&hslot->lock);
|
|
|
- sk_nulls_for_each(sk, node, &hslot->head) {
|
|
|
+ sk_nulls_for_each_entry_offset(sk, node, &hslot->head, offset) {
|
|
|
if (__udp_is_mcast_sock(net, sk,
|
|
|
uh->dest, daddr,
|
|
|
uh->source, saddr,
|
|
@@ -1664,24 +1676,23 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
|
|
|
count = 0;
|
|
|
}
|
|
|
stack[count++] = sk;
|
|
|
+ sock_hold(sk);
|
|
|
}
|
|
|
}
|
|
|
- /*
|
|
|
- * before releasing chain lock, we must take a reference on sockets
|
|
|
- */
|
|
|
- for (i = 0; i < count; i++)
|
|
|
- sock_hold(stack[i]);
|
|
|
|
|
|
spin_unlock(&hslot->lock);
|
|
|
|
|
|
+ /* Also lookup *:port if we are using hash2 and haven't done so yet. */
|
|
|
+ if (use_hash2 && hash2 != hash2_any) {
|
|
|
+ hash2 = hash2_any;
|
|
|
+ goto start_lookup;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* do the slow work with no lock held
|
|
|
*/
|
|
|
if (count) {
|
|
|
flush_stack(stack, count, skb, count - 1);
|
|
|
-
|
|
|
- for (i = 0; i < count; i++)
|
|
|
- sock_put(stack[i]);
|
|
|
} else {
|
|
|
kfree_skb(skb);
|
|
|
}
|