]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipmr: Convert ipmr_rtm_dumproute() to RCU.
authorKuniyuki Iwashima <kuniyu@google.com>
Sat, 28 Feb 2026 22:17:24 +0000 (22:17 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 3 Mar 2026 02:49:40 +0000 (18:49 -0800)
ipmr_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, _ipmr_fill_mroute().

_ipmr_fill_mroute() is a wrapper of ipmr_fill_mroute() to cast
struct mr_mfc * to struct mfc_cache *.

ipmr_fill_mroute() can be already called safely under RCU.

Let's convert ipmr_rtm_dumproute() to RCU.

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260228221800.1082070-7-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/ipmr.c

index cb1a5e3a6296db62e240ef4b488cf0ea0170216c..5c8508788fb64c6b8a372577ef72a883fb6945b8 100644 (file)
@@ -2736,15 +2736,17 @@ errout_unlock:
 static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
 {
        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), cb->nlh,
                                            &filter, cb);
                if (err < 0)
-                       return err;
+                       goto out;
        }
 
        if (filter.table_id) {
@@ -2752,19 +2754,28 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
 
                mrt = __ipmr_get_table(sock_net(skb->sk), filter.table_id);
                if (!mrt) {
-                       if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IPMR)
-                               return skb->len;
+                       if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IPMR) {
+                               err = skb->len;
+                               goto out;
+                       }
 
                        NL_SET_ERR_MSG(cb->extack, "ipv4: MR table does not exist");
-                       return -ENOENT;
+                       err = -ENOENT;
+                       goto out;
                }
+
                err = mr_table_dump(mrt, skb, cb, _ipmr_fill_mroute,
                                    &mfc_unres_lock, &filter);
-               return skb->len ? : err;
+               err = skb->len ? : err;
+               goto out;
        }
 
-       return mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter,
-                               _ipmr_fill_mroute, &mfc_unres_lock, &filter);
+       err = mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter,
+                              _ipmr_fill_mroute, &mfc_unres_lock, &filter);
+out:
+       rcu_read_unlock();
+
+       return err;
 }
 
 static const struct nla_policy rtm_ipmr_policy[RTA_MAX + 1] = {
@@ -3299,7 +3310,7 @@ static const struct rtnl_msg_handler ipmr_rtnl_msg_handlers[] __initconst = {
         .doit = ipmr_rtm_route},
        {.protocol = RTNL_FAMILY_IPMR, .msgtype = RTM_GETROUTE,
         .doit = ipmr_rtm_getroute, .dumpit = ipmr_rtm_dumproute,
-        .flags = RTNL_FLAG_DOIT_UNLOCKED},
+        .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},
 };
 
 int __init ip_mr_init(void)