patch-2.4.3 linux/net/ipv6/ip6_fib.c

Next file: linux/net/ipv6/ipv6_sockglue.c
Previous file: linux/net/ipv4/sysctl_net_ipv4.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.2/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_fib.c,v 1.22 2000/09/12 00:38:34 davem Exp $
+ *	$Id: ip6_fib.c,v 1.23 2001/03/19 20:31:17 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -76,7 +76,7 @@
 #endif
 
 static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
-static void fib6_repair_tree(struct fib6_node *fn);
+static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
 
 /*
  *	A routing update causes an increase of the serial number on the
@@ -774,7 +774,7 @@
  *	is the node we want to try and remove.
  */
 
-static void fib6_repair_tree(struct fib6_node *fn)
+static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
 {
 	int children;
 	int nstate;
@@ -809,7 +809,7 @@
 			}
 #endif
 			atomic_inc(&fn->leaf->rt6i_ref);
-			return;
+			return fn->parent;
 		}
 
 		pn = fn->parent;
@@ -865,7 +865,7 @@
 
 		node_free(fn);
 		if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn))
-			return;
+			return pn;
 
 		rt6_release(pn->leaf);
 		pn->leaf = NULL;
@@ -903,7 +903,26 @@
 	if (fn->leaf == NULL) {
 		fn->fn_flags &= ~RTN_RTINFO;
 		rt6_stats.fib_route_nodes--;
-		fib6_repair_tree(fn);
+		fn = fib6_repair_tree(fn);
+	}
+
+	if (atomic_read(&rt->rt6i_ref) != 1) {
+		/* This route is used as dummy address holder in some split
+		 * nodes. It is not leaked, but it still holds other resources,
+		 * which must be released in time. So, scan ascendant nodes
+		 * and replace dummy references to this route with references
+		 * to still alive ones.
+		 */
+		while (fn) {
+			if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
+				fn->leaf = fib6_find_prefix(fn);
+				atomic_inc(&fn->leaf->rt6i_ref);
+				rt6_release(rt);
+			}
+			fn = fn->parent;
+		}
+		/* No more references are possiible at this point. */
+		if (atomic_read(&rt->rt6i_ref) != 1) BUG();
 	}
 
 #ifdef CONFIG_RTNETLINK

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)