aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2015-03-13 22:57:25 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-15 01:35:34 -0400
commitc4db8848af6af92f90462258603be844baeab44d (patch)
tree582bc65b98879f06bc3e9f28b9adefdc90314725 /lib
parent63d512d0cffcae40505d9448abd509972465e846 (diff)
rhashtable: Move future_tbl into struct bucket_table
This patch moves future_tbl to open up the possibility of having multiple rehashes on the same table. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib')
-rw-r--r--lib/rhashtable.c27
1 files changed, 11 insertions, 16 deletions
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index ff4ea1704546..9d53a46dcca9 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -207,8 +207,9 @@ static bool rht_shrink_below_30(const struct rhashtable *ht,
207 207
208static int rhashtable_rehash_one(struct rhashtable *ht, unsigned old_hash) 208static int rhashtable_rehash_one(struct rhashtable *ht, unsigned old_hash)
209{ 209{
210 struct bucket_table *new_tbl = rht_dereference(ht->future_tbl, ht);
211 struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht); 210 struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht);
211 struct bucket_table *new_tbl =
212 rht_dereference(old_tbl->future_tbl, ht) ?: old_tbl;
212 struct rhash_head __rcu **pprev = &old_tbl->buckets[old_hash]; 213 struct rhash_head __rcu **pprev = &old_tbl->buckets[old_hash];
213 int err = -ENOENT; 214 int err = -ENOENT;
214 struct rhash_head *head, *next, *entry; 215 struct rhash_head *head, *next, *entry;
@@ -273,10 +274,8 @@ static void rhashtable_rehash(struct rhashtable *ht,
273 274
274 /* Make insertions go into the new, empty table right away. Deletions 275 /* Make insertions go into the new, empty table right away. Deletions
275 * and lookups will be attempted in both tables until we synchronize. 276 * and lookups will be attempted in both tables until we synchronize.
276 * The synchronize_rcu() guarantees for the new table to be picked up
277 * so no new additions go into the old table while we relink.
278 */ 277 */
279 rcu_assign_pointer(ht->future_tbl, new_tbl); 278 rcu_assign_pointer(old_tbl->future_tbl, new_tbl);
280 279
281 /* Ensure the new table is visible to readers. */ 280 /* Ensure the new table is visible to readers. */
282 smp_wmb(); 281 smp_wmb();
@@ -400,7 +399,7 @@ static bool __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj,
400 * also grab the bucket lock in old_tbl because until the 399 * also grab the bucket lock in old_tbl because until the
401 * rehash completes ht->tbl won't be changed. 400 * rehash completes ht->tbl won't be changed.
402 */ 401 */
403 tbl = rht_dereference_rcu(ht->future_tbl, ht); 402 tbl = rht_dereference_rcu(old_tbl->future_tbl, ht) ?: old_tbl;
404 if (tbl != old_tbl) { 403 if (tbl != old_tbl) {
405 hash = head_hashfn(ht, tbl, obj); 404 hash = head_hashfn(ht, tbl, obj);
406 spin_lock_nested(bucket_lock(tbl, hash), SINGLE_DEPTH_NESTING); 405 spin_lock_nested(bucket_lock(tbl, hash), SINGLE_DEPTH_NESTING);
@@ -525,7 +524,7 @@ bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *obj)
525 * visible then that guarantees the entry to still be in 524 * visible then that guarantees the entry to still be in
526 * old_tbl if it exists. 525 * old_tbl if it exists.
527 */ 526 */
528 tbl = rht_dereference_rcu(ht->future_tbl, ht); 527 tbl = rht_dereference_rcu(old_tbl->future_tbl, ht) ?: old_tbl;
529 if (!ret && old_tbl != tbl) 528 if (!ret && old_tbl != tbl)
530 ret = __rhashtable_remove(ht, tbl, obj); 529 ret = __rhashtable_remove(ht, tbl, obj);
531 530
@@ -599,7 +598,7 @@ EXPORT_SYMBOL_GPL(rhashtable_lookup);
599void *rhashtable_lookup_compare(struct rhashtable *ht, const void *key, 598void *rhashtable_lookup_compare(struct rhashtable *ht, const void *key,
600 bool (*compare)(void *, void *), void *arg) 599 bool (*compare)(void *, void *), void *arg)
601{ 600{
602 const struct bucket_table *tbl, *old_tbl; 601 const struct bucket_table *tbl;
603 struct rhash_head *he; 602 struct rhash_head *he;
604 u32 hash; 603 u32 hash;
605 604
@@ -618,9 +617,8 @@ restart:
618 /* Ensure we see any new tables. */ 617 /* Ensure we see any new tables. */
619 smp_rmb(); 618 smp_rmb();
620 619
621 old_tbl = tbl; 620 tbl = rht_dereference_rcu(tbl->future_tbl, ht);
622 tbl = rht_dereference_rcu(ht->future_tbl, ht); 621 if (unlikely(tbl))
623 if (unlikely(tbl != old_tbl))
624 goto restart; 622 goto restart;
625 rcu_read_unlock(); 623 rcu_read_unlock();
626 624
@@ -830,14 +828,13 @@ next:
830 iter->skip = 0; 828 iter->skip = 0;
831 } 829 }
832 830
833 iter->walker->tbl = rht_dereference_rcu(ht->future_tbl, ht); 831 iter->walker->tbl = rht_dereference_rcu(tbl->future_tbl, ht);
834 if (iter->walker->tbl != tbl) { 832 if (iter->walker->tbl) {
835 iter->slot = 0; 833 iter->slot = 0;
836 iter->skip = 0; 834 iter->skip = 0;
837 return ERR_PTR(-EAGAIN); 835 return ERR_PTR(-EAGAIN);
838 } 836 }
839 837
840 iter->walker->tbl = NULL;
841 iter->p = NULL; 838 iter->p = NULL;
842 839
843out: 840out:
@@ -865,8 +862,7 @@ void rhashtable_walk_stop(struct rhashtable_iter *iter)
865 ht = iter->ht; 862 ht = iter->ht;
866 863
867 mutex_lock(&ht->mutex); 864 mutex_lock(&ht->mutex);
868 if (rht_dereference(ht->tbl, ht) == tbl || 865 if (tbl->rehash < tbl->size)
869 rht_dereference(ht->future_tbl, ht) == tbl)
870 list_add(&iter->walker->list, &tbl->walkers); 866 list_add(&iter->walker->list, &tbl->walkers);
871 else 867 else
872 iter->walker->tbl = NULL; 868 iter->walker->tbl = NULL;
@@ -961,7 +957,6 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params)
961 atomic_set(&ht->nelems, 0); 957 atomic_set(&ht->nelems, 0);
962 958
963 RCU_INIT_POINTER(ht->tbl, tbl); 959 RCU_INIT_POINTER(ht->tbl, tbl);
964 RCU_INIT_POINTER(ht->future_tbl, tbl);
965 960
966 INIT_WORK(&ht->run_work, rht_deferred_worker); 961 INIT_WORK(&ht->run_work, rht_deferred_worker);
967 962