aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc/llc_conn.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_conn.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_conn.c')
-rw-r--r--net/llc/llc_conn.c93
1 files changed, 62 insertions, 31 deletions
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index c6bab39b018e..77bb3816655e 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -468,6 +468,19 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
468 return rc; 468 return rc;
469} 469}
470 470
471static inline bool llc_estab_match(const struct llc_sap *sap,
472 const struct llc_addr *daddr,
473 const struct llc_addr *laddr,
474 const struct sock *sk)
475{
476 struct llc_sock *llc = llc_sk(sk);
477
478 return llc->laddr.lsap == laddr->lsap &&
479 llc->daddr.lsap == daddr->lsap &&
480 llc_mac_match(llc->laddr.mac, laddr->mac) &&
481 llc_mac_match(llc->daddr.mac, daddr->mac);
482}
483
471/** 484/**
472 * __llc_lookup_established - Finds connection for the remote/local sap/mac 485 * __llc_lookup_established - Finds connection for the remote/local sap/mac
473 * @sap: SAP 486 * @sap: SAP
@@ -484,23 +497,26 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap,
484 struct llc_addr *laddr) 497 struct llc_addr *laddr)
485{ 498{
486 struct sock *rc; 499 struct sock *rc;
487 struct hlist_node *node; 500 struct hlist_nulls_node *node;
488 501
489 read_lock(&sap->sk_list.lock); 502 rcu_read_lock();
490 sk_for_each(rc, node, &sap->sk_list.list) { 503again:
491 struct llc_sock *llc = llc_sk(rc); 504 sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
492 505 if (llc_estab_match(sap, daddr, laddr, rc)) {
493 if (llc->laddr.lsap == laddr->lsap && 506 /* Extra checks required by SLAB_DESTROY_BY_RCU */
494 llc->daddr.lsap == daddr->lsap && 507 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
495 llc_mac_match(llc->laddr.mac, laddr->mac) && 508 goto again;
496 llc_mac_match(llc->daddr.mac, daddr->mac)) { 509 if (unlikely(llc_sk(rc)->sap != sap ||
497 sock_hold(rc); 510 !llc_estab_match(sap, daddr, laddr, rc))) {
511 sock_put(rc);
512 continue;
513 }
498 goto found; 514 goto found;
499 } 515 }
500 } 516 }
501 rc = NULL; 517 rc = NULL;
502found: 518found:
503 read_unlock(&sap->sk_list.lock); 519 rcu_read_unlock();
504 return rc; 520 return rc;
505} 521}
506 522
@@ -516,6 +532,18 @@ struct sock *llc_lookup_established(struct llc_sap *sap,
516 return sk; 532 return sk;
517} 533}
518 534
535static inline bool llc_listener_match(const struct llc_sap *sap,
536 const struct llc_addr *laddr,
537 const struct sock *sk)
538{
539 struct llc_sock *llc = llc_sk(sk);
540
541 return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN &&
542 llc->laddr.lsap == laddr->lsap &&
543 (llc_mac_match(llc->laddr.mac, laddr->mac) ||
544 llc_mac_null(llc->laddr.mac));
545}
546
519/** 547/**
520 * llc_lookup_listener - Finds listener for local MAC + SAP 548 * llc_lookup_listener - Finds listener for local MAC + SAP
521 * @sap: SAP 549 * @sap: SAP
@@ -530,23 +558,26 @@ static struct sock *llc_lookup_listener(struct llc_sap *sap,
530 struct llc_addr *laddr) 558 struct llc_addr *laddr)
531{ 559{
532 struct sock *rc; 560 struct sock *rc;
533 struct hlist_node *node; 561 struct hlist_nulls_node *node;
534 562
535 read_lock(&sap->sk_list.lock); 563 rcu_read_lock();
536 sk_for_each(rc, node, &sap->sk_list.list) { 564again:
537 struct llc_sock *llc = llc_sk(rc); 565 sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
538 566 if (llc_listener_match(sap, laddr, rc)) {
539 if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN && 567 /* Extra checks required by SLAB_DESTROY_BY_RCU */
540 llc->laddr.lsap == laddr->lsap && 568 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
541 (llc_mac_match(llc->laddr.mac, laddr->mac) || 569 goto again;
542 llc_mac_null(llc->laddr.mac))) { 570 if (unlikely(llc_sk(rc)->sap != sap ||
543 sock_hold(rc); 571 !llc_listener_match(sap, laddr, rc))) {
572 sock_put(rc);
573 continue;
574 }
544 goto found; 575 goto found;
545 } 576 }
546 } 577 }
547 rc = NULL; 578 rc = NULL;
548found: 579found:
549 read_unlock(&sap->sk_list.lock); 580 rcu_read_unlock();
550 return rc; 581 return rc;
551} 582}
552 583
@@ -652,10 +683,10 @@ static int llc_find_offset(int state, int ev_type)
652void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk) 683void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
653{ 684{
654 llc_sap_hold(sap); 685 llc_sap_hold(sap);
655 write_lock_bh(&sap->sk_list.lock); 686 spin_lock_bh(&sap->sk_lock);
656 llc_sk(sk)->sap = sap; 687 llc_sk(sk)->sap = sap;
657 sk_add_node(sk, &sap->sk_list.list); 688 sk_nulls_add_node_rcu(sk, &sap->sk_list);
658 write_unlock_bh(&sap->sk_list.lock); 689 spin_unlock_bh(&sap->sk_lock);
659} 690}
660 691
661/** 692/**
@@ -663,14 +694,14 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
663 * @sap: SAP 694 * @sap: SAP
664 * @sk: socket 695 * @sk: socket
665 * 696 *
666 * This function removes a connection from sk_list.list of a SAP if 697 * This function removes a connection from sk_list of a SAP if
667 * the connection was in this list. 698 * the connection was in this list.
668 */ 699 */
669void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk) 700void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
670{ 701{
671 write_lock_bh(&sap->sk_list.lock); 702 spin_lock_bh(&sap->sk_lock);
672 sk_del_node_init(sk); 703 sk_nulls_del_node_init_rcu(sk);
673 write_unlock_bh(&sap->sk_list.lock); 704 spin_unlock_bh(&sap->sk_lock);
674 llc_sap_put(sap); 705 llc_sap_put(sap);
675} 706}
676 707