l2tp: add session reorder queue purge function to core
[pandora-kernel.git] / net / ipv6 / ip6_fib.c
index 96d4d1c..33de352 100644 (file)
@@ -670,7 +670,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
 
        rt->dst.rt6_next = iter;
        *ins = rt;
-       rt->rt6i_node = fn;
+       rcu_assign_pointer(rt->rt6i_node, fn);
        atomic_inc(&rt->rt6i_ref);
        inet6_rt_notify(RTM_NEWROUTE, rt, info);
        info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
@@ -1181,8 +1181,9 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
 
 int fib6_del(struct rt6_info *rt, struct nl_info *info)
 {
+       struct fib6_node *fn = rcu_dereference_protected(rt->rt6i_node,
+                                   lockdep_is_held(&rt->rt6i_table->tb6_lock));
        struct net *net = info->nl_net;
-       struct fib6_node *fn = rt->rt6i_node;
        struct rt6_info **rtp;
 
 #if RT6_DEBUG >= 2
@@ -1360,7 +1361,10 @@ static int fib6_clean_node(struct fib6_walker_t *w)
                        res = fib6_del(rt, &info);
                        if (res) {
 #if RT6_DEBUG >= 2
-                               printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res);
+                               pr_debug("%s: del failed: rt=%p@%p err=%d\n",
+                                        __func__, rt,
+                                        rcu_access_pointer(rt->rt6i_node),
+                                        res);
 #endif
                                continue;
                        }
@@ -1573,13 +1577,22 @@ out_timer:
 
 static void fib6_net_exit(struct net *net)
 {
+       unsigned int i;
+
        rt6_ifdown(net, NULL);
        del_timer_sync(&net->ipv6.ip6_fib_timer);
 
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-       kfree(net->ipv6.fib6_local_tbl);
-#endif
-       kfree(net->ipv6.fib6_main_tbl);
+       for (i = 0; i < FIB6_TABLE_HASHSZ; i++) {
+               struct hlist_head *head = &net->ipv6.fib_table_hash[i];
+               struct hlist_node *node, *tmp;
+               struct fib6_table *tb;
+
+               hlist_for_each_entry_safe(tb, node, tmp, head, tb6_hlist) {
+                       hlist_del(&tb->tb6_hlist);
+                       kfree(tb);
+               }
+       }
+
        kfree(net->ipv6.fib_table_hash);
        kfree(net->ipv6.rt6_stats);
 }