diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-21 00:59:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-21 11:23:35 -0400 |
commit | cc216c5d429892872f70f76975e243aef7ad9db1 (patch) | |
tree | 6455048df83fb61c870367f7a88e701e44ebdd24 /include/linux/list.h | |
parent | 3925e6fc1f774048404fdd910b0345b06c699eb4 (diff) |
Fix RCU list iterator use of 'rcu_dereference()'
The RCU iterators used 'rcu_dereference()' on an already-fetched RCU
pointer value, which defeats the whole point of the exercise.
When we dereference a pointer protected by RCU, we need to make sure
that we only fetch the value _once_, because if the compiler ends up
re-loading it due to register pressure, the newly reloaded value could
be different from the previously fetched one, and you get inconsistent
results.
Cleaned-up, fixed, and the pointless list_for_each_safe_rcu #define
deleted by Paul Kenney.
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux/list.h')
-rw-r--r-- | include/linux/list.h | 48 |
1 files changed, 15 insertions, 33 deletions
diff --git a/include/linux/list.h b/include/linux/list.h index 75ce2cb4ff6e..dac16f99c701 100644 --- a/include/linux/list.h +++ b/include/linux/list.h | |||
@@ -631,31 +631,14 @@ static inline void list_splice_init_rcu(struct list_head *list, | |||
631 | * as long as the traversal is guarded by rcu_read_lock(). | 631 | * as long as the traversal is guarded by rcu_read_lock(). |
632 | */ | 632 | */ |
633 | #define list_for_each_rcu(pos, head) \ | 633 | #define list_for_each_rcu(pos, head) \ |
634 | for (pos = (head)->next; \ | 634 | for (pos = rcu_dereference((head)->next); \ |
635 | prefetch(rcu_dereference(pos)->next), pos != (head); \ | 635 | prefetch(pos->next), pos != (head); \ |
636 | pos = pos->next) | 636 | pos = rcu_dereference(pos->next)) |
637 | 637 | ||
638 | #define __list_for_each_rcu(pos, head) \ | 638 | #define __list_for_each_rcu(pos, head) \ |
639 | for (pos = (head)->next; \ | 639 | for (pos = rcu_dereference((head)->next); \ |
640 | rcu_dereference(pos) != (head); \ | 640 | pos != (head); \ |
641 | pos = pos->next) | 641 | pos = rcu_dereference(pos->next)) |
642 | |||
643 | /** | ||
644 | * list_for_each_safe_rcu | ||
645 | * @pos: the &struct list_head to use as a loop cursor. | ||
646 | * @n: another &struct list_head to use as temporary storage | ||
647 | * @head: the head for your list. | ||
648 | * | ||
649 | * Iterate over an rcu-protected list, safe against removal of list entry. | ||
650 | * | ||
651 | * This list-traversal primitive may safely run concurrently with | ||
652 | * the _rcu list-mutation primitives such as list_add_rcu() | ||
653 | * as long as the traversal is guarded by rcu_read_lock(). | ||
654 | */ | ||
655 | #define list_for_each_safe_rcu(pos, n, head) \ | ||
656 | for (pos = (head)->next; \ | ||
657 | n = rcu_dereference(pos)->next, pos != (head); \ | ||
658 | pos = n) | ||
659 | 642 | ||
660 | /** | 643 | /** |
661 | * list_for_each_entry_rcu - iterate over rcu list of given type | 644 | * list_for_each_entry_rcu - iterate over rcu list of given type |
@@ -668,10 +651,9 @@ static inline void list_splice_init_rcu(struct list_head *list, | |||
668 | * as long as the traversal is guarded by rcu_read_lock(). | 651 | * as long as the traversal is guarded by rcu_read_lock(). |
669 | */ | 652 | */ |
670 | #define list_for_each_entry_rcu(pos, head, member) \ | 653 | #define list_for_each_entry_rcu(pos, head, member) \ |
671 | for (pos = list_entry((head)->next, typeof(*pos), member); \ | 654 | for (pos = list_entry(rcu_dereference((head)->next), typeof(*pos), member); \ |
672 | prefetch(rcu_dereference(pos)->member.next), \ | 655 | prefetch(pos->member.next), &pos->member != (head); \ |
673 | &pos->member != (head); \ | 656 | pos = list_entry(rcu_dereference(pos->member.next), typeof(*pos), member)) |
674 | pos = list_entry(pos->member.next, typeof(*pos), member)) | ||
675 | 657 | ||
676 | 658 | ||
677 | /** | 659 | /** |
@@ -686,9 +668,9 @@ static inline void list_splice_init_rcu(struct list_head *list, | |||
686 | * as long as the traversal is guarded by rcu_read_lock(). | 668 | * as long as the traversal is guarded by rcu_read_lock(). |
687 | */ | 669 | */ |
688 | #define list_for_each_continue_rcu(pos, head) \ | 670 | #define list_for_each_continue_rcu(pos, head) \ |
689 | for ((pos) = (pos)->next; \ | 671 | for ((pos) = rcu_dereference((pos)->next); \ |
690 | prefetch(rcu_dereference((pos))->next), (pos) != (head); \ | 672 | prefetch((pos)->next), (pos) != (head); \ |
691 | (pos) = (pos)->next) | 673 | (pos) = rcu_dereference((pos)->next)) |
692 | 674 | ||
693 | /* | 675 | /* |
694 | * Double linked lists with a single pointer list head. | 676 | * Double linked lists with a single pointer list head. |
@@ -986,10 +968,10 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, | |||
986 | * as long as the traversal is guarded by rcu_read_lock(). | 968 | * as long as the traversal is guarded by rcu_read_lock(). |
987 | */ | 969 | */ |
988 | #define hlist_for_each_entry_rcu(tpos, pos, head, member) \ | 970 | #define hlist_for_each_entry_rcu(tpos, pos, head, member) \ |
989 | for (pos = (head)->first; \ | 971 | for (pos = rcu_dereference((head)->first); \ |
990 | rcu_dereference(pos) && ({ prefetch(pos->next); 1;}) && \ | 972 | pos && ({ prefetch(pos->next); 1;}) && \ |
991 | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ | 973 | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
992 | pos = pos->next) | 974 | pos = rcu_dereference(pos->next)) |
993 | 975 | ||
994 | #else | 976 | #else |
995 | #warning "don't include kernel headers in userspace" | 977 | #warning "don't include kernel headers in userspace" |