aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2015-03-12 22:07:49 +1100
committerDavid S. Miller <davem@davemloft.net>2015-03-12 23:02:30 -0400
commit9497df88ab5567daa001829051c5f87161a81ff0 (patch)
tree4631c01eb33d6f8bbcf018f47d31d19ad4fac5a4 /lib
parentMerge branch 'listener_refactor' (diff)
downloadlinux-dev-9497df88ab5567daa001829051c5f87161a81ff0.tar.xz
linux-dev-9497df88ab5567daa001829051c5f87161a81ff0.zip
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.c6
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,
*/
rcu_assign_pointer(ht->future_tbl, new_tbl);
+ /* Ensure the new table is visible to readers. */
+ smp_wmb();
+
for (old_hash = 0; old_hash < old_tbl->size; old_hash++)
rhashtable_rehash_chain(ht, old_hash);
@@ -618,6 +621,9 @@ restart:
return rht_obj(ht, he);
}
+ /* Ensure we see any new tables. */
+ smp_rmb();
+
old_tbl = tbl;
tbl = rht_dereference_rcu(ht->future_tbl, ht);
if (unlikely(tbl != old_tbl))