diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2015-03-12 07:07:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-12 23:02:30 -0400 |
commit | 9497df88ab5567daa001829051c5f87161a81ff0 (patch) | |
tree | 4631c01eb33d6f8bbcf018f47d31d19ad4fac5a4 /lib | |
parent | 5ff0d16aac91857246770f477942878a4d4f31f7 (diff) |
rhashtable: Fix reader/rehash race
There is a potential race condition between readers and the rehasher.
In particular, the rehasher could have started a rehash while the
reader finishes a scan of the old table but fails to see the new
table pointer.
This patch closes this window by adding smp_wmb/smp_rmb.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rhashtable.c | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 6ffc793145f3..68210cc2bab8 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c | |||
@@ -271,6 +271,9 @@ static void rhashtable_rehash(struct rhashtable *ht, | |||
271 | */ | 271 | */ |
272 | rcu_assign_pointer(ht->future_tbl, new_tbl); | 272 | rcu_assign_pointer(ht->future_tbl, new_tbl); |
273 | 273 | ||
274 | /* Ensure the new table is visible to readers. */ | ||
275 | smp_wmb(); | ||
276 | |||
274 | for (old_hash = 0; old_hash < old_tbl->size; old_hash++) | 277 | for (old_hash = 0; old_hash < old_tbl->size; old_hash++) |
275 | rhashtable_rehash_chain(ht, old_hash); | 278 | rhashtable_rehash_chain(ht, old_hash); |
276 | 279 | ||
@@ -618,6 +621,9 @@ restart: | |||
618 | return rht_obj(ht, he); | 621 | return rht_obj(ht, he); |
619 | } | 622 | } |
620 | 623 | ||
624 | /* Ensure we see any new tables. */ | ||
625 | smp_rmb(); | ||
626 | |||
621 | old_tbl = tbl; | 627 | old_tbl = tbl; |
622 | tbl = rht_dereference_rcu(ht->future_tbl, ht); | 628 | tbl = rht_dereference_rcu(ht->future_tbl, ht); |
623 | if (unlikely(tbl != old_tbl)) | 629 | if (unlikely(tbl != old_tbl)) |