diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
| -rw-r--r-- | net/xfrm/xfrm_state.c | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 23c92891758a..1bb971f46fc6 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -432,7 +432,7 @@ void xfrm_state_free(struct xfrm_state *x) | |||
| 432 | } | 432 | } |
| 433 | EXPORT_SYMBOL(xfrm_state_free); | 433 | EXPORT_SYMBOL(xfrm_state_free); |
| 434 | 434 | ||
| 435 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 435 | static void ___xfrm_state_destroy(struct xfrm_state *x) |
| 436 | { | 436 | { |
| 437 | tasklet_hrtimer_cancel(&x->mtimer); | 437 | tasklet_hrtimer_cancel(&x->mtimer); |
| 438 | del_timer_sync(&x->rtimer); | 438 | del_timer_sync(&x->rtimer); |
| @@ -474,7 +474,7 @@ static void xfrm_state_gc_task(struct work_struct *work) | |||
| 474 | synchronize_rcu(); | 474 | synchronize_rcu(); |
| 475 | 475 | ||
| 476 | hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) | 476 | hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) |
| 477 | xfrm_state_gc_destroy(x); | 477 | ___xfrm_state_destroy(x); |
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) | 480 | static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) |
| @@ -598,14 +598,19 @@ struct xfrm_state *xfrm_state_alloc(struct net *net) | |||
| 598 | } | 598 | } |
| 599 | EXPORT_SYMBOL(xfrm_state_alloc); | 599 | EXPORT_SYMBOL(xfrm_state_alloc); |
| 600 | 600 | ||
| 601 | void __xfrm_state_destroy(struct xfrm_state *x) | 601 | void __xfrm_state_destroy(struct xfrm_state *x, bool sync) |
| 602 | { | 602 | { |
| 603 | WARN_ON(x->km.state != XFRM_STATE_DEAD); | 603 | WARN_ON(x->km.state != XFRM_STATE_DEAD); |
| 604 | 604 | ||
| 605 | spin_lock_bh(&xfrm_state_gc_lock); | 605 | if (sync) { |
| 606 | hlist_add_head(&x->gclist, &xfrm_state_gc_list); | 606 | synchronize_rcu(); |
| 607 | spin_unlock_bh(&xfrm_state_gc_lock); | 607 | ___xfrm_state_destroy(x); |
| 608 | schedule_work(&xfrm_state_gc_work); | 608 | } else { |
| 609 | spin_lock_bh(&xfrm_state_gc_lock); | ||
| 610 | hlist_add_head(&x->gclist, &xfrm_state_gc_list); | ||
| 611 | spin_unlock_bh(&xfrm_state_gc_lock); | ||
| 612 | schedule_work(&xfrm_state_gc_work); | ||
| 613 | } | ||
| 609 | } | 614 | } |
| 610 | EXPORT_SYMBOL(__xfrm_state_destroy); | 615 | EXPORT_SYMBOL(__xfrm_state_destroy); |
| 611 | 616 | ||
| @@ -708,7 +713,7 @@ xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool | |||
| 708 | } | 713 | } |
| 709 | #endif | 714 | #endif |
| 710 | 715 | ||
| 711 | int xfrm_state_flush(struct net *net, u8 proto, bool task_valid) | 716 | int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync) |
| 712 | { | 717 | { |
| 713 | int i, err = 0, cnt = 0; | 718 | int i, err = 0, cnt = 0; |
| 714 | 719 | ||
| @@ -730,7 +735,10 @@ restart: | |||
| 730 | err = xfrm_state_delete(x); | 735 | err = xfrm_state_delete(x); |
| 731 | xfrm_audit_state_delete(x, err ? 0 : 1, | 736 | xfrm_audit_state_delete(x, err ? 0 : 1, |
| 732 | task_valid); | 737 | task_valid); |
| 733 | xfrm_state_put(x); | 738 | if (sync) |
| 739 | xfrm_state_put_sync(x); | ||
| 740 | else | ||
| 741 | xfrm_state_put(x); | ||
| 734 | if (!err) | 742 | if (!err) |
| 735 | cnt++; | 743 | cnt++; |
| 736 | 744 | ||
| @@ -2215,7 +2223,7 @@ void xfrm_state_delete_tunnel(struct xfrm_state *x) | |||
| 2215 | if (atomic_read(&t->tunnel_users) == 2) | 2223 | if (atomic_read(&t->tunnel_users) == 2) |
| 2216 | xfrm_state_delete(t); | 2224 | xfrm_state_delete(t); |
| 2217 | atomic_dec(&t->tunnel_users); | 2225 | atomic_dec(&t->tunnel_users); |
| 2218 | xfrm_state_put(t); | 2226 | xfrm_state_put_sync(t); |
| 2219 | x->tunnel = NULL; | 2227 | x->tunnel = NULL; |
| 2220 | } | 2228 | } |
| 2221 | } | 2229 | } |
| @@ -2375,8 +2383,8 @@ void xfrm_state_fini(struct net *net) | |||
| 2375 | unsigned int sz; | 2383 | unsigned int sz; |
| 2376 | 2384 | ||
| 2377 | flush_work(&net->xfrm.state_hash_work); | 2385 | flush_work(&net->xfrm.state_hash_work); |
| 2378 | xfrm_state_flush(net, IPSEC_PROTO_ANY, false); | ||
| 2379 | flush_work(&xfrm_state_gc_work); | 2386 | flush_work(&xfrm_state_gc_work); |
| 2387 | xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true); | ||
| 2380 | 2388 | ||
| 2381 | WARN_ON(!list_empty(&net->xfrm.state_all)); | 2389 | WARN_ON(!list_empty(&net->xfrm.state_all)); |
| 2382 | 2390 | ||
