]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
rtnetlink: change nlk->cb_mutex role
authorEric Dumazet <edumazet@google.com>
Thu, 22 Feb 2024 10:50:14 +0000 (10:50 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 26 Feb 2024 11:46:12 +0000 (11:46 +0000)
In commit af65bdfce98d ("[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: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/netlink/af_netlink.c
net/netlink/af_netlink.h

index 94f3860526bfaa5793e8b3917250ec0e751687b5..84cad7be6d4335bfb5301ef49f84af8e7b3bc842 100644 (file)
@@ -636,7 +636,7 @@ static struct proto netlink_proto = {
 };
 
 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)
 {
        struct sock *sk;
@@ -651,15 +651,11 @@ static int __netlink_create(struct net *net, struct socket *sock,
        sock_init_data(sock, sk);
 
        nlk = nlk_sk(sk);
-       if (cb_mutex) {
-               nlk->cb_mutex = cb_mutex;
-       } else {
-               nlk->cb_mutex = &nlk->cb_def_mutex;
-               mutex_init(nlk->cb_mutex);
-               lockdep_set_class_and_name(nlk->cb_mutex,
+       mutex_init(&nlk->nl_cb_mutex);
+       lockdep_set_class_and_name(&nlk->nl_cb_mutex,
                                           nlk_cb_mutex_keys + protocol,
                                           nlk_cb_mutex_key_strings[protocol]);
-       }
+       nlk->dump_cb_mutex = dump_cb_mutex;
        init_waitqueue_head(&nlk->wait);
 
        sk->sk_destruct = netlink_sock_destruct;
@@ -2209,7 +2205,7 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
        int alloc_size;
 
        if (!lock_taken)
-               mutex_lock(nlk->cb_mutex);
+               mutex_lock(&nlk->nl_cb_mutex);
        if (!nlk->cb_running) {
                err = -EINVAL;
                goto errout_skb;
@@ -2261,14 +2257,22 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
        netlink_skb_set_owner_r(skb, sk);
 
        if (nlk->dump_done_errno > 0) {
+               struct mutex *extra_mutex = nlk->dump_cb_mutex;
+
                cb->extack = &extack;
+
+               if (extra_mutex)
+                       mutex_lock(extra_mutex);
                nlk->dump_done_errno = cb->dump(skb, cb);
+               if (extra_mutex)
+                       mutex_unlock(extra_mutex);
+
                cb->extack = NULL;
        }
 
        if (nlk->dump_done_errno > 0 ||
            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))
                        kfree_skb(skb);
@@ -2302,13 +2306,13 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
        WRITE_ONCE(nlk->cb_running, false);
        module = cb->module;
        skb = cb->skb;
-       mutex_unlock(nlk->cb_mutex);
+       mutex_unlock(&nlk->nl_cb_mutex);
        module_put(module);
        consume_skb(skb);
        return 0;
 
 errout_skb:
-       mutex_unlock(nlk->cb_mutex);
+       mutex_unlock(&nlk->nl_cb_mutex);
        kfree_skb(skb);
        return err;
 }
@@ -2331,7 +2335,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
        }
 
        nlk = nlk_sk(sk);
-       mutex_lock(nlk->cb_mutex);
+       mutex_lock(&nlk->nl_cb_mutex);
        /* A dump is in progress... */
        if (nlk->cb_running) {
                ret = -EBUSY;
@@ -2382,7 +2386,7 @@ error_put:
        module_put(control->module);
 error_unlock:
        sock_put(sk);
-       mutex_unlock(nlk->cb_mutex);
+       mutex_unlock(&nlk->nl_cb_mutex);
 error_free:
        kfree_skb(skb);
        return ret;
index 2145979b9986a0331b34b6ba2fda867f23d0d71c..9751e29d4bbb9ad9cb7900e2cfaedbe7ab138cf4 100644 (file)
@@ -39,8 +39,9 @@ struct netlink_sock {
        bool                    cb_running;
        int                     dump_done_errno;
        struct netlink_callback cb;
-       struct mutex            *cb_mutex;
-       struct mutex            cb_def_mutex;
+       struct mutex            nl_cb_mutex;
+
+       struct mutex            *dump_cb_mutex;
        void                    (*netlink_rcv)(struct sk_buff *skb);
        int                     (*netlink_bind)(struct net *net, int group);
        void                    (*netlink_unbind)(struct net *net, int group);