diff options
author | Dmitriy Vyukov <dvyukov@google.com> | 2015-09-22 10:51:52 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-09-22 17:36:07 -0700 |
commit | 7def0f952eccdd0edb3c504f4dab35ee0d3aba1f (patch) | |
tree | b07b5d821064709d15bf725818ab3e3a751daafe /lib/rhashtable.c | |
parent | 23eedbc2435ddd226717603c4f3c8efec7bdbb4d (diff) | |
download | linux-7def0f952eccdd0edb3c504f4dab35ee0d3aba1f.tar.gz linux-7def0f952eccdd0edb3c504f4dab35ee0d3aba1f.tar.bz2 linux-7def0f952eccdd0edb3c504f4dab35ee0d3aba1f.zip |
lib: fix data race in rhashtable_rehash_one
rhashtable_rehash_one() uses complex logic to update entry->next field,
after INIT_RHT_NULLS_HEAD and NULLS_MARKER expansion:
entry->next = 1 | ((base + off) << 1)
This can be compiled along the lines of:
entry->next = base + off
entry->next <<= 1
entry->next |= 1
Which will break concurrent readers.
NULLS value recomputation is not needed here, so just remove
the complex logic.
The data race was found with KernelThreadSanitizer (KTSAN).
Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Acked-by: Thomas Graf <tgraf@suug.ch>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib/rhashtable.c')
-rw-r--r-- | lib/rhashtable.c | 5 |
1 files changed, 1 insertions, 4 deletions
diff --git a/lib/rhashtable.c b/lib/rhashtable.c index cc0c69710dcf..a54ff8949f91 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -187,10 +187,7 @@ static int rhashtable_rehash_one(struct rhashtable *ht, unsigned int old_hash) head = rht_dereference_bucket(new_tbl->buckets[new_hash], new_tbl, new_hash); - if (rht_is_a_nulls(head)) - INIT_RHT_NULLS_HEAD(entry->next, ht, new_hash); - else - RCU_INIT_POINTER(entry->next, head); + RCU_INIT_POINTER(entry->next, head); rcu_assign_pointer(new_tbl->buckets[new_hash], entry); spin_unlock(new_bucket_lock); |