Skip to content

Commit 8d5b2c0

Browse files
Eric Dumazetdavem330
authored andcommitted
gre: convert hash tables locking to RCU
GRE tunnels use one rwlock to protect their hash tables. This locking scheme can be converted to RCU for free, since netdevice already must wait for a RCU grace period at dismantle time. Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2922bc8 commit 8d5b2c0

File tree

1 file changed

+23
-17
lines changed

1 file changed

+23
-17
lines changed

net/ipv4/ip_gre.c

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,13 @@ struct ipgre_net {
156156
#define tunnels_r tunnels[2]
157157
#define tunnels_l tunnels[1]
158158
#define tunnels_wc tunnels[0]
159+
/*
160+
* Locking : hash tables are protected by RCU and a spinlock
161+
*/
162+
static DEFINE_SPINLOCK(ipgre_lock);
159163

160-
static DEFINE_RWLOCK(ipgre_lock);
164+
#define for_each_ip_tunnel_rcu(start) \
165+
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
161166

162167
/* Given src, dst and key, find appropriate for input tunnel. */
163168

@@ -175,7 +180,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
175180
ARPHRD_ETHER : ARPHRD_IPGRE;
176181
int score, cand_score = 4;
177182

178-
for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) {
183+
for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
179184
if (local != t->parms.iph.saddr ||
180185
remote != t->parms.iph.daddr ||
181186
key != t->parms.i_key ||
@@ -200,7 +205,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
200205
}
201206
}
202207

203-
for (t = ign->tunnels_r[h0^h1]; t; t = t->next) {
208+
for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
204209
if (remote != t->parms.iph.daddr ||
205210
key != t->parms.i_key ||
206211
!(t->dev->flags & IFF_UP))
@@ -224,7 +229,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
224229
}
225230
}
226231

227-
for (t = ign->tunnels_l[h1]; t; t = t->next) {
232+
for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
228233
if ((local != t->parms.iph.saddr &&
229234
(local != t->parms.iph.daddr ||
230235
!ipv4_is_multicast(local))) ||
@@ -250,7 +255,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
250255
}
251256
}
252257

253-
for (t = ign->tunnels_wc[h1]; t; t = t->next) {
258+
for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
254259
if (t->parms.i_key != key ||
255260
!(t->dev->flags & IFF_UP))
256261
continue;
@@ -276,8 +281,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
276281
if (cand != NULL)
277282
return cand;
278283

279-
if (ign->fb_tunnel_dev->flags & IFF_UP)
280-
return netdev_priv(ign->fb_tunnel_dev);
284+
dev = ign->fb_tunnel_dev;
285+
if (dev->flags & IFF_UP)
286+
return netdev_priv(dev);
281287

282288
return NULL;
283289
}
@@ -311,10 +317,10 @@ static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
311317
{
312318
struct ip_tunnel **tp = ipgre_bucket(ign, t);
313319

320+
spin_lock_bh(&ipgre_lock);
314321
t->next = *tp;
315-
write_lock_bh(&ipgre_lock);
316-
*tp = t;
317-
write_unlock_bh(&ipgre_lock);
322+
rcu_assign_pointer(*tp, t);
323+
spin_unlock_bh(&ipgre_lock);
318324
}
319325

320326
static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
@@ -323,9 +329,9 @@ static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
323329

324330
for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) {
325331
if (t == *tp) {
326-
write_lock_bh(&ipgre_lock);
332+
spin_lock_bh(&ipgre_lock);
327333
*tp = t->next;
328-
write_unlock_bh(&ipgre_lock);
334+
spin_unlock_bh(&ipgre_lock);
329335
break;
330336
}
331337
}
@@ -476,7 +482,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
476482
break;
477483
}
478484

479-
read_lock(&ipgre_lock);
485+
rcu_read_lock();
480486
t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
481487
flags & GRE_KEY ?
482488
*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
@@ -494,7 +500,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
494500
t->err_count = 1;
495501
t->err_time = jiffies;
496502
out:
497-
read_unlock(&ipgre_lock);
503+
rcu_read_unlock();
498504
return;
499505
}
500506

@@ -573,7 +579,7 @@ static int ipgre_rcv(struct sk_buff *skb)
573579

574580
gre_proto = *(__be16 *)(h + 2);
575581

576-
read_lock(&ipgre_lock);
582+
rcu_read_lock();
577583
if ((tunnel = ipgre_tunnel_lookup(skb->dev,
578584
iph->saddr, iph->daddr, key,
579585
gre_proto))) {
@@ -647,13 +653,13 @@ static int ipgre_rcv(struct sk_buff *skb)
647653
ipgre_ecn_decapsulate(iph, skb);
648654

649655
netif_rx(skb);
650-
read_unlock(&ipgre_lock);
656+
rcu_read_unlock();
651657
return(0);
652658
}
653659
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
654660

655661
drop:
656-
read_unlock(&ipgre_lock);
662+
rcu_read_unlock();
657663
drop_nolock:
658664
kfree_skb(skb);
659665
return(0);

0 commit comments

Comments
 (0)