aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2016-08-09 06:16:05 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2016-08-10 05:23:23 -0400
commit02efdff7e209859c2755ebe93b3bd0e3d40123ab (patch)
treed7008910ee8bc52787e18eda78733c31ea44ba39 /net/xfrm
parentae3fb6d32140e5c5b491892105ca89066171d217 (diff)
xfrm: state: use atomic_inc_not_zero to increment refcount
Once xfrm_state_lookup_byaddr no longer acquires the state lock another cpu might be freeing the state entry at the same time. To detect this we use atomic_inc_not_zero, we then signal -EAGAIN to caller in case our result was stale. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_state.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 904ab4d4ac05..84c1db6254d5 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -37,6 +37,11 @@
37 37
38static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; 38static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
39 39
40static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x)
41{
42 return atomic_inc_not_zero(&x->refcnt);
43}
44
40static inline unsigned int xfrm_dst_hash(struct net *net, 45static inline unsigned int xfrm_dst_hash(struct net *net,
41 const xfrm_address_t *daddr, 46 const xfrm_address_t *daddr,
42 const xfrm_address_t *saddr, 47 const xfrm_address_t *saddr,
@@ -668,7 +673,8 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
668 673
669 if ((mark & x->mark.m) != x->mark.v) 674 if ((mark & x->mark.m) != x->mark.v)
670 continue; 675 continue;
671 xfrm_state_hold(x); 676 if (!xfrm_state_hold_rcu(x))
677 continue;
672 return x; 678 return x;
673 } 679 }
674 680
@@ -692,7 +698,8 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark,
692 698
693 if ((mark & x->mark.m) != x->mark.v) 699 if ((mark & x->mark.m) != x->mark.v)
694 continue; 700 continue;
695 xfrm_state_hold(x); 701 if (!xfrm_state_hold_rcu(x))
702 continue;
696 return x; 703 return x;
697 } 704 }
698 705
@@ -871,10 +878,14 @@ found:
871 } 878 }
872 } 879 }
873out: 880out:
874 if (x) 881 if (x) {
875 xfrm_state_hold(x); 882 if (!xfrm_state_hold_rcu(x)) {
876 else 883 *err = -EAGAIN;
884 x = NULL;
885 }
886 } else {
877 *err = acquire_in_progress ? -EAGAIN : error; 887 *err = acquire_in_progress ? -EAGAIN : error;
888 }
878 spin_unlock_bh(&net->xfrm.xfrm_state_lock); 889 spin_unlock_bh(&net->xfrm.xfrm_state_lock);
879 if (to_put) 890 if (to_put)
880 xfrm_state_put(to_put); 891 xfrm_state_put(to_put);