]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ip6mr: Convert ip6mr_rtm_dumproute() to RCU.
authorKuniyuki Iwashima <kuniyu@google.com>
Thu, 4 Jun 2026 22:46:24 +0000 (22:46 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 9 Jun 2026 00:06:23 +0000 (17:06 -0700)
ip6mr_rtm_dumproute() calls mr_table_dump() or mr_rtm_dumproute(),
and mr_rtm_dumproute() finally calls mr_table_dump().

mr_table_dump() calls the passed function, _ip6mr_fill_mroute().

_ip6mr_fill_mroute() is a wrapper for ip6mr_fill_mroute() to cast
struct mr_mfc * to struct mfc6_cache *.

ip6mr_fill_mroute() can already be called safely under RCU.

Let's convert ip6mr_rtm_dumproute() to RCU.

Now there is no user of the rtnl_held field in struct
fib_dump_filter, and the next patch will remove it.

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260604224712.3209821-7-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv6/ip6mr.c

index 51ba22f595068952e4a4e6431adbc3b23392b3a1..380e5eb9416d9e0a1f10189946bb226de173abbb 100644 (file)
@@ -1387,7 +1387,7 @@ static const struct rtnl_msg_handler ip6mr_rtnl_msg_handlers[] __initconst_or_mo
        {.owner = THIS_MODULE, .protocol = RTNL_FAMILY_IP6MR,
         .msgtype = RTM_GETROUTE,
         .doit = ip6mr_rtm_getroute, .dumpit = ip6mr_rtm_dumproute,
-        .flags = RTNL_FLAG_DOIT_UNLOCKED},
+        .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},
 };
 
 int __init ip6_mr_init(void)
@@ -2746,15 +2746,17 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
 {
        const struct nlmsghdr *nlh = cb->nlh;
        struct fib_dump_filter filter = {
-               .rtnl_held = true,
+               .rtnl_held = false,
        };
        int err;
 
+       rcu_read_lock();
+
        if (cb->strict_check) {
                err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh,
                                            &filter, cb);
                if (err < 0)
-                       return err;
+                       goto unlock;
        }
 
        if (filter.table_id) {
@@ -2762,17 +2764,26 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
 
                mrt = __ip6mr_get_table(sock_net(skb->sk), filter.table_id);
                if (!mrt) {
-                       if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR)
-                               return skb->len;
+                       if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR) {
+                               err = skb->len;
+                               goto unlock;
+                       }
 
                        NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist");
-                       return -ENOENT;
+                       err = -ENOENT;
+                       goto unlock;
                }
+
                err = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute,
                                    &mfc_unres_lock, &filter);
-               return skb->len ? : err;
+               err = skb->len ? : err;
+               goto unlock;
        }
 
-       return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
-                               _ip6mr_fill_mroute, &mfc_unres_lock, &filter);
+       err = mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
+                              _ip6mr_fill_mroute, &mfc_unres_lock, &filter);
+unlock:
+       rcu_read_unlock();
+
+       return err;
 }