summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2013-10-14 19:21:11 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2013-10-14 19:21:11 +0200
commit807fde8a03408dd659112cce7bd75813366fea9b (patch)
tree8a9450c15d2ca83e7932c632377f236fa16cd073
parent6e93844647f2af858cf1ee4d6351f6f78dc1e5b7 (diff)
downloadmodfastd-807fde8a03408dd659112cce7bd75813366fea9b.tar
modfastd-807fde8a03408dd659112cce7bd75813366fea9b.zip
Free netdev in rcu callback
-rw-r--r--fastd.c41
-rw-r--r--fastd.h9
2 files changed, 27 insertions, 23 deletions
diff --git a/fastd.c b/fastd.c
index c9afc67..00dd41e 100644
--- a/fastd.c
+++ b/fastd.c
@@ -89,6 +89,7 @@ struct fastd_struct {
struct list_head sockets;
struct work_struct destroy_work;
+ struct rcu_head rcu;
};
struct fastd_socket {
@@ -204,27 +205,9 @@ static const struct ethtool_ops fastd_ethtool_ops = {
};
-static void fastd_netdev_free(struct net_device *dev)
-{
- struct fastd_struct *fastd = netdev_priv(dev);
- struct fastd_socket *socket, *next;
-
- list_for_each_entry_safe(socket, next, &fastd->sockets, list) {
- list_del(&socket->list);
- sock_release(socket->sock);
- kfree(socket);
- }
-
- put_net(fastd->net);
- free_netdev(dev);
-
- module_put(THIS_MODULE);
-}
-
static void fastd_netdev_setup(struct net_device *dev)
{
dev->ethtool_ops = &fastd_ethtool_ops;
- dev->destructor = fastd_netdev_free;
}
static inline u16 fastd_header_len(u16 mode)
@@ -262,6 +245,24 @@ static void fastd_netdev_init(struct net_device *dev)
dev->hard_header_len = fastd_header_len(fastd->mode);
}
+static void fastd_netdev_free(struct rcu_head *rcu)
+{
+ struct fastd_struct *fastd = container_of(rcu, struct fastd_struct,
+ rcu);
+ struct fastd_socket *socket, *next;
+
+ list_for_each_entry_safe(socket, next, &fastd->sockets, list) {
+ list_del(&socket->list);
+ sk_release_kernel(socket->sock->sk);
+ kfree(socket);
+ }
+
+ put_net(fastd->net);
+ free_netdev(fastd->dev);
+
+ module_put(THIS_MODULE);
+}
+
static void fastd_destroy_work(struct work_struct *work)
{
struct fastd_struct *fastd = container_of(work, struct fastd_struct,
@@ -273,6 +274,8 @@ static void fastd_destroy_work(struct work_struct *work)
unregister_netdevice(fastd->dev);
rtnl_unlock();
+
+ call_rcu(&fastd->rcu, fastd_netdev_free);
}
static int fastd_cmd_create(struct sk_buff *skb, struct genl_info *info)
@@ -413,7 +416,7 @@ err_unlock_rcu:
rcu_read_unlock();
err_release_sock:
- sock_release(socket->sock);
+ sk_release_kernel(socket->sock->sk);
err_free_socket:
kfree(socket);
diff --git a/fastd.h b/fastd.h
index 55878cc..3017c18 100644
--- a/fastd.h
+++ b/fastd.h
@@ -40,15 +40,16 @@
#define __LINUX_FASTD_H
enum {
- FASTD_MODE_ETH = 1,
- FASTD_MODE_IP
+ FASTD_MODE_UNSPEC,
+ FASTD_MODE_ETH,
+ FASTD_MODE_IP,
};
enum {
FASTD_CMD_UNSPEC,
FASTD_CMD_CREATE,
FASTD_CMD_BIND,
- __FASTD_CMD_MAX
+ __FASTD_CMD_MAX,
};
enum {
@@ -58,7 +59,7 @@ enum {
FASTD_A_MTU,
FASTD_A_LOCALADDR,
FASTD_A_REMOTEADDR,
- __FASTD_A_MAX
+ __FASTD_A_MAX,
};