diff options
| author | James Morris <jmorris@intercode.com.au> | 2003-04-04 18:35:32 -0800 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2003-04-04 18:35:32 -0800 |
| commit | 751ec6f5991b2d444c96fc3ba5892ee0c422a148 (patch) | |
| tree | e01be805625d8d89af16fd29bac09bb5bcbf3139 | |
| parent | e2635a884201893cba84b8a1192f59c104f79575 (diff) | |
[IPSEC]: Move xfrm type destructor out of spinlock.
| -rw-r--r-- | include/net/xfrm.h | 1 | ||||
| -rw-r--r-- | net/xfrm/xfrm_state.c | 57 |
2 files changed, 45 insertions, 13 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index fe32e5c32354..b75d2651adf0 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -84,6 +84,7 @@ extern struct semaphore xfrm_cfg_sem; /* Full description of state of transformer. */ struct xfrm_state { + /* Note: bydst is re-used during gc */ struct list_head bydst; struct list_head byspi; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 162fa975f050..a609612c4c38 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -13,6 +13,7 @@ * */ +#include <linux/workqueue.h> #include <net/xfrm.h> #include <linux/pfkeyv2.h> #include <linux/ipsec.h> @@ -41,8 +42,45 @@ DECLARE_WAIT_QUEUE_HEAD(km_waitq); static rwlock_t xfrm_state_afinfo_lock = RW_LOCK_UNLOCKED; static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; +static struct work_struct xfrm_state_gc_work; +static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list); +static spinlock_t xfrm_state_gc_lock = SPIN_LOCK_UNLOCKED; + static void __xfrm_state_delete(struct xfrm_state *x); +static void xfrm_state_gc_destroy(struct xfrm_state *x) +{ + if (del_timer(&x->timer)) + BUG(); + if (x->aalg) + kfree(x->aalg); + if (x->ealg) + kfree(x->ealg); + if (x->calg) + kfree(x->calg); + if (x->encap) + kfree(x->encap); + if (x->type) + xfrm_put_type(x->type); + kfree(x); +} + +static void xfrm_state_gc_task(void *data) +{ + struct xfrm_state *x; + struct list_head *entry, *tmp; + struct list_head gc_list = LIST_HEAD_INIT(gc_list); + + spin_lock_bh(&xfrm_state_gc_lock); + list_splice_init(&xfrm_state_gc_list, &gc_list); + spin_unlock_bh(&xfrm_state_gc_lock); + + list_for_each_safe(entry, tmp, &gc_list) { + x = list_entry(entry, struct xfrm_state, bydst); + xfrm_state_gc_destroy(x); + } +} + static inline unsigned long make_jiffies(long secs) { if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) @@ -149,19 +187,11 @@ struct xfrm_state *xfrm_state_alloc(void) void __xfrm_state_destroy(struct xfrm_state *x) { BUG_TRAP(x->km.state == XFRM_STATE_DEAD); - if (del_timer(&x->timer)) - BUG(); - if (x->aalg) - kfree(x->aalg); - if (x->ealg) - kfree(x->ealg); - if (x->calg) - kfree(x->calg); - if (x->encap) - kfree(x->encap); - if (x->type) - xfrm_put_type(x->type); - kfree(x); + + spin_lock_bh(&xfrm_state_gc_lock); + list_add(&x->bydst, &xfrm_state_gc_list); + spin_unlock_bh(&xfrm_state_gc_lock); + schedule_work(&xfrm_state_gc_work); } static void __xfrm_state_delete(struct xfrm_state *x) @@ -773,5 +803,6 @@ void __init xfrm_state_init(void) INIT_LIST_HEAD(&xfrm_state_bydst[i]); INIT_LIST_HEAD(&xfrm_state_byspi[i]); } + INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL); } |
