Thanks guys. This patch should fix both problems.
Herbert, if we check inetdev->dead when trying to grab
a reference it fixes the RCU destroy race you mentioned.
I really don't want to put that ref drop into the
RCU callback as that would kill performance.
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
# 2004/08/13 09:17:07-07:00 davem@xxxxxxxxxxxxxxxxxx
# [IPV4]: Fix two bugs in inetdev RCU handling.
#
# - Two missing smp_read_barrier_depends() noticed by
# Stephen Hemminger.
# - Fix RCU inetdev destroy race spotted by Herbert Xu.
# Check in_dev->dead when trying to grab a reference.
#
# Signed-off-by: David S. Miller <davem@xxxxxxxxxx>
#
# net/ipv4/devinet.c
# 2004/08/13 09:15:41-07:00 davem@xxxxxxxxxxxxxxxxxx +1 -0
# [IPV4]: Fix two bugs in inetdev RCU handling.
#
# include/linux/inetdevice.h
# 2004/08/13 09:15:41-07:00 davem@xxxxxxxxxxxxxxxxxx +7 -2
# [IPV4]: Fix two bugs in inetdev RCU handling.
#
diff -Nru a/include/linux/inetdevice.h b/include/linux/inetdevice.h
--- a/include/linux/inetdevice.h 2004-08-13 09:20:01 -07:00
+++ b/include/linux/inetdevice.h 2004-08-13 09:20:01 -07:00
@@ -143,9 +143,14 @@
struct in_device *in_dev;
rcu_read_lock();
+ smp_read_barrier_depends();
in_dev = dev->ip_ptr;
- if (in_dev)
- atomic_inc(&in_dev->refcnt);
+ if (in_dev) {
+ if (in_dev->dead)
+ in_dev = NULL;
+ else
+ atomic_inc(&in_dev->refcnt);
+ }
rcu_read_unlock();
return in_dev;
}
diff -Nru a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c 2004-08-13 09:20:01 -07:00
+++ b/net/ipv4/devinet.c 2004-08-13 09:20:01 -07:00
@@ -210,6 +210,7 @@
int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
{
rcu_read_lock();
+ smp_read_barrier_depends();
for_primary_ifa(in_dev) {
if (inet_ifa_match(a, ifa)) {
if (!b || inet_ifa_match(b, ifa)) {
|