aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r--net/xfrm/xfrm_state.c30
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}
433EXPORT_SYMBOL(xfrm_state_free); 433EXPORT_SYMBOL(xfrm_state_free);
434 434
435static void xfrm_state_gc_destroy(struct xfrm_state *x) 435static 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
480static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) 480static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
@@ -598,14 +598,19 @@ struct xfrm_state *xfrm_state_alloc(struct net *net)
598} 598}
599EXPORT_SYMBOL(xfrm_state_alloc); 599EXPORT_SYMBOL(xfrm_state_alloc);
600 600
601void __xfrm_state_destroy(struct xfrm_state *x) 601void __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}
610EXPORT_SYMBOL(__xfrm_state_destroy); 615EXPORT_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
711int xfrm_state_flush(struct net *net, u8 proto, bool task_valid) 716int 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