aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-09-15 07:35:10 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-15 22:29:47 -0400
commit3a43be3c328ff42327da0b141de360dc4587aab7 (patch)
tree669c86867533e70dfe3a2aa52e17802aeb2e60bf /net/ipv6
parent1507850b400492fdedc3064d3b8db5e9a1c871e3 (diff)
sit: get rid of ipip6_lock
As RTNL is held while doing tunnels inserts and deletes, we can remove ipip6_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/ipv6')
-rw-r--r--net/ipv6/sit.c64
1 files changed, 31 insertions, 33 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 86618eb30335..6822481ff766 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -68,19 +68,18 @@ static void ipip6_tunnel_setup(struct net_device *dev);
68 68
69static int sit_net_id __read_mostly; 69static int sit_net_id __read_mostly;
70struct sit_net { 70struct sit_net {
71 struct ip_tunnel *tunnels_r_l[HASH_SIZE]; 71 struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE];
72 struct ip_tunnel *tunnels_r[HASH_SIZE]; 72 struct ip_tunnel __rcu *tunnels_r[HASH_SIZE];
73 struct ip_tunnel *tunnels_l[HASH_SIZE]; 73 struct ip_tunnel __rcu *tunnels_l[HASH_SIZE];
74 struct ip_tunnel *tunnels_wc[1]; 74 struct ip_tunnel __rcu *tunnels_wc[1];
75 struct ip_tunnel **tunnels[4]; 75 struct ip_tunnel __rcu **tunnels[4];
76 76
77 struct net_device *fb_tunnel_dev; 77 struct net_device *fb_tunnel_dev;
78}; 78};
79 79
80/* 80/*
81 * Locking : hash tables are protected by RCU and a spinlock 81 * Locking : hash tables are protected by RCU and RTNL
82 */ 82 */
83static DEFINE_SPINLOCK(ipip6_lock);
84 83
85#define for_each_ip_tunnel_rcu(start) \ 84#define for_each_ip_tunnel_rcu(start) \
86 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) 85 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
@@ -91,8 +90,8 @@ static DEFINE_SPINLOCK(ipip6_lock);
91static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, 90static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
92 struct net_device *dev, __be32 remote, __be32 local) 91 struct net_device *dev, __be32 remote, __be32 local)
93{ 92{
94 unsigned h0 = HASH(remote); 93 unsigned int h0 = HASH(remote);
95 unsigned h1 = HASH(local); 94 unsigned int h1 = HASH(local);
96 struct ip_tunnel *t; 95 struct ip_tunnel *t;
97 struct sit_net *sitn = net_generic(net, sit_net_id); 96 struct sit_net *sitn = net_generic(net, sit_net_id);
98 97
@@ -121,12 +120,12 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
121 return NULL; 120 return NULL;
122} 121}
123 122
124static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, 123static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn,
125 struct ip_tunnel_parm *parms) 124 struct ip_tunnel_parm *parms)
126{ 125{
127 __be32 remote = parms->iph.daddr; 126 __be32 remote = parms->iph.daddr;
128 __be32 local = parms->iph.saddr; 127 __be32 local = parms->iph.saddr;
129 unsigned h = 0; 128 unsigned int h = 0;
130 int prio = 0; 129 int prio = 0;
131 130
132 if (remote) { 131 if (remote) {
@@ -140,7 +139,7 @@ static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn,
140 return &sitn->tunnels[prio][h]; 139 return &sitn->tunnels[prio][h];
141} 140}
142 141
143static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, 142static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn,
144 struct ip_tunnel *t) 143 struct ip_tunnel *t)
145{ 144{
146 return __ipip6_bucket(sitn, &t->parms); 145 return __ipip6_bucket(sitn, &t->parms);
@@ -148,13 +147,14 @@ static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn,
148 147
149static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) 148static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
150{ 149{
151 struct ip_tunnel **tp; 150 struct ip_tunnel __rcu **tp;
152 151 struct ip_tunnel *iter;
153 for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { 152
154 if (t == *tp) { 153 for (tp = ipip6_bucket(sitn, t);
155 spin_lock_bh(&ipip6_lock); 154 (iter = rtnl_dereference(*tp)) != NULL;
156 *tp = t->next; 155 tp = &iter->next) {
157 spin_unlock_bh(&ipip6_lock); 156 if (t == iter) {
157 rcu_assign_pointer(*tp, t->next);
158 break; 158 break;
159 } 159 }
160 } 160 }
@@ -162,12 +162,10 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
162 162
163static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) 163static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
164{ 164{
165 struct ip_tunnel **tp = ipip6_bucket(sitn, t); 165 struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t);
166 166
167 spin_lock_bh(&ipip6_lock); 167 rcu_assign_pointer(t->next, rtnl_dereference(*tp));
168 t->next = *tp;
169 rcu_assign_pointer(*tp, t); 168 rcu_assign_pointer(*tp, t);
170 spin_unlock_bh(&ipip6_lock);
171} 169}
172 170
173static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) 171static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
@@ -187,17 +185,20 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
187#endif 185#endif
188} 186}
189 187
190static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, 188static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
191 struct ip_tunnel_parm *parms, int create) 189 struct ip_tunnel_parm *parms, int create)
192{ 190{
193 __be32 remote = parms->iph.daddr; 191 __be32 remote = parms->iph.daddr;
194 __be32 local = parms->iph.saddr; 192 __be32 local = parms->iph.saddr;
195 struct ip_tunnel *t, **tp, *nt; 193 struct ip_tunnel *t, *nt;
194 struct ip_tunnel __rcu **tp;
196 struct net_device *dev; 195 struct net_device *dev;
197 char name[IFNAMSIZ]; 196 char name[IFNAMSIZ];
198 struct sit_net *sitn = net_generic(net, sit_net_id); 197 struct sit_net *sitn = net_generic(net, sit_net_id);
199 198
200 for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { 199 for (tp = __ipip6_bucket(sitn, parms);
200 (t = rtnl_dereference(*tp)) != NULL;
201 tp = &t->next) {
201 if (local == t->parms.iph.saddr && 202 if (local == t->parms.iph.saddr &&
202 remote == t->parms.iph.daddr && 203 remote == t->parms.iph.daddr &&
203 parms->link == t->parms.link) { 204 parms->link == t->parms.link) {
@@ -340,7 +341,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
340 341
341 ASSERT_RTNL(); 342 ASSERT_RTNL();
342 343
343 for (p = t->prl; p; p = p->next) { 344 for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) {
344 if (p->addr == a->addr) { 345 if (p->addr == a->addr) {
345 if (chg) { 346 if (chg) {
346 p->flags = a->flags; 347 p->flags = a->flags;
@@ -451,15 +452,12 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
451 struct sit_net *sitn = net_generic(net, sit_net_id); 452 struct sit_net *sitn = net_generic(net, sit_net_id);
452 453
453 if (dev == sitn->fb_tunnel_dev) { 454 if (dev == sitn->fb_tunnel_dev) {
454 spin_lock_bh(&ipip6_lock); 455 rcu_assign_pointer(sitn->tunnels_wc[0], NULL);
455 sitn->tunnels_wc[0] = NULL;
456 spin_unlock_bh(&ipip6_lock);
457 dev_put(dev);
458 } else { 456 } else {
459 ipip6_tunnel_unlink(sitn, netdev_priv(dev)); 457 ipip6_tunnel_unlink(sitn, netdev_priv(dev));
460 ipip6_tunnel_del_prl(netdev_priv(dev), NULL); 458 ipip6_tunnel_del_prl(netdev_priv(dev), NULL);
461 dev_put(dev);
462 } 459 }
460 dev_put(dev);
463} 461}
464 462
465 463
@@ -590,7 +588,7 @@ __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel)
590#ifdef CONFIG_IPV6_SIT_6RD 588#ifdef CONFIG_IPV6_SIT_6RD
591 if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, 589 if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix,
592 tunnel->ip6rd.prefixlen)) { 590 tunnel->ip6rd.prefixlen)) {
593 unsigned pbw0, pbi0; 591 unsigned int pbw0, pbi0;
594 int pbi1; 592 int pbi1;
595 u32 d; 593 u32 d;
596 594