diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-09-15 07:35:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-15 22:29:47 -0400 |
commit | 3a43be3c328ff42327da0b141de360dc4587aab7 (patch) | |
tree | 669c86867533e70dfe3a2aa52e17802aeb2e60bf /net/ipv6/sit.c | |
parent | 1507850b400492fdedc3064d3b8db5e9a1c871e3 (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/sit.c')
-rw-r--r-- | net/ipv6/sit.c | 64 |
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 | ||
69 | static int sit_net_id __read_mostly; | 69 | static int sit_net_id __read_mostly; |
70 | struct sit_net { | 70 | struct 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 | */ |
83 | static 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); | |||
91 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | 90 | static 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 | ||
124 | static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, | 123 | static 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 | ||
143 | static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, | 142 | static 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 | ||
149 | static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) | 148 | static 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 | ||
163 | static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) | 163 | static 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 | ||
173 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | 171 | static 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 | ||
190 | static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | 188 | static 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 | ||