Skip to content

Commit c5adde9

Browse files
ying-xuedavem330
authored andcommitted
netlink: eliminate nl_sk_hash_lock
As rhashtable_lookup_compare_insert() can guarantee the process of search and insertion is atomic, it's safe to eliminate the nl_sk_hash_lock. After this, object insertion or removal will be protected with per bucket lock on write side while object lookup is guarded with rcu read lock on read side. Signed-off-by: Ying Xue <[email protected]> Cc: Thomas Graf <[email protected]> Acked-by: Thomas Graf <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7a868d1 commit c5adde9

File tree

3 files changed

+25
-19
lines changed

3 files changed

+25
-19
lines changed

net/netlink/af_netlink.c

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ static void netlink_skb_destructor(struct sk_buff *skb);
9898

9999
/* nl_table locking explained:
100100
* Lookup and traversal are protected with an RCU read-side lock. Insertion
101-
* and removal are protected with nl_sk_hash_lock while using RCU list
101+
* and removal are protected with per bucket lock while using RCU list
102102
* modification primitives and may run in parallel to RCU protected lookups.
103103
* Destruction of the Netlink socket may only occur *after* nl_table_lock has
104104
* been acquired * either during or after the socket has been removed from
@@ -110,10 +110,6 @@ static atomic_t nl_table_users = ATOMIC_INIT(0);
110110

111111
#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock));
112112

113-
/* Protects netlink socket hash table mutations */
114-
DEFINE_MUTEX(nl_sk_hash_lock);
115-
EXPORT_SYMBOL_GPL(nl_sk_hash_lock);
116-
117113
static ATOMIC_NOTIFIER_HEAD(netlink_chain);
118114

119115
static DEFINE_SPINLOCK(netlink_tap_lock);
@@ -998,6 +994,19 @@ static struct sock *__netlink_lookup(struct netlink_table *table, u32 portid,
998994
&netlink_compare, &arg);
999995
}
1000996

997+
static bool __netlink_insert(struct netlink_table *table, struct sock *sk,
998+
struct net *net)
999+
{
1000+
struct netlink_compare_arg arg = {
1001+
.net = net,
1002+
.portid = nlk_sk(sk)->portid,
1003+
};
1004+
1005+
return rhashtable_lookup_compare_insert(&table->hash,
1006+
&nlk_sk(sk)->node,
1007+
&netlink_compare, &arg);
1008+
}
1009+
10011010
static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid)
10021011
{
10031012
struct netlink_table *table = &nl_table[protocol];
@@ -1043,9 +1052,7 @@ static int netlink_insert(struct sock *sk, struct net *net, u32 portid)
10431052
struct netlink_table *table = &nl_table[sk->sk_protocol];
10441053
int err = -EADDRINUSE;
10451054

1046-
mutex_lock(&nl_sk_hash_lock);
1047-
if (__netlink_lookup(table, portid, net))
1048-
goto err;
1055+
lock_sock(sk);
10491056

10501057
err = -EBUSY;
10511058
if (nlk_sk(sk)->portid)
@@ -1058,24 +1065,24 @@ static int netlink_insert(struct sock *sk, struct net *net, u32 portid)
10581065

10591066
nlk_sk(sk)->portid = portid;
10601067
sock_hold(sk);
1061-
rhashtable_insert(&table->hash, &nlk_sk(sk)->node);
1062-
err = 0;
1068+
if (__netlink_insert(table, sk, net))
1069+
err = 0;
1070+
else
1071+
sock_put(sk);
10631072
err:
1064-
mutex_unlock(&nl_sk_hash_lock);
1073+
release_sock(sk);
10651074
return err;
10661075
}
10671076

10681077
static void netlink_remove(struct sock *sk)
10691078
{
10701079
struct netlink_table *table;
10711080

1072-
mutex_lock(&nl_sk_hash_lock);
10731081
table = &nl_table[sk->sk_protocol];
10741082
if (rhashtable_remove(&table->hash, &nlk_sk(sk)->node)) {
10751083
WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
10761084
__sock_put(sk);
10771085
}
1078-
mutex_unlock(&nl_sk_hash_lock);
10791086

10801087
netlink_table_grab();
10811088
if (nlk_sk(sk)->subscriptions) {

net/netlink/af_netlink.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,5 @@ struct netlink_table {
7474

7575
extern struct netlink_table *nl_table;
7676
extern rwlock_t nl_table_lock;
77-
extern struct mutex nl_sk_hash_lock;
7877

7978
#endif

net/netlink/diag.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
103103
{
104104
struct netlink_table *tbl = &nl_table[protocol];
105105
struct rhashtable *ht = &tbl->hash;
106-
const struct bucket_table *htbl = rht_dereference(ht->tbl, ht);
106+
const struct bucket_table *htbl = rht_dereference_rcu(ht->tbl, ht);
107107
struct net *net = sock_net(skb->sk);
108108
struct netlink_diag_req *req;
109109
struct netlink_sock *nlsk;
@@ -115,7 +115,7 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
115115
for (i = 0; i < htbl->size; i++) {
116116
struct rhash_head *pos;
117117

118-
rht_for_each_entry(nlsk, pos, htbl, i, node) {
118+
rht_for_each_entry_rcu(nlsk, pos, htbl, i, node) {
119119
sk = (struct sock *)nlsk;
120120

121121
if (!net_eq(sock_net(sk), net))
@@ -172,7 +172,7 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
172172

173173
req = nlmsg_data(cb->nlh);
174174

175-
mutex_lock(&nl_sk_hash_lock);
175+
rcu_read_lock();
176176
read_lock(&nl_table_lock);
177177

178178
if (req->sdiag_protocol == NDIAG_PROTO_ALL) {
@@ -186,15 +186,15 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
186186
} else {
187187
if (req->sdiag_protocol >= MAX_LINKS) {
188188
read_unlock(&nl_table_lock);
189-
mutex_unlock(&nl_sk_hash_lock);
189+
rcu_read_unlock();
190190
return -ENOENT;
191191
}
192192

193193
__netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num);
194194
}
195195

196196
read_unlock(&nl_table_lock);
197-
mutex_unlock(&nl_sk_hash_lock);
197+
rcu_read_unlock();
198198

199199
return skb->len;
200200
}

0 commit comments

Comments
 (0)