On Sun, 13 Jun 2004 21:00:53 +0200 Andreas Schwab <schwab@suse.de> wrote: > Somewhere between 2.6.7-rc2 and 2.6.7-rc3 the reference counting in the > tun driver has been messed up. Looking through the patches I can't find > anything obvious. Any ideas? Fixed in current BK as follows: # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/06/12 10:52:09-07:00 yoshfuji@linux-ipv6.org # [NET]: Add dst->ifdown callback. # # Use it to release protocol specific objects that may be # tied to a dst cache object, at ifdown time. Currently # this is used to release ipv4/ipv6 specific device state. # diff -Nru a/include/net/dst.h b/include/net/dst.h --- a/include/net/dst.h 2004-06-13 06:04:50 -07:00 +++ b/include/net/dst.h 2004-06-13 06:04:50 -07:00 @@ -89,6 +89,7 @@ int (*gc)(void); struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); void (*destroy)(struct dst_entry *); + void (*ifdown)(struct dst_entry *, int how); struct dst_entry * (*negative_advice)(struct dst_entry *); void (*link_failure)(struct sk_buff *); void (*update_pmtu)(struct dst_entry *dst, u32 mtu); diff -Nru a/net/core/dst.c b/net/core/dst.c --- a/net/core/dst.c 2004-06-13 06:04:49 -07:00 +++ b/net/core/dst.c 2004-06-13 06:04:49 -07:00 @@ -230,8 +230,8 @@ if (event!=NETDEV_DOWN && dst->output == dst_discard_out) { dst->dev = &loopback_dev; - dev_put(dev); dev_hold(&loopback_dev); + dev_put(dev); dst->output = dst_discard_out; if (dst->neighbour && dst->neighbour->dev == dev) { dst->neighbour->dev = &loopback_dev; @@ -242,6 +242,8 @@ dst->input = dst_discard_in; dst->output = dst_discard_out; } + if (dst->ops->ifdown) + dst->ops->ifdown(dst, event != NETDEV_DOWN); } } spin_unlock_bh(&dst_lock); diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c --- a/net/ipv4/route.c 2004-06-13 06:04:50 -07:00 +++ b/net/ipv4/route.c 2004-06-13 06:04:50 -07:00 @@ -138,6 +138,7 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); static void ipv4_dst_destroy(struct dst_entry *dst); +static void ipv4_dst_ifdown(struct dst_entry *dst, int how); static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); static void ipv4_link_failure(struct sk_buff *skb); static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); @@ -150,6 +151,7 @@ .gc = rt_garbage_collect, .check = ipv4_dst_check, .destroy = ipv4_dst_destroy, + .ifdown = ipv4_dst_ifdown, .negative_advice = ipv4_negative_advice, .link_failure = ipv4_link_failure, .update_pmtu = ip_rt_update_pmtu, @@ -1330,6 +1332,16 @@ inet_putpeer(peer); } + if (idev) { + rt->idev = NULL; + in_dev_put(idev); + } +} + +static void ipv4_dst_ifdown(struct dst_entry *dst, int how) +{ + struct rtable *rt = (struct rtable *) dst; + struct in_device *idev = rt->idev; if (idev) { rt->idev = NULL; in_dev_put(idev); diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c --- a/net/ipv6/route.c 2004-06-13 06:04:49 -07:00 +++ b/net/ipv6/route.c 2004-06-13 06:04:50 -07:00 @@ -84,6 +84,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); static struct dst_entry *ip6_negative_advice(struct dst_entry *); static void ip6_dst_destroy(struct dst_entry *); +static void ip6_dst_ifdown(struct dst_entry *, int how); static int ip6_dst_gc(void); static int ip6_pkt_discard(struct sk_buff *skb); @@ -98,6 +99,7 @@ .gc_thresh = 1024, .check = ip6_dst_check, .destroy = ip6_dst_destroy, + .ifdown = ip6_dst_ifdown, .negative_advice = ip6_negative_advice, .link_failure = ip6_link_failure, .update_pmtu = ip6_rt_update_pmtu, @@ -143,9 +145,17 @@ static void ip6_dst_destroy(struct dst_entry *dst) { struct rt6_info *rt = (struct rt6_info *)dst; - if (rt->rt6i_idev != NULL) - in6_dev_put(rt->rt6i_idev); - + struct inet6_dev *idev = rt->rt6i_idev; + + if (idev != NULL) { + rt->rt6i_idev = NULL; + in6_dev_put(idev); + } +} + +static void ip6_dst_ifdown(struct dst_entry *dst, int how) +{ + ip6_dst_destroy(dst); } /* - : send the line "unsubscribe linux-net" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html