path: root/ipc
diff options
authorHugh Dickins <>2012-01-20 22:34:21 (GMT)
committerLinus Torvalds <>2012-01-23 16:38:48 (GMT)
commit245132643e1cfcd145bbc86a716c1818371fcb93 (patch)
treee5bf3cb56efedb059b1a68fd8efd37482131783b /ipc
parent85046579bde15e532983438f86b36856e358f417 (diff)
SHM_UNLOCK: fix Unevictable pages stranded after swap
Commit cc39c6a9bbde ("mm: account skipped entries to avoid looping in find_get_pages") correctly fixed an infinite loop; but left a problem that find_get_pages() on shmem would return 0 (appearing to callers to mean end of tree) when it meets a run of nr_pages swap entries. The only uses of find_get_pages() on shmem are via pagevec_lookup(), called from invalidate_mapping_pages(), and from shmctl SHM_UNLOCK's scan_mapping_unevictable_pages(). The first is already commented, and not worth worrying about; but the second can leave pages on the Unevictable list after an unusual sequence of swapping and locking. Fix that by using shmem_find_get_pages_and_swap() (then ignoring the swap) instead of pagevec_lookup(). But I don't want to contaminate vmscan.c with shmem internals, nor shmem.c with LRU locking. So move scan_mapping_unevictable_pages() into shmem.c, renaming it shmem_unlock_mapping(); and rename check_move_unevictable_page() to check_move_unevictable_pages(), looping down an array of pages, oftentimes under the same lock. Leave out the "rotate unevictable list" block: that's a leftover from when this was used for /proc/sys/vm/scan_unevictable_pages, whose flawed handling involved looking at pages at tail of LRU. Was there significance to the sequence first ClearPageUnevictable, then test page_evictable, then SetPageUnevictable here? I think not, we're under LRU lock, and have no barriers between those. Signed-off-by: Hugh Dickins <> Reviewed-by: KOSAKI Motohiro <> Cc: Minchan Kim <> Cc: Rik van Riel <> Cc: Shaohua Li <> Cc: Eric Dumazet <> Cc: Johannes Weiner <> Cc: Michel Lespinasse <> Cc: <> [back to 3.1 but will need respins] Signed-off-by: Andrew Morton <> Signed-off-by: Linus Torvalds <>
Diffstat (limited to 'ipc')
1 files changed, 1 insertions, 1 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index 854ab58..b76be5b 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -916,7 +916,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
shp->mlock_user = NULL;
- scan_mapping_unevictable_pages(shm_file->f_mapping);
+ shmem_unlock_mapping(shm_file->f_mapping);
goto out;