diff options
Diffstat (limited to 'lib/rhashtable.c')
| -rw-r--r-- | lib/rhashtable.c | 51 | 
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 | } | ||
| 784 | found: | ||
| 742 | return 0; | 785 | return 0; | 
| 743 | } | 786 | } | 
| 744 | EXPORT_SYMBOL_GPL(rhashtable_walk_start_check); | 787 | EXPORT_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 | |||
| 919 | out: | 960 | out: | 
| 920 | rcu_read_unlock(); | 961 | rcu_read_unlock(); | 
| 921 | } | 962 | } | 
