@@ -298,11 +298,12 @@ static void tun_flow_cleanup(unsigned long data)
298298}
299299
300300static void tun_flow_update (struct tun_struct * tun , u32 rxhash ,
301- u16 queue_index )
301+ struct tun_file * tfile )
302302{
303303 struct hlist_head * head ;
304304 struct tun_flow_entry * e ;
305305 unsigned long delay = tun -> ageing_time ;
306+ u16 queue_index = tfile -> queue_index ;
306307
307308 if (!rxhash )
308309 return ;
@@ -311,7 +312,9 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash,
311312
312313 rcu_read_lock ();
313314
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 )
315318 goto unlock ;
316319
317320 e = tun_flow_find (head , rxhash );
@@ -411,21 +414,21 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
411414
412415 tun = rtnl_dereference (tfile -> tun );
413416
414- if (tun ) {
417+ if (tun && ! tfile -> detached ) {
415418 u16 index = tfile -> queue_index ;
416419 BUG_ON (index >= tun -> numqueues );
417420 dev = tun -> dev ;
418421
419422 rcu_assign_pointer (tun -> tfiles [index ],
420423 tun -> tfiles [tun -> numqueues - 1 ]);
421- rcu_assign_pointer (tfile -> tun , NULL );
422424 ntfile = rtnl_dereference (tun -> tfiles [index ]);
423425 ntfile -> queue_index = index ;
424426
425427 -- tun -> numqueues ;
426- if (clean )
428+ if (clean ) {
429+ rcu_assign_pointer (tfile -> tun , NULL );
427430 sock_put (& tfile -> sk );
428- else
431+ } else
429432 tun_disable_queue (tun , tfile );
430433
431434 synchronize_net ();
@@ -439,10 +442,13 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
439442 }
440443
441444 if (clean ) {
442- if (tun && tun -> numqueues == 0 && tun -> numdisabled == 0 &&
443- !(tun -> flags & TUN_PERSIST ))
444- if (tun -> dev -> reg_state == NETREG_REGISTERED )
445+ if (tun && tun -> numqueues == 0 && tun -> numdisabled == 0 ) {
446+ netif_carrier_off (tun -> dev );
447+
448+ if (!(tun -> flags & TUN_PERSIST ) &&
449+ tun -> dev -> reg_state == NETREG_REGISTERED )
445450 unregister_netdevice (tun -> dev );
451+ }
446452
447453 BUG_ON (!test_bit (SOCK_EXTERNALLY_ALLOCATED ,
448454 & tfile -> socket .flags ));
@@ -470,6 +476,10 @@ static void tun_detach_all(struct net_device *dev)
470476 rcu_assign_pointer (tfile -> tun , NULL );
471477 -- tun -> numqueues ;
472478 }
479+ list_for_each_entry (tfile , & tun -> disabled , next ) {
480+ wake_up_all (& tfile -> wq .wait );
481+ rcu_assign_pointer (tfile -> tun , NULL );
482+ }
473483 BUG_ON (tun -> numqueues != 0 );
474484
475485 synchronize_net ();
@@ -500,7 +510,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
500510 goto out ;
501511
502512 err = - EINVAL ;
503- if (rtnl_dereference (tfile -> tun ))
513+ if (rtnl_dereference (tfile -> tun ) && ! tfile -> detached )
504514 goto out ;
505515
506516 err = - EBUSY ;
@@ -1203,7 +1213,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
12031213 tun -> dev -> stats .rx_packets ++ ;
12041214 tun -> dev -> stats .rx_bytes += len ;
12051215
1206- tun_flow_update (tun , rxhash , tfile -> queue_index );
1216+ tun_flow_update (tun , rxhash , tfile );
12071217 return total_len ;
12081218}
12091219
@@ -1662,10 +1672,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
16621672 device_create_file (& tun -> dev -> dev , & dev_attr_owner ) ||
16631673 device_create_file (& tun -> dev -> dev , & dev_attr_group ))
16641674 pr_err ("Failed to create tun sysfs files\n" );
1665-
1666- netif_carrier_on (tun -> dev );
16671675 }
16681676
1677+ netif_carrier_on (tun -> dev );
1678+
16691679 tun_debug (KERN_INFO , tun , "tun_set_iff\n" );
16701680
16711681 if (ifr -> ifr_flags & IFF_NO_PI )
@@ -1817,7 +1827,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
18171827 ret = tun_attach (tun , file );
18181828 } else if (ifr -> ifr_flags & IFF_DETACH_QUEUE ) {
18191829 tun = rtnl_dereference (tfile -> tun );
1820- if (!tun || !(tun -> flags & TUN_TAP_MQ ))
1830+ if (!tun || !(tun -> flags & TUN_TAP_MQ ) || tfile -> detached )
18211831 ret = - EINVAL ;
18221832 else
18231833 __tun_detach (tfile , false);
0 commit comments