diff options
| -rw-r--r-- | net/ipv6/route.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 74b9b6fd4168..047c47224dba 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -1274,18 +1274,29 @@ static DEFINE_SPINLOCK(rt6_exception_lock); | |||
| 1274 | static void rt6_remove_exception(struct rt6_exception_bucket *bucket, | 1274 | static void rt6_remove_exception(struct rt6_exception_bucket *bucket, |
| 1275 | struct rt6_exception *rt6_ex) | 1275 | struct rt6_exception *rt6_ex) |
| 1276 | { | 1276 | { |
| 1277 | struct fib6_info *from; | ||
| 1277 | struct net *net; | 1278 | struct net *net; |
| 1278 | 1279 | ||
| 1279 | if (!bucket || !rt6_ex) | 1280 | if (!bucket || !rt6_ex) |
| 1280 | return; | 1281 | return; |
| 1281 | 1282 | ||
| 1282 | net = dev_net(rt6_ex->rt6i->dst.dev); | 1283 | net = dev_net(rt6_ex->rt6i->dst.dev); |
| 1284 | net->ipv6.rt6_stats->fib_rt_cache--; | ||
| 1285 | |||
| 1286 | /* purge completely the exception to allow releasing the held resources: | ||
| 1287 | * some [sk] cache may keep the dst around for unlimited time | ||
| 1288 | */ | ||
| 1289 | from = rcu_dereference_protected(rt6_ex->rt6i->from, | ||
| 1290 | lockdep_is_held(&rt6_exception_lock)); | ||
| 1291 | rcu_assign_pointer(rt6_ex->rt6i->from, NULL); | ||
| 1292 | fib6_info_release(from); | ||
| 1293 | dst_dev_put(&rt6_ex->rt6i->dst); | ||
| 1294 | |||
| 1283 | hlist_del_rcu(&rt6_ex->hlist); | 1295 | hlist_del_rcu(&rt6_ex->hlist); |
| 1284 | dst_release(&rt6_ex->rt6i->dst); | 1296 | dst_release(&rt6_ex->rt6i->dst); |
| 1285 | kfree_rcu(rt6_ex, rcu); | 1297 | kfree_rcu(rt6_ex, rcu); |
| 1286 | WARN_ON_ONCE(!bucket->depth); | 1298 | WARN_ON_ONCE(!bucket->depth); |
| 1287 | bucket->depth--; | 1299 | bucket->depth--; |
| 1288 | net->ipv6.rt6_stats->fib_rt_cache--; | ||
| 1289 | } | 1300 | } |
| 1290 | 1301 | ||
| 1291 | /* Remove oldest rt6_ex in bucket and free the memory | 1302 | /* Remove oldest rt6_ex in bucket and free the memory |
