Commit 91cc3bb0 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

xfrm6_tunnel: RCU conversion

xfrm6_tunnels use one rwlock to protect their hash tables.

Plain and straightforward conversion to RCU locking to permit better SMP
performance.
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4543c10d
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/xfrm.h> #include <linux/xfrm.h>
#include <linux/list.h> #include <linux/rculist.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/ipv6.h> #include <net/ipv6.h>
...@@ -41,9 +41,10 @@ struct xfrm6_tunnel_spi { ...@@ -41,9 +41,10 @@ struct xfrm6_tunnel_spi {
xfrm_address_t addr; xfrm_address_t addr;
u32 spi; u32 spi;
atomic_t refcnt; atomic_t refcnt;
struct rcu_head rcu_head;
}; };
static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock); static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock);
static u32 xfrm6_tunnel_spi; static u32 xfrm6_tunnel_spi;
...@@ -107,6 +108,7 @@ static void xfrm6_tunnel_spi_fini(void) ...@@ -107,6 +108,7 @@ static void xfrm6_tunnel_spi_fini(void)
if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i]))
return; return;
} }
rcu_barrier();
kmem_cache_destroy(xfrm6_tunnel_spi_kmem); kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
xfrm6_tunnel_spi_kmem = NULL; xfrm6_tunnel_spi_kmem = NULL;
} }
...@@ -116,7 +118,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) ...@@ -116,7 +118,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
struct xfrm6_tunnel_spi *x6spi; struct xfrm6_tunnel_spi *x6spi;
struct hlist_node *pos; struct hlist_node *pos;
hlist_for_each_entry(x6spi, pos, hlist_for_each_entry_rcu(x6spi, pos,
&xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
list_byaddr) { list_byaddr) {
if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0)
...@@ -131,10 +133,10 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) ...@@ -131,10 +133,10 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
struct xfrm6_tunnel_spi *x6spi; struct xfrm6_tunnel_spi *x6spi;
u32 spi; u32 spi;
read_lock_bh(&xfrm6_tunnel_spi_lock); rcu_read_lock_bh();
x6spi = __xfrm6_tunnel_spi_lookup(saddr); x6spi = __xfrm6_tunnel_spi_lookup(saddr);
spi = x6spi ? x6spi->spi : 0; spi = x6spi ? x6spi->spi : 0;
read_unlock_bh(&xfrm6_tunnel_spi_lock); rcu_read_unlock_bh();
return htonl(spi); return htonl(spi);
} }
...@@ -185,14 +187,15 @@ alloc_spi: ...@@ -185,14 +187,15 @@ alloc_spi:
if (!x6spi) if (!x6spi)
goto out; goto out;
INIT_RCU_HEAD(&x6spi->rcu_head);
memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr));
x6spi->spi = spi; x6spi->spi = spi;
atomic_set(&x6spi->refcnt, 1); atomic_set(&x6spi->refcnt, 1);
hlist_add_head(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]);
index = xfrm6_tunnel_spi_hash_byaddr(saddr); index = xfrm6_tunnel_spi_hash_byaddr(saddr);
hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]);
out: out:
return spi; return spi;
} }
...@@ -202,26 +205,32 @@ __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) ...@@ -202,26 +205,32 @@ __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
struct xfrm6_tunnel_spi *x6spi; struct xfrm6_tunnel_spi *x6spi;
u32 spi; u32 spi;
write_lock_bh(&xfrm6_tunnel_spi_lock); spin_lock_bh(&xfrm6_tunnel_spi_lock);
x6spi = __xfrm6_tunnel_spi_lookup(saddr); x6spi = __xfrm6_tunnel_spi_lookup(saddr);
if (x6spi) { if (x6spi) {
atomic_inc(&x6spi->refcnt); atomic_inc(&x6spi->refcnt);
spi = x6spi->spi; spi = x6spi->spi;
} else } else
spi = __xfrm6_tunnel_alloc_spi(saddr); spi = __xfrm6_tunnel_alloc_spi(saddr);
write_unlock_bh(&xfrm6_tunnel_spi_lock); spin_unlock_bh(&xfrm6_tunnel_spi_lock);
return htonl(spi); return htonl(spi);
} }
EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
static void x6spi_destroy_rcu(struct rcu_head *head)
{
kmem_cache_free(xfrm6_tunnel_spi_kmem,
container_of(head, struct xfrm6_tunnel_spi, rcu_head));
}
void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
{ {
struct xfrm6_tunnel_spi *x6spi; struct xfrm6_tunnel_spi *x6spi;
struct hlist_node *pos, *n; struct hlist_node *pos, *n;
write_lock_bh(&xfrm6_tunnel_spi_lock); spin_lock_bh(&xfrm6_tunnel_spi_lock);
hlist_for_each_entry_safe(x6spi, pos, n, hlist_for_each_entry_safe(x6spi, pos, n,
&xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
...@@ -229,14 +238,14 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) ...@@ -229,14 +238,14 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
{ {
if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
if (atomic_dec_and_test(&x6spi->refcnt)) { if (atomic_dec_and_test(&x6spi->refcnt)) {
hlist_del(&x6spi->list_byaddr); hlist_del_rcu(&x6spi->list_byaddr);
hlist_del(&x6spi->list_byspi); hlist_del_rcu(&x6spi->list_byspi);
kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi); call_rcu(&x6spi->rcu_head, x6spi_destroy_rcu);
break; break;
} }
} }
} }
write_unlock_bh(&xfrm6_tunnel_spi_lock); spin_unlock_bh(&xfrm6_tunnel_spi_lock);
} }
EXPORT_SYMBOL(xfrm6_tunnel_free_spi); EXPORT_SYMBOL(xfrm6_tunnel_free_spi);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment