diff options
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 2 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 72 |
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 | ||
37 | int sysctl_xfrm_larval_drop __read_mostly; | 37 | int sysctl_xfrm_larval_drop __read_mostly = 1; |
38 | 38 | ||
39 | #ifdef CONFIG_XFRM_STATISTICS | 39 | #ifdef CONFIG_XFRM_STATISTICS |
40 | DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly; | 40 | DEFINE_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; | |||
59 | static unsigned int xfrm_state_num; | 59 | static unsigned int xfrm_state_num; |
60 | static unsigned int xfrm_state_genid; | 60 | static unsigned int xfrm_state_genid; |
61 | 61 | ||
62 | /* Counter indicating ongoing walk, protected by xfrm_state_lock. */ | ||
63 | static unsigned long xfrm_state_walk_ongoing; | ||
64 | /* Counter indicating walk completion, protected by xfrm_cfg_mutex. */ | ||
65 | static unsigned long xfrm_state_walk_completed; | ||
66 | |||
67 | /* List of outstanding state walks used to set the completed counter. */ | ||
68 | static LIST_HEAD(xfrm_state_walks); | ||
69 | |||
62 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | 70 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); |
63 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | 71 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); |
64 | 72 | ||
@@ -191,7 +199,8 @@ static DEFINE_RWLOCK(xfrm_state_afinfo_lock); | |||
191 | static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; | 199 | static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; |
192 | 200 | ||
193 | static struct work_struct xfrm_state_gc_work; | 201 | static struct work_struct xfrm_state_gc_work; |
194 | static HLIST_HEAD(xfrm_state_gc_list); | 202 | static LIST_HEAD(xfrm_state_gc_leftovers); |
203 | static LIST_HEAD(xfrm_state_gc_list); | ||
195 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); | 204 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); |
196 | 205 | ||
197 | int __xfrm_state_delete(struct xfrm_state *x); | 206 | int __xfrm_state_delete(struct xfrm_state *x); |
@@ -403,17 +412,23 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
403 | 412 | ||
404 | static void xfrm_state_gc_task(struct work_struct *data) | 413 | static 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 | } |
1595 | EXPORT_SYMBOL(xfrm_state_walk); | 1608 | EXPORT_SYMBOL(xfrm_state_walk); |
1596 | 1609 | ||
1610 | void 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 | } | ||
1618 | EXPORT_SYMBOL(xfrm_state_walk_init); | ||
1619 | |||
1620 | void 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 | } | ||
1643 | EXPORT_SYMBOL(xfrm_state_walk_done); | ||
1644 | |||
1597 | 1645 | ||
1598 | void xfrm_replay_notify(struct xfrm_state *x, int event) | 1646 | void xfrm_replay_notify(struct xfrm_state *x, int event) |
1599 | { | 1647 | { |