aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r--drivers/net/tun.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index db16d7a13e00..aab0be40d443 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -787,7 +787,8 @@ static void tun_detach_all(struct net_device *dev)
787} 787}
788 788
789static int tun_attach(struct tun_struct *tun, struct file *file, 789static int tun_attach(struct tun_struct *tun, struct file *file,
790 bool skip_filter, bool napi, bool napi_frags) 790 bool skip_filter, bool napi, bool napi_frags,
791 bool publish_tun)
791{ 792{
792 struct tun_file *tfile = file->private_data; 793 struct tun_file *tfile = file->private_data;
793 struct net_device *dev = tun->dev; 794 struct net_device *dev = tun->dev;
@@ -870,7 +871,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
870 * initialized tfile; otherwise we risk using half-initialized 871 * initialized tfile; otherwise we risk using half-initialized
871 * object. 872 * object.
872 */ 873 */
873 rcu_assign_pointer(tfile->tun, tun); 874 if (publish_tun)
875 rcu_assign_pointer(tfile->tun, tun);
874 rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile); 876 rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile);
875 tun->numqueues++; 877 tun->numqueues++;
876 tun_set_real_num_queues(tun); 878 tun_set_real_num_queues(tun);
@@ -2730,7 +2732,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
2730 2732
2731 err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER, 2733 err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER,
2732 ifr->ifr_flags & IFF_NAPI, 2734 ifr->ifr_flags & IFF_NAPI,
2733 ifr->ifr_flags & IFF_NAPI_FRAGS); 2735 ifr->ifr_flags & IFF_NAPI_FRAGS, true);
2734 if (err < 0) 2736 if (err < 0)
2735 return err; 2737 return err;
2736 2738
@@ -2829,13 +2831,17 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
2829 2831
2830 INIT_LIST_HEAD(&tun->disabled); 2832 INIT_LIST_HEAD(&tun->disabled);
2831 err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI, 2833 err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
2832 ifr->ifr_flags & IFF_NAPI_FRAGS); 2834 ifr->ifr_flags & IFF_NAPI_FRAGS, false);
2833 if (err < 0) 2835 if (err < 0)
2834 goto err_free_flow; 2836 goto err_free_flow;
2835 2837
2836 err = register_netdevice(tun->dev); 2838 err = register_netdevice(tun->dev);
2837 if (err < 0) 2839 if (err < 0)
2838 goto err_detach; 2840 goto err_detach;
2841 /* free_netdev() won't check refcnt, to aovid race
2842 * with dev_put() we need publish tun after registration.
2843 */
2844 rcu_assign_pointer(tfile->tun, tun);
2839 } 2845 }
2840 2846
2841 netif_carrier_on(tun->dev); 2847 netif_carrier_on(tun->dev);
@@ -2978,7 +2984,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
2978 if (ret < 0) 2984 if (ret < 0)
2979 goto unlock; 2985 goto unlock;
2980 ret = tun_attach(tun, file, false, tun->flags & IFF_NAPI, 2986 ret = tun_attach(tun, file, false, tun->flags & IFF_NAPI,
2981 tun->flags & IFF_NAPI_FRAGS); 2987 tun->flags & IFF_NAPI_FRAGS, true);
2982 } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { 2988 } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
2983 tun = rtnl_dereference(tfile->tun); 2989 tun = rtnl_dereference(tfile->tun);
2984 if (!tun || !(tun->flags & IFF_MULTI_QUEUE) || tfile->detached) 2990 if (!tun || !(tun->flags & IFF_MULTI_QUEUE) || tfile->detached)