diff options
-rw-r--r-- | quicktun.c | 59 |
1 files changed, 35 insertions, 24 deletions
@@ -40,6 +40,7 @@ struct quicktun_struct { struct quicktun_list_entry { struct list_head list; + struct rcu_head rcu; struct quicktun_struct *quicktun; }; @@ -366,14 +367,34 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf return err; } +static void quicktun_free_list_entry(struct rcu_head *rcu) { + struct quicktun_list_entry *entry = container_of(rcu, struct quicktun_list_entry, rcu); + kfree(entry); +} + +static void __quicktun_delete_device(struct net_device *dev) { + struct quicktun_struct *tun = netdev_priv(dev); + struct socket *sock = tun->sock; + struct quicktun_list_entry *entry = NULL; + + list_for_each_entry(entry, &quicktun_list, list) { + if (entry->quicktun->dev == dev) { + break; + } + } + + list_del_rcu(&entry->list); + call_rcu(&entry->rcu, quicktun_free_list_entry); + + unregister_netdevice(dev); + sock_release(sock); +} + static int quicktun_cmd_delete_device(struct sk_buff *skb, struct genl_info *info) { int err; struct net *net = genl_info_net(info); struct net_device *dev; - struct quicktun_struct *tun; - struct quicktun_list_entry *entry = NULL; - struct socket *sock; char *name; if (!capable(CAP_NET_ADMIN)) @@ -397,30 +418,10 @@ static int quicktun_cmd_delete_device(struct sk_buff *skb, struct genl_info *inf goto err_unlock; } - tun = netdev_priv(dev); - sock = tun->sock; - - rcu_read_lock(); - - list_for_each_entry_rcu(entry, &quicktun_list, list) { - if (entry->quicktun->dev == dev) { - break; - } - } - - list_del_rcu(&entry->list); - - rcu_read_unlock(); - - unregister_netdevice(dev); + __quicktun_delete_device(dev); rtnl_unlock(); - sock_release(sock); - - synchronize_rcu(); - kfree(entry); - return 0; err_unlock: @@ -474,7 +475,17 @@ static int __init quicktun_init(void) static void quicktun_exit(void) { + struct quicktun_list_entry *entry, *next; + genl_unregister_family(&quicktun_nl_family); + + rtnl_lock(); + + list_for_each_entry_safe(entry, next, &quicktun_list, list) { + __quicktun_delete_device(entry->quicktun->dev); + } + + rtnl_unlock(); } |