Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Eric Dumazet and committed by
David S. Miller
3a43be3c 1507850b

+30 -32
+30 -32
net/ipv6/sit.c
··· 68 68 69 69 static int sit_net_id __read_mostly; 70 70 struct sit_net { 71 - struct ip_tunnel *tunnels_r_l[HASH_SIZE]; 72 - struct ip_tunnel *tunnels_r[HASH_SIZE]; 73 - struct ip_tunnel *tunnels_l[HASH_SIZE]; 74 - struct ip_tunnel *tunnels_wc[1]; 75 - struct ip_tunnel **tunnels[4]; 71 + struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE]; 72 + struct ip_tunnel __rcu *tunnels_r[HASH_SIZE]; 73 + struct ip_tunnel __rcu *tunnels_l[HASH_SIZE]; 74 + struct ip_tunnel __rcu *tunnels_wc[1]; 75 + struct ip_tunnel __rcu **tunnels[4]; 76 76 77 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 84 #define for_each_ip_tunnel_rcu(start) \ 86 85 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) ··· 90 91 static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, 91 92 struct net_device *dev, __be32 remote, __be32 local) 92 93 { 93 - unsigned h0 = HASH(remote); 94 - unsigned h1 = HASH(local); 94 + unsigned int h0 = HASH(remote); 95 + unsigned int h1 = HASH(local); 95 96 struct ip_tunnel *t; 96 97 struct sit_net *sitn = net_generic(net, sit_net_id); 97 98 ··· 120 121 return NULL; 121 122 } 122 123 123 - static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, 124 + static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn, 124 125 struct ip_tunnel_parm *parms) 125 126 { 126 127 __be32 remote = parms->iph.daddr; 127 128 __be32 local = parms->iph.saddr; 128 - unsigned h = 0; 129 + unsigned int h = 0; 129 130 int prio = 0; 130 131 131 132 if (remote) { ··· 139 140 return &sitn->tunnels[prio][h]; 140 141 } 141 142 142 - static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, 143 + static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn, 143 144 struct ip_tunnel *t) 144 145 { 145 146 return __ipip6_bucket(sitn, &t->parms); ··· 147 148 148 149 static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) 149 150 { 150 - struct ip_tunnel **tp; 151 + struct ip_tunnel __rcu **tp; 152 + struct ip_tunnel *iter; 151 153 152 - for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { 153 - if (t == *tp) { 154 - spin_lock_bh(&ipip6_lock); 155 - *tp = t->next; 156 - spin_unlock_bh(&ipip6_lock); 154 + for (tp = ipip6_bucket(sitn, t); 155 + (iter = rtnl_dereference(*tp)) != NULL; 156 + tp = &iter->next) { 157 + if (t == iter) { 158 + rcu_assign_pointer(*tp, t->next); 157 159 break; 158 160 } 159 161 } ··· 162 162 163 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); 168 - t->next = *tp; 167 + rcu_assign_pointer(t->next, rtnl_dereference(*tp)); 169 168 rcu_assign_pointer(*tp, t); 170 - spin_unlock_bh(&ipip6_lock); 171 169 } 172 170 173 171 static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) ··· 185 187 #endif 186 188 } 187 189 188 - static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, 190 + static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, 189 191 struct ip_tunnel_parm *parms, int create) 190 192 { 191 193 __be32 remote = parms->iph.daddr; 192 194 __be32 local = parms->iph.saddr; 193 - struct ip_tunnel *t, **tp, *nt; 195 + struct ip_tunnel *t, *nt; 196 + struct ip_tunnel __rcu **tp; 194 197 struct net_device *dev; 195 198 char name[IFNAMSIZ]; 196 199 struct sit_net *sitn = net_generic(net, sit_net_id); 197 200 198 - for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { 201 + for (tp = __ipip6_bucket(sitn, parms); 202 + (t = rtnl_dereference(*tp)) != NULL; 203 + tp = &t->next) { 199 204 if (local == t->parms.iph.saddr && 200 205 remote == t->parms.iph.daddr && 201 206 parms->link == t->parms.link) { ··· 341 340 342 341 ASSERT_RTNL(); 343 342 344 - for (p = t->prl; p; p = p->next) { 343 + for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) { 345 344 if (p->addr == a->addr) { 346 345 if (chg) { 347 346 p->flags = a->flags; ··· 452 451 struct sit_net *sitn = net_generic(net, sit_net_id); 453 452 454 453 if (dev == sitn->fb_tunnel_dev) { 455 - spin_lock_bh(&ipip6_lock); 456 - sitn->tunnels_wc[0] = NULL; 457 - spin_unlock_bh(&ipip6_lock); 458 - dev_put(dev); 454 + rcu_assign_pointer(sitn->tunnels_wc[0], NULL); 459 455 } else { 460 456 ipip6_tunnel_unlink(sitn, netdev_priv(dev)); 461 457 ipip6_tunnel_del_prl(netdev_priv(dev), NULL); 462 - dev_put(dev); 463 458 } 459 + dev_put(dev); 464 460 } 465 461 466 462 ··· 588 590 #ifdef CONFIG_IPV6_SIT_6RD 589 591 if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, 590 592 tunnel->ip6rd.prefixlen)) { 591 - unsigned pbw0, pbi0; 593 + unsigned int pbw0, pbi0; 592 594 int pbi1; 593 595 u32 d; 594 596