Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 133883
b: refs/heads/master
c: c70f182
h: refs/heads/master
i:
  133881: e6c929d
  133879: 6e7624a
v: v3
  • Loading branch information
Eric W. Biederman authored and David S. Miller committed Jan 22, 2009
1 parent 1f9dd52 commit 87b7a3e
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b2430de37ef0bc0799ffba7b5219d38ca417eb76
refs/heads/master: c70f182940f988448f3c12a209d18b1edc276e33
50 changes: 48 additions & 2 deletions trunk/drivers/net/tun.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct tap_filter {
};

struct tun_file {
atomic_t count;
struct tun_struct *tun;
struct net *net;
wait_queue_head_t read_wait;
Expand Down Expand Up @@ -138,6 +139,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
err = 0;
tfile->tun = tun;
tun->tfile = tfile;
dev_hold(tun->dev);
atomic_inc(&tfile->count);

out:
netif_tx_unlock_bh(tun->dev);
Expand All @@ -156,11 +159,26 @@ static void __tun_detach(struct tun_struct *tun)

/* Drop read queue */
skb_queue_purge(&tun->readq);

/* Drop the extra count on the net device */
dev_put(tun->dev);
}

static void tun_detach(struct tun_struct *tun)
{
rtnl_lock();
__tun_detach(tun);
rtnl_unlock();
}

static struct tun_struct *__tun_get(struct tun_file *tfile)
{
return tfile->tun;
struct tun_struct *tun = NULL;

if (atomic_inc_not_zero(&tfile->count))
tun = tfile->tun;

return tun;
}

static struct tun_struct *tun_get(struct file *file)
Expand All @@ -170,7 +188,10 @@ static struct tun_struct *tun_get(struct file *file)

static void tun_put(struct tun_struct *tun)
{
/* Noop for now */
struct tun_file *tfile = tun->tfile;

if (atomic_dec_and_test(&tfile->count))
tun_detach(tfile->tun);
}

/* TAP filterting */
Expand Down Expand Up @@ -281,6 +302,21 @@ static int check_filter(struct tap_filter *filter, const struct sk_buff *skb)

static const struct ethtool_ops tun_ethtool_ops;

/* Net device detach from fd. */
static void tun_net_uninit(struct net_device *dev)
{
struct tun_struct *tun = netdev_priv(dev);
struct tun_file *tfile = tun->tfile;

/* Inform the methods they need to stop using the dev.
*/
if (tfile) {
wake_up_all(&tfile->read_wait);
if (atomic_dec_and_test(&tfile->count))
__tun_detach(tun);
}
}

/* Net device open. */
static int tun_net_open(struct net_device *dev)
{
Expand Down Expand Up @@ -367,13 +403,15 @@ tun_net_change_mtu(struct net_device *dev, int new_mtu)
}

static const struct net_device_ops tun_netdev_ops = {
.ndo_uninit = tun_net_uninit,
.ndo_open = tun_net_open,
.ndo_stop = tun_net_close,
.ndo_start_xmit = tun_net_xmit,
.ndo_change_mtu = tun_net_change_mtu,
};

static const struct net_device_ops tap_netdev_ops = {
.ndo_uninit = tun_net_uninit,
.ndo_open = tun_net_open,
.ndo_stop = tun_net_close,
.ndo_start_xmit = tun_net_xmit,
Expand Down Expand Up @@ -434,6 +472,9 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
if (!skb_queue_empty(&tun->readq))
mask |= POLLIN | POLLRDNORM;

if (tun->dev->reg_state != NETREG_REGISTERED)
mask = POLLERR;

tun_put(tun);
return mask;
}
Expand Down Expand Up @@ -734,6 +775,10 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
ret = -ERESTARTSYS;
break;
}
if (tun->dev->reg_state != NETREG_REGISTERED) {
ret = -EIO;
break;
}

/* Nothing to read, let's sleep */
schedule();
Expand Down Expand Up @@ -1135,6 +1180,7 @@ static int tun_chr_open(struct inode *inode, struct file * file)
tfile = kmalloc(sizeof(*tfile), GFP_KERNEL);
if (!tfile)
return -ENOMEM;
atomic_set(&tfile->count, 0);
tfile->tun = NULL;
tfile->net = get_net(current->nsproxy->net_ns);
init_waitqueue_head(&tfile->read_wait);
Expand Down

0 comments on commit 87b7a3e

Please sign in to comment.