diff options
-rw-r--r-- | drivers/net/tun.c | 32 |
1 files changed, 19 insertions, 13 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 16716aef184c..95ae40ab8718 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -156,6 +156,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) | |||
156 | tfile->tun = tun; | 156 | tfile->tun = tun; |
157 | tun->tfile = tfile; | 157 | tun->tfile = tfile; |
158 | dev_hold(tun->dev); | 158 | dev_hold(tun->dev); |
159 | sock_hold(tun->sk); | ||
159 | atomic_inc(&tfile->count); | 160 | atomic_inc(&tfile->count); |
160 | 161 | ||
161 | out: | 162 | out: |
@@ -165,11 +166,8 @@ out: | |||
165 | 166 | ||
166 | static void __tun_detach(struct tun_struct *tun) | 167 | static void __tun_detach(struct tun_struct *tun) |
167 | { | 168 | { |
168 | struct tun_file *tfile = tun->tfile; | ||
169 | |||
170 | /* Detach from net device */ | 169 | /* Detach from net device */ |
171 | netif_tx_lock_bh(tun->dev); | 170 | netif_tx_lock_bh(tun->dev); |
172 | tfile->tun = NULL; | ||
173 | tun->tfile = NULL; | 171 | tun->tfile = NULL; |
174 | netif_tx_unlock_bh(tun->dev); | 172 | netif_tx_unlock_bh(tun->dev); |
175 | 173 | ||
@@ -339,6 +337,13 @@ static void tun_net_uninit(struct net_device *dev) | |||
339 | } | 337 | } |
340 | } | 338 | } |
341 | 339 | ||
340 | static void tun_free_netdev(struct net_device *dev) | ||
341 | { | ||
342 | struct tun_struct *tun = netdev_priv(dev); | ||
343 | |||
344 | sock_put(tun->sk); | ||
345 | } | ||
346 | |||
342 | /* Net device open. */ | 347 | /* Net device open. */ |
343 | static int tun_net_open(struct net_device *dev) | 348 | static int tun_net_open(struct net_device *dev) |
344 | { | 349 | { |
@@ -811,7 +816,7 @@ static void tun_setup(struct net_device *dev) | |||
811 | tun->group = -1; | 816 | tun->group = -1; |
812 | 817 | ||
813 | dev->ethtool_ops = &tun_ethtool_ops; | 818 | dev->ethtool_ops = &tun_ethtool_ops; |
814 | dev->destructor = free_netdev; | 819 | dev->destructor = tun_free_netdev; |
815 | } | 820 | } |
816 | 821 | ||
817 | /* Trivial set of netlink ops to allow deleting tun or tap | 822 | /* Trivial set of netlink ops to allow deleting tun or tap |
@@ -848,7 +853,7 @@ static void tun_sock_write_space(struct sock *sk) | |||
848 | 853 | ||
849 | static void tun_sock_destruct(struct sock *sk) | 854 | static void tun_sock_destruct(struct sock *sk) |
850 | { | 855 | { |
851 | dev_put(container_of(sk, struct tun_sock, sk)->tun->dev); | 856 | free_netdev(container_of(sk, struct tun_sock, sk)->tun->dev); |
852 | } | 857 | } |
853 | 858 | ||
854 | static struct proto tun_proto = { | 859 | static struct proto tun_proto = { |
@@ -920,11 +925,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
920 | if (!sk) | 925 | if (!sk) |
921 | goto err_free_dev; | 926 | goto err_free_dev; |
922 | 927 | ||
923 | /* This ref count is for tun->sk. */ | ||
924 | dev_hold(dev); | ||
925 | sock_init_data(&tun->socket, sk); | 928 | sock_init_data(&tun->socket, sk); |
926 | sk->sk_write_space = tun_sock_write_space; | 929 | sk->sk_write_space = tun_sock_write_space; |
927 | sk->sk_destruct = tun_sock_destruct; | ||
928 | sk->sk_sndbuf = INT_MAX; | 930 | sk->sk_sndbuf = INT_MAX; |
929 | sk->sk_sleep = &tfile->read_wait; | 931 | sk->sk_sleep = &tfile->read_wait; |
930 | 932 | ||
@@ -942,11 +944,13 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
942 | err = -EINVAL; | 944 | err = -EINVAL; |
943 | err = register_netdevice(tun->dev); | 945 | err = register_netdevice(tun->dev); |
944 | if (err < 0) | 946 | if (err < 0) |
945 | goto err_free_dev; | 947 | goto err_free_sk; |
948 | |||
949 | sk->sk_destruct = tun_sock_destruct; | ||
946 | 950 | ||
947 | err = tun_attach(tun, file); | 951 | err = tun_attach(tun, file); |
948 | if (err < 0) | 952 | if (err < 0) |
949 | goto err_free_dev; | 953 | goto failed; |
950 | } | 954 | } |
951 | 955 | ||
952 | DBG(KERN_INFO "%s: tun_set_iff\n", tun->dev->name); | 956 | DBG(KERN_INFO "%s: tun_set_iff\n", tun->dev->name); |
@@ -1284,14 +1288,16 @@ static int tun_chr_close(struct inode *inode, struct file *file) | |||
1284 | __tun_detach(tun); | 1288 | __tun_detach(tun); |
1285 | 1289 | ||
1286 | /* If desireable, unregister the netdevice. */ | 1290 | /* If desireable, unregister the netdevice. */ |
1287 | if (!(tun->flags & TUN_PERSIST)) { | 1291 | if (!(tun->flags & TUN_PERSIST)) |
1288 | sock_put(tun->sk); | ||
1289 | unregister_netdevice(tun->dev); | 1292 | unregister_netdevice(tun->dev); |
1290 | } | ||
1291 | 1293 | ||
1292 | rtnl_unlock(); | 1294 | rtnl_unlock(); |
1293 | } | 1295 | } |
1294 | 1296 | ||
1297 | tun = tfile->tun; | ||
1298 | if (tun) | ||
1299 | sock_put(tun->sk); | ||
1300 | |||
1295 | put_net(tfile->net); | 1301 | put_net(tfile->net); |
1296 | kfree(tfile); | 1302 | kfree(tfile); |
1297 | 1303 | ||