aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2013-01-27 20:05:19 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-29 15:43:04 -0500
commit9e85722d58ca9d49d718929184492a1180bced3c (patch)
treebb31d4d5e54a54ad587dc6301e0c8e48745b0986
parent2b8b328b61c799957a456a5a8dab8cc7dea68575 (diff)
tuntap: allow polling/writing/reading when detached
We forbid polling, writing and reading when the file were detached, this may complex the user in several cases: - when guest pass some buffers to vhost/qemu and then disable some queues, host/qemu needs to do its own cleanup on those buffers which is complex sometimes. We can do this simply by allowing a user can still write to an disabled queue. Write to an disabled queue will cause the packet pass to the kernel and read will get nothing. - align the polling behavior with macvtap which never fails when the queue is created. This can simplify the polling errors handling of its user (e.g vhost) We can simply achieve this by don't assign NULL to tfile->tun when detached. Signed-off-by: Jason Wang <jasowang@redhat.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/tun.c25
1 files changed, 16 insertions, 9 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index ffdb84474c47..2917a86f4c43 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -298,11 +298,12 @@ static void tun_flow_cleanup(unsigned long data)
298} 298}
299 299
300static void tun_flow_update(struct tun_struct *tun, u32 rxhash, 300static void tun_flow_update(struct tun_struct *tun, u32 rxhash,
301 u16 queue_index) 301 struct tun_file *tfile)
302{ 302{
303 struct hlist_head *head; 303 struct hlist_head *head;
304 struct tun_flow_entry *e; 304 struct tun_flow_entry *e;
305 unsigned long delay = tun->ageing_time; 305 unsigned long delay = tun->ageing_time;
306 u16 queue_index = tfile->queue_index;
306 307
307 if (!rxhash) 308 if (!rxhash)
308 return; 309 return;
@@ -311,7 +312,9 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash,
311 312
312 rcu_read_lock(); 313 rcu_read_lock();
313 314
314 if (tun->numqueues == 1) 315 /* We may get a very small possibility of OOO during switching, not
316 * worth to optimize.*/
317 if (tun->numqueues == 1 || tfile->detached)
315 goto unlock; 318 goto unlock;
316 319
317 e = tun_flow_find(head, rxhash); 320 e = tun_flow_find(head, rxhash);
@@ -411,21 +414,21 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
411 414
412 tun = rtnl_dereference(tfile->tun); 415 tun = rtnl_dereference(tfile->tun);
413 416
414 if (tun) { 417 if (tun && !tfile->detached) {
415 u16 index = tfile->queue_index; 418 u16 index = tfile->queue_index;
416 BUG_ON(index >= tun->numqueues); 419 BUG_ON(index >= tun->numqueues);
417 dev = tun->dev; 420 dev = tun->dev;
418 421
419 rcu_assign_pointer(tun->tfiles[index], 422 rcu_assign_pointer(tun->tfiles[index],
420 tun->tfiles[tun->numqueues - 1]); 423 tun->tfiles[tun->numqueues - 1]);
421 rcu_assign_pointer(tfile->tun, NULL);
422 ntfile = rtnl_dereference(tun->tfiles[index]); 424 ntfile = rtnl_dereference(tun->tfiles[index]);
423 ntfile->queue_index = index; 425 ntfile->queue_index = index;
424 426
425 --tun->numqueues; 427 --tun->numqueues;
426 if (clean) 428 if (clean) {
429 rcu_assign_pointer(tfile->tun, NULL);
427 sock_put(&tfile->sk); 430 sock_put(&tfile->sk);
428 else 431 } else
429 tun_disable_queue(tun, tfile); 432 tun_disable_queue(tun, tfile);
430 433
431 synchronize_net(); 434 synchronize_net();
@@ -473,6 +476,10 @@ static void tun_detach_all(struct net_device *dev)
473 rcu_assign_pointer(tfile->tun, NULL); 476 rcu_assign_pointer(tfile->tun, NULL);
474 --tun->numqueues; 477 --tun->numqueues;
475 } 478 }
479 list_for_each_entry(tfile, &tun->disabled, next) {
480 wake_up_all(&tfile->wq.wait);
481 rcu_assign_pointer(tfile->tun, NULL);
482 }
476 BUG_ON(tun->numqueues != 0); 483 BUG_ON(tun->numqueues != 0);
477 484
478 synchronize_net(); 485 synchronize_net();
@@ -503,7 +510,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
503 goto out; 510 goto out;
504 511
505 err = -EINVAL; 512 err = -EINVAL;
506 if (rtnl_dereference(tfile->tun)) 513 if (rtnl_dereference(tfile->tun) && !tfile->detached)
507 goto out; 514 goto out;
508 515
509 err = -EBUSY; 516 err = -EBUSY;
@@ -1202,7 +1209,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
1202 tun->dev->stats.rx_packets++; 1209 tun->dev->stats.rx_packets++;
1203 tun->dev->stats.rx_bytes += len; 1210 tun->dev->stats.rx_bytes += len;
1204 1211
1205 tun_flow_update(tun, rxhash, tfile->queue_index); 1212 tun_flow_update(tun, rxhash, tfile);
1206 return total_len; 1213 return total_len;
1207} 1214}
1208 1215
@@ -1816,7 +1823,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
1816 ret = tun_attach(tun, file); 1823 ret = tun_attach(tun, file);
1817 } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { 1824 } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
1818 tun = rtnl_dereference(tfile->tun); 1825 tun = rtnl_dereference(tfile->tun);
1819 if (!tun || !(tun->flags & TUN_TAP_MQ)) 1826 if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached)
1820 ret = -EINVAL; 1827 ret = -EINVAL;
1821 else 1828 else
1822 __tun_detach(tfile, false); 1829 __tun_detach(tfile, false);