Commit 75da3492 authored by Alexey Kuznetsov's avatar Alexey Kuznetsov Committed by David S. Miller

IPv4 FIB routing fixes:

- fix device leakage in multipath
- fix oops due to race by adding spinlock
parent ff36c646
...@@ -579,6 +579,9 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, ...@@ -579,6 +579,9 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
switch (event) { switch (event) {
case NETDEV_UP: case NETDEV_UP:
fib_add_ifaddr(ifa); fib_add_ifaddr(ifa);
#ifdef CONFIG_IP_ROUTE_MULTIPATH
fib_sync_up(ifa->ifa_dev->dev);
#endif
rt_cache_flush(-1); rt_cache_flush(-1);
break; break;
case NETDEV_DOWN: case NETDEV_DOWN:
......
...@@ -56,6 +56,8 @@ int fib_info_cnt; ...@@ -56,6 +56,8 @@ int fib_info_cnt;
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
static spinlock_t fib_multipath_lock = SPIN_LOCK_UNLOCKED;
#define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \ #define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \
for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++) for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
...@@ -869,8 +871,14 @@ int fib_sync_down(u32 local, struct net_device *dev, int force) ...@@ -869,8 +871,14 @@ int fib_sync_down(u32 local, struct net_device *dev, int force)
nh->nh_scope != scope) { nh->nh_scope != scope) {
nh->nh_flags |= RTNH_F_DEAD; nh->nh_flags |= RTNH_F_DEAD;
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
spin_lock_bh(&fib_multipath_lock);
fi->fib_power -= nh->nh_power; fi->fib_power -= nh->nh_power;
nh->nh_power = 0; nh->nh_power = 0;
spin_unlock_bh(&fib_multipath_lock);
if (force && nh->nh_dev) {
dev_put(nh->nh_dev);
nh->nh_dev = NULL;
}
#endif #endif
dead++; dead++;
} }
...@@ -906,13 +914,19 @@ int fib_sync_up(struct net_device *dev) ...@@ -906,13 +914,19 @@ int fib_sync_up(struct net_device *dev)
alive++; alive++;
continue; continue;
} }
if (nh->nh_dev == NULL && nh->nh_oif == dev->ifindex) {
dev_hold(dev);
nh->nh_dev = dev;
}
if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP)) if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
continue; continue;
if (nh->nh_dev != dev || __in_dev_get(dev) == NULL) if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
continue; continue;
alive++; alive++;
spin_lock_bh(&fib_multipath_lock);
nh->nh_power = 0; nh->nh_power = 0;
nh->nh_flags &= ~RTNH_F_DEAD; nh->nh_flags &= ~RTNH_F_DEAD;
spin_unlock_bh(&fib_multipath_lock);
} endfor_nexthops(fi) } endfor_nexthops(fi)
if (alive > 0) { if (alive > 0) {
...@@ -933,6 +947,7 @@ void fib_select_multipath(const struct rt_key *key, struct fib_result *res) ...@@ -933,6 +947,7 @@ void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
struct fib_info *fi = res->fi; struct fib_info *fi = res->fi;
int w; int w;
spin_lock_bh(&fib_multipath_lock);
if (fi->fib_power <= 0) { if (fi->fib_power <= 0) {
int power = 0; int power = 0;
change_nexthops(fi) { change_nexthops(fi) {
...@@ -942,12 +957,12 @@ void fib_select_multipath(const struct rt_key *key, struct fib_result *res) ...@@ -942,12 +957,12 @@ void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
} }
} endfor_nexthops(fi); } endfor_nexthops(fi);
fi->fib_power = power; fi->fib_power = power;
#if 1
if (power <= 0) { if (power <= 0) {
printk(KERN_CRIT "impossible 777\n"); spin_unlock_bh(&fib_multipath_lock);
/* Race condition: route has just become dead. */
res->nh_sel = 0;
return; return;
} }
#endif
} }
...@@ -963,15 +978,15 @@ void fib_select_multipath(const struct rt_key *key, struct fib_result *res) ...@@ -963,15 +978,15 @@ void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
nh->nh_power--; nh->nh_power--;
fi->fib_power--; fi->fib_power--;
res->nh_sel = nhsel; res->nh_sel = nhsel;
spin_unlock_bh(&fib_multipath_lock);
return; return;
} }
} }
} endfor_nexthops(fi); } endfor_nexthops(fi);
#if 1 /* Race condition: route has just become dead. */
printk(KERN_CRIT "impossible 888\n"); res->nh_sel = 0;
#endif spin_unlock_bh(&fib_multipath_lock);
return;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment