Re: 2.6.7-rc3: unregister_netdevice: waiting for tun0 to become free. Usage count = 1

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux