aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc/llc_sap.c
diff options
context:
space:
mode:
authorOctavian Purdila <opurdila@ixiacom.com>2009-12-26 06:51:02 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-26 23:41:43 -0500
commitb76f5a8427ac2928c07fa4ff2144bb8db072c240 (patch)
tree542d64a8bd28baf69f87b199a0156f865a06551d /net/llc/llc_sap.c
parentabf9d537fea225af60762640361af7fb233b3103 (diff)
llc: convert the socket list to RCU locking
For the reclamation phase we use the SLAB_DESTROY_BY_RCU mechanism, which require some extra checks in the lookup code: a) If the current socket was released, reallocated & inserted in another list it will short circuit the iteration for the current list, thus we need to restart the lookup. b) If the current socket was released, reallocated & inserted in the same list we just need to recheck it matches the look-up criteria and if not we can skip to the next element. In this case there is no need to restart the lookup, since sockets are inserted at the start of the list and the worst that will happen is that we will iterate throught some of the list elements more then once. Note that the /proc and multicast delivery was not yet converted to RCU, it still uses spinlocks for protection. Signed-off-by: Octavian Purdila <opurdila@ixiacom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/llc/llc_sap.c')
-rw-r--r--net/llc/llc_sap.c66
1 files changed, 43 insertions, 23 deletions
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 008de1fc42ca..39760d013ce2 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -297,6 +297,17 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
297 llc_sap_state_process(sap, skb); 297 llc_sap_state_process(sap, skb);
298} 298}
299 299
300static inline bool llc_dgram_match(const struct llc_sap *sap,
301 const struct llc_addr *laddr,
302 const struct sock *sk)
303{
304 struct llc_sock *llc = llc_sk(sk);
305
306 return sk->sk_type == SOCK_DGRAM &&
307 llc->laddr.lsap == laddr->lsap &&
308 llc_mac_match(llc->laddr.mac, laddr->mac);
309}
310
300/** 311/**
301 * llc_lookup_dgram - Finds dgram socket for the local sap/mac 312 * llc_lookup_dgram - Finds dgram socket for the local sap/mac
302 * @sap: SAP 313 * @sap: SAP
@@ -309,25 +320,41 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
309 const struct llc_addr *laddr) 320 const struct llc_addr *laddr)
310{ 321{
311 struct sock *rc; 322 struct sock *rc;
312 struct hlist_node *node; 323 struct hlist_nulls_node *node;
313 324
314 read_lock_bh(&sap->sk_list.lock); 325 rcu_read_lock_bh();
315 sk_for_each(rc, node, &sap->sk_list.list) { 326again:
316 struct llc_sock *llc = llc_sk(rc); 327 sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
317 328 if (llc_dgram_match(sap, laddr, rc)) {
318 if (rc->sk_type == SOCK_DGRAM && 329 /* Extra checks required by SLAB_DESTROY_BY_RCU */
319 llc->laddr.lsap == laddr->lsap && 330 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
320 llc_mac_match(llc->laddr.mac, laddr->mac)) { 331 goto again;
321 sock_hold(rc); 332 if (unlikely(llc_sk(rc)->sap != sap ||
333 !llc_dgram_match(sap, laddr, rc))) {
334 sock_put(rc);
335 continue;
336 }
322 goto found; 337 goto found;
323 } 338 }
324 } 339 }
325 rc = NULL; 340 rc = NULL;
326found: 341found:
327 read_unlock_bh(&sap->sk_list.lock); 342 rcu_read_unlock_bh();
328 return rc; 343 return rc;
329} 344}
330 345
346static inline bool llc_mcast_match(const struct llc_sap *sap,
347 const struct llc_addr *laddr,
348 const struct sk_buff *skb,
349 const struct sock *sk)
350{
351 struct llc_sock *llc = llc_sk(sk);
352
353 return sk->sk_type == SOCK_DGRAM &&
354 llc->laddr.lsap == laddr->lsap &&
355 llc->dev == skb->dev;
356}
357
331/** 358/**
332 * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. 359 * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
333 * @sap: SAP 360 * @sap: SAP
@@ -341,20 +368,13 @@ static void llc_sap_mcast(struct llc_sap *sap,
341 struct sk_buff *skb) 368 struct sk_buff *skb)
342{ 369{
343 struct sock *sk; 370 struct sock *sk;
344 struct hlist_node *node; 371 struct hlist_nulls_node *node;
345 372
346 read_lock_bh(&sap->sk_list.lock); 373 spin_lock_bh(&sap->sk_lock);
347 sk_for_each(sk, node, &sap->sk_list.list) { 374 sk_nulls_for_each_rcu(sk, node, &sap->sk_list) {
348 struct llc_sock *llc = llc_sk(sk);
349 struct sk_buff *skb1; 375 struct sk_buff *skb1;
350 376
351 if (sk->sk_type != SOCK_DGRAM) 377 if (!llc_mcast_match(sap, laddr, skb, sk))
352 continue;
353
354 if (llc->laddr.lsap != laddr->lsap)
355 continue;
356
357 if (llc->dev != skb->dev)
358 continue; 378 continue;
359 379
360 skb1 = skb_clone(skb, GFP_ATOMIC); 380 skb1 = skb_clone(skb, GFP_ATOMIC);
@@ -365,7 +385,7 @@ static void llc_sap_mcast(struct llc_sap *sap,
365 llc_sap_rcv(sap, skb1, sk); 385 llc_sap_rcv(sap, skb1, sk);
366 sock_put(sk); 386 sock_put(sk);
367 } 387 }
368 read_unlock_bh(&sap->sk_list.lock); 388 spin_unlock_bh(&sap->sk_lock);
369} 389}
370 390
371 391