aboutsummaryrefslogtreecommitdiffstats
path: root/lib/rhashtable.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rhashtable.c')
-rw-r--r--lib/rhashtable.c51
1 files changed, 46 insertions, 5 deletions
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index 2b2b79974b61..9427b5766134 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -668,8 +668,9 @@ EXPORT_SYMBOL_GPL(rhashtable_insert_slow);
668 * For a completely stable walk you should construct your own data 668 * For a completely stable walk you should construct your own data
669 * structure outside the hash table. 669 * structure outside the hash table.
670 * 670 *
671 * This function may sleep so you must not call it from interrupt 671 * This function may be called from any process context, including
672 * context or with spin locks held. 672 * non-preemptable context, but cannot be called from softirq or
673 * hardirq context.
673 * 674 *
674 * You must call rhashtable_walk_exit after this function returns. 675 * You must call rhashtable_walk_exit after this function returns.
675 */ 676 */
@@ -726,6 +727,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter)
726 __acquires(RCU) 727 __acquires(RCU)
727{ 728{
728 struct rhashtable *ht = iter->ht; 729 struct rhashtable *ht = iter->ht;
730 bool rhlist = ht->rhlist;
729 731
730 rcu_read_lock(); 732 rcu_read_lock();
731 733
@@ -734,11 +736,52 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter)
734 list_del(&iter->walker.list); 736 list_del(&iter->walker.list);
735 spin_unlock(&ht->lock); 737 spin_unlock(&ht->lock);
736 738
737 if (!iter->walker.tbl && !iter->end_of_table) { 739 if (iter->end_of_table)
740 return 0;
741 if (!iter->walker.tbl) {
738 iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht); 742 iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht);
743 iter->slot = 0;
744 iter->skip = 0;
739 return -EAGAIN; 745 return -EAGAIN;
740 } 746 }
741 747
748 if (iter->p && !rhlist) {
749 /*
750 * We need to validate that 'p' is still in the table, and
751 * if so, update 'skip'
752 */
753 struct rhash_head *p;
754 int skip = 0;
755 rht_for_each_rcu(p, iter->walker.tbl, iter->slot) {
756 skip++;
757 if (p == iter->p) {
758 iter->skip = skip;
759 goto found;
760 }
761 }
762 iter->p = NULL;
763 } else if (iter->p && rhlist) {
764 /* Need to validate that 'list' is still in the table, and
765 * if so, update 'skip' and 'p'.
766 */
767 struct rhash_head *p;
768 struct rhlist_head *list;
769 int skip = 0;
770 rht_for_each_rcu(p, iter->walker.tbl, iter->slot) {
771 for (list = container_of(p, struct rhlist_head, rhead);
772 list;
773 list = rcu_dereference(list->next)) {
774 skip++;
775 if (list == iter->list) {
776 iter->p = p;
777 skip = skip;
778 goto found;
779 }
780 }
781 }
782 iter->p = NULL;
783 }
784found:
742 return 0; 785 return 0;
743} 786}
744EXPORT_SYMBOL_GPL(rhashtable_walk_start_check); 787EXPORT_SYMBOL_GPL(rhashtable_walk_start_check);
@@ -914,8 +957,6 @@ void rhashtable_walk_stop(struct rhashtable_iter *iter)
914 iter->walker.tbl = NULL; 957 iter->walker.tbl = NULL;
915 spin_unlock(&ht->lock); 958 spin_unlock(&ht->lock);
916 959
917 iter->p = NULL;
918
919out: 960out:
920 rcu_read_unlock(); 961 rcu_read_unlock();
921} 962}