* @shift: Current size (1 << shift)
  * @locks_mask: Mask to apply before accessing locks[]
  * @locks: Array of spinlocks protecting individual buckets
+ * @walkers: List of active walkers
  * @buckets: size * hash buckets
  */
 struct bucket_table {
        u32                     shift;
        unsigned int            locks_mask;
        spinlock_t              *locks;
+       struct list_head        walkers;
 
        struct rhash_head __rcu *buckets[] ____cacheline_aligned_in_smp;
 };
  * @p: Configuration parameters
  * @run_work: Deferred worker to expand/shrink asynchronously
  * @mutex: Mutex to protect current/future table swapping
- * @walkers: List of active walkers
  * @being_destroyed: True if table is set up for destruction
  */
 struct rhashtable {
        struct rhashtable_params        p;
        struct work_struct              run_work;
        struct mutex                    mutex;
-       struct list_head                walkers;
 };
 
 /**
  * struct rhashtable_walker - Hash table walker
  * @list: List entry on list of walkers
- * @resize: Resize event occured
+ * @tbl: The table that we were walking over
  */
 struct rhashtable_walker {
        struct list_head list;
-       bool resize;
+       struct bucket_table *tbl;
 };
 
 /**
 
                return NULL;
        }
 
+       INIT_LIST_HEAD(&tbl->walkers);
+
        for (i = 0; i < nbuckets; i++)
                INIT_RHT_NULLS_HEAD(tbl->buckets[i], ht, i);
 
                              struct bucket_table *new_tbl)
 {
        struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht);
+       struct rhashtable_walker *walker;
        unsigned old_hash;
 
        get_random_bytes(&new_tbl->hash_rnd, sizeof(new_tbl->hash_rnd));
        /* Publish the new table pointer. */
        rcu_assign_pointer(ht->tbl, new_tbl);
 
+       list_for_each_entry(walker, &old_tbl->walkers, list)
+               walker->tbl = NULL;
+
        /* Wait for readers. All new readers will see the new
         * table, and thus no references to the old table will
         * remain.
 {
        struct rhashtable *ht;
        struct bucket_table *tbl;
-       struct rhashtable_walker *walker;
 
        ht = container_of(work, struct rhashtable, run_work);
        mutex_lock(&ht->mutex);
 
        tbl = rht_dereference(ht->tbl, ht);
 
-       list_for_each_entry(walker, &ht->walkers, list)
-               walker->resize = true;
-
        if (rht_grow_above_75(ht, tbl))
                rhashtable_expand(ht);
        else if (rht_shrink_below_30(ht, tbl))
        if (!iter->walker)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&iter->walker->list);
-       iter->walker->resize = false;
-
        mutex_lock(&ht->mutex);
-       list_add(&iter->walker->list, &ht->walkers);
+       iter->walker->tbl = rht_dereference(ht->tbl, ht);
+       list_add(&iter->walker->list, &iter->walker->tbl->walkers);
        mutex_unlock(&ht->mutex);
 
        return 0;
 void rhashtable_walk_exit(struct rhashtable_iter *iter)
 {
        mutex_lock(&iter->ht->mutex);
-       list_del(&iter->walker->list);
+       if (iter->walker->tbl)
+               list_del(&iter->walker->list);
        mutex_unlock(&iter->ht->mutex);
        kfree(iter->walker);
 }
  */
 int rhashtable_walk_start(struct rhashtable_iter *iter)
 {
+       struct rhashtable *ht = iter->ht;
+
+       mutex_lock(&ht->mutex);
+
+       if (iter->walker->tbl)
+               list_del(&iter->walker->list);
+
        rcu_read_lock();
 
-       if (iter->walker->resize) {
-               iter->slot = 0;
-               iter->skip = 0;
-               iter->walker->resize = false;
+       mutex_unlock(&ht->mutex);
+
+       if (!iter->walker->tbl) {
+               iter->walker->tbl = rht_dereference_rcu(ht->tbl, ht);
                return -EAGAIN;
        }
 
  */
 void *rhashtable_walk_next(struct rhashtable_iter *iter)
 {
-       const struct bucket_table *tbl;
+       struct bucket_table *tbl = iter->walker->tbl;
        struct rhashtable *ht = iter->ht;
        struct rhash_head *p = iter->p;
        void *obj = NULL;
 
-       tbl = rht_dereference_rcu(ht->tbl, ht);
-
        if (p) {
                p = rht_dereference_bucket_rcu(p->next, tbl, iter->slot);
                goto next;
                iter->skip = 0;
        }
 
-       iter->p = NULL;
-
-out:
-       if (iter->walker->resize) {
-               iter->p = NULL;
+       iter->walker->tbl = rht_dereference_rcu(ht->future_tbl, ht);
+       if (iter->walker->tbl != tbl) {
                iter->slot = 0;
                iter->skip = 0;
-               iter->walker->resize = false;
                return ERR_PTR(-EAGAIN);
        }
 
+       iter->walker->tbl = NULL;
+       iter->p = NULL;
+
+out:
+
        return obj;
 }
 EXPORT_SYMBOL_GPL(rhashtable_walk_next);
  */
 void rhashtable_walk_stop(struct rhashtable_iter *iter)
 {
+       struct rhashtable *ht;
+       struct bucket_table *tbl = iter->walker->tbl;
+
        rcu_read_unlock();
+
+       if (!tbl)
+               return;
+
+       ht = iter->ht;
+
+       mutex_lock(&ht->mutex);
+       if (rht_dereference(ht->tbl, ht) == tbl ||
+           rht_dereference(ht->future_tbl, ht) == tbl)
+               list_add(&iter->walker->list, &tbl->walkers);
+       else
+               iter->walker->tbl = NULL;
+       mutex_unlock(&ht->mutex);
+
        iter->p = NULL;
 }
 EXPORT_SYMBOL_GPL(rhashtable_walk_stop);
        memset(ht, 0, sizeof(*ht));
        mutex_init(&ht->mutex);
        memcpy(&ht->p, params, sizeof(*params));
-       INIT_LIST_HEAD(&ht->walkers);
 
        if (params->locks_mul)
                ht->p.locks_mul = roundup_pow_of_two(params->locks_mul);