aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2009-01-20 06:03:21 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-21 19:00:46 -0500
commitb2430de37ef0bc0799ffba7b5219d38ca417eb76 (patch)
tree19a5a5103ed2227f230aa06f87dc7807e871d5b5 /drivers/net/tun.c
parent38231b7a8d1b74c920822640d1ce8eb8046377fb (diff)
tun: Move read_wait into tun_file
The poll interface requires that the waitqueue exist while the struct file is open. In the rare case when a tun device disappears before the tun file closes we fail to provide this property, so move read_wait. This is safe now that tun_net_xmit is atomic with tun_detach. Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r--drivers/net/tun.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index fa93160bf522..030d9858bb68 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -90,6 +90,7 @@ struct tap_filter {
90struct tun_file { 90struct tun_file {
91 struct tun_struct *tun; 91 struct tun_struct *tun;
92 struct net *net; 92 struct net *net;
93 wait_queue_head_t read_wait;
93}; 94};
94 95
95struct tun_struct { 96struct tun_struct {
@@ -98,7 +99,6 @@ struct tun_struct {
98 uid_t owner; 99 uid_t owner;
99 gid_t group; 100 gid_t group;
100 101
101 wait_queue_head_t read_wait;
102 struct sk_buff_head readq; 102 struct sk_buff_head readq;
103 103
104 struct net_device *dev; 104 struct net_device *dev;
@@ -335,7 +335,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
335 /* Notify and wake up reader process */ 335 /* Notify and wake up reader process */
336 if (tun->flags & TUN_FASYNC) 336 if (tun->flags & TUN_FASYNC)
337 kill_fasync(&tun->fasync, SIGIO, POLL_IN); 337 kill_fasync(&tun->fasync, SIGIO, POLL_IN);
338 wake_up_interruptible(&tun->read_wait); 338 wake_up_interruptible(&tun->tfile->read_wait);
339 return 0; 339 return 0;
340 340
341drop: 341drop:
@@ -420,7 +420,8 @@ static void tun_net_init(struct net_device *dev)
420/* Poll */ 420/* Poll */
421static unsigned int tun_chr_poll(struct file *file, poll_table * wait) 421static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
422{ 422{
423 struct tun_struct *tun = tun_get(file); 423 struct tun_file *tfile = file->private_data;
424 struct tun_struct *tun = __tun_get(tfile);
424 unsigned int mask = POLLOUT | POLLWRNORM; 425 unsigned int mask = POLLOUT | POLLWRNORM;
425 426
426 if (!tun) 427 if (!tun)
@@ -428,7 +429,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
428 429
429 DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); 430 DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
430 431
431 poll_wait(file, &tun->read_wait, wait); 432 poll_wait(file, &tfile->read_wait, wait);
432 433
433 if (!skb_queue_empty(&tun->readq)) 434 if (!skb_queue_empty(&tun->readq))
434 mask |= POLLIN | POLLRDNORM; 435 mask |= POLLIN | POLLRDNORM;
@@ -702,7 +703,8 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
702 unsigned long count, loff_t pos) 703 unsigned long count, loff_t pos)
703{ 704{
704 struct file *file = iocb->ki_filp; 705 struct file *file = iocb->ki_filp;
705 struct tun_struct *tun = tun_get(file); 706 struct tun_file *tfile = file->private_data;
707 struct tun_struct *tun = __tun_get(tfile);
706 DECLARE_WAITQUEUE(wait, current); 708 DECLARE_WAITQUEUE(wait, current);
707 struct sk_buff *skb; 709 struct sk_buff *skb;
708 ssize_t len, ret = 0; 710 ssize_t len, ret = 0;
@@ -718,7 +720,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
718 goto out; 720 goto out;
719 } 721 }
720 722
721 add_wait_queue(&tun->read_wait, &wait); 723 add_wait_queue(&tfile->read_wait, &wait);
722 while (len) { 724 while (len) {
723 current->state = TASK_INTERRUPTIBLE; 725 current->state = TASK_INTERRUPTIBLE;
724 726
@@ -745,7 +747,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
745 } 747 }
746 748
747 current->state = TASK_RUNNING; 749 current->state = TASK_RUNNING;
748 remove_wait_queue(&tun->read_wait, &wait); 750 remove_wait_queue(&tfile->read_wait, &wait);
749 751
750out: 752out:
751 tun_put(tun); 753 tun_put(tun);
@@ -757,7 +759,6 @@ static void tun_setup(struct net_device *dev)
757 struct tun_struct *tun = netdev_priv(dev); 759 struct tun_struct *tun = netdev_priv(dev);
758 760
759 skb_queue_head_init(&tun->readq); 761 skb_queue_head_init(&tun->readq);
760 init_waitqueue_head(&tun->read_wait);
761 762
762 tun->owner = -1; 763 tun->owner = -1;
763 tun->group = -1; 764 tun->group = -1;
@@ -1136,6 +1137,7 @@ static int tun_chr_open(struct inode *inode, struct file * file)
1136 return -ENOMEM; 1137 return -ENOMEM;
1137 tfile->tun = NULL; 1138 tfile->tun = NULL;
1138 tfile->net = get_net(current->nsproxy->net_ns); 1139 tfile->net = get_net(current->nsproxy->net_ns);
1140 init_waitqueue_head(&tfile->read_wait);
1139 file->private_data = tfile; 1141 file->private_data = tfile;
1140 return 0; 1142 return 0;
1141} 1143}