Commit 7def0f95 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov Committed by David S. Miller

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: default avatarDmitry Vyukov <dvyukov@google.com>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarThomas Graf <tgraf@suug.ch>
Acked-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 23eedbc2
...@@ -187,10 +187,7 @@ static int rhashtable_rehash_one(struct rhashtable *ht, unsigned int old_hash) ...@@ -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], head = rht_dereference_bucket(new_tbl->buckets[new_hash],
new_tbl, new_hash); new_tbl, new_hash);
if (rht_is_a_nulls(head)) RCU_INIT_POINTER(entry->next, head);
INIT_RHT_NULLS_HEAD(entry->next, ht, new_hash);
else
RCU_INIT_POINTER(entry->next, head);
rcu_assign_pointer(new_tbl->buckets[new_hash], entry); rcu_assign_pointer(new_tbl->buckets[new_hash], entry);
spin_unlock(new_bucket_lock); spin_unlock(new_bucket_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment