diff options
author | Thomas Graf <tgraf@suug.ch> | 2015-02-05 02:03:35 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-02-06 15:18:34 -0800 |
commit | 7cd10db8de2b6a32ccabef2e0e01c7444faa49d4 (patch) | |
tree | 2cc37d47c4dfba4564a075254c3025952cf04a8a /lib | |
parent | a03eaec0df52a0f1fd37ebf7dcb2dc505d891255 (diff) | |
download | lwn-7cd10db8de2b6a32ccabef2e0e01c7444faa49d4.tar.gz lwn-7cd10db8de2b6a32ccabef2e0e01c7444faa49d4.zip |
rhashtable: Add more lock verification
Catch hash miscalculations which result in hard to track down race
conditions.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rhashtable.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/lib/rhashtable.c b/lib/rhashtable.c index c2c39495fac6..ef0816b6be82 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -348,9 +348,11 @@ static bool hashtable_chain_unzip(struct rhashtable *ht, return !rht_is_a_nulls(p); } -static void link_old_to_new(struct bucket_table *new_tbl, +static void link_old_to_new(struct rhashtable *ht, struct bucket_table *new_tbl, unsigned int new_hash, struct rhash_head *entry) { + ASSERT_BUCKET_LOCK(ht, new_tbl, new_hash); + rcu_assign_pointer(*bucket_tail(new_tbl, new_hash), entry); } @@ -406,7 +408,7 @@ int rhashtable_expand(struct rhashtable *ht) lock_buckets(new_tbl, old_tbl, new_hash); rht_for_each(he, old_tbl, old_hash) { if (head_hashfn(ht, new_tbl, he) == new_hash) { - link_old_to_new(new_tbl, new_hash, he); + link_old_to_new(ht, new_tbl, new_hash, he); break; } } @@ -492,6 +494,7 @@ int rhashtable_shrink(struct rhashtable *ht) rcu_assign_pointer(*bucket_tail(new_tbl, new_hash), tbl->buckets[new_hash]); + ASSERT_BUCKET_LOCK(ht, tbl, new_hash + new_tbl->size); rcu_assign_pointer(*bucket_tail(new_tbl, new_hash), tbl->buckets[new_hash + new_tbl->size]); @@ -557,6 +560,8 @@ static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj, struct rhash_head *head = rht_dereference_bucket(tbl->buckets[hash], tbl, hash); + ASSERT_BUCKET_LOCK(ht, tbl, hash); + if (rht_is_a_nulls(head)) INIT_RHT_NULLS_HEAD(obj->next, ht, hash); else @@ -641,6 +646,7 @@ restart: continue; } + ASSERT_BUCKET_LOCK(ht, tbl, hash); rcu_assign_pointer(*pprev, obj->next); ret = true; |