diff options
-rw-r--r-- | include/linux/radix-tree.h | 16 | ||||
-rw-r--r-- | mm/migrate.c | 4 |
2 files changed, 18 insertions, 2 deletions
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index ab2baa5c4884..23241c2fecce 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h | |||
@@ -146,6 +146,22 @@ static inline void *radix_tree_deref_slot(void **pslot) | |||
146 | } | 146 | } |
147 | 147 | ||
148 | /** | 148 | /** |
149 | * radix_tree_deref_slot_protected - dereference a slot without RCU lock but with tree lock held | ||
150 | * @pslot: pointer to slot, returned by radix_tree_lookup_slot | ||
151 | * Returns: item that was stored in that slot with any direct pointer flag | ||
152 | * removed. | ||
153 | * | ||
154 | * Similar to radix_tree_deref_slot but only used during migration when a pages | ||
155 | * mapping is being moved. The caller does not hold the RCU read lock but it | ||
156 | * must hold the tree lock to prevent parallel updates. | ||
157 | */ | ||
158 | static inline void *radix_tree_deref_slot_protected(void **pslot, | ||
159 | spinlock_t *treelock) | ||
160 | { | ||
161 | return rcu_dereference_protected(*pslot, lockdep_is_held(treelock)); | ||
162 | } | ||
163 | |||
164 | /** | ||
149 | * radix_tree_deref_retry - check radix_tree_deref_slot | 165 | * radix_tree_deref_retry - check radix_tree_deref_slot |
150 | * @arg: pointer returned by radix_tree_deref_slot | 166 | * @arg: pointer returned by radix_tree_deref_slot |
151 | * Returns: 0 if retry is not required, otherwise retry is required | 167 | * Returns: 0 if retry is not required, otherwise retry is required |
diff --git a/mm/migrate.c b/mm/migrate.c index 1a531b760b3b..89a6bc8cd307 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -248,7 +248,7 @@ static int migrate_page_move_mapping(struct address_space *mapping, | |||
248 | 248 | ||
249 | expected_count = 2 + page_has_private(page); | 249 | expected_count = 2 + page_has_private(page); |
250 | if (page_count(page) != expected_count || | 250 | if (page_count(page) != expected_count || |
251 | (struct page *)radix_tree_deref_slot(pslot) != page) { | 251 | radix_tree_deref_slot_protected(pslot, &mapping->tree_lock) != page) { |
252 | spin_unlock_irq(&mapping->tree_lock); | 252 | spin_unlock_irq(&mapping->tree_lock); |
253 | return -EAGAIN; | 253 | return -EAGAIN; |
254 | } | 254 | } |
@@ -320,7 +320,7 @@ int migrate_huge_page_move_mapping(struct address_space *mapping, | |||
320 | 320 | ||
321 | expected_count = 2 + page_has_private(page); | 321 | expected_count = 2 + page_has_private(page); |
322 | if (page_count(page) != expected_count || | 322 | if (page_count(page) != expected_count || |
323 | (struct page *)radix_tree_deref_slot(pslot) != page) { | 323 | radix_tree_deref_slot_protected(pslot, &mapping->tree_lock) != page) { |
324 | spin_unlock_irq(&mapping->tree_lock); | 324 | spin_unlock_irq(&mapping->tree_lock); |
325 | return -EAGAIN; | 325 | return -EAGAIN; |
326 | } | 326 | } |