diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2009-01-20 06:03:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-21 19:00:46 -0500 |
commit | b2430de37ef0bc0799ffba7b5219d38ca417eb76 (patch) | |
tree | 19a5a5103ed2227f230aa06f87dc7807e871d5b5 /drivers/net/tun.c | |
parent | 38231b7a8d1b74c920822640d1ce8eb8046377fb (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.c | 18 |
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 { | |||
90 | struct tun_file { | 90 | struct 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 | ||
95 | struct tun_struct { | 96 | struct 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 | ||
341 | drop: | 341 | drop: |
@@ -420,7 +420,8 @@ static void tun_net_init(struct net_device *dev) | |||
420 | /* Poll */ | 420 | /* Poll */ |
421 | static unsigned int tun_chr_poll(struct file *file, poll_table * wait) | 421 | static 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 | ||
750 | out: | 752 | out: |
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 | } |