diff options
author | Hugh Dickins <hughd@google.com> | 2014-03-21 00:52:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-21 01:09:09 -0400 |
commit | 7e09e738afd21ef99f047425fc0b0c9be8b03254 (patch) | |
tree | 423cb848a7d6875509b99720d4afcfa208bac078 /mm/rmap.c | |
parent | 3fb725c48b93c0a152174b6dbbc1029b5e734c7b (diff) |
mm: fix swapops.h:131 bug if remap_file_pages raced migration
Add remove_linear_migration_ptes_from_nonlinear(), to fix an interesting
little include/linux/swapops.h:131 BUG_ON(!PageLocked) found by trinity:
indicating that remove_migration_ptes() failed to find one of the
migration entries that was temporarily inserted.
The problem comes from remap_file_pages()'s switch from vma_interval_tree
(good for inserting the migration entry) to i_mmap_nonlinear list (no good
for locating it again); but can only be a problem if the remap_file_pages()
range does not cover the whole of the vma (zap_pte() clears the range).
remove_migration_ptes() needs a file_nonlinear method to go down the
i_mmap_nonlinear list, applying linear location to look for migration
entries in those vmas too, just in case there was this race.
The file_nonlinear method does need rmap_walk_control.arg to do this;
but it never needed vma passed in - vma comes from its own iteration.
Reported-and-tested-by: Dave Jones <davej@redhat.com>
Reported-and-tested-by: Sasha Levin <sasha.levin@oracle.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/rmap.c')
-rw-r--r-- | mm/rmap.c | 5 |
1 files changed, 3 insertions, 2 deletions
@@ -1360,8 +1360,9 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount, | |||
1360 | } | 1360 | } |
1361 | 1361 | ||
1362 | static int try_to_unmap_nonlinear(struct page *page, | 1362 | static int try_to_unmap_nonlinear(struct page *page, |
1363 | struct address_space *mapping, struct vm_area_struct *vma) | 1363 | struct address_space *mapping, void *arg) |
1364 | { | 1364 | { |
1365 | struct vm_area_struct *vma; | ||
1365 | int ret = SWAP_AGAIN; | 1366 | int ret = SWAP_AGAIN; |
1366 | unsigned long cursor; | 1367 | unsigned long cursor; |
1367 | unsigned long max_nl_cursor = 0; | 1368 | unsigned long max_nl_cursor = 0; |
@@ -1663,7 +1664,7 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc) | |||
1663 | if (list_empty(&mapping->i_mmap_nonlinear)) | 1664 | if (list_empty(&mapping->i_mmap_nonlinear)) |
1664 | goto done; | 1665 | goto done; |
1665 | 1666 | ||
1666 | ret = rwc->file_nonlinear(page, mapping, vma); | 1667 | ret = rwc->file_nonlinear(page, mapping, rwc->arg); |
1667 | 1668 | ||
1668 | done: | 1669 | done: |
1669 | mutex_unlock(&mapping->i_mmap_mutex); | 1670 | mutex_unlock(&mapping->i_mmap_mutex); |