Skip to content

Commit 21e4902

Browse files
tgrafdavem330
authored andcommitted
netlink: Lockless lookup with RCU grace period in socket release
Defers the release of the socket reference using call_rcu() to allow using an RCU read-side protected call to rhashtable_lookup() This restores behaviour and performance gains as previously introduced by e341694 ("netlink: Convert netlink_lookup() to use RCU protected hash table") without the side effect of severely delayed socket destruction. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent f89bd6f commit 21e4902

File tree

2 files changed

+17
-16
lines changed

2 files changed

+17
-16
lines changed

net/netlink/af_netlink.c

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,12 @@ static int netlink_dump(struct sock *sk);
9797
static void netlink_skb_destructor(struct sk_buff *skb);
9898

9999
/* nl_table locking explained:
100-
* Lookup and traversal are protected with nl_sk_hash_lock or nl_table_lock
101-
* combined with an RCU read-side lock. Insertion and removal are protected
102-
* with nl_sk_hash_lock while using RCU list modification primitives and may
103-
* run in parallel to nl_table_lock protected lookups. Destruction of the
104-
* Netlink socket may only occur *after* nl_table_lock has been acquired
105-
* either during or after the socket has been removed from the list.
100+
* 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
102+
* modification primitives and may run in parallel to RCU protected lookups.
103+
* Destruction of the Netlink socket may only occur *after* nl_table_lock has
104+
* been acquired * either during or after the socket has been removed from
105+
* the list and after an RCU grace period.
106106
*/
107107
DEFINE_RWLOCK(nl_table_lock);
108108
EXPORT_SYMBOL_GPL(nl_table_lock);
@@ -1003,13 +1003,11 @@ static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid)
10031003
struct netlink_table *table = &nl_table[protocol];
10041004
struct sock *sk;
10051005

1006-
read_lock(&nl_table_lock);
10071006
rcu_read_lock();
10081007
sk = __netlink_lookup(table, portid, net);
10091008
if (sk)
10101009
sock_hold(sk);
10111010
rcu_read_unlock();
1012-
read_unlock(&nl_table_lock);
10131011

10141012
return sk;
10151013
}
@@ -1183,6 +1181,13 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
11831181
goto out;
11841182
}
11851183

1184+
static void deferred_put_nlk_sk(struct rcu_head *head)
1185+
{
1186+
struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu);
1187+
1188+
sock_put(&nlk->sk);
1189+
}
1190+
11861191
static int netlink_release(struct socket *sock)
11871192
{
11881193
struct sock *sk = sock->sk;
@@ -1248,7 +1253,7 @@ static int netlink_release(struct socket *sock)
12481253
local_bh_disable();
12491254
sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1);
12501255
local_bh_enable();
1251-
sock_put(sk);
1256+
call_rcu(&nlk->rcu, deferred_put_nlk_sk);
12521257
return 0;
12531258
}
12541259

@@ -1263,19 +1268,16 @@ static int netlink_autobind(struct socket *sock)
12631268

12641269
retry:
12651270
cond_resched();
1266-
netlink_table_grab();
12671271
rcu_read_lock();
12681272
if (__netlink_lookup(table, portid, net)) {
12691273
/* Bind collision, search negative portid values. */
12701274
portid = rover--;
12711275
if (rover > -4097)
12721276
rover = -4097;
12731277
rcu_read_unlock();
1274-
netlink_table_ungrab();
12751278
goto retry;
12761279
}
12771280
rcu_read_unlock();
1278-
netlink_table_ungrab();
12791281

12801282
err = netlink_insert(sk, net, portid);
12811283
if (err == -EADDRINUSE)
@@ -2910,9 +2912,8 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos)
29102912
}
29112913

29122914
static void *netlink_seq_start(struct seq_file *seq, loff_t *pos)
2913-
__acquires(nl_table_lock) __acquires(RCU)
2915+
__acquires(RCU)
29142916
{
2915-
read_lock(&nl_table_lock);
29162917
rcu_read_lock();
29172918
return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN;
29182919
}
@@ -2964,10 +2965,9 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
29642965
}
29652966

29662967
static void netlink_seq_stop(struct seq_file *seq, void *v)
2967-
__releases(RCU) __releases(nl_table_lock)
2968+
__releases(RCU)
29682969
{
29692970
rcu_read_unlock();
2970-
read_unlock(&nl_table_lock);
29712971
}
29722972

29732973

net/netlink/af_netlink.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct netlink_sock {
5050
#endif /* CONFIG_NETLINK_MMAP */
5151

5252
struct rhash_head node;
53+
struct rcu_head rcu;
5354
};
5455

5556
static inline struct netlink_sock *nlk_sk(struct sock *sk)

0 commit comments

Comments
 (0)