diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-08-24 06:54:22 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 18:08:47 -0400 |
commit | a47f0ce05ae12ce9acad62896ff703175764104e (patch) | |
tree | 7d2d64d86ca869b2039ffe8ec066a5daa87b8673 | |
parent | 1c0953997567b22e32fdf85d3b4bc0f2461fd161 (diff) |
[XFRM]: Kill excessive refcounting of xfrm_state objects.
The refcounting done for timers and hash table insertions
are just wasted cycles. We can eliminate all of this
refcounting because:
1) The implicit refcount when the xfrm_state object is active
will always be held while the object is in the hash tables.
We never kfree() the xfrm_state until long after we've made
sure that it has been unhashed.
2) Timers are even easier. Once we mark that x->km.state as
anything other than XFRM_STATE_VALID (__xfrm_state_delete
sets it to XFRM_STATE_DEAD), any timer that fires will
do nothing and return without rearming the timer.
Therefore we can defer the del_timer calls until when the
object is about to be freed up during GC. We have to use
del_timer_sync() and defer it to GC because we can't do
a del_timer_sync() while holding x->lock which all callers
of __xfrm_state_delete hold.
This makes SA changes even more light-weight.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/xfrm/xfrm_state.c | 53 |
1 files changed, 12 insertions, 41 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 9ff00b7d6ad3..0bc6a4b1ceae 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -266,10 +266,8 @@ void km_state_expired(struct xfrm_state *x, int hard, u32 pid); | |||
266 | 266 | ||
267 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 267 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
268 | { | 268 | { |
269 | if (del_timer(&x->timer)) | 269 | del_timer_sync(&x->timer); |
270 | BUG(); | 270 | del_timer_sync(&x->rtimer); |
271 | if (del_timer(&x->rtimer)) | ||
272 | BUG(); | ||
273 | kfree(x->aalg); | 271 | kfree(x->aalg); |
274 | kfree(x->ealg); | 272 | kfree(x->ealg); |
275 | kfree(x->calg); | 273 | kfree(x->calg); |
@@ -361,9 +359,9 @@ static void xfrm_timer_handler(unsigned long data) | |||
361 | if (warn) | 359 | if (warn) |
362 | km_state_expired(x, 0, 0); | 360 | km_state_expired(x, 0, 0); |
363 | resched: | 361 | resched: |
364 | if (next != LONG_MAX && | 362 | if (next != LONG_MAX) |
365 | !mod_timer(&x->timer, jiffies + make_jiffies(next))) | 363 | mod_timer(&x->timer, jiffies + make_jiffies(next)); |
366 | xfrm_state_hold(x); | 364 | |
367 | goto out; | 365 | goto out; |
368 | 366 | ||
369 | expired: | 367 | expired: |
@@ -378,7 +376,6 @@ expired: | |||
378 | 376 | ||
379 | out: | 377 | out: |
380 | spin_unlock(&x->lock); | 378 | spin_unlock(&x->lock); |
381 | xfrm_state_put(x); | ||
382 | } | 379 | } |
383 | 380 | ||
384 | static void xfrm_replay_timer_handler(unsigned long data); | 381 | static void xfrm_replay_timer_handler(unsigned long data); |
@@ -433,19 +430,11 @@ int __xfrm_state_delete(struct xfrm_state *x) | |||
433 | x->km.state = XFRM_STATE_DEAD; | 430 | x->km.state = XFRM_STATE_DEAD; |
434 | spin_lock(&xfrm_state_lock); | 431 | spin_lock(&xfrm_state_lock); |
435 | hlist_del(&x->bydst); | 432 | hlist_del(&x->bydst); |
436 | __xfrm_state_put(x); | ||
437 | hlist_del(&x->bysrc); | 433 | hlist_del(&x->bysrc); |
438 | __xfrm_state_put(x); | 434 | if (x->id.spi) |
439 | if (x->id.spi) { | ||
440 | hlist_del(&x->byspi); | 435 | hlist_del(&x->byspi); |
441 | __xfrm_state_put(x); | ||
442 | } | ||
443 | xfrm_state_num--; | 436 | xfrm_state_num--; |
444 | spin_unlock(&xfrm_state_lock); | 437 | spin_unlock(&xfrm_state_lock); |
445 | if (del_timer(&x->timer)) | ||
446 | __xfrm_state_put(x); | ||
447 | if (del_timer(&x->rtimer)) | ||
448 | __xfrm_state_put(x); | ||
449 | 438 | ||
450 | /* All xfrm_state objects are created by xfrm_state_alloc. | 439 | /* All xfrm_state objects are created by xfrm_state_alloc. |
451 | * The xfrm_state_alloc call gives a reference, and that | 440 | * The xfrm_state_alloc call gives a reference, and that |
@@ -676,17 +665,13 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
676 | if (km_query(x, tmpl, pol) == 0) { | 665 | if (km_query(x, tmpl, pol) == 0) { |
677 | x->km.state = XFRM_STATE_ACQ; | 666 | x->km.state = XFRM_STATE_ACQ; |
678 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | 667 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); |
679 | xfrm_state_hold(x); | ||
680 | h = xfrm_src_hash(saddr, family); | 668 | h = xfrm_src_hash(saddr, family); |
681 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); | 669 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); |
682 | xfrm_state_hold(x); | ||
683 | if (x->id.spi) { | 670 | if (x->id.spi) { |
684 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); | 671 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); |
685 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); | 672 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); |
686 | xfrm_state_hold(x); | ||
687 | } | 673 | } |
688 | x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; | 674 | x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; |
689 | xfrm_state_hold(x); | ||
690 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; | 675 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; |
691 | add_timer(&x->timer); | 676 | add_timer(&x->timer); |
692 | } else { | 677 | } else { |
@@ -713,26 +698,20 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
713 | 698 | ||
714 | h = xfrm_dst_hash(&x->id.daddr, x->props.reqid, x->props.family); | 699 | h = xfrm_dst_hash(&x->id.daddr, x->props.reqid, x->props.family); |
715 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | 700 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); |
716 | xfrm_state_hold(x); | ||
717 | 701 | ||
718 | h = xfrm_src_hash(&x->props.saddr, x->props.family); | 702 | h = xfrm_src_hash(&x->props.saddr, x->props.family); |
719 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); | 703 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); |
720 | xfrm_state_hold(x); | ||
721 | 704 | ||
722 | if (xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY)) { | 705 | if (xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY)) { |
723 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, | 706 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, |
724 | x->props.family); | 707 | x->props.family); |
725 | 708 | ||
726 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); | 709 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); |
727 | xfrm_state_hold(x); | ||
728 | } | 710 | } |
729 | 711 | ||
730 | if (!mod_timer(&x->timer, jiffies + HZ)) | 712 | mod_timer(&x->timer, jiffies + HZ); |
731 | xfrm_state_hold(x); | 713 | if (x->replay_maxage) |
732 | 714 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); | |
733 | if (x->replay_maxage && | ||
734 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | ||
735 | xfrm_state_hold(x); | ||
736 | 715 | ||
737 | wake_up(&km_waitq); | 716 | wake_up(&km_waitq); |
738 | 717 | ||
@@ -844,10 +823,8 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re | |||
844 | xfrm_state_hold(x); | 823 | xfrm_state_hold(x); |
845 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; | 824 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; |
846 | add_timer(&x->timer); | 825 | add_timer(&x->timer); |
847 | xfrm_state_hold(x); | ||
848 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | 826 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); |
849 | h = xfrm_src_hash(saddr, family); | 827 | h = xfrm_src_hash(saddr, family); |
850 | xfrm_state_hold(x); | ||
851 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); | 828 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); |
852 | wake_up(&km_waitq); | 829 | wake_up(&km_waitq); |
853 | } | 830 | } |
@@ -955,8 +932,7 @@ out: | |||
955 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); | 932 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); |
956 | x1->km.dying = 0; | 933 | x1->km.dying = 0; |
957 | 934 | ||
958 | if (!mod_timer(&x1->timer, jiffies + HZ)) | 935 | mod_timer(&x1->timer, jiffies + HZ); |
959 | xfrm_state_hold(x1); | ||
960 | if (x1->curlft.use_time) | 936 | if (x1->curlft.use_time) |
961 | xfrm_state_check_expire(x1); | 937 | xfrm_state_check_expire(x1); |
962 | 938 | ||
@@ -981,8 +957,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
981 | if (x->curlft.bytes >= x->lft.hard_byte_limit || | 957 | if (x->curlft.bytes >= x->lft.hard_byte_limit || |
982 | x->curlft.packets >= x->lft.hard_packet_limit) { | 958 | x->curlft.packets >= x->lft.hard_packet_limit) { |
983 | x->km.state = XFRM_STATE_EXPIRED; | 959 | x->km.state = XFRM_STATE_EXPIRED; |
984 | if (!mod_timer(&x->timer, jiffies)) | 960 | mod_timer(&x->timer, jiffies); |
985 | xfrm_state_hold(x); | ||
986 | return -EINVAL; | 961 | return -EINVAL; |
987 | } | 962 | } |
988 | 963 | ||
@@ -1177,7 +1152,6 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) | |||
1177 | spin_lock_bh(&xfrm_state_lock); | 1152 | spin_lock_bh(&xfrm_state_lock); |
1178 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); | 1153 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); |
1179 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); | 1154 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); |
1180 | xfrm_state_hold(x); | ||
1181 | spin_unlock_bh(&xfrm_state_lock); | 1155 | spin_unlock_bh(&xfrm_state_lock); |
1182 | wake_up(&km_waitq); | 1156 | wake_up(&km_waitq); |
1183 | } | 1157 | } |
@@ -1264,10 +1238,8 @@ void xfrm_replay_notify(struct xfrm_state *x, int event) | |||
1264 | km_state_notify(x, &c); | 1238 | km_state_notify(x, &c); |
1265 | 1239 | ||
1266 | if (x->replay_maxage && | 1240 | if (x->replay_maxage && |
1267 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) { | 1241 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) |
1268 | xfrm_state_hold(x); | ||
1269 | x->xflags &= ~XFRM_TIME_DEFER; | 1242 | x->xflags &= ~XFRM_TIME_DEFER; |
1270 | } | ||
1271 | } | 1243 | } |
1272 | EXPORT_SYMBOL(xfrm_replay_notify); | 1244 | EXPORT_SYMBOL(xfrm_replay_notify); |
1273 | 1245 | ||
@@ -1285,7 +1257,6 @@ static void xfrm_replay_timer_handler(unsigned long data) | |||
1285 | } | 1257 | } |
1286 | 1258 | ||
1287 | spin_unlock(&x->lock); | 1259 | spin_unlock(&x->lock); |
1288 | xfrm_state_put(x); | ||
1289 | } | 1260 | } |
1290 | 1261 | ||
1291 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) | 1262 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) |