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 <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
b37b62fea1
commit
ef9a9d1183
@@ -45,6 +45,7 @@ struct ip_tunnel_prl_entry
|
|||||||
struct ip_tunnel_prl_entry *next;
|
struct ip_tunnel_prl_entry *next;
|
||||||
__be32 addr;
|
__be32 addr;
|
||||||
u16 flags;
|
u16 flags;
|
||||||
|
struct rcu_head rcu_head;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IPTUNNEL_XMIT() do { \
|
#define IPTUNNEL_XMIT() do { \
|
||||||
|
@@ -240,15 +240,22 @@ failed:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(ipip6_prl_lock);
|
||||||
|
|
||||||
|
#define for_each_prl_rcu(start) \
|
||||||
|
for (prl = rcu_dereference(start); \
|
||||||
|
prl; \
|
||||||
|
prl = rcu_dereference(prl->next))
|
||||||
|
|
||||||
static struct ip_tunnel_prl_entry *
|
static struct ip_tunnel_prl_entry *
|
||||||
__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
|
__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
|
||||||
{
|
{
|
||||||
struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL;
|
struct ip_tunnel_prl_entry *prl;
|
||||||
|
|
||||||
for (p = t->prl; p; p = p->next)
|
for_each_prl_rcu(t->prl)
|
||||||
if (p->addr == addr)
|
if (prl->addr == addr)
|
||||||
break;
|
break;
|
||||||
return p;
|
return prl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +280,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
|
|||||||
kcalloc(cmax, sizeof(*kp), GFP_KERNEL) :
|
kcalloc(cmax, sizeof(*kp), GFP_KERNEL) :
|
||||||
NULL;
|
NULL;
|
||||||
|
|
||||||
read_lock(&ipip6_lock);
|
rcu_read_lock();
|
||||||
|
|
||||||
ca = t->prl_count < cmax ? t->prl_count : cmax;
|
ca = t->prl_count < cmax ? t->prl_count : cmax;
|
||||||
|
|
||||||
@@ -291,7 +298,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
|
|||||||
}
|
}
|
||||||
|
|
||||||
c = 0;
|
c = 0;
|
||||||
for (prl = t->prl; prl; prl = prl->next) {
|
for_each_prl_rcu(t->prl) {
|
||||||
if (c >= cmax)
|
if (c >= cmax)
|
||||||
break;
|
break;
|
||||||
if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr)
|
if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr)
|
||||||
@@ -303,7 +310,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
read_unlock(&ipip6_lock);
|
rcu_read_unlock();
|
||||||
|
|
||||||
len = sizeof(*kp) * c;
|
len = sizeof(*kp) * c;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -324,12 +331,14 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
|
|||||||
if (a->addr == htonl(INADDR_ANY))
|
if (a->addr == htonl(INADDR_ANY))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
write_lock(&ipip6_lock);
|
spin_lock(&ipip6_prl_lock);
|
||||||
|
|
||||||
for (p = t->prl; p; p = p->next) {
|
for (p = t->prl; p; p = p->next) {
|
||||||
if (p->addr == a->addr) {
|
if (p->addr == a->addr) {
|
||||||
if (chg)
|
if (chg) {
|
||||||
goto update;
|
p->flags = a->flags;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -346,46 +355,63 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INIT_RCU_HEAD(&p->rcu_head);
|
||||||
p->next = t->prl;
|
p->next = t->prl;
|
||||||
t->prl = p;
|
|
||||||
t->prl_count++;
|
|
||||||
update:
|
|
||||||
p->addr = a->addr;
|
p->addr = a->addr;
|
||||||
p->flags = a->flags;
|
p->flags = a->flags;
|
||||||
|
t->prl_count++;
|
||||||
|
rcu_assign_pointer(t->prl, p);
|
||||||
out:
|
out:
|
||||||
write_unlock(&ipip6_lock);
|
spin_unlock(&ipip6_prl_lock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prl_entry_destroy_rcu(struct rcu_head *head)
|
||||||
|
{
|
||||||
|
kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prl_list_destroy_rcu(struct rcu_head *head)
|
||||||
|
{
|
||||||
|
struct ip_tunnel_prl_entry *p, *n;
|
||||||
|
|
||||||
|
p = container_of(head, struct ip_tunnel_prl_entry, rcu_head);
|
||||||
|
do {
|
||||||
|
n = p->next;
|
||||||
|
kfree(p);
|
||||||
|
p = n;
|
||||||
|
} while (p);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
|
ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
|
||||||
{
|
{
|
||||||
struct ip_tunnel_prl_entry *x, **p;
|
struct ip_tunnel_prl_entry *x, **p;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
write_lock(&ipip6_lock);
|
spin_lock(&ipip6_prl_lock);
|
||||||
|
|
||||||
if (a && a->addr != htonl(INADDR_ANY)) {
|
if (a && a->addr != htonl(INADDR_ANY)) {
|
||||||
for (p = &t->prl; *p; p = &(*p)->next) {
|
for (p = &t->prl; *p; p = &(*p)->next) {
|
||||||
if ((*p)->addr == a->addr) {
|
if ((*p)->addr == a->addr) {
|
||||||
x = *p;
|
x = *p;
|
||||||
*p = x->next;
|
*p = x->next;
|
||||||
kfree(x);
|
call_rcu(&x->rcu_head, prl_entry_destroy_rcu);
|
||||||
t->prl_count--;
|
t->prl_count--;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = -ENXIO;
|
err = -ENXIO;
|
||||||
} else {
|
} else {
|
||||||
while (t->prl) {
|
if (t->prl) {
|
||||||
|
t->prl_count = 0;
|
||||||
x = t->prl;
|
x = t->prl;
|
||||||
t->prl = t->prl->next;
|
call_rcu(&x->rcu_head, prl_list_destroy_rcu);
|
||||||
kfree(x);
|
t->prl = NULL;
|
||||||
t->prl_count--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
write_unlock(&ipip6_lock);
|
spin_unlock(&ipip6_prl_lock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +421,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
|
|||||||
struct ip_tunnel_prl_entry *p;
|
struct ip_tunnel_prl_entry *p;
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
|
|
||||||
read_lock(&ipip6_lock);
|
rcu_read_lock();
|
||||||
p = __ipip6_tunnel_locate_prl(t, iph->saddr);
|
p = __ipip6_tunnel_locate_prl(t, iph->saddr);
|
||||||
if (p) {
|
if (p) {
|
||||||
if (p->flags & PRL_DEFAULT)
|
if (p->flags & PRL_DEFAULT)
|
||||||
@@ -411,7 +437,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
|
|||||||
else
|
else
|
||||||
ok = 0;
|
ok = 0;
|
||||||
}
|
}
|
||||||
read_unlock(&ipip6_lock);
|
rcu_read_unlock();
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1192,6 +1218,7 @@ static void __exit sit_cleanup(void)
|
|||||||
xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
|
xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
|
||||||
|
|
||||||
unregister_pernet_gen_device(sit_net_id, &sit_net_ops);
|
unregister_pernet_gen_device(sit_net_id, &sit_net_ops);
|
||||||
|
rcu_barrier(); /* Wait for completion of call_rcu()'s */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init sit_init(void)
|
static int __init sit_init(void)
|
||||||
|
Reference in New Issue
Block a user