diff options
Diffstat (limited to 'mm/rmap.c')
| -rw-r--r-- | mm/rmap.c | 18 |
1 files changed, 13 insertions, 5 deletions
| @@ -212,25 +212,33 @@ out: | |||
| 212 | * through real pte's pointing to valid pages and then releasing | 212 | * through real pte's pointing to valid pages and then releasing |
| 213 | * the page from the swap cache. | 213 | * the page from the swap cache. |
| 214 | * | 214 | * |
| 215 | * Must hold page lock on page. | 215 | * Must hold page lock on page and mmap_sem of one vma that contains |
| 216 | * the page. | ||
| 216 | */ | 217 | */ |
| 217 | void remove_from_swap(struct page *page) | 218 | void remove_from_swap(struct page *page) |
| 218 | { | 219 | { |
| 219 | struct anon_vma *anon_vma; | 220 | struct anon_vma *anon_vma; |
| 220 | struct vm_area_struct *vma; | 221 | struct vm_area_struct *vma; |
| 222 | unsigned long mapping; | ||
| 221 | 223 | ||
| 222 | if (!PageAnon(page) || !PageSwapCache(page)) | 224 | if (!PageSwapCache(page)) |
| 223 | return; | 225 | return; |
| 224 | 226 | ||
| 225 | anon_vma = page_lock_anon_vma(page); | 227 | mapping = (unsigned long)page->mapping; |
| 226 | if (!anon_vma) | 228 | |
| 229 | if (!mapping || (mapping & PAGE_MAPPING_ANON) == 0) | ||
| 227 | return; | 230 | return; |
| 228 | 231 | ||
| 232 | /* | ||
| 233 | * We hold the mmap_sem lock. So no need to call page_lock_anon_vma. | ||
| 234 | */ | ||
| 235 | anon_vma = (struct anon_vma *) (mapping - PAGE_MAPPING_ANON); | ||
| 236 | spin_lock(&anon_vma->lock); | ||
| 237 | |||
| 229 | list_for_each_entry(vma, &anon_vma->head, anon_vma_node) | 238 | list_for_each_entry(vma, &anon_vma->head, anon_vma_node) |
| 230 | remove_vma_swap(vma, page); | 239 | remove_vma_swap(vma, page); |
| 231 | 240 | ||
| 232 | spin_unlock(&anon_vma->lock); | 241 | spin_unlock(&anon_vma->lock); |
| 233 | |||
| 234 | delete_from_swap_cache(page); | 242 | delete_from_swap_cache(page); |
| 235 | } | 243 | } |
| 236 | EXPORT_SYMBOL(remove_from_swap); | 244 | EXPORT_SYMBOL(remove_from_swap); |
