aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-09-15 07:07:53 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-15 22:29:46 -0400
commit1507850b400492fdedc3064d3b8db5e9a1c871e3 (patch)
tree0f0039380a7c2ec30b3bb114b68edba7865762d5 /net
parentb7285b7912776a4492744949c747c88d539006fa (diff)
gre: get rid of ipgre_lock
As RTNL is held while doing tunnels inserts and deletes, we can remove ipgre_lock spinlock. My initial RCU conversion was conservative and converted the rwlock to spinlock, with no RTNL requirement. Use appropriate rcu annotations and modern lockdep checks as well. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ip_gre.c61
1 files changed, 32 insertions, 29 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 85176895495a..fc20e687e933 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -129,7 +129,7 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev);
129 129
130static int ipgre_net_id __read_mostly; 130static int ipgre_net_id __read_mostly;
131struct ipgre_net { 131struct ipgre_net {
132 struct ip_tunnel *tunnels[4][HASH_SIZE]; 132 struct ip_tunnel __rcu *tunnels[4][HASH_SIZE];
133 133
134 struct net_device *fb_tunnel_dev; 134 struct net_device *fb_tunnel_dev;
135}; 135};
@@ -159,9 +159,8 @@ struct ipgre_net {
159#define tunnels_l tunnels[1] 159#define tunnels_l tunnels[1]
160#define tunnels_wc tunnels[0] 160#define tunnels_wc tunnels[0]
161/* 161/*
162 * Locking : hash tables are protected by RCU and a spinlock 162 * Locking : hash tables are protected by RCU and RTNL
163 */ 163 */
164static DEFINE_SPINLOCK(ipgre_lock);
165 164
166#define for_each_ip_tunnel_rcu(start) \ 165#define for_each_ip_tunnel_rcu(start) \
167 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) 166 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
@@ -174,8 +173,8 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
174{ 173{
175 struct net *net = dev_net(dev); 174 struct net *net = dev_net(dev);
176 int link = dev->ifindex; 175 int link = dev->ifindex;
177 unsigned h0 = HASH(remote); 176 unsigned int h0 = HASH(remote);
178 unsigned h1 = HASH(key); 177 unsigned int h1 = HASH(key);
179 struct ip_tunnel *t, *cand = NULL; 178 struct ip_tunnel *t, *cand = NULL;
180 struct ipgre_net *ign = net_generic(net, ipgre_net_id); 179 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
181 int dev_type = (gre_proto == htons(ETH_P_TEB)) ? 180 int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
@@ -290,13 +289,13 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
290 return NULL; 289 return NULL;
291} 290}
292 291
293static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign, 292static struct ip_tunnel __rcu **__ipgre_bucket(struct ipgre_net *ign,
294 struct ip_tunnel_parm *parms) 293 struct ip_tunnel_parm *parms)
295{ 294{
296 __be32 remote = parms->iph.daddr; 295 __be32 remote = parms->iph.daddr;
297 __be32 local = parms->iph.saddr; 296 __be32 local = parms->iph.saddr;
298 __be32 key = parms->i_key; 297 __be32 key = parms->i_key;
299 unsigned h = HASH(key); 298 unsigned int h = HASH(key);
300 int prio = 0; 299 int prio = 0;
301 300
302 if (local) 301 if (local)
@@ -309,7 +308,7 @@ static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign,
309 return &ign->tunnels[prio][h]; 308 return &ign->tunnels[prio][h];
310} 309}
311 310
312static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign, 311static inline struct ip_tunnel __rcu **ipgre_bucket(struct ipgre_net *ign,
313 struct ip_tunnel *t) 312 struct ip_tunnel *t)
314{ 313{
315 return __ipgre_bucket(ign, &t->parms); 314 return __ipgre_bucket(ign, &t->parms);
@@ -317,23 +316,22 @@ static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign,
317 316
318static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t) 317static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
319{ 318{
320 struct ip_tunnel **tp = ipgre_bucket(ign, t); 319 struct ip_tunnel __rcu **tp = ipgre_bucket(ign, t);
321 320
322 spin_lock_bh(&ipgre_lock); 321 rcu_assign_pointer(t->next, rtnl_dereference(*tp));
323 t->next = *tp;
324 rcu_assign_pointer(*tp, t); 322 rcu_assign_pointer(*tp, t);
325 spin_unlock_bh(&ipgre_lock);
326} 323}
327 324
328static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t) 325static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
329{ 326{
330 struct ip_tunnel **tp; 327 struct ip_tunnel __rcu **tp;
331 328 struct ip_tunnel *iter;
332 for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) { 329
333 if (t == *tp) { 330 for (tp = ipgre_bucket(ign, t);
334 spin_lock_bh(&ipgre_lock); 331 (iter = rtnl_dereference(*tp)) != NULL;
335 *tp = t->next; 332 tp = &iter->next) {
336 spin_unlock_bh(&ipgre_lock); 333 if (t == iter) {
334 rcu_assign_pointer(*tp, t->next);
337 break; 335 break;
338 } 336 }
339 } 337 }
@@ -347,10 +345,13 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
347 __be32 local = parms->iph.saddr; 345 __be32 local = parms->iph.saddr;
348 __be32 key = parms->i_key; 346 __be32 key = parms->i_key;
349 int link = parms->link; 347 int link = parms->link;
350 struct ip_tunnel *t, **tp; 348 struct ip_tunnel *t;
349 struct ip_tunnel __rcu **tp;
351 struct ipgre_net *ign = net_generic(net, ipgre_net_id); 350 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
352 351
353 for (tp = __ipgre_bucket(ign, parms); (t = *tp) != NULL; tp = &t->next) 352 for (tp = __ipgre_bucket(ign, parms);
353 (t = rtnl_dereference(*tp)) != NULL;
354 tp = &t->next)
354 if (local == t->parms.iph.saddr && 355 if (local == t->parms.iph.saddr &&
355 remote == t->parms.iph.daddr && 356 remote == t->parms.iph.daddr &&
356 key == t->parms.i_key && 357 key == t->parms.i_key &&
@@ -361,7 +362,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
361 return t; 362 return t;
362} 363}
363 364
364static struct ip_tunnel * ipgre_tunnel_locate(struct net *net, 365static struct ip_tunnel *ipgre_tunnel_locate(struct net *net,
365 struct ip_tunnel_parm *parms, int create) 366 struct ip_tunnel_parm *parms, int create)
366{ 367{
367 struct ip_tunnel *t, *nt; 368 struct ip_tunnel *t, *nt;
@@ -669,7 +670,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
669 u8 tos; 670 u8 tos;
670 __be16 df; 671 __be16 df;
671 struct rtable *rt; /* Route to the other host */ 672 struct rtable *rt; /* Route to the other host */
672 struct net_device *tdev; /* Device to other host */ 673 struct net_device *tdev; /* Device to other host */
673 struct iphdr *iph; /* Our new IP header */ 674 struct iphdr *iph; /* Our new IP header */
674 unsigned int max_headroom; /* The extra header space needed */ 675 unsigned int max_headroom; /* The extra header space needed */
675 int gre_hlen; 676 int gre_hlen;
@@ -1013,7 +1014,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
1013 break; 1014 break;
1014 } 1015 }
1015 } else { 1016 } else {
1016 unsigned nflags = 0; 1017 unsigned int nflags = 0;
1017 1018
1018 t = netdev_priv(dev); 1019 t = netdev_priv(dev);
1019 1020
@@ -1126,7 +1127,7 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
1126 1127
1127static int ipgre_header(struct sk_buff *skb, struct net_device *dev, 1128static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
1128 unsigned short type, 1129 unsigned short type,
1129 const void *daddr, const void *saddr, unsigned len) 1130 const void *daddr, const void *saddr, unsigned int len)
1130{ 1131{
1131 struct ip_tunnel *t = netdev_priv(dev); 1132 struct ip_tunnel *t = netdev_priv(dev);
1132 struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); 1133 struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
@@ -1275,7 +1276,7 @@ static void ipgre_fb_tunnel_init(struct net_device *dev)
1275 tunnel->hlen = sizeof(struct iphdr) + 4; 1276 tunnel->hlen = sizeof(struct iphdr) + 4;
1276 1277
1277 dev_hold(dev); 1278 dev_hold(dev);
1278 ign->tunnels_wc[0] = tunnel; 1279 rcu_assign_pointer(ign->tunnels_wc[0], tunnel);
1279} 1280}
1280 1281
1281 1282
@@ -1291,11 +1292,13 @@ static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
1291 for (prio = 0; prio < 4; prio++) { 1292 for (prio = 0; prio < 4; prio++) {
1292 int h; 1293 int h;
1293 for (h = 0; h < HASH_SIZE; h++) { 1294 for (h = 0; h < HASH_SIZE; h++) {
1294 struct ip_tunnel *t = ign->tunnels[prio][h]; 1295 struct ip_tunnel *t;
1296
1297 t = rtnl_dereference(ign->tunnels[prio][h]);
1295 1298
1296 while (t != NULL) { 1299 while (t != NULL) {
1297 unregister_netdevice_queue(t->dev, head); 1300 unregister_netdevice_queue(t->dev, head);
1298 t = t->next; 1301 t = rtnl_dereference(t->next);
1299 } 1302 }
1300 } 1303 }
1301 } 1304 }
@@ -1522,7 +1525,7 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1522 t = nt; 1525 t = nt;
1523 1526
1524 if (dev->type != ARPHRD_ETHER) { 1527 if (dev->type != ARPHRD_ETHER) {
1525 unsigned nflags = 0; 1528 unsigned int nflags = 0;
1526 1529
1527 if (ipv4_is_multicast(p.iph.daddr)) 1530 if (ipv4_is_multicast(p.iph.daddr))
1528 nflags = IFF_BROADCAST; 1531 nflags = IFF_BROADCAST;