* FAILED: patch "[PATCH] ipv6: start using dst_dev_rcu()" failed to apply to 6.12-stable tree
@ 2026-09-17 11:15 gregkh
2026-09-17 18:39 ` [PATCH 6.12.y 1/2] ipv6: mcast: Don't hold RTNL for MCAST_ socket options Sasha Levin
0 siblings, 1 reply; 4+ messages in thread
From: gregkh @ 2026-09-17 11:15 UTC (permalink / raw)
To: edumazet, dsahern, kuba; +Cc: stable
The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x b775ecf1655cedbc465fd6699ab18a2bc4e7a352
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026091758-subsector-deity-17bd@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From b775ecf1655cedbc465fd6699ab18a2bc4e7a352 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <edumazet@google.com>
Date: Thu, 28 Aug 2025 19:58:17 +0000
Subject: [PATCH] ipv6: start using dst_dev_rcu()
Refactor icmpv6_xrlim_allow() and ip6_dst_hoplimit()
so that we acquire rcu_read_lock() a bit longer
to be able to use dst_dev_rcu() instead of dst_dev().
__ip6_rt_update_pmtu() and rt6_do_redirect can directly
use dst_dev_rcu() in sections already holding rcu_read_lock().
Small changes to use dst_dev_net_rcu() in
ip6_default_advmss(), ipv6_sock_ac_join(),
ip6_mc_find_dev() and ndisc_send_skb().
Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250828195823.3958522-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index f8a8e46286b8..52599584422b 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -104,7 +104,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
rcu_read_lock();
rt = rt6_lookup(net, addr, NULL, 0, NULL, 0);
if (rt) {
- dev = dst_dev(&rt->dst);
+ dev = dst_dev_rcu(&rt->dst);
netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
ip6_rt_put(rt);
} else if (ishost) {
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 44550957fd4e..95cdd4cacb00 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -209,7 +209,8 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
* this lookup should be more aggressive (not longer than timeout).
*/
dst = ip6_route_output(net, sk, fl6);
- dev = dst_dev(dst);
+ rcu_read_lock();
+ dev = dst_dev_rcu(dst);
if (dst->error) {
IP6_INC_STATS(net, ip6_dst_idev(dst),
IPSTATS_MIB_OUTNOROUTES);
@@ -224,11 +225,10 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
if (rt->rt6i_dst.plen < 128)
tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
- rcu_read_lock();
peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr);
res = inet_peer_xrlim_allow(peer, tmo);
- rcu_read_unlock();
}
+ rcu_read_unlock();
if (!res)
__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
ICMP6_MIB_RATELIMITHOST);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 55c49dc14b1b..016b572e7d6f 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -180,7 +180,7 @@ static struct net_device *ip6_mc_find_dev(struct net *net,
rcu_read_lock();
rt = rt6_lookup(net, group, NULL, 0, NULL, 0);
if (rt) {
- dev = dst_dev(&rt->dst);
+ dev = dst_dev_rcu(&rt->dst);
dev_hold(dev);
ip6_rt_put(rt);
}
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 57aaa7ae8ac3..f427e41e9c49 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -505,7 +505,7 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
ip6_nd_hdr(skb, saddr, daddr, READ_ONCE(inet6_sk(sk)->hop_limit), skb->len);
- dev = dst_dev(dst);
+ dev = dst_dev_rcu(dst);
idev = __in6_dev_get(dev);
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS);
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index d21fe27fe21e..1c9b283a4132 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -104,18 +104,20 @@ EXPORT_SYMBOL(ip6_find_1stfragopt);
int ip6_dst_hoplimit(struct dst_entry *dst)
{
int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
+
+ rcu_read_lock();
if (hoplimit == 0) {
- struct net_device *dev = dst_dev(dst);
+ struct net_device *dev = dst_dev_rcu(dst);
struct inet6_dev *idev;
- rcu_read_lock();
idev = __in6_dev_get(dev);
if (idev)
hoplimit = READ_ONCE(idev->cnf.hop_limit);
else
hoplimit = READ_ONCE(dev_net(dev)->ipv6.devconf_all->hop_limit);
- rcu_read_unlock();
}
+ rcu_read_unlock();
+
return hoplimit;
}
EXPORT_SYMBOL(ip6_dst_hoplimit);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 3299cfa12e21..3371f16b7a3e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2943,7 +2943,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
if (res.f6i->nh) {
struct fib6_nh_match_arg arg = {
- .dev = dst_dev(dst),
+ .dev = dst_dev_rcu(dst),
.gw = &rt6->rt6i_gateway,
};
@@ -3238,7 +3238,6 @@ EXPORT_SYMBOL_GPL(ip6_sk_redirect);
static unsigned int ip6_default_advmss(const struct dst_entry *dst)
{
- struct net_device *dev = dst_dev(dst);
unsigned int mtu = dst_mtu(dst);
struct net *net;
@@ -3246,7 +3245,7 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst)
rcu_read_lock();
- net = dev_net_rcu(dev);
+ net = dst_dev_net_rcu(dst);
if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
@@ -4301,7 +4300,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
if (res.f6i->nh) {
struct fib6_nh_match_arg arg = {
- .dev = dst_dev(dst),
+ .dev = dst_dev_rcu(dst),
.gw = &rt->rt6i_gateway,
};
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 6.12.y 1/2] ipv6: mcast: Don't hold RTNL for MCAST_ socket options.
2026-09-17 11:15 FAILED: patch "[PATCH] ipv6: start using dst_dev_rcu()" failed to apply to 6.12-stable tree gregkh
@ 2026-09-17 18:39 ` Sasha Levin
2026-09-17 18:39 ` [PATCH 6.12.y 2/2] ipv6: start using dst_dev_rcu() Sasha Levin
0 siblings, 1 reply; 4+ messages in thread
From: Sasha Levin @ 2026-09-17 18:39 UTC (permalink / raw)
To: stable; +Cc: Kuniyuki Iwashima, Eric Dumazet, Jakub Kicinski, Sasha Levin
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit e6e14d582dd2cbee362c48a1865f8d03ca0a5611 ]
In ip6_mc_source() and ip6_mc_msfilter(), per-socket mld data is
protected by lock_sock() and inet6_dev->mc_lock is also held for
some per-interface functions.
ip6_mc_find_dev_rtnl() only depends on RTNL. If we want to remove
it, we need to check inet6_dev->dead under mc_lock to close the race
with addrconf_ifdown(), as mentioned earlier.
Let's do that and drop RTNL for the rest of MCAST_ socket options.
Note that ip6_mc_msfilter() has unnecessary lock dances and they
are integrated into one to avoid the last-minute error and simplify
the error handling.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250702230210.3115355-10-kuni1840@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Backport adaptation for Linux 6.12:
Keep setsockopt_needs_rtnl() unchanged. The stable multicast join and
drop paths still require RTNL, including source-group joins and the
leave-group cases in ip6_mc_source() and ip6_mc_msfilter(). The stable
addrconf_ifdown() also still publishes idev->dead outside mc_lock.
Retaining RTNL avoids depending on the missing multicast lock-removal
predecessors while keeping the referenced lookup and filter locking
changes needed by the target.
Move the existing multicast lookup before __ipv6_sock_mc_join(), matching
the location used by the target's parent. A plain patch check succeeds
without this move, but a three-way cherry-pick otherwise sees the target
as modifying a deleted helper and conflicts. Keep the helper's inet6_dev
return type and existing callers; no additional helper is introduced.
Prepare the existing ipv6_sock_ac_join() lookup for target commit
b775ecf1655cedbc465fd6699ab18a2bc4e7a352 as well: use dst_dev() under RCU,
take a tracked device reference before releasing the route, and balance
the references for the explicit-interface and fallback-device paths at
the common exit. Keep its RTNL requirement and the existing device
lookup APIs. This supplies the target's anycast context without adding
functions or importing the unrelated anycast lock-removal series.
[ sashal: Reduced backport -- upstream e6e14d582dd2c touches 2 file(s), this
backport carries 2. Not backported here:
net/ipv6/ipv6_sockglue.c
This note is generated from the file lists only; see the resolution record
for the reasoning. ]
Stable-dep-of: b775ecf1655c ("ipv6: start using dst_dev_rcu()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv6/anycast.c | 25 ++++++++---
net/ipv6/mcast.c | 108 ++++++++++++++++++++++++++-------------------
2 files changed, 80 insertions(+), 53 deletions(-)
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 0627c4c18d1a5..19ab520ea049d 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -65,8 +65,9 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
struct ipv6_pinfo *np = inet6_sk(sk);
struct net_device *dev = NULL;
struct inet6_dev *idev;
- struct ipv6_ac_socklist *pac;
+ struct ipv6_ac_socklist *pac = NULL;
struct net *net = sock_net(sk);
+ netdevice_tracker dev_tracker;
int ishost = !net->ipv6.devconf_all->forwarding;
int err = 0;
@@ -78,32 +79,41 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
return -EINVAL;
if (ifindex)
- dev = __dev_get_by_index(net, ifindex);
+ dev = netdev_get_by_index(net, ifindex, &dev_tracker, GFP_KERNEL);
- if (ipv6_chk_addr_and_flags(net, addr, dev, true, 0, IFA_F_TENTATIVE))
- return -EINVAL;
+ if (ipv6_chk_addr_and_flags(net, addr, dev, true, 0, IFA_F_TENTATIVE)) {
+ err = -EINVAL;
+ goto error;
+ }
pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL);
- if (!pac)
- return -ENOMEM;
+ if (!pac) {
+ err = -ENOMEM;
+ goto error;
+ }
pac->acl_next = NULL;
pac->acl_addr = *addr;
if (ifindex == 0) {
struct rt6_info *rt;
+ rcu_read_lock();
rt = rt6_lookup(net, addr, NULL, 0, NULL, 0);
if (rt) {
- dev = rt->dst.dev;
+ dev = dst_dev(&rt->dst);
+ netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
ip6_rt_put(rt);
} else if (ishost) {
+ rcu_read_unlock();
err = -EADDRNOTAVAIL;
goto error;
} else {
/* router, no matching interface: just pick one */
dev = __dev_get_by_flags(net, IFF_UP,
IFF_UP | IFF_LOOPBACK);
+ netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
}
+ rcu_read_unlock();
}
if (!dev) {
@@ -144,6 +154,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
}
error:
+ netdev_put(dev, &dev_tracker);
if (pac)
sock_kfree_s(sk, pac, sizeof(*pac));
return err;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 92f321635e4ec..8a37e878e5f8e 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -166,6 +166,39 @@ static int unsolicited_report_interval(struct inet6_dev *idev)
return iv > 0 ? iv : 1;
}
+static struct inet6_dev *ip6_mc_find_dev(struct net *net,
+ const struct in6_addr *group,
+ int ifindex)
+{
+ struct net_device *dev = NULL;
+ struct inet6_dev *idev;
+
+ if (ifindex == 0) {
+ struct rt6_info *rt;
+
+ rcu_read_lock();
+ rt = rt6_lookup(net, group, NULL, 0, NULL, 0);
+ if (rt) {
+ dev = dst_dev(&rt->dst);
+ dev_hold(dev);
+ ip6_rt_put(rt);
+ }
+ rcu_read_unlock();
+ } else {
+ dev = dev_get_by_index(net, ifindex);
+ }
+ if (!dev)
+ return NULL;
+
+ idev = in6_dev_get(dev);
+ dev_put(dev);
+
+ if (!idev)
+ return NULL;
+
+ return idev;
+}
+
/*
* socket join on multicast group
*/
@@ -290,34 +323,6 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
}
EXPORT_SYMBOL(ipv6_sock_mc_drop);
-static struct inet6_dev *ip6_mc_find_dev_rtnl(struct net *net,
- const struct in6_addr *group,
- int ifindex)
-{
- struct net_device *dev = NULL;
- struct inet6_dev *idev = NULL;
-
- if (ifindex == 0) {
- struct rt6_info *rt = rt6_lookup(net, group, NULL, 0, NULL, 0);
-
- if (rt) {
- dev = rt->dst.dev;
- ip6_rt_put(rt);
- }
- } else {
- dev = __dev_get_by_index(net, ifindex);
- }
-
- if (!dev)
- return NULL;
- idev = __in6_dev_get(dev);
- if (!idev)
- return NULL;
- if (idev->dead)
- return NULL;
- return idev;
-}
-
void __ipv6_sock_mc_close(struct sock *sk)
{
struct ipv6_pinfo *np = inet6_sk(sk);
@@ -362,16 +367,16 @@ void ipv6_sock_mc_close(struct sock *sk)
}
int ip6_mc_source(int add, int omode, struct sock *sk,
- struct group_source_req *pgsr)
+ struct group_source_req *pgsr)
{
+ struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct in6_addr *source, *group;
+ struct net *net = sock_net(sk);
struct ipv6_mc_socklist *pmc;
- struct inet6_dev *idev;
- struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct ip6_sf_socklist *psl;
- struct net *net = sock_net(sk);
- int i, j, rv;
+ struct inet6_dev *idev;
int leavegroup = 0;
+ int i, j, rv;
int err;
source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr;
@@ -380,13 +385,19 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
if (!ipv6_addr_is_multicast(group))
return -EINVAL;
- idev = ip6_mc_find_dev_rtnl(net, group, pgsr->gsr_interface);
+ idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface);
if (!idev)
return -ENODEV;
+ mutex_lock(&idev->mc_lock);
+
+ if (idev->dead) {
+ err = -ENODEV;
+ goto done;
+ }
+
err = -EADDRNOTAVAIL;
- mutex_lock(&idev->mc_lock);
for_each_pmc_socklock(inet6, sk, pmc) {
if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface)
continue;
@@ -483,6 +494,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
ip6_mc_add_src(idev, group, omode, 1, source, 1);
done:
mutex_unlock(&idev->mc_lock);
+ in6_dev_put(idev);
if (leavegroup)
err = ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group);
return err;
@@ -491,12 +503,12 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
struct sockaddr_storage *list)
{
- const struct in6_addr *group;
- struct ipv6_mc_socklist *pmc;
- struct inet6_dev *idev;
struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct ip6_sf_socklist *newpsl, *psl;
struct net *net = sock_net(sk);
+ const struct in6_addr *group;
+ struct ipv6_mc_socklist *pmc;
+ struct inet6_dev *idev;
int leavegroup = 0;
int i, err;
@@ -508,10 +520,17 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
gsf->gf_fmode != MCAST_EXCLUDE)
return -EINVAL;
- idev = ip6_mc_find_dev_rtnl(net, group, gsf->gf_interface);
+ idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
if (!idev)
return -ENODEV;
+ mutex_lock(&idev->mc_lock);
+
+ if (idev->dead) {
+ err = -ENODEV;
+ goto done;
+ }
+
err = 0;
if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
@@ -544,24 +563,19 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
psin6 = (struct sockaddr_in6 *)list;
newpsl->sl_addr[i] = psin6->sin6_addr;
}
- mutex_lock(&idev->mc_lock);
+
err = ip6_mc_add_src(idev, group, gsf->gf_fmode,
newpsl->sl_count, newpsl->sl_addr, 0);
if (err) {
- mutex_unlock(&idev->mc_lock);
sock_kfree_s(sk, newpsl, struct_size(newpsl, sl_addr,
newpsl->sl_max));
goto done;
}
- mutex_unlock(&idev->mc_lock);
} else {
newpsl = NULL;
- mutex_lock(&idev->mc_lock);
ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
- mutex_unlock(&idev->mc_lock);
}
- mutex_lock(&idev->mc_lock);
psl = sock_dereference(pmc->sflist, sk);
if (psl) {
ip6_mc_del_src(idev, group, pmc->sfmode,
@@ -571,12 +585,14 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
} else {
ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
}
+
rcu_assign_pointer(pmc->sflist, newpsl);
- mutex_unlock(&idev->mc_lock);
kfree_rcu(psl, rcu);
pmc->sfmode = gsf->gf_fmode;
err = 0;
done:
+ mutex_unlock(&idev->mc_lock);
+ in6_dev_put(idev);
if (leavegroup)
err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
return err;
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 6.12.y 2/2] ipv6: start using dst_dev_rcu()
2026-09-17 18:39 ` [PATCH 6.12.y 1/2] ipv6: mcast: Don't hold RTNL for MCAST_ socket options Sasha Levin
@ 2026-09-17 18:39 ` Sasha Levin
2026-09-30 13:18 ` Greg KH
0 siblings, 1 reply; 4+ messages in thread
From: Sasha Levin @ 2026-09-17 18:39 UTC (permalink / raw)
To: stable; +Cc: Eric Dumazet, David Ahern, Jakub Kicinski, Sasha Levin
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit b775ecf1655cedbc465fd6699ab18a2bc4e7a352 ]
Refactor icmpv6_xrlim_allow() and ip6_dst_hoplimit()
so that we acquire rcu_read_lock() a bit longer
to be able to use dst_dev_rcu() instead of dst_dev().
__ip6_rt_update_pmtu() and rt6_do_redirect can directly
use dst_dev_rcu() in sections already holding rcu_read_lock().
Small changes to use dst_dev_net_rcu() in
ip6_default_advmss(), ipv6_sock_ac_join(),
ip6_mc_find_dev() and ndisc_send_skb().
Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250828195823.3958522-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv6/anycast.c | 2 +-
net/ipv6/icmp.c | 6 +++---
net/ipv6/mcast.c | 2 +-
net/ipv6/ndisc.c | 2 +-
net/ipv6/output_core.c | 8 +++++---
net/ipv6/route.c | 7 +++----
6 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 19ab520ea049d..8bf06f8cf9d68 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -100,7 +100,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
rcu_read_lock();
rt = rt6_lookup(net, addr, NULL, 0, NULL, 0);
if (rt) {
- dev = dst_dev(&rt->dst);
+ dev = dst_dev_rcu(&rt->dst);
netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
ip6_rt_put(rt);
} else if (ishost) {
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 229ae205450d3..e4e40f0694238 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -209,7 +209,8 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
* this lookup should be more aggressive (not longer than timeout).
*/
dst = ip6_route_output(net, sk, fl6);
- dev = dst_dev(dst);
+ rcu_read_lock();
+ dev = dst_dev_rcu(dst);
if (dst->error) {
IP6_INC_STATS(net, ip6_dst_idev(dst),
IPSTATS_MIB_OUTNOROUTES);
@@ -224,11 +225,10 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
if (rt->rt6i_dst.plen < 128)
tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
- rcu_read_lock();
peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr);
res = inet_peer_xrlim_allow(peer, tmo);
- rcu_read_unlock();
}
+ rcu_read_unlock();
if (!res)
__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
ICMP6_MIB_RATELIMITHOST);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 8a37e878e5f8e..298bf64899548 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -179,7 +179,7 @@ static struct inet6_dev *ip6_mc_find_dev(struct net *net,
rcu_read_lock();
rt = rt6_lookup(net, group, NULL, 0, NULL, 0);
if (rt) {
- dev = dst_dev(&rt->dst);
+ dev = dst_dev_rcu(&rt->dst);
dev_hold(dev);
ip6_rt_put(rt);
}
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 87bed84a00532..26ad7cab0383f 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -508,7 +508,7 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
ip6_nd_hdr(skb, saddr, daddr, READ_ONCE(inet6_sk(sk)->hop_limit), skb->len);
- dev = dst_dev(dst);
+ dev = dst_dev_rcu(dst);
idev = __in6_dev_get(dev);
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS);
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index 90a178dd24aae..5be101401a00e 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -104,18 +104,20 @@ EXPORT_SYMBOL(ip6_find_1stfragopt);
int ip6_dst_hoplimit(struct dst_entry *dst)
{
int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
+
+ rcu_read_lock();
if (hoplimit == 0) {
- struct net_device *dev = dst_dev(dst);
+ struct net_device *dev = dst_dev_rcu(dst);
struct inet6_dev *idev;
- rcu_read_lock();
idev = __in6_dev_get(dev);
if (idev)
hoplimit = READ_ONCE(idev->cnf.hop_limit);
else
hoplimit = READ_ONCE(dev_net(dev)->ipv6.devconf_all->hop_limit);
- rcu_read_unlock();
}
+ rcu_read_unlock();
+
return hoplimit;
}
EXPORT_SYMBOL(ip6_dst_hoplimit);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 3e5bf8a5b32b2..f49b0578ae347 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2949,7 +2949,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
if (res.f6i->nh) {
struct fib6_nh_match_arg arg = {
- .dev = dst_dev(dst),
+ .dev = dst_dev_rcu(dst),
.gw = &rt6->rt6i_gateway,
};
@@ -3244,7 +3244,6 @@ EXPORT_SYMBOL_GPL(ip6_sk_redirect);
static unsigned int ip6_default_advmss(const struct dst_entry *dst)
{
- struct net_device *dev = dst_dev(dst);
unsigned int mtu = dst_mtu(dst);
struct net *net;
@@ -3252,7 +3251,7 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst)
rcu_read_lock();
- net = dev_net_rcu(dev);
+ net = dst_dev_net_rcu(dst);
if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
@@ -4266,7 +4265,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
if (res.f6i->nh) {
struct fib6_nh_match_arg arg = {
- .dev = dst_dev(dst),
+ .dev = dst_dev_rcu(dst),
.gw = &rt->rt6i_gateway,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 6.12.y 2/2] ipv6: start using dst_dev_rcu()
2026-09-17 18:39 ` [PATCH 6.12.y 2/2] ipv6: start using dst_dev_rcu() Sasha Levin
@ 2026-09-30 13:18 ` Greg KH
0 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2026-09-30 13:18 UTC (permalink / raw)
To: Sasha Levin; +Cc: stable, Eric Dumazet, David Ahern, Jakub Kicinski
On Thu, Sep 17, 2026 at 02:39:45PM -0400, Sasha Levin wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> [ Upstream commit b775ecf1655cedbc465fd6699ab18a2bc4e7a352 ]
>
> Refactor icmpv6_xrlim_allow() and ip6_dst_hoplimit()
> so that we acquire rcu_read_lock() a bit longer
> to be able to use dst_dev_rcu() instead of dst_dev().
>
> __ip6_rt_update_pmtu() and rt6_do_redirect can directly
> use dst_dev_rcu() in sections already holding rcu_read_lock().
>
> Small changes to use dst_dev_net_rcu() in
> ip6_default_advmss(), ipv6_sock_ac_join(),
> ip6_mc_find_dev() and ndisc_send_skb().
>
> Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Reviewed-by: David Ahern <dsahern@kernel.org>
> Link: https://patch.msgid.link/20250828195823.3958522-3-edumazet@google.com
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> Signed-off-by: Sasha Levin <sashal@kernel.org>
> ---
> net/ipv6/anycast.c | 2 +-
> net/ipv6/icmp.c | 6 +++---
> net/ipv6/mcast.c | 2 +-
> net/ipv6/ndisc.c | 2 +-
> net/ipv6/output_core.c | 8 +++++---
> net/ipv6/route.c | 7 +++----
> 6 files changed, 14 insertions(+), 13 deletions(-)
>
> diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
> index 19ab520ea049d..8bf06f8cf9d68 100644
> --- a/net/ipv6/anycast.c
> +++ b/net/ipv6/anycast.c
> @@ -100,7 +100,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
> rcu_read_lock();
> rt = rt6_lookup(net, addr, NULL, 0, NULL, 0);
> if (rt) {
> - dev = dst_dev(&rt->dst);
> + dev = dst_dev_rcu(&rt->dst);
> netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
> ip6_rt_put(rt);
> } else if (ishost) {
> diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
> index 229ae205450d3..e4e40f0694238 100644
> --- a/net/ipv6/icmp.c
> +++ b/net/ipv6/icmp.c
> @@ -209,7 +209,8 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
> * this lookup should be more aggressive (not longer than timeout).
> */
> dst = ip6_route_output(net, sk, fl6);
> - dev = dst_dev(dst);
> + rcu_read_lock();
> + dev = dst_dev_rcu(dst);
> if (dst->error) {
> IP6_INC_STATS(net, ip6_dst_idev(dst),
> IPSTATS_MIB_OUTNOROUTES);
> @@ -224,11 +225,10 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
> if (rt->rt6i_dst.plen < 128)
> tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
>
> - rcu_read_lock();
> peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr);
> res = inet_peer_xrlim_allow(peer, tmo);
> - rcu_read_unlock();
> }
> + rcu_read_unlock();
> if (!res)
> __ICMP6_INC_STATS(net, ip6_dst_idev(dst),
> ICMP6_MIB_RATELIMITHOST);
> diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
> index 8a37e878e5f8e..298bf64899548 100644
> --- a/net/ipv6/mcast.c
> +++ b/net/ipv6/mcast.c
> @@ -179,7 +179,7 @@ static struct inet6_dev *ip6_mc_find_dev(struct net *net,
> rcu_read_lock();
> rt = rt6_lookup(net, group, NULL, 0, NULL, 0);
> if (rt) {
> - dev = dst_dev(&rt->dst);
> + dev = dst_dev_rcu(&rt->dst);
> dev_hold(dev);
> ip6_rt_put(rt);
> }
> diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
> index 87bed84a00532..26ad7cab0383f 100644
> --- a/net/ipv6/ndisc.c
> +++ b/net/ipv6/ndisc.c
> @@ -508,7 +508,7 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
>
> ip6_nd_hdr(skb, saddr, daddr, READ_ONCE(inet6_sk(sk)->hop_limit), skb->len);
>
> - dev = dst_dev(dst);
> + dev = dst_dev_rcu(dst);
> idev = __in6_dev_get(dev);
> IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS);
>
> diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
> index 90a178dd24aae..5be101401a00e 100644
> --- a/net/ipv6/output_core.c
> +++ b/net/ipv6/output_core.c
> @@ -104,18 +104,20 @@ EXPORT_SYMBOL(ip6_find_1stfragopt);
> int ip6_dst_hoplimit(struct dst_entry *dst)
> {
> int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
> +
> + rcu_read_lock();
> if (hoplimit == 0) {
> - struct net_device *dev = dst_dev(dst);
> + struct net_device *dev = dst_dev_rcu(dst);
> struct inet6_dev *idev;
>
> - rcu_read_lock();
> idev = __in6_dev_get(dev);
> if (idev)
> hoplimit = READ_ONCE(idev->cnf.hop_limit);
> else
> hoplimit = READ_ONCE(dev_net(dev)->ipv6.devconf_all->hop_limit);
> - rcu_read_unlock();
> }
> + rcu_read_unlock();
> +
> return hoplimit;
> }
> EXPORT_SYMBOL(ip6_dst_hoplimit);
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index 3e5bf8a5b32b2..f49b0578ae347 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -2949,7 +2949,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
>
> if (res.f6i->nh) {
> struct fib6_nh_match_arg arg = {
> - .dev = dst_dev(dst),
> + .dev = dst_dev_rcu(dst),
> .gw = &rt6->rt6i_gateway,
> };
>
> @@ -3244,7 +3244,6 @@ EXPORT_SYMBOL_GPL(ip6_sk_redirect);
>
> static unsigned int ip6_default_advmss(const struct dst_entry *dst)
> {
> - struct net_device *dev = dst_dev(dst);
> unsigned int mtu = dst_mtu(dst);
> struct net *net;
>
> @@ -3252,7 +3251,7 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst)
>
> rcu_read_lock();
>
> - net = dev_net_rcu(dev);
> + net = dst_dev_net_rcu(dst);
> if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
> mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
>
> @@ -4266,7 +4265,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
>
> if (res.f6i->nh) {
> struct fib6_nh_match_arg arg = {
> - .dev = dst_dev(dst),
> + .dev = dst_dev_rcu(dst),
> .gw = &rt->rt6i_gateway,
> };
>
> --
> 2.53.0
>
>
did not apply
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-30 13:18 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17 11:15 FAILED: patch "[PATCH] ipv6: start using dst_dev_rcu()" failed to apply to 6.12-stable tree gregkh
2026-09-17 18:39 ` [PATCH 6.12.y 1/2] ipv6: mcast: Don't hold RTNL for MCAST_ socket options Sasha Levin
2026-09-17 18:39 ` [PATCH 6.12.y 2/2] ipv6: start using dst_dev_rcu() Sasha Levin
2026-09-30 13:18 ` Greg KH
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox