Commit e39951d9 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

rtnetlink: change nlk->cb_mutex role

In commit af65bdfc ("[NETLINK]: Switch cb_lock spinlock
to mutex and allow to override it"), Patrick McHardy used
a common mutex to protect both nlk->cb and the dump() operations.

The override is used for rtnl dumps, registered with
rntl_register() and rntl_register_module().

We want to be able to opt-out some dump() operations
to not acquire RTNL, so we need to protect nlk->cb
with a per socket mutex.

This patch renames nlk->cb_def_mutex to nlk->nl_cb_mutex

The optional pointer to the mutex used to protect dump()
call is stored in nlk->dump_cb_mutex
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b5590270
...@@ -636,7 +636,7 @@ static struct proto netlink_proto = { ...@@ -636,7 +636,7 @@ static struct proto netlink_proto = {
}; };
static int __netlink_create(struct net *net, struct socket *sock, static int __netlink_create(struct net *net, struct socket *sock,
struct mutex *cb_mutex, int protocol, struct mutex *dump_cb_mutex, int protocol,
int kern) int kern)
{ {
struct sock *sk; struct sock *sk;
...@@ -651,15 +651,11 @@ static int __netlink_create(struct net *net, struct socket *sock, ...@@ -651,15 +651,11 @@ static int __netlink_create(struct net *net, struct socket *sock,
sock_init_data(sock, sk); sock_init_data(sock, sk);
nlk = nlk_sk(sk); nlk = nlk_sk(sk);
if (cb_mutex) { mutex_init(&nlk->nl_cb_mutex);
nlk->cb_mutex = cb_mutex; lockdep_set_class_and_name(&nlk->nl_cb_mutex,
} else {
nlk->cb_mutex = &nlk->cb_def_mutex;
mutex_init(nlk->cb_mutex);
lockdep_set_class_and_name(nlk->cb_mutex,
nlk_cb_mutex_keys + protocol, nlk_cb_mutex_keys + protocol,
nlk_cb_mutex_key_strings[protocol]); nlk_cb_mutex_key_strings[protocol]);
} nlk->dump_cb_mutex = dump_cb_mutex;
init_waitqueue_head(&nlk->wait); init_waitqueue_head(&nlk->wait);
sk->sk_destruct = netlink_sock_destruct; sk->sk_destruct = netlink_sock_destruct;
...@@ -2209,7 +2205,7 @@ static int netlink_dump(struct sock *sk, bool lock_taken) ...@@ -2209,7 +2205,7 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
int alloc_size; int alloc_size;
if (!lock_taken) if (!lock_taken)
mutex_lock(nlk->cb_mutex); mutex_lock(&nlk->nl_cb_mutex);
if (!nlk->cb_running) { if (!nlk->cb_running) {
err = -EINVAL; err = -EINVAL;
goto errout_skb; goto errout_skb;
...@@ -2261,14 +2257,22 @@ static int netlink_dump(struct sock *sk, bool lock_taken) ...@@ -2261,14 +2257,22 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
netlink_skb_set_owner_r(skb, sk); netlink_skb_set_owner_r(skb, sk);
if (nlk->dump_done_errno > 0) { if (nlk->dump_done_errno > 0) {
struct mutex *extra_mutex = nlk->dump_cb_mutex;
cb->extack = &extack; cb->extack = &extack;
if (extra_mutex)
mutex_lock(extra_mutex);
nlk->dump_done_errno = cb->dump(skb, cb); nlk->dump_done_errno = cb->dump(skb, cb);
if (extra_mutex)
mutex_unlock(extra_mutex);
cb->extack = NULL; cb->extack = NULL;
} }
if (nlk->dump_done_errno > 0 || if (nlk->dump_done_errno > 0 ||
skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) { skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) {
mutex_unlock(nlk->cb_mutex); mutex_unlock(&nlk->nl_cb_mutex);
if (sk_filter(sk, skb)) if (sk_filter(sk, skb))
kfree_skb(skb); kfree_skb(skb);
...@@ -2302,13 +2306,13 @@ static int netlink_dump(struct sock *sk, bool lock_taken) ...@@ -2302,13 +2306,13 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
WRITE_ONCE(nlk->cb_running, false); WRITE_ONCE(nlk->cb_running, false);
module = cb->module; module = cb->module;
skb = cb->skb; skb = cb->skb;
mutex_unlock(nlk->cb_mutex); mutex_unlock(&nlk->nl_cb_mutex);
module_put(module); module_put(module);
consume_skb(skb); consume_skb(skb);
return 0; return 0;
errout_skb: errout_skb:
mutex_unlock(nlk->cb_mutex); mutex_unlock(&nlk->nl_cb_mutex);
kfree_skb(skb); kfree_skb(skb);
return err; return err;
} }
...@@ -2331,7 +2335,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, ...@@ -2331,7 +2335,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
} }
nlk = nlk_sk(sk); nlk = nlk_sk(sk);
mutex_lock(nlk->cb_mutex); mutex_lock(&nlk->nl_cb_mutex);
/* A dump is in progress... */ /* A dump is in progress... */
if (nlk->cb_running) { if (nlk->cb_running) {
ret = -EBUSY; ret = -EBUSY;
...@@ -2382,7 +2386,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, ...@@ -2382,7 +2386,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
module_put(control->module); module_put(control->module);
error_unlock: error_unlock:
sock_put(sk); sock_put(sk);
mutex_unlock(nlk->cb_mutex); mutex_unlock(&nlk->nl_cb_mutex);
error_free: error_free:
kfree_skb(skb); kfree_skb(skb);
return ret; return ret;
......
...@@ -39,8 +39,9 @@ struct netlink_sock { ...@@ -39,8 +39,9 @@ struct netlink_sock {
bool cb_running; bool cb_running;
int dump_done_errno; int dump_done_errno;
struct netlink_callback cb; struct netlink_callback cb;
struct mutex *cb_mutex; struct mutex nl_cb_mutex;
struct mutex cb_def_mutex;
struct mutex *dump_cb_mutex;
void (*netlink_rcv)(struct sk_buff *skb); void (*netlink_rcv)(struct sk_buff *skb);
int (*netlink_bind)(struct net *net, int group); int (*netlink_bind)(struct net *net, int group);
void (*netlink_unbind)(struct net *net, int group); void (*netlink_unbind)(struct net *net, int group);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment