Skip to content

Commit

Permalink
[XFRM]: Kill excessive refcounting of xfrm_state objects.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David S. Miller committed Sep 22, 2006
1 parent 1c09539 commit a47f0ce
Showing 1 changed file with 12 additions and 41 deletions.
53 changes: 12 additions & 41 deletions net/xfrm/xfrm_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,8 @@ void km_state_expired(struct xfrm_state *x, int hard, u32 pid);

static void xfrm_state_gc_destroy(struct xfrm_state *x)
{
if (del_timer(&x->timer))
BUG();
if (del_timer(&x->rtimer))
BUG();
del_timer_sync(&x->timer);
del_timer_sync(&x->rtimer);
kfree(x->aalg);
kfree(x->ealg);
kfree(x->calg);
Expand Down Expand Up @@ -361,9 +359,9 @@ static void xfrm_timer_handler(unsigned long data)
if (warn)
km_state_expired(x, 0, 0);
resched:
if (next != LONG_MAX &&
!mod_timer(&x->timer, jiffies + make_jiffies(next)))
xfrm_state_hold(x);
if (next != LONG_MAX)
mod_timer(&x->timer, jiffies + make_jiffies(next));

goto out;

expired:
Expand All @@ -378,7 +376,6 @@ static void xfrm_timer_handler(unsigned long data)

out:
spin_unlock(&x->lock);
xfrm_state_put(x);
}

static void xfrm_replay_timer_handler(unsigned long data);
Expand Down Expand Up @@ -433,19 +430,11 @@ int __xfrm_state_delete(struct xfrm_state *x)
x->km.state = XFRM_STATE_DEAD;
spin_lock(&xfrm_state_lock);
hlist_del(&x->bydst);
__xfrm_state_put(x);
hlist_del(&x->bysrc);
__xfrm_state_put(x);
if (x->id.spi) {
if (x->id.spi)
hlist_del(&x->byspi);
__xfrm_state_put(x);
}
xfrm_state_num--;
spin_unlock(&xfrm_state_lock);
if (del_timer(&x->timer))
__xfrm_state_put(x);
if (del_timer(&x->rtimer))
__xfrm_state_put(x);

/* All xfrm_state objects are created by xfrm_state_alloc.
* The xfrm_state_alloc call gives a reference, and that
Expand Down Expand Up @@ -676,17 +665,13 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
if (km_query(x, tmpl, pol) == 0) {
x->km.state = XFRM_STATE_ACQ;
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
xfrm_state_hold(x);
h = xfrm_src_hash(saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
xfrm_state_hold(x);
if (x->id.spi) {
h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
hlist_add_head(&x->byspi, xfrm_state_byspi+h);
xfrm_state_hold(x);
}
x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
xfrm_state_hold(x);
x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
add_timer(&x->timer);
} else {
Expand All @@ -713,26 +698,20 @@ static void __xfrm_state_insert(struct xfrm_state *x)

h = xfrm_dst_hash(&x->id.daddr, x->props.reqid, x->props.family);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
xfrm_state_hold(x);

h = xfrm_src_hash(&x->props.saddr, x->props.family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
xfrm_state_hold(x);

if (xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY)) {
h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
x->props.family);

hlist_add_head(&x->byspi, xfrm_state_byspi+h);
xfrm_state_hold(x);
}

if (!mod_timer(&x->timer, jiffies + HZ))
xfrm_state_hold(x);

if (x->replay_maxage &&
!mod_timer(&x->rtimer, jiffies + x->replay_maxage))
xfrm_state_hold(x);
mod_timer(&x->timer, jiffies + HZ);
if (x->replay_maxage)
mod_timer(&x->rtimer, jiffies + x->replay_maxage);

wake_up(&km_waitq);

Expand Down Expand Up @@ -844,10 +823,8 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
xfrm_state_hold(x);
x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
add_timer(&x->timer);
xfrm_state_hold(x);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
h = xfrm_src_hash(saddr, family);
xfrm_state_hold(x);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
wake_up(&km_waitq);
}
Expand Down Expand Up @@ -955,8 +932,7 @@ int xfrm_state_update(struct xfrm_state *x)
memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
x1->km.dying = 0;

if (!mod_timer(&x1->timer, jiffies + HZ))
xfrm_state_hold(x1);
mod_timer(&x1->timer, jiffies + HZ);
if (x1->curlft.use_time)
xfrm_state_check_expire(x1);

Expand All @@ -981,8 +957,7 @@ int xfrm_state_check_expire(struct xfrm_state *x)
if (x->curlft.bytes >= x->lft.hard_byte_limit ||
x->curlft.packets >= x->lft.hard_packet_limit) {
x->km.state = XFRM_STATE_EXPIRED;
if (!mod_timer(&x->timer, jiffies))
xfrm_state_hold(x);
mod_timer(&x->timer, jiffies);
return -EINVAL;
}

Expand Down Expand Up @@ -1177,7 +1152,6 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
spin_lock_bh(&xfrm_state_lock);
h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
hlist_add_head(&x->byspi, xfrm_state_byspi+h);
xfrm_state_hold(x);
spin_unlock_bh(&xfrm_state_lock);
wake_up(&km_waitq);
}
Expand Down Expand Up @@ -1264,10 +1238,8 @@ void xfrm_replay_notify(struct xfrm_state *x, int event)
km_state_notify(x, &c);

if (x->replay_maxage &&
!mod_timer(&x->rtimer, jiffies + x->replay_maxage)) {
xfrm_state_hold(x);
!mod_timer(&x->rtimer, jiffies + x->replay_maxage))
x->xflags &= ~XFRM_TIME_DEFER;
}
}
EXPORT_SYMBOL(xfrm_replay_notify);

Expand All @@ -1285,7 +1257,6 @@ static void xfrm_replay_timer_handler(unsigned long data)
}

spin_unlock(&x->lock);
xfrm_state_put(x);
}

int xfrm_replay_check(struct xfrm_state *x, u32 seq)
Expand Down

0 comments on commit a47f0ce

Please sign in to comment.