X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=net%2Fipv6%2Fxfrm6_tunnel.c;h=438831d3359315718ff5cca2ca11ca01f878ae02;hb=a83d8e8d099fc373a5ca7112ad08c553bb2c180f;hp=c2b278138604c15507cf074a185df295c1b9d2e8;hpb=df8ea19b5d2e7512095bb1e0737513b8da196d64;p=safe%2Fjmp%2Flinux-2.6 diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index c2b2781..438831d 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -23,7 +23,7 @@ */ #include #include -#include +#include #include #include #include @@ -36,14 +36,15 @@ * per xfrm_address_t. */ struct xfrm6_tunnel_spi { - struct hlist_node list_byaddr; - struct hlist_node list_byspi; - xfrm_address_t addr; - u32 spi; - atomic_t refcnt; + struct hlist_node list_byaddr; + struct hlist_node list_byspi; + xfrm_address_t addr; + u32 spi; + 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; @@ -107,6 +108,7 @@ static void xfrm6_tunnel_spi_fini(void) if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) return; } + rcu_barrier(); kmem_cache_destroy(xfrm6_tunnel_spi_kmem); xfrm6_tunnel_spi_kmem = NULL; } @@ -116,7 +118,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) struct xfrm6_tunnel_spi *x6spi; 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)], list_byaddr) { if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) @@ -131,10 +133,10 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) struct xfrm6_tunnel_spi *x6spi; u32 spi; - read_lock_bh(&xfrm6_tunnel_spi_lock); + rcu_read_lock_bh(); x6spi = __xfrm6_tunnel_spi_lookup(saddr); spi = x6spi ? x6spi->spi : 0; - read_unlock_bh(&xfrm6_tunnel_spi_lock); + rcu_read_unlock_bh(); return htonl(spi); } @@ -185,14 +187,15 @@ alloc_spi: if (!x6spi) goto out; + INIT_RCU_HEAD(&x6spi->rcu_head); memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); x6spi->spi = spi; 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); - hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); + hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); out: return spi; } @@ -202,26 +205,32 @@ __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) struct xfrm6_tunnel_spi *x6spi; u32 spi; - write_lock_bh(&xfrm6_tunnel_spi_lock); + spin_lock_bh(&xfrm6_tunnel_spi_lock); x6spi = __xfrm6_tunnel_spi_lookup(saddr); if (x6spi) { atomic_inc(&x6spi->refcnt); spi = x6spi->spi; } else spi = __xfrm6_tunnel_alloc_spi(saddr); - write_unlock_bh(&xfrm6_tunnel_spi_lock); + spin_unlock_bh(&xfrm6_tunnel_spi_lock); return htonl(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) { struct xfrm6_tunnel_spi *x6spi; 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, &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], @@ -229,14 +238,14 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) { if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { if (atomic_dec_and_test(&x6spi->refcnt)) { - hlist_del(&x6spi->list_byaddr); - hlist_del(&x6spi->list_byspi); - kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi); + hlist_del_rcu(&x6spi->list_byaddr); + hlist_del_rcu(&x6spi->list_byspi); + call_rcu(&x6spi->rcu_head, x6spi_destroy_rcu); break; } } } - write_unlock_bh(&xfrm6_tunnel_spi_lock); + spin_unlock_bh(&xfrm6_tunnel_spi_lock); } EXPORT_SYMBOL(xfrm6_tunnel_free_spi); @@ -262,7 +271,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb) } static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { /* xfrm6_tunnel native err handling */ switch (type) { @@ -345,24 +354,23 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = { static int __init xfrm6_tunnel_init(void) { if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) - return -EAGAIN; - - if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) { - xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); - return -EAGAIN; - } - if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) { - xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); - xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); - return -EAGAIN; - } - if (xfrm6_tunnel_spi_init() < 0) { - xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); - xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); - xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); - return -EAGAIN; - } + goto err; + if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) + goto unreg; + if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) + goto dereg6; + if (xfrm6_tunnel_spi_init() < 0) + goto dereg46; return 0; + +dereg46: + xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); +dereg6: + xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); +unreg: + xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); +err: + return -EAGAIN; } static void __exit xfrm6_tunnel_fini(void)