Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipmr: Convert ipmr_rtm_getroute() to RCU.

ipmr_rtm_getroute() calls __ipmr_get_table(), ipmr_cache_find(),
and ipmr_fill_mroute().

The table is not removed until netns dismantle, and net->ipv4.mr_tables
is managed with RCU list API, so __ipmr_get_table() is safe under RCU.

struct mfc_cache is freed by mr_cache_put() after RCU grace period,
so we can use ipmr_cache_find() under RCU. rcu_read_lock() around
it was just to avoid lockdep splat for rhl_for_each_entry_rcu().

ipmr_fill_mroute() calls mr_fill_mroute(), which properly uses RCU.

Let's drop RTNL for ipmr_rtm_getroute() and use RCU instead.

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

authored by

Kuniyuki Iwashima and committed by
Jakub Kicinski
295a17b3 2bd6c9d6

+25 -23
+23 -21
net/ipv4/ipmr.c
··· 2680 2680 { 2681 2681 struct net *net = sock_net(in_skb->sk); 2682 2682 struct nlattr *tb[RTA_MAX + 1]; 2683 - struct sk_buff *skb = NULL; 2684 2683 struct mfc_cache *cache; 2685 2684 struct mr_table *mrt; 2685 + struct sk_buff *skb; 2686 2686 __be32 src, grp; 2687 2687 u32 tableid; 2688 2688 int err; ··· 2695 2695 grp = nla_get_in_addr_default(tb[RTA_DST], 0); 2696 2696 tableid = nla_get_u32_default(tb[RTA_TABLE], 0); 2697 2697 2698 - mrt = __ipmr_get_table(net, tableid ? tableid : RT_TABLE_DEFAULT); 2699 - if (!mrt) { 2700 - err = -ENOENT; 2701 - goto errout_free; 2702 - } 2703 - 2704 - /* entries are added/deleted only under RTNL */ 2705 - rcu_read_lock(); 2706 - cache = ipmr_cache_find(mrt, src, grp); 2707 - rcu_read_unlock(); 2708 - if (!cache) { 2709 - err = -ENOENT; 2710 - goto errout_free; 2711 - } 2712 - 2713 2698 skb = nlmsg_new(mroute_msgsize(false), GFP_KERNEL); 2714 2699 if (!skb) { 2715 2700 err = -ENOBUFS; 2716 - goto errout_free; 2701 + goto errout; 2702 + } 2703 + 2704 + rcu_read_lock(); 2705 + 2706 + mrt = __ipmr_get_table(net, tableid ? tableid : RT_TABLE_DEFAULT); 2707 + if (!mrt) { 2708 + err = -ENOENT; 2709 + goto errout_unlock; 2710 + } 2711 + 2712 + cache = ipmr_cache_find(mrt, src, grp); 2713 + if (!cache) { 2714 + err = -ENOENT; 2715 + goto errout_unlock; 2717 2716 } 2718 2717 2719 2718 err = ipmr_fill_mroute(mrt, skb, NETLINK_CB(in_skb).portid, 2720 2719 nlh->nlmsg_seq, cache, 2721 2720 RTM_NEWROUTE, 0); 2722 2721 if (err < 0) 2723 - goto errout_free; 2722 + goto errout_unlock; 2723 + 2724 + rcu_read_unlock(); 2724 2725 2725 2726 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); 2726 - 2727 2727 errout: 2728 2728 return err; 2729 2729 2730 - errout_free: 2730 + errout_unlock: 2731 + rcu_read_unlock(); 2731 2732 kfree_skb(skb); 2732 2733 goto errout; 2733 2734 } ··· 3298 3297 {.protocol = RTNL_FAMILY_IPMR, .msgtype = RTM_DELROUTE, 3299 3298 .doit = ipmr_rtm_route}, 3300 3299 {.protocol = RTNL_FAMILY_IPMR, .msgtype = RTM_GETROUTE, 3301 - .doit = ipmr_rtm_getroute, .dumpit = ipmr_rtm_dumproute}, 3300 + .doit = ipmr_rtm_getroute, .dumpit = ipmr_rtm_dumproute, 3301 + .flags = RTNL_FLAG_DOIT_UNLOCKED}, 3302 3302 }; 3303 3303 3304 3304 int __init ip_mr_init(void)
+2 -2
net/ipv4/ipmr_base.c
··· 223 223 224 224 rcu_read_lock(); 225 225 vif_dev = rcu_dereference(mrt->vif_table[c->mfc_parent].dev); 226 - if (vif_dev && nla_put_u32(skb, RTA_IIF, vif_dev->ifindex) < 0) { 226 + if (vif_dev && nla_put_u32(skb, RTA_IIF, READ_ONCE(vif_dev->ifindex)) < 0) { 227 227 rcu_read_unlock(); 228 228 return -EMSGSIZE; 229 229 } ··· 252 252 253 253 nhp->rtnh_flags = 0; 254 254 nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; 255 - nhp->rtnh_ifindex = vif_dev->ifindex; 255 + nhp->rtnh_ifindex = READ_ONCE(vif_dev->ifindex); 256 256 nhp->rtnh_len = sizeof(*nhp); 257 257 } 258 258 }