diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memory.c | 7 | ||||
-rw-r--r-- | mm/shmem.c | 8 | ||||
-rw-r--r-- | mm/swapfile.c | 7 |
3 files changed, 22 insertions, 0 deletions
diff --git a/mm/memory.c b/mm/memory.c index 7a11ddd5060..2bee1f21aa8 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1871,6 +1871,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, goto out; entry = pte_to_swp_entry(orig_pte); +again: page = lookup_swap_cache(entry); if (!page) { swapin_readahead(entry, address, vma); @@ -1894,6 +1895,12 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, mark_page_accessed(page); lock_page(page); + if (!PageSwapCache(page)) { + /* Page migration has occured */ + unlock_page(page); + page_cache_release(page); + goto again; + } /* * Back out if somebody else already faulted in this pte. diff --git a/mm/shmem.c b/mm/shmem.c index ce501bce1c2..f7ac7b812f9 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1028,6 +1028,14 @@ repeat: page_cache_release(swappage); goto repeat; } + if (!PageSwapCache(swappage)) { + /* Page migration has occured */ + shmem_swp_unmap(entry); + spin_unlock(&info->lock); + unlock_page(swappage); + page_cache_release(swappage); + goto repeat; + } if (PageWriteback(swappage)) { shmem_swp_unmap(entry); spin_unlock(&info->lock); diff --git a/mm/swapfile.c b/mm/swapfile.c index f1e69c30d20..9678182e0ee 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -646,6 +646,7 @@ static int try_to_unuse(unsigned int type) */ swap_map = &si->swap_map[i]; entry = swp_entry(type, i); +again: page = read_swap_cache_async(entry, NULL, 0); if (!page) { /* @@ -680,6 +681,12 @@ static int try_to_unuse(unsigned int type) wait_on_page_locked(page); wait_on_page_writeback(page); lock_page(page); + if (!PageSwapCache(page)) { + /* Page migration has occured */ + unlock_page(page); + page_cache_release(page); + goto again; + } wait_on_page_writeback(page); /* |