]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - lib/rhashtable.c
printk/nmi: Prevent deadlock when accessing the main log buffer in NMI
[mirror_ubuntu-bionic-kernel.git] / lib / rhashtable.c
index ddd7dde87c3ca0db910d67a567f2a68c8d8e847e..2c83e280ac49fc24b4fc0d151862806d2af2766d 100644 (file)
@@ -537,8 +537,10 @@ static void *rhashtable_lookup_one(struct rhashtable *ht,
                if (!key ||
                    (ht->p.obj_cmpfn ?
                     ht->p.obj_cmpfn(&arg, rht_obj(ht, head)) :
-                    rhashtable_compare(&arg, rht_obj(ht, head))))
+                    rhashtable_compare(&arg, rht_obj(ht, head)))) {
+                       pprev = &head->next;
                        continue;
+               }
 
                if (!ht->rhlist)
                        return rht_obj(ht, head);
@@ -876,8 +878,16 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_stop);
 
 static size_t rounded_hashtable_size(const struct rhashtable_params *params)
 {
-       return max(roundup_pow_of_two(params->nelem_hint * 4 / 3),
-                  (unsigned long)params->min_size);
+       size_t retsize;
+
+       if (params->nelem_hint)
+               retsize = max(roundup_pow_of_two(params->nelem_hint * 4 / 3),
+                             (unsigned long)params->min_size);
+       else
+               retsize = max(HASH_DEFAULT_SIZE,
+                             (unsigned long)params->min_size);
+
+       return retsize;
 }
 
 static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed)
@@ -934,8 +944,6 @@ int rhashtable_init(struct rhashtable *ht,
        struct bucket_table *tbl;
        size_t size;
 
-       size = HASH_DEFAULT_SIZE;
-
        if ((!params->key_len && !params->obj_hashfn) ||
            (params->obj_hashfn && !params->obj_cmpfn))
                return -EINVAL;
@@ -962,8 +970,7 @@ int rhashtable_init(struct rhashtable *ht,
 
        ht->p.min_size = max_t(u16, ht->p.min_size, HASH_MIN_SIZE);
 
-       if (params->nelem_hint)
-               size = rounded_hashtable_size(&ht->p);
+       size = rounded_hashtable_size(&ht->p);
 
        if (params->locks_mul)
                ht->p.locks_mul = roundup_pow_of_two(params->locks_mul);
@@ -1055,13 +1062,14 @@ void rhashtable_free_and_destroy(struct rhashtable *ht,
                                 void (*free_fn)(void *ptr, void *arg),
                                 void *arg)
 {
-       struct bucket_table *tbl;
+       struct bucket_table *tbl, *next_tbl;
        unsigned int i;
 
        cancel_work_sync(&ht->run_work);
 
        mutex_lock(&ht->mutex);
        tbl = rht_dereference(ht->tbl, ht);
+restart:
        if (free_fn) {
                for (i = 0; i < tbl->size; i++) {
                        struct rhash_head *pos, *next;
@@ -1077,7 +1085,12 @@ void rhashtable_free_and_destroy(struct rhashtable *ht,
                }
        }
 
+       next_tbl = rht_dereference(tbl->future_tbl, ht);
        bucket_table_free(tbl);
+       if (next_tbl) {
+               tbl = next_tbl;
+               goto restart;
+       }
        mutex_unlock(&ht->mutex);
 }
 EXPORT_SYMBOL_GPL(rhashtable_free_and_destroy);