tun: don't hold network namespace by tun sockets
[firefly-linux-kernel-4.4.55.git] / drivers / net / tun.c
index 93c5d72711b023be9623e85b3fc9044d50cfef59..2d7601dd6660e5a273cdabe75278ee1231e7fc23 100644 (file)
@@ -359,7 +359,7 @@ static void tun_free_netdev(struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
 
-       sock_put(tun->socket.sk);
+       sk_release_kernel(tun->socket.sk);
 }
 
 /* Net device open. */
@@ -980,10 +980,18 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
        return ret;
 }
 
+static int tun_release(struct socket *sock)
+{
+       if (sock->sk)
+               sock_put(sock->sk);
+       return 0;
+}
+
 /* Ops structure to mimic raw sockets with tun */
 static const struct proto_ops tun_socket_ops = {
        .sendmsg = tun_sendmsg,
        .recvmsg = tun_recvmsg,
+       .release = tun_release,
 };
 
 static struct proto tun_proto = {
@@ -1110,10 +1118,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
 
                err = -ENOMEM;
-               sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
+               sk = sk_alloc(&init_net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
                if (!sk)
                        goto err_free_dev;
 
+               sk_change_net(sk, net);
                tun->socket.wq = &tun->wq;
                init_waitqueue_head(&tun->wq.wait);
                tun->socket.ops = &tun_socket_ops;
@@ -1174,7 +1183,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
        return 0;
 
  err_free_sk:
-       sock_put(sk);
+       tun_free_netdev(dev);
  err_free_dev:
        free_netdev(dev);
  failed: