Skip to content

Commit ef9a9d1

Browse files
Eric Dumazetdavem330
authored andcommitted
ipv6 sit: RCU conversion phase I
SIT tunnels use one rwlock to protect their prl entries. This first patch adds RCU locking for prl management, with standard call_rcu() calls. Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b37b62f commit ef9a9d1

File tree

2 files changed

+51
-23
lines changed

2 files changed

+51
-23
lines changed

include/net/ipip.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct ip_tunnel_prl_entry
4545
struct ip_tunnel_prl_entry *next;
4646
__be32 addr;
4747
u16 flags;
48+
struct rcu_head rcu_head;
4849
};
4950

5051
#define IPTUNNEL_XMIT() do { \

net/ipv6/sit.c

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -240,15 +240,22 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
240240
return NULL;
241241
}
242242

243+
static DEFINE_SPINLOCK(ipip6_prl_lock);
244+
245+
#define for_each_prl_rcu(start) \
246+
for (prl = rcu_dereference(start); \
247+
prl; \
248+
prl = rcu_dereference(prl->next))
249+
243250
static struct ip_tunnel_prl_entry *
244251
__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
245252
{
246-
struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL;
253+
struct ip_tunnel_prl_entry *prl;
247254

248-
for (p = t->prl; p; p = p->next)
249-
if (p->addr == addr)
255+
for_each_prl_rcu(t->prl)
256+
if (prl->addr == addr)
250257
break;
251-
return p;
258+
return prl;
252259

253260
}
254261

@@ -273,7 +280,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
273280
kcalloc(cmax, sizeof(*kp), GFP_KERNEL) :
274281
NULL;
275282

276-
read_lock(&ipip6_lock);
283+
rcu_read_lock();
277284

278285
ca = t->prl_count < cmax ? t->prl_count : cmax;
279286

@@ -291,7 +298,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
291298
}
292299

293300
c = 0;
294-
for (prl = t->prl; prl; prl = prl->next) {
301+
for_each_prl_rcu(t->prl) {
295302
if (c >= cmax)
296303
break;
297304
if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr)
@@ -303,7 +310,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
303310
break;
304311
}
305312
out:
306-
read_unlock(&ipip6_lock);
313+
rcu_read_unlock();
307314

308315
len = sizeof(*kp) * c;
309316
ret = 0;
@@ -324,12 +331,14 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
324331
if (a->addr == htonl(INADDR_ANY))
325332
return -EINVAL;
326333

327-
write_lock(&ipip6_lock);
334+
spin_lock(&ipip6_prl_lock);
328335

329336
for (p = t->prl; p; p = p->next) {
330337
if (p->addr == a->addr) {
331-
if (chg)
332-
goto update;
338+
if (chg) {
339+
p->flags = a->flags;
340+
goto out;
341+
}
333342
err = -EEXIST;
334343
goto out;
335344
}
@@ -346,46 +355,63 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
346355
goto out;
347356
}
348357

358+
INIT_RCU_HEAD(&p->rcu_head);
349359
p->next = t->prl;
350-
t->prl = p;
351-
t->prl_count++;
352-
update:
353360
p->addr = a->addr;
354361
p->flags = a->flags;
362+
t->prl_count++;
363+
rcu_assign_pointer(t->prl, p);
355364
out:
356-
write_unlock(&ipip6_lock);
365+
spin_unlock(&ipip6_prl_lock);
357366
return err;
358367
}
359368

369+
static void prl_entry_destroy_rcu(struct rcu_head *head)
370+
{
371+
kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head));
372+
}
373+
374+
static void prl_list_destroy_rcu(struct rcu_head *head)
375+
{
376+
struct ip_tunnel_prl_entry *p, *n;
377+
378+
p = container_of(head, struct ip_tunnel_prl_entry, rcu_head);
379+
do {
380+
n = p->next;
381+
kfree(p);
382+
p = n;
383+
} while (p);
384+
}
385+
360386
static int
361387
ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
362388
{
363389
struct ip_tunnel_prl_entry *x, **p;
364390
int err = 0;
365391

366-
write_lock(&ipip6_lock);
392+
spin_lock(&ipip6_prl_lock);
367393

368394
if (a && a->addr != htonl(INADDR_ANY)) {
369395
for (p = &t->prl; *p; p = &(*p)->next) {
370396
if ((*p)->addr == a->addr) {
371397
x = *p;
372398
*p = x->next;
373-
kfree(x);
399+
call_rcu(&x->rcu_head, prl_entry_destroy_rcu);
374400
t->prl_count--;
375401
goto out;
376402
}
377403
}
378404
err = -ENXIO;
379405
} else {
380-
while (t->prl) {
406+
if (t->prl) {
407+
t->prl_count = 0;
381408
x = t->prl;
382-
t->prl = t->prl->next;
383-
kfree(x);
384-
t->prl_count--;
409+
call_rcu(&x->rcu_head, prl_list_destroy_rcu);
410+
t->prl = NULL;
385411
}
386412
}
387413
out:
388-
write_unlock(&ipip6_lock);
414+
spin_unlock(&ipip6_prl_lock);
389415
return err;
390416
}
391417

@@ -395,7 +421,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
395421
struct ip_tunnel_prl_entry *p;
396422
int ok = 1;
397423

398-
read_lock(&ipip6_lock);
424+
rcu_read_lock();
399425
p = __ipip6_tunnel_locate_prl(t, iph->saddr);
400426
if (p) {
401427
if (p->flags & PRL_DEFAULT)
@@ -411,7 +437,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
411437
else
412438
ok = 0;
413439
}
414-
read_unlock(&ipip6_lock);
440+
rcu_read_unlock();
415441
return ok;
416442
}
417443

@@ -1192,6 +1218,7 @@ static void __exit sit_cleanup(void)
11921218
xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
11931219

11941220
unregister_pernet_gen_device(sit_net_id, &sit_net_ops);
1221+
rcu_barrier(); /* Wait for completion of call_rcu()'s */
11951222
}
11961223

11971224
static int __init sit_init(void)

0 commit comments

Comments
 (0)