diff options
| author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2011-04-04 09:19:25 -0400 |
|---|---|---|
| committer | Patrick McHardy <kaber@trash.net> | 2011-04-04 09:19:25 -0400 |
| commit | 2f9f28b212a2bd4948c8ceaaec33ce0123632129 (patch) | |
| tree | 8c9961f59a190ab05a568216d69f4809ab3041e2 | |
| parent | 512d06b5b64fb422d90f199b1be188082729edf9 (diff) | |
netfilter: ipset: references are protected by rwlock instead of mutex
The timeout variant of the list:set type must reference the member sets.
However, its garbage collector runs at timer interrupt so the mutex
protection of the references is a no go. Therefore the reference protection
is converted to rwlock.
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set.h | 2 | ||||
| -rw-r--r-- | include/linux/netfilter/ipset/ip_set_ahash.h | 3 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_ip.c | 3 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_ipmac.c | 3 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_port.c | 3 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 109 | ||||
| -rw-r--r-- | net/netfilter/ipset/ip_set_list_set.c | 6 |
7 files changed, 73 insertions, 56 deletions
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index ec333d83f3b4..5a262e3ae715 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h | |||
| @@ -293,7 +293,7 @@ struct ip_set { | |||
| 293 | /* Lock protecting the set data */ | 293 | /* Lock protecting the set data */ |
| 294 | rwlock_t lock; | 294 | rwlock_t lock; |
| 295 | /* References to the set */ | 295 | /* References to the set */ |
| 296 | atomic_t ref; | 296 | u32 ref; |
| 297 | /* The core set type */ | 297 | /* The core set type */ |
| 298 | struct ip_set_type *type; | 298 | struct ip_set_type *type; |
| 299 | /* The type variant doing the real job */ | 299 | /* The type variant doing the real job */ |
diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h index ec9d9bea1e37..a0196ac79051 100644 --- a/include/linux/netfilter/ipset/ip_set_ahash.h +++ b/include/linux/netfilter/ipset/ip_set_ahash.h | |||
| @@ -515,8 +515,7 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb) | |||
| 515 | if (h->netmask != HOST_MASK) | 515 | if (h->netmask != HOST_MASK) |
| 516 | NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask); | 516 | NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask); |
| 517 | #endif | 517 | #endif |
| 518 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, | 518 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); |
| 519 | htonl(atomic_read(&set->ref) - 1)); | ||
| 520 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)); | 519 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)); |
| 521 | if (with_timeout(h->timeout)) | 520 | if (with_timeout(h->timeout)) |
| 522 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout)); | 521 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout)); |
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index bca96990218d..a113ff066928 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c | |||
| @@ -338,8 +338,7 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb) | |||
| 338 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); | 338 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); |
| 339 | if (map->netmask != 32) | 339 | if (map->netmask != 32) |
| 340 | NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask); | 340 | NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask); |
| 341 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, | 341 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); |
| 342 | htonl(atomic_read(&set->ref) - 1)); | ||
| 343 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, | 342 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, |
| 344 | htonl(sizeof(*map) + map->memsize)); | 343 | htonl(sizeof(*map) + map->memsize)); |
| 345 | if (with_timeout(map->timeout)) | 344 | if (with_timeout(map->timeout)) |
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 5e790172deff..00a33242e90c 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c | |||
| @@ -434,8 +434,7 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb) | |||
| 434 | goto nla_put_failure; | 434 | goto nla_put_failure; |
| 435 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip)); | 435 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip)); |
| 436 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); | 436 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); |
| 437 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, | 437 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); |
| 438 | htonl(atomic_read(&set->ref) - 1)); | ||
| 439 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, | 438 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, |
| 440 | htonl(sizeof(*map) | 439 | htonl(sizeof(*map) |
| 441 | + (map->last_ip - map->first_ip + 1) * map->dsize)); | 440 | + (map->last_ip - map->first_ip + 1) * map->dsize)); |
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 165f09b1a9cb..6b38eb8f6ed8 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c | |||
| @@ -320,8 +320,7 @@ bitmap_port_head(struct ip_set *set, struct sk_buff *skb) | |||
| 320 | goto nla_put_failure; | 320 | goto nla_put_failure; |
| 321 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port)); | 321 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port)); |
| 322 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port)); | 322 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port)); |
| 323 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, | 323 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); |
| 324 | htonl(atomic_read(&set->ref) - 1)); | ||
| 325 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, | 324 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, |
| 326 | htonl(sizeof(*map) + map->memsize)); | 325 | htonl(sizeof(*map) + map->memsize)); |
| 327 | if (with_timeout(map->timeout)) | 326 | if (with_timeout(map->timeout)) |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index d6b48230a540..e88ac3c3ed07 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | static LIST_HEAD(ip_set_type_list); /* all registered set types */ | 27 | static LIST_HEAD(ip_set_type_list); /* all registered set types */ |
| 28 | static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ | 28 | static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ |
| 29 | static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ | ||
| 29 | 30 | ||
| 30 | static struct ip_set **ip_set_list; /* all individual sets */ | 31 | static struct ip_set **ip_set_list; /* all individual sets */ |
| 31 | static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ | 32 | static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ |
| @@ -301,13 +302,18 @@ EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); | |||
| 301 | static inline void | 302 | static inline void |
| 302 | __ip_set_get(ip_set_id_t index) | 303 | __ip_set_get(ip_set_id_t index) |
| 303 | { | 304 | { |
| 304 | atomic_inc(&ip_set_list[index]->ref); | 305 | write_lock_bh(&ip_set_ref_lock); |
| 306 | ip_set_list[index]->ref++; | ||
| 307 | write_unlock_bh(&ip_set_ref_lock); | ||
| 305 | } | 308 | } |
| 306 | 309 | ||
| 307 | static inline void | 310 | static inline void |
| 308 | __ip_set_put(ip_set_id_t index) | 311 | __ip_set_put(ip_set_id_t index) |
| 309 | { | 312 | { |
| 310 | atomic_dec(&ip_set_list[index]->ref); | 313 | write_lock_bh(&ip_set_ref_lock); |
| 314 | BUG_ON(ip_set_list[index]->ref == 0); | ||
| 315 | ip_set_list[index]->ref--; | ||
| 316 | write_unlock_bh(&ip_set_ref_lock); | ||
| 311 | } | 317 | } |
| 312 | 318 | ||
| 313 | /* | 319 | /* |
| @@ -324,7 +330,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, | |||
| 324 | struct ip_set *set = ip_set_list[index]; | 330 | struct ip_set *set = ip_set_list[index]; |
| 325 | int ret = 0; | 331 | int ret = 0; |
| 326 | 332 | ||
| 327 | BUG_ON(set == NULL || atomic_read(&set->ref) == 0); | 333 | BUG_ON(set == NULL); |
| 328 | pr_debug("set %s, index %u\n", set->name, index); | 334 | pr_debug("set %s, index %u\n", set->name, index); |
| 329 | 335 | ||
| 330 | if (dim < set->type->dimension || | 336 | if (dim < set->type->dimension || |
| @@ -356,7 +362,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb, | |||
| 356 | struct ip_set *set = ip_set_list[index]; | 362 | struct ip_set *set = ip_set_list[index]; |
| 357 | int ret; | 363 | int ret; |
| 358 | 364 | ||
| 359 | BUG_ON(set == NULL || atomic_read(&set->ref) == 0); | 365 | BUG_ON(set == NULL); |
| 360 | pr_debug("set %s, index %u\n", set->name, index); | 366 | pr_debug("set %s, index %u\n", set->name, index); |
| 361 | 367 | ||
| 362 | if (dim < set->type->dimension || | 368 | if (dim < set->type->dimension || |
| @@ -378,7 +384,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb, | |||
| 378 | struct ip_set *set = ip_set_list[index]; | 384 | struct ip_set *set = ip_set_list[index]; |
| 379 | int ret = 0; | 385 | int ret = 0; |
| 380 | 386 | ||
| 381 | BUG_ON(set == NULL || atomic_read(&set->ref) == 0); | 387 | BUG_ON(set == NULL); |
| 382 | pr_debug("set %s, index %u\n", set->name, index); | 388 | pr_debug("set %s, index %u\n", set->name, index); |
| 383 | 389 | ||
| 384 | if (dim < set->type->dimension || | 390 | if (dim < set->type->dimension || |
| @@ -397,7 +403,6 @@ EXPORT_SYMBOL_GPL(ip_set_del); | |||
| 397 | * Find set by name, reference it once. The reference makes sure the | 403 | * Find set by name, reference it once. The reference makes sure the |
| 398 | * thing pointed to, does not go away under our feet. | 404 | * thing pointed to, does not go away under our feet. |
| 399 | * | 405 | * |
| 400 | * The nfnl mutex must already be activated. | ||
| 401 | */ | 406 | */ |
| 402 | ip_set_id_t | 407 | ip_set_id_t |
| 403 | ip_set_get_byname(const char *name, struct ip_set **set) | 408 | ip_set_get_byname(const char *name, struct ip_set **set) |
| @@ -423,15 +428,12 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname); | |||
| 423 | * reference count by 1. The caller shall not assume the index | 428 | * reference count by 1. The caller shall not assume the index |
| 424 | * to be valid, after calling this function. | 429 | * to be valid, after calling this function. |
| 425 | * | 430 | * |
| 426 | * The nfnl mutex must already be activated. | ||
| 427 | */ | 431 | */ |
| 428 | void | 432 | void |
| 429 | ip_set_put_byindex(ip_set_id_t index) | 433 | ip_set_put_byindex(ip_set_id_t index) |
| 430 | { | 434 | { |
| 431 | if (ip_set_list[index] != NULL) { | 435 | if (ip_set_list[index] != NULL) |
| 432 | BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0); | ||
| 433 | __ip_set_put(index); | 436 | __ip_set_put(index); |
| 434 | } | ||
