summaryrefslogtreecommitdiffstats
path: root/drivers/net/macvtap.c
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevic@redhat.com>2013-06-25 16:04:19 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-25 19:44:56 -0400
commit441ac0fcaadc76ad09771812382345001dd2b813 (patch)
tree7ec1df8d9dfabfab411693461b65a3841a3ec276 /drivers/net/macvtap.c
parent2d48d67fa8cd129ea85ea02d91b4a793286866f8 (diff)
macvtap: Convert to using rtnl lock
Macvtap uses a private lock to protect the relationship between macvtap_queue and macvlan_dev. The private lock is not needed since the relationship is managed by user via open(), release(), and dellink() calls. dellink() already happens under rtnl, so we can safely convert open() and release(), and use it in ioctl() as well. Suggested by Eric Dumazet. Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvtap.c')
-rw-r--r--drivers/net/macvtap.c62
1 files changed, 25 insertions, 37 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 5a76f20776af..efbf2eb6ae78 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -69,7 +69,7 @@ static const struct proto_ops macvtap_socket_ops;
69 * RCU usage: 69 * RCU usage:
70 * The macvtap_queue and the macvlan_dev are loosely coupled, the 70 * The macvtap_queue and the macvlan_dev are loosely coupled, the
71 * pointers from one to the other can only be read while rcu_read_lock 71 * pointers from one to the other can only be read while rcu_read_lock
72 * or macvtap_lock is held. 72 * or rtnl is held.
73 * 73 *
74 * Both the file and the macvlan_dev hold a reference on the macvtap_queue 74 * Both the file and the macvlan_dev hold a reference on the macvtap_queue
75 * through sock_hold(&q->sk). When the macvlan_dev goes away first, 75 * through sock_hold(&q->sk). When the macvlan_dev goes away first,
@@ -81,7 +81,6 @@ static const struct proto_ops macvtap_socket_ops;
81 * file or the dev. The data structure is freed through __sk_free 81 * file or the dev. The data structure is freed through __sk_free
82 * when both our references and any pending SKBs are gone. 82 * when both our references and any pending SKBs are gone.
83 */ 83 */
84static DEFINE_SPINLOCK(macvtap_lock);
85 84
86static int macvtap_enable_queue(struct net_device *dev, struct file *file, 85static int macvtap_enable_queue(struct net_device *dev, struct file *file,
87 struct macvtap_queue *q) 86 struct macvtap_queue *q)
@@ -89,7 +88,7 @@ static int macvtap_enable_queue(struct net_device *dev, struct file *file,
89 struct macvlan_dev *vlan = netdev_priv(dev); 88 struct macvlan_dev *vlan = netdev_priv(dev);
90 int err = -EINVAL; 89 int err = -EINVAL;
91 90
92 spin_lock(&macvtap_lock); 91 ASSERT_RTNL();
93 92
94 if (q->enabled) 93 if (q->enabled)
95 goto out; 94 goto out;
@@ -101,7 +100,6 @@ static int macvtap_enable_queue(struct net_device *dev, struct file *file,
101 100
102 vlan->numvtaps++; 101 vlan->numvtaps++;
103out: 102out:
104 spin_unlock(&macvtap_lock);
105 return err; 103 return err;
106} 104}
107 105
@@ -111,7 +109,7 @@ static int macvtap_set_queue(struct net_device *dev, struct file *file,
111 struct macvlan_dev *vlan = netdev_priv(dev); 109 struct macvlan_dev *vlan = netdev_priv(dev);
112 int err = -EBUSY; 110 int err = -EBUSY;
113 111
114 spin_lock(&macvtap_lock); 112 rtnl_lock();
115 if (vlan->numqueues == MAX_MACVTAP_QUEUES) 113 if (vlan->numqueues == MAX_MACVTAP_QUEUES)
116 goto out; 114 goto out;
117 115
@@ -130,26 +128,25 @@ static int macvtap_set_queue(struct net_device *dev, struct file *file,
130 vlan->numqueues++; 128 vlan->numqueues++;
131 129
132out: 130out:
133 spin_unlock(&macvtap_lock); 131 rtnl_unlock();
134 return err; 132 return err;
135} 133}
136 134
137static int __macvtap_disable_queue(struct macvtap_queue *q) 135static int macvtap_disable_queue(struct macvtap_queue *q)
138{ 136{
139 struct macvlan_dev *vlan; 137 struct macvlan_dev *vlan;
140 struct macvtap_queue *nq; 138 struct macvtap_queue *nq;
141 139
142 vlan = rcu_dereference_protected(q->vlan, 140 ASSERT_RTNL();
143 lockdep_is_held(&macvtap_lock));
144
145 if (!q->enabled) 141 if (!q->enabled)
146 return -EINVAL; 142 return -EINVAL;
147 143
144 vlan = rtnl_dereference(q->vlan);
145
148 if (vlan) { 146 if (vlan) {
149 int index = q->queue_index; 147 int index = q->queue_index;
150 BUG_ON(index >= vlan->numvtaps); 148 BUG_ON(index >= vlan->numvtaps);
151 nq = rcu_dereference_protected(vlan->taps[vlan->numvtaps - 1], 149 nq = rtnl_dereference(vlan->taps[vlan->numvtaps - 1]);
152 lockdep_is_held(&macvtap_lock));
153 nq->queue_index = index; 150 nq->queue_index = index;
154 151
155 rcu_assign_pointer(vlan->taps[index], nq); 152 rcu_assign_pointer(vlan->taps[index], nq);
@@ -162,17 +159,6 @@ static int __macvtap_disable_queue(struct macvtap_queue *q)
162 return 0; 159 return 0;
163} 160}
164 161
165static int macvtap_disable_queue(struct macvtap_queue *q)
166{
167 int err;
168
169 spin_lock(&macvtap_lock);
170 err = __macvtap_disable_queue(q);
171 spin_unlock(&macvtap_lock);
172
173 return err;
174}
175
176/* 162/*
177 * The file owning the queue got closed, give up both 163 * The file owning the queue got closed, give up both
178 * the reference that the files holds as well as the 164 * the reference that the files holds as well as the
@@ -185,12 +171,12 @@ static void macvtap_put_queue(struct macvtap_queue *q)
185{ 171{
186 struct macvlan_dev *vlan; 172 struct macvlan_dev *vlan;
187 173
188 spin_lock(&macvtap_lock); 174 rtnl_lock();
189 vlan = rcu_dereference_protected(q->vlan, 175 vlan = rtnl_dereference(q->vlan);
190 lockdep_is_held(&macvtap_lock)); 176
191 if (vlan) { 177 if (vlan) {
192 if (q->enabled) 178 if (q->enabled)
193 BUG_ON(__macvtap_disable_queue(q)); 179 BUG_ON(macvtap_disable_queue(q));
194 180
195 vlan->numqueues--; 181 vlan->numqueues--;
196 RCU_INIT_POINTER(q->vlan, NULL); 182 RCU_INIT_POINTER(q->vlan, NULL);
@@ -198,7 +184,7 @@ static void macvtap_put_queue(struct macvtap_queue *q)
198 list_del_init(&q->next); 184 list_del_init(&q->next);
199 } 185 }
200 186
201 spin_unlock(&macvtap_lock); 187 rtnl_unlock();
202 188
203 synchronize_rcu(); 189 synchronize_rcu();
204 sock_put(&q->sk); 190 sock_put(&q->sk);
@@ -260,7 +246,7 @@ static void macvtap_del_queues(struct net_device *dev)
260 struct macvtap_queue *q, *tmp, *qlist[MAX_MACVTAP_QUEUES]; 246 struct macvtap_queue *q, *tmp, *qlist[MAX_MACVTAP_QUEUES];
261 int i, j = 0; 247 int i, j = 0;
262 248
263 spin_lock(&macvtap_lock); 249 ASSERT_RTNL();
264 list_for_each_entry_safe(q, tmp, &vlan->queue_list, next) { 250 list_for_each_entry_safe(q, tmp, &vlan->queue_list, next) {
265 list_del_init(&q->next); 251 list_del_init(&q->next);
266 qlist[j++] = q; 252 qlist[j++] = q;
@@ -275,9 +261,6 @@ static void macvtap_del_queues(struct net_device *dev)
275 BUG_ON(vlan->numqueues); 261 BUG_ON(vlan->numqueues);
276 /* guarantee that any future macvtap_set_queue will fail */ 262 /* guarantee that any future macvtap_set_queue will fail */
277 vlan->numvtaps = MAX_MACVTAP_QUEUES; 263 vlan->numvtaps = MAX_MACVTAP_QUEUES;
278 spin_unlock(&macvtap_lock);
279
280 synchronize_rcu();
281 264
282 for (--j; j >= 0; j--) 265 for (--j; j >= 0; j--)
283 sock_put(&qlist[j]->sk); 266 sock_put(&qlist[j]->sk);
@@ -941,11 +924,10 @@ static struct macvlan_dev *macvtap_get_vlan(struct macvtap_queue *q)
941{ 924{
942 struct macvlan_dev *vlan; 925 struct macvlan_dev *vlan;
943 926
944 rcu_read_lock_bh(); 927 ASSERT_RTNL();
945 vlan = rcu_dereference_bh(q->vlan); 928 vlan = rtnl_dereference(q->vlan);
946 if (vlan) 929 if (vlan)
947 dev_hold(vlan->dev); 930 dev_hold(vlan->dev);
948 rcu_read_unlock_bh();
949 931
950 return vlan; 932 return vlan;
951} 933}
@@ -1008,21 +990,27 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
1008 return ret; 990 return ret;
1009 991
1010 case TUNGETIFF: 992 case TUNGETIFF:
993 rtnl_lock();
1011 vlan = macvtap_get_vlan(q); 994 vlan = macvtap_get_vlan(q);
1012 if (!vlan) 995 if (!vlan) {
996 rtnl_unlock();
1013 return -ENOLINK; 997 return -ENOLINK;
998 }
1014 999
1015 ret = 0; 1000 ret = 0;
1016 if (copy_to_user(&ifr->ifr_name, vlan->dev->name, IFNAMSIZ) || 1001 if (copy_to_user(&ifr->ifr_name, vlan->dev->name, IFNAMSIZ) ||
1017 put_user(q->flags, &ifr->ifr_flags)) 1002 put_user(q->flags, &ifr->ifr_flags))
1018 ret = -EFAULT; 1003 ret = -EFAULT;
1019 macvtap_put_vlan(vlan); 1004 macvtap_put_vlan(vlan);
1005 rtnl_unlock();
1020 return ret; 1006 return ret;
1021 1007
1022 case TUNSETQUEUE: 1008 case TUNSETQUEUE:
1023 if (get_user(u, &ifr->ifr_flags)) 1009 if (get_user(u, &ifr->ifr_flags))
1024 return -EFAULT; 1010 return -EFAULT;
1025 return macvtap_ioctl_set_queue(file, u); 1011 rtnl_lock();
1012 ret = macvtap_ioctl_set_queue(file, u);
1013 rtnl_unlock();
1026 1014
1027 case TUNGETFEATURES: 1015 case TUNGETFEATURES:
1028 if (put_user(IFF_TAP | IFF_NO_PI | IFF_VNET_HDR | 1016 if (put_user(IFF_TAP | IFF_NO_PI | IFF_VNET_HDR |