aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c2
-rw-r--r--net/xfrm/xfrm_state.c72
2 files changed, 61 insertions, 13 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b7754b1b73a4..ef9ccbc38752 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -34,7 +34,7 @@
34 34
35#include "xfrm_hash.h" 35#include "xfrm_hash.h"
36 36
37int sysctl_xfrm_larval_drop __read_mostly; 37int sysctl_xfrm_larval_drop __read_mostly = 1;
38 38
39#ifdef CONFIG_XFRM_STATISTICS 39#ifdef CONFIG_XFRM_STATISTICS
40DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly; 40DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 0a8f09c3144c..053970e8765d 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -59,6 +59,14 @@ static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
59static unsigned int xfrm_state_num; 59static unsigned int xfrm_state_num;
60static unsigned int xfrm_state_genid; 60static unsigned int xfrm_state_genid;
61 61
62/* Counter indicating ongoing walk, protected by xfrm_state_lock. */
63static unsigned long xfrm_state_walk_ongoing;
64/* Counter indicating walk completion, protected by xfrm_cfg_mutex. */
65static unsigned long xfrm_state_walk_completed;
66
67/* List of outstanding state walks used to set the completed counter. */
68static LIST_HEAD(xfrm_state_walks);
69
62static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); 70static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
63static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); 71static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
64 72
@@ -191,7 +199,8 @@ static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
191static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; 199static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
192 200
193static struct work_struct xfrm_state_gc_work; 201static struct work_struct xfrm_state_gc_work;
194static HLIST_HEAD(xfrm_state_gc_list); 202static LIST_HEAD(xfrm_state_gc_leftovers);
203static LIST_HEAD(xfrm_state_gc_list);
195static DEFINE_SPINLOCK(xfrm_state_gc_lock); 204static DEFINE_SPINLOCK(xfrm_state_gc_lock);
196 205
197int __xfrm_state_delete(struct xfrm_state *x); 206int __xfrm_state_delete(struct xfrm_state *x);
@@ -403,17 +412,23 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
403 412
404static void xfrm_state_gc_task(struct work_struct *data) 413static void xfrm_state_gc_task(struct work_struct *data)
405{ 414{
406 struct xfrm_state *x; 415 struct xfrm_state *x, *tmp;
407 struct hlist_node *entry, *tmp; 416 unsigned long completed;
408 struct hlist_head gc_list;
409 417
418 mutex_lock(&xfrm_cfg_mutex);
410 spin_lock_bh(&xfrm_state_gc_lock); 419 spin_lock_bh(&xfrm_state_gc_lock);
411 gc_list.first = xfrm_state_gc_list.first; 420 list_splice_tail_init(&xfrm_state_gc_list, &xfrm_state_gc_leftovers);
412 INIT_HLIST_HEAD(&xfrm_state_gc_list);
413 spin_unlock_bh(&xfrm_state_gc_lock); 421 spin_unlock_bh(&xfrm_state_gc_lock);
414 422
415 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst) 423 completed = xfrm_state_walk_completed;
424 mutex_unlock(&xfrm_cfg_mutex);
425
426 list_for_each_entry_safe(x, tmp, &xfrm_state_gc_leftovers, gclist) {
427 if ((long)(x->lastused - completed) > 0)
428 break;
429 list_del(&x->gclist);
416 xfrm_state_gc_destroy(x); 430 xfrm_state_gc_destroy(x);
431 }
417 432
418 wake_up(&km_waitq); 433 wake_up(&km_waitq);
419} 434}
@@ -540,12 +555,8 @@ void __xfrm_state_destroy(struct xfrm_state *x)
540{ 555{
541 WARN_ON(x->km.state != XFRM_STATE_DEAD); 556 WARN_ON(x->km.state != XFRM_STATE_DEAD);
542 557
543 spin_lock_bh(&xfrm_state_lock);
544 list_del(&x->all);
545 spin_unlock_bh(&xfrm_state_lock);
546
547 spin_lock_bh(&xfrm_state_gc_lock); 558 spin_lock_bh(&xfrm_state_gc_lock);
548 hlist_add_head(&x->bydst, &xfrm_state_gc_list); 559 list_add_tail(&x->gclist, &xfrm_state_gc_list);
549 spin_unlock_bh(&xfrm_state_gc_lock); 560 spin_unlock_bh(&xfrm_state_gc_lock);
550 schedule_work(&xfrm_state_gc_work); 561 schedule_work(&xfrm_state_gc_work);
551} 562}
@@ -558,6 +569,8 @@ int __xfrm_state_delete(struct xfrm_state *x)
558 if (x->km.state != XFRM_STATE_DEAD) { 569 if (x->km.state != XFRM_STATE_DEAD) {
559 x->km.state = XFRM_STATE_DEAD; 570 x->km.state = XFRM_STATE_DEAD;
560 spin_lock(&xfrm_state_lock); 571 spin_lock(&xfrm_state_lock);
572 x->lastused = xfrm_state_walk_ongoing;
573 list_del_rcu(&x->all);
561 hlist_del(&x->bydst); 574 hlist_del(&x->bydst);
562 hlist_del(&x->bysrc); 575 hlist_del(&x->bysrc);
563 if (x->id.spi) 576 if (x->id.spi)
@@ -1594,6 +1607,41 @@ out:
1594} 1607}
1595EXPORT_SYMBOL(xfrm_state_walk); 1608EXPORT_SYMBOL(xfrm_state_walk);
1596 1609
1610void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1611{
1612 walk->proto = proto;
1613 walk->state = NULL;
1614 walk->count = 0;
1615 list_add_tail(&walk->list, &xfrm_state_walks);
1616 walk->genid = ++xfrm_state_walk_ongoing;
1617}
1618EXPORT_SYMBOL(xfrm_state_walk_init);
1619
1620void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1621{
1622 struct list_head *prev;
1623
1624 if (walk->state != NULL) {
1625 xfrm_state_put(walk->state);
1626 walk->state = NULL;
1627 }
1628
1629 prev = walk->list.prev;
1630 list_del(&walk->list);
1631
1632 if (prev != &xfrm_state_walks) {
1633 list_entry(prev, struct xfrm_state_walk, list)->genid =
1634 walk->genid;
1635 return;
1636 }
1637
1638 xfrm_state_walk_completed = walk->genid;
1639
1640 if (!list_empty(&xfrm_state_gc_leftovers))
1641 schedule_work(&xfrm_state_gc_work);
1642}
1643EXPORT_SYMBOL(xfrm_state_walk_done);
1644
1597 1645
1598void xfrm_replay_notify(struct xfrm_state *x, int event) 1646void xfrm_replay_notify(struct xfrm_state *x, int event)
1599{ 1647{