Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef9a9d11 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b37b62fe
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ struct ip_tunnel_prl_entry
	struct ip_tunnel_prl_entry	*next;
	__be32				addr;
	u16				flags;
	struct rcu_head			rcu_head;
};

#define IPTUNNEL_XMIT() do {						\
+50 −23
Original line number Diff line number Diff line
@@ -240,15 +240,22 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
	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 *
__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)
		if (p->addr == addr)
	for_each_prl_rcu(t->prl)
		if (prl->addr == addr)
			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) :
		NULL;

	read_lock(&ipip6_lock);
	rcu_read_lock();

	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;
	for (prl = t->prl; prl; prl = prl->next) {
	for_each_prl_rcu(t->prl) {
		if (c >= cmax)
			break;
		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;
	}
out:
	read_unlock(&ipip6_lock);
	rcu_read_unlock();

	len = sizeof(*kp) * c;
	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))
		return -EINVAL;

	write_lock(&ipip6_lock);
	spin_lock(&ipip6_prl_lock);

	for (p = t->prl; p; p = p->next) {
		if (p->addr == a->addr) {
			if (chg)
				goto update;
			if (chg) {
				p->flags = a->flags;
				goto out;
			}
			err = -EEXIST;
			goto out;
		}
@@ -346,46 +355,63 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
		goto out;
	}

	INIT_RCU_HEAD(&p->rcu_head);
	p->next = t->prl;
	t->prl = p;
	t->prl_count++;
update:
	p->addr = a->addr;
	p->flags = a->flags;
	t->prl_count++;
	rcu_assign_pointer(t->prl, p);
out:
	write_unlock(&ipip6_lock);
	spin_unlock(&ipip6_prl_lock);
	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
ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
{
	struct ip_tunnel_prl_entry *x, **p;
	int err = 0;

	write_lock(&ipip6_lock);
	spin_lock(&ipip6_prl_lock);

	if (a && a->addr != htonl(INADDR_ANY)) {
		for (p = &t->prl; *p; p = &(*p)->next) {
			if ((*p)->addr == a->addr) {
				x = *p;
				*p = x->next;
				kfree(x);
				call_rcu(&x->rcu_head, prl_entry_destroy_rcu);
				t->prl_count--;
				goto out;
			}
		}
		err = -ENXIO;
	} else {
		while (t->prl) {
		if (t->prl) {
			t->prl_count = 0;
			x = t->prl;
			t->prl = t->prl->next;
			kfree(x);
			t->prl_count--;
			call_rcu(&x->rcu_head, prl_list_destroy_rcu);
			t->prl = NULL;
		}
	}
out:
	write_unlock(&ipip6_lock);
	spin_unlock(&ipip6_prl_lock);
	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;
	int ok = 1;

	read_lock(&ipip6_lock);
	rcu_read_lock();
	p = __ipip6_tunnel_locate_prl(t, iph->saddr);
	if (p) {
		if (p->flags & PRL_DEFAULT)
@@ -411,7 +437,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
		else
			ok = 0;
	}
	read_unlock(&ipip6_lock);
	rcu_read_unlock();
	return ok;
}

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

	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)