summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/xfrm/xfrm_state.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 78d6c52a65cc..102bb826e273 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -48,6 +48,8 @@ static struct work_struct xfrm_state_gc_work;
static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
+static int xfrm_state_gc_flush_bundles;
+
static void __xfrm_state_delete(struct xfrm_state *x);
static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
@@ -81,6 +83,11 @@ static void xfrm_state_gc_task(void *data)
struct list_head *entry, *tmp;
struct list_head gc_list = LIST_HEAD_INIT(gc_list);
+ if (xfrm_state_gc_flush_bundles) {
+ xfrm_state_gc_flush_bundles = 0;
+ xfrm_flush_bundles();
+ }
+
spin_lock_bh(&xfrm_state_gc_lock);
list_splice_init(&xfrm_state_gc_list, &gc_list);
spin_unlock_bh(&xfrm_state_gc_lock);
@@ -228,8 +235,10 @@ static void __xfrm_state_delete(struct xfrm_state *x)
* our caller holds. A larger value means that
* there are DSTs attached to this xfrm_state.
*/
- if (atomic_read(&x->refcnt) > 2)
- xfrm_flush_bundles();
+ if (atomic_read(&x->refcnt) > 2) {
+ xfrm_state_gc_flush_bundles = 1;
+ schedule_work(&xfrm_state_gc_work);
+ }
/* All xfrm_state objects are created by xfrm_state_alloc.
* The xfrm_state_alloc call gives a reference, and that