summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Morris <jmorris@intercode.com.au>2003-04-04 18:35:32 -0800
committerDavid S. Miller <davem@nuts.ninka.net>2003-04-04 18:35:32 -0800
commit751ec6f5991b2d444c96fc3ba5892ee0c422a148 (patch)
treee01be805625d8d89af16fd29bac09bb5bcbf3139
parente2635a884201893cba84b8a1192f59c104f79575 (diff)
[IPSEC]: Move xfrm type destructor out of spinlock.
-rw-r--r--include/net/xfrm.h1
-rw-r--r--net/xfrm/xfrm_state.c57
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);
}