diff options
author | Florian Westphal <fw@strlen.de> | 2016-08-09 06:16:07 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2016-08-10 05:23:24 -0400 |
commit | b65e3d7be06fd8ff5236439254f338fe1a8d4bbd (patch) | |
tree | e9831de71641f57f8987811bdfd8b74b9cdbb438 /net/xfrm | |
parent | df7274eb70b7c8488170ebe8757dd94647a8e1e5 (diff) |
xfrm: state: add sequence count to detect hash resizes
Once xfrm_state_find is lockless we have to cope with a concurrent
resize opertion.
We use a sequence counter to block in case a resize is in progress
and to detect if we might have missed a state that got moved to
a new hash table.
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.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 8e373876924f..ac4037cf6a29 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -36,6 +36,7 @@ | |||
36 | */ | 36 | */ |
37 | 37 | ||
38 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | 38 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; |
39 | static __read_mostly seqcount_t xfrm_state_hash_generation = SEQCNT_ZERO(xfrm_state_hash_generation); | ||
39 | 40 | ||
40 | static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x) | 41 | static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x) |
41 | { | 42 | { |
@@ -127,6 +128,7 @@ static void xfrm_hash_resize(struct work_struct *work) | |||
127 | } | 128 | } |
128 | 129 | ||
129 | spin_lock_bh(&net->xfrm.xfrm_state_lock); | 130 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
131 | write_seqcount_begin(&xfrm_state_hash_generation); | ||
130 | 132 | ||
131 | nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; | 133 | nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; |
132 | for (i = net->xfrm.state_hmask; i >= 0; i--) | 134 | for (i = net->xfrm.state_hmask; i >= 0; i--) |
@@ -143,6 +145,7 @@ static void xfrm_hash_resize(struct work_struct *work) | |||
143 | net->xfrm.state_byspi = nspi; | 145 | net->xfrm.state_byspi = nspi; |
144 | net->xfrm.state_hmask = nhashmask; | 146 | net->xfrm.state_hmask = nhashmask; |
145 | 147 | ||
148 | write_seqcount_end(&xfrm_state_hash_generation); | ||
146 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); | 149 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
147 | 150 | ||
148 | osize = (ohashmask + 1) * sizeof(struct hlist_head); | 151 | osize = (ohashmask + 1) * sizeof(struct hlist_head); |
@@ -787,10 +790,13 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, | |||
787 | struct xfrm_state *best = NULL; | 790 | struct xfrm_state *best = NULL; |
788 | u32 mark = pol->mark.v & pol->mark.m; | 791 | u32 mark = pol->mark.v & pol->mark.m; |
789 | unsigned short encap_family = tmpl->encap_family; | 792 | unsigned short encap_family = tmpl->encap_family; |
793 | unsigned int sequence; | ||
790 | struct km_event c; | 794 | struct km_event c; |
791 | 795 | ||
792 | to_put = NULL; | 796 | to_put = NULL; |
793 | 797 | ||
798 | sequence = read_seqcount_begin(&xfrm_state_hash_generation); | ||
799 | |||
794 | spin_lock_bh(&net->xfrm.xfrm_state_lock); | 800 | spin_lock_bh(&net->xfrm.xfrm_state_lock); |
795 | h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); | 801 | h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); |
796 | hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { | 802 | hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { |
@@ -894,6 +900,15 @@ out: | |||
894 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); | 900 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); |
895 | if (to_put) | 901 | if (to_put) |
896 | xfrm_state_put(to_put); | 902 | xfrm_state_put(to_put); |
903 | |||
904 | if (read_seqcount_retry(&xfrm_state_hash_generation, sequence)) { | ||
905 | *err = -EAGAIN; | ||
906 | if (x) { | ||
907 | xfrm_state_put(x); | ||
908 | x = NULL; | ||
909 | } | ||
910 | } | ||
911 | |||
897 | return x; | 912 | return x; |
898 | } | 913 | } |
899 | 914 | ||