@@ -355,6 +355,14 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net,
return NULL;
}
+static void ip6gre_destructor_free(struct net_device *dev)
+{
+ struct ip6_tnl *t = netdev_priv(dev);
+
+ dst_cache_destroy(&t->dst_cache);
+ free_percpu(dev->tstats);
+}
+
static void ip6gre_tunnel_uninit(struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
@@ -363,6 +371,10 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)
ip6gre_tunnel_unlink(ign, t);
dst_cache_reset(&t->dst_cache);
dev_put(dev);
+
+ /* dev is not registered, perform the free instead of destructor */
+ if (dev->reg_state == NETREG_UNINITIALIZED)
+ ip6gre_destructor_free(dev);
}
@@ -981,10 +993,7 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
static void ip6gre_dev_free(struct net_device *dev)
{
- struct ip6_tnl *t = netdev_priv(dev);
-
- dst_cache_destroy(&t->dst_cache);
- free_percpu(dev->tstats);
+ ip6gre_destructor_free(dev);
free_netdev(dev);
}