You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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>
This commit is contained in:
committed by
David S. Miller
parent
abf9d537fe
commit
b76f5a8427
+60
-29
@@ -468,6 +468,19 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline bool llc_estab_match(const struct llc_sap *sap,
|
||||
const struct llc_addr *daddr,
|
||||
const struct llc_addr *laddr,
|
||||
const struct sock *sk)
|
||||
{
|
||||
struct llc_sock *llc = llc_sk(sk);
|
||||
|
||||
return llc->laddr.lsap == laddr->lsap &&
|
||||
llc->daddr.lsap == daddr->lsap &&
|
||||
llc_mac_match(llc->laddr.mac, laddr->mac) &&
|
||||
llc_mac_match(llc->daddr.mac, daddr->mac);
|
||||
}
|
||||
|
||||
/**
|
||||
* __llc_lookup_established - Finds connection for the remote/local sap/mac
|
||||
* @sap: SAP
|
||||
@@ -484,23 +497,26 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap,
|
||||
struct llc_addr *laddr)
|
||||
{
|
||||
struct sock *rc;
|
||||
struct hlist_node *node;
|
||||
struct hlist_nulls_node *node;
|
||||
|
||||
read_lock(&sap->sk_list.lock);
|
||||
sk_for_each(rc, node, &sap->sk_list.list) {
|
||||
struct llc_sock *llc = llc_sk(rc);
|
||||
|
||||
if (llc->laddr.lsap == laddr->lsap &&
|
||||
llc->daddr.lsap == daddr->lsap &&
|
||||
llc_mac_match(llc->laddr.mac, laddr->mac) &&
|
||||
llc_mac_match(llc->daddr.mac, daddr->mac)) {
|
||||
sock_hold(rc);
|
||||
rcu_read_lock();
|
||||
again:
|
||||
sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
|
||||
if (llc_estab_match(sap, daddr, laddr, rc)) {
|
||||
/* Extra checks required by SLAB_DESTROY_BY_RCU */
|
||||
if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
|
||||
goto again;
|
||||
if (unlikely(llc_sk(rc)->sap != sap ||
|
||||
!llc_estab_match(sap, daddr, laddr, rc))) {
|
||||
sock_put(rc);
|
||||
continue;
|
||||
}
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
rc = NULL;
|
||||
found:
|
||||
read_unlock(&sap->sk_list.lock);
|
||||
rcu_read_unlock();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -516,6 +532,18 @@ struct sock *llc_lookup_established(struct llc_sap *sap,
|
||||
return sk;
|
||||
}
|
||||
|
||||
static inline bool llc_listener_match(const struct llc_sap *sap,
|
||||
const struct llc_addr *laddr,
|
||||
const struct sock *sk)
|
||||
{
|
||||
struct llc_sock *llc = llc_sk(sk);
|
||||
|
||||
return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN &&
|
||||
llc->laddr.lsap == laddr->lsap &&
|
||||
(llc_mac_match(llc->laddr.mac, laddr->mac) ||
|
||||
llc_mac_null(llc->laddr.mac));
|
||||
}
|
||||
|
||||
/**
|
||||
* llc_lookup_listener - Finds listener for local MAC + SAP
|
||||
* @sap: SAP
|
||||
@@ -530,23 +558,26 @@ static struct sock *llc_lookup_listener(struct llc_sap *sap,
|
||||
struct llc_addr *laddr)
|
||||
{
|
||||
struct sock *rc;
|
||||
struct hlist_node *node;
|
||||
struct hlist_nulls_node *node;
|
||||
|
||||
read_lock(&sap->sk_list.lock);
|
||||
sk_for_each(rc, node, &sap->sk_list.list) {
|
||||
struct llc_sock *llc = llc_sk(rc);
|
||||
|
||||
if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN &&
|
||||
llc->laddr.lsap == laddr->lsap &&
|
||||
(llc_mac_match(llc->laddr.mac, laddr->mac) ||
|
||||
llc_mac_null(llc->laddr.mac))) {
|
||||
sock_hold(rc);
|
||||
rcu_read_lock();
|
||||
again:
|
||||
sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
|
||||
if (llc_listener_match(sap, laddr, rc)) {
|
||||
/* Extra checks required by SLAB_DESTROY_BY_RCU */
|
||||
if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
|
||||
goto again;
|
||||
if (unlikely(llc_sk(rc)->sap != sap ||
|
||||
!llc_listener_match(sap, laddr, rc))) {
|
||||
sock_put(rc);
|
||||
continue;
|
||||
}
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
rc = NULL;
|
||||
found:
|
||||
read_unlock(&sap->sk_list.lock);
|
||||
rcu_read_unlock();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -652,10 +683,10 @@ static int llc_find_offset(int state, int ev_type)
|
||||
void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
|
||||
{
|
||||
llc_sap_hold(sap);
|
||||
write_lock_bh(&sap->sk_list.lock);
|
||||
spin_lock_bh(&sap->sk_lock);
|
||||
llc_sk(sk)->sap = sap;
|
||||
sk_add_node(sk, &sap->sk_list.list);
|
||||
write_unlock_bh(&sap->sk_list.lock);
|
||||
sk_nulls_add_node_rcu(sk, &sap->sk_list);
|
||||
spin_unlock_bh(&sap->sk_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -663,14 +694,14 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
|
||||
* @sap: SAP
|
||||
* @sk: socket
|
||||
*
|
||||
* This function removes a connection from sk_list.list of a SAP if
|
||||
* This function removes a connection from sk_list of a SAP if
|
||||
* the connection was in this list.
|
||||
*/
|
||||
void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
|
||||
{
|
||||
write_lock_bh(&sap->sk_list.lock);
|
||||
sk_del_node_init(sk);
|
||||
write_unlock_bh(&sap->sk_list.lock);
|
||||
spin_lock_bh(&sap->sk_lock);
|
||||
sk_nulls_del_node_init_rcu(sk);
|
||||
spin_unlock_bh(&sap->sk_lock);
|
||||
llc_sap_put(sap);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user