diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-09-15 07:07:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-15 22:29:46 -0400 |
commit | 1507850b400492fdedc3064d3b8db5e9a1c871e3 (patch) | |
tree | 0f0039380a7c2ec30b3bb114b68edba7865762d5 /net | |
parent | b7285b7912776a4492744949c747c88d539006fa (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.c | 61 |
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 | ||
130 | static int ipgre_net_id __read_mostly; | 130 | static int ipgre_net_id __read_mostly; |
131 | struct ipgre_net { | 131 | struct 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 | */ |
164 | static 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 | ||
293 | static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign, | 292 | static 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 | ||
312 | static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign, | 311 | static 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 | ||
318 | static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t) | 317 | static 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 | ||
328 | static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t) | 325 | static 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 | ||
364 | static struct ip_tunnel * ipgre_tunnel_locate(struct net *net, | 365 | static 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 | ||
1127 | static int ipgre_header(struct sk_buff *skb, struct net_device *dev, | 1128 | static 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; |