diff options
| author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-10-23 14:19:19 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-10-24 09:07:57 -0400 |
| commit | 91cc3bb0b04ffef49bb044e06b221ea5de053e91 (patch) | |
| tree | 584484218c73a4b6a8315dbabb5049f6c4355668 | |
| parent | 4543c10de267bdd4f9acdb7708456909ed7eed3c (diff) | |
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: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | net/ipv6/xfrm6_tunnel.c | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 81a95c00e503..438831d33593 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | */ | 23 | */ |
| 24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 25 | #include <linux/xfrm.h> | 25 | #include <linux/xfrm.h> |
| 26 | #include <linux/list.h> | 26 | #include <linux/rculist.h> |
| 27 | #include <net/ip.h> | 27 | #include <net/ip.h> |
| 28 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
| 29 | #include <net/ipv6.h> | 29 | #include <net/ipv6.h> |
| @@ -36,14 +36,15 @@ | |||
| 36 | * per xfrm_address_t. | 36 | * per xfrm_address_t. |
| 37 | */ | 37 | */ |
| 38 | struct xfrm6_tunnel_spi { | 38 | struct xfrm6_tunnel_spi { |
| 39 | struct hlist_node list_byaddr; | 39 | struct hlist_node list_byaddr; |
| 40 | struct hlist_node list_byspi; | 40 | struct hlist_node list_byspi; |
| 41 | xfrm_address_t addr; | 41 | xfrm_address_t addr; |
| 42 | u32 spi; | 42 | u32 spi; |
| 43 | atomic_t refcnt; | 43 | atomic_t refcnt; |
| 44 | struct rcu_head rcu_head; | ||
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock); | 47 | static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); |
| 47 | 48 | ||
| 48 | static u32 xfrm6_tunnel_spi; | 49 | static u32 xfrm6_tunnel_spi; |
| 49 | 50 | ||
| @@ -107,6 +108,7 @@ static void xfrm6_tunnel_spi_fini(void) | |||
| 107 | if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) | 108 | if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) |
| 108 | return; | 109 | return; |
| 109 | } | 110 | } |
| 111 | rcu_barrier(); | ||
| 110 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | 112 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); |
| 111 | xfrm6_tunnel_spi_kmem = NULL; | 113 | xfrm6_tunnel_spi_kmem = NULL; |
| 112 | } | 114 | } |
| @@ -116,7 +118,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
| 116 | struct xfrm6_tunnel_spi *x6spi; | 118 | struct xfrm6_tunnel_spi *x6spi; |
| 117 | struct hlist_node *pos; | 119 | struct hlist_node *pos; |
| 118 | 120 | ||
| 119 | hlist_for_each_entry(x6spi, pos, | 121 | hlist_for_each_entry_rcu(x6spi, pos, |
| 120 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 122 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
| 121 | list_byaddr) { | 123 | list_byaddr) { |
| 122 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) | 124 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) |
| @@ -131,10 +133,10 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
| 131 | struct xfrm6_tunnel_spi *x6spi; | 133 | struct xfrm6_tunnel_spi *x6spi; |
| 132 | u32 spi; | 134 | u32 spi; |
| 133 | 135 | ||
| 134 | read_lock_bh(&xfrm6_tunnel_spi_lock); | 136 | rcu_read_lock_bh(); |
| 135 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 137 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); |
| 136 | spi = x6spi ? x6spi->spi : 0; | 138 | spi = x6spi ? x6spi->spi : 0; |
| 137 | read_unlock_bh(&xfrm6_tunnel_spi_lock); | 139 | rcu_read_unlock_bh(); |
| 138 | return htonl(spi); | 140 | return htonl(spi); |
| 139 | } | 141 | } |
| 140 | 142 | ||
| @@ -185,14 +187,15 @@ alloc_spi: | |||
| 185 | if (!x6spi) | 187 | if (!x6spi) |
| 186 | goto out; | 188 | goto out; |
| 187 | 189 | ||
| 190 | INIT_RCU_HEAD(&x6spi->rcu_head); | ||
| 188 | memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); | 191 | memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); |
| 189 | x6spi->spi = spi; | 192 | x6spi->spi = spi; |
| 190 | atomic_set(&x6spi->refcnt, 1); | 193 | atomic_set(&x6spi->refcnt, 1); |
| 191 | 194 | ||
| 192 | hlist_add_head(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); | 195 | hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); |
| 193 | 196 | ||
| 194 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); | 197 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); |
| 195 | hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); | 198 | hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); |
| 196 | out: | 199 | out: |
| 197 | return spi; | 200 | return spi; |
| 198 | } | 201 | } |
| @@ -202,26 +205,32 @@ __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | |||
| 202 | struct xfrm6_tunnel_spi *x6spi; | 205 | struct xfrm6_tunnel_spi *x6spi; |
| 203 | u32 spi; | 206 | u32 spi; |
| 204 | 207 | ||
| 205 | write_lock_bh(&xfrm6_tunnel_spi_lock); | 208 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
| 206 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 209 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); |
| 207 | if (x6spi) { | 210 | if (x6spi) { |
| 208 | atomic_inc(&x6spi->refcnt); | 211 | atomic_inc(&x6spi->refcnt); |
| 209 | spi = x6spi->spi; | 212 | spi = x6spi->spi; |
| 210 | } else | 213 | } else |
| 211 | spi = __xfrm6_tunnel_alloc_spi(saddr); | 214 | spi = __xfrm6_tunnel_alloc_spi(saddr); |
| 212 | write_unlock_bh(&xfrm6_tunnel_spi_lock); | 215 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
| 213 | 216 | ||
| 214 | return htonl(spi); | 217 | return htonl(spi); |
| 215 | } | 218 | } |
| 216 | 219 | ||
| 217 | EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); | 220 | EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); |
| 218 | 221 | ||
| 222 | static void x6spi_destroy_rcu(struct rcu_head *head) | ||
| 223 | { | ||
| 224 | kmem_cache_free(xfrm6_tunnel_spi_kmem, | ||
| 225 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); | ||
| 226 | } | ||
| 227 | |||
| 219 | void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) | 228 | void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) |
| 220 | { | 229 | { |
| 221 | struct xfrm6_tunnel_spi *x6spi; | 230 | struct xfrm6_tunnel_spi *x6spi; |
| 222 | struct hlist_node *pos, *n; | 231 | struct hlist_node *pos, *n; |
| 223 | 232 | ||
| 224 | write_lock_bh(&xfrm6_tunnel_spi_lock); | 233 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
| 225 | 234 | ||
| 226 | hlist_for_each_entry_safe(x6spi, pos, n, | 235 | hlist_for_each_entry_safe(x6spi, pos, n, |
| 227 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 236 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
| @@ -229,14 +238,14 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) | |||
| 229 | { | 238 | { |
| 230 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { | 239 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { |
| 231 | if (atomic_dec_and_test(&x6spi->refcnt)) { | 240 | if (atomic_dec_and_test(&x6spi->refcnt)) { |
| 232 | hlist_del(&x6spi->list_byaddr); | 241 | hlist_del_rcu(&x6spi->list_byaddr); |
| 233 | hlist_del(&x6spi->list_byspi); | 242 | hlist_del_rcu(&x6spi->list_byspi); |
| 234 | kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi); | 243 | call_rcu(&x6spi->rcu_head, x6spi_destroy_rcu); |
| 235 | break; | 244 | break; |
| 236 | } | 245 | } |
| 237 | } | 246 | } |
| 238 | } | 247 | } |
| 239 | write_unlock_bh(&xfrm6_tunnel_spi_lock); | 248 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
| 240 | } | 249 | } |
| 241 | 250 | ||
| 242 | EXPORT_SYMBOL(xfrm6_tunnel_free_spi); | 251 | EXPORT_SYMBOL(xfrm6_tunnel_free_spi); |
