rhashtable: Add more lock verification
authorThomas Graf <tgraf@suug.ch>
Thu, 5 Feb 2015 01:03:35 +0000 (02:03 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 6 Feb 2015 23:18:34 +0000 (15:18 -0800)
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>
lib/rhashtable.c

index c2c39495fac6a038c968fa2791f79e41465397ce..ef0816b6be8200a075595bb33a29a9ce4693d008 100644 (file)
@@ -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;