aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugh Dickins <hughd@google.com>2012-01-20 17:34:19 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-23 11:38:48 -0500
commit85046579bde15e532983438f86b36856e358f417 (patch)
tree9b80b31791e63520277617a5abe85692dc480cd0
parentcb78edfdcef5259ac9e9088bd63810d21299928d (diff)
SHM_UNLOCK: fix long unpreemptible section
scan_mapping_unevictable_pages() is used to make SysV SHM_LOCKed pages evictable again once the shared memory is unlocked. It does this with pagevec_lookup()s across the whole object (which might occupy most of memory), and takes 300ms to unlock 7GB here. A cond_resched() every PAGEVEC_SIZE pages would be good. However, KOSAKI-san points out that this is called under shmem.c's info->lock, and it's also under shm.c's shm_lock(), both spinlocks. There is no strong reason for that: we need to take these pages off the unevictable list soonish, but those locks are not required for it. So move the call to scan_mapping_unevictable_pages() from shmem.c's unlock handling up to shm.c's unlock handling. Remove the recently added barrier, not needed now we have spin_unlock() before the scan. Use get_file(), with subsequent fput(), to make sure we have a reference to mapping throughout scan_mapping_unevictable_pages(): that's something that was previously guaranteed by the shm_lock(). Remove shmctl's lru_add_drain_all(): we don't fault in pages at SHM_LOCK time, and we lazily discover them to be Unevictable later, so it serves no purpose for SHM_LOCK; and serves no purpose for SHM_UNLOCK, since pages still on pagevec are not marked Unevictable. The original code avoided redundant rescans by checking VM_LOCKED flag at its level: now avoid them by checking shp's SHM_LOCKED. The original code called scan_mapping_unevictable_pages() on a locked area at shm_destroy() time: perhaps we once had accounting cross-checks which required that, but not now, so skip the overhead and just let inode eviction deal with them. Put check_move_unevictable_page() and scan_mapping_unevictable_pages() under CONFIG_SHMEM (with stub for the TINY case when ramfs is used), more as comment than to save space; comment them used for SHM_UNLOCK. Signed-off-by: Hugh Dickins <hughd@google.com> Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Minchan Kim <minchan.kim@gmail.com> Cc: Rik van Riel <riel@redhat.com> Cc: Shaohua Li <shaohua.li@intel.com> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michel Lespinasse <walken@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--ipc/shm.c37
-rw-r--r--mm/shmem.c7
-rw-r--r--mm/vmscan.c12
3 files changed, 33 insertions, 23 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index 02ecf2c078fc..854ab58e5f6e 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -870,9 +870,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
870 case SHM_LOCK: 870 case SHM_LOCK:
871 case SHM_UNLOCK: 871 case SHM_UNLOCK:
872 { 872 {
873 struct file *uninitialized_var(shm_file); 873 struct file *shm_file;
874
875 lru_add_drain_all(); /* drain pagevecs to lru lists */
876 874
877 shp = shm_lock_check(ns, shmid); 875 shp = shm_lock_check(ns, shmid);
878 if (IS_ERR(shp)) { 876 if (IS_ERR(shp)) {
@@ -895,22 +893,31 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
895 err = security_shm_shmctl(shp, cmd); 893 err = security_shm_shmctl(shp, cmd);
896 if (err) 894 if (err)
897 goto out_unlock; 895 goto out_unlock;
898 896
899 if(cmd==SHM_LOCK) { 897 shm_file = shp->shm_file;
898 if (is_file_hugepages(shm_file))
899 goto out_unlock;
900
901 if (cmd == SHM_LOCK) {
900 struct user_struct *user = current_user(); 902 struct user_struct *user = current_user();
901 if (!is_file_hugepages(shp->shm_file)) { 903 err = shmem_lock(shm_file, 1, user);
902 err = shmem_lock(shp->shm_file, 1, user); 904 if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) {
903 if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){ 905 shp->shm_perm.mode |= SHM_LOCKED;
904 shp->shm_perm.mode |= SHM_LOCKED; 906 shp->mlock_user = user;
905 shp->mlock_user = user;
906 }
907 } 907 }
908 } else if (!is_file_hugepages(shp->shm_file)) { 908 goto out_unlock;
909 shmem_lock(shp->shm_file, 0, shp->mlock_user);
910 shp->shm_perm.mode &= ~SHM_LOCKED;
911 shp->mlock_user = NULL;
912 } 909 }
910
911 /* SHM_UNLOCK */
912 if (!(shp->shm_perm.mode & SHM_LOCKED))
913 goto out_unlock;
914 shmem_lock(shm_file, 0, shp->mlock_user);
915 shp->shm_perm.mode &= ~SHM_LOCKED;
916 shp->mlock_user = NULL;
917 get_file(shm_file);
913 shm_unlock(shp); 918 shm_unlock(shp);
919 scan_mapping_unevictable_pages(shm_file->f_mapping);
920 fput(shm_file);
914 goto out; 921 goto out;
915 } 922 }
916 case IPC_RMID: 923 case IPC_RMID:
diff --git a/mm/shmem.c b/mm/shmem.c
index feead1943d92..4aaa53abe302 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1068,13 +1068,6 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user)
1068 user_shm_unlock(inode->i_size, user); 1068 user_shm_unlock(inode->i_size, user);
1069 info->flags &= ~VM_LOCKED; 1069 info->flags &= ~VM_LOCKED;
1070 mapping_clear_unevictable(file->f_mapping); 1070 mapping_clear_unevictable(file->f_mapping);
1071 /*
1072 * Ensure that a racing putback_lru_page() can see
1073 * the pages of this mapping are evictable when we
1074 * skip them due to !PageLRU during the scan.
1075 */
1076 smp_mb__after_clear_bit();
1077 scan_mapping_unevictable_pages(file->f_mapping);
1078 } 1071 }
1079 retval = 0; 1072 retval = 0;
1080 1073
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 2880396f7953..e097c1026b58 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -3499,6 +3499,7 @@ int page_evictable(struct page *page, struct vm_area_struct *vma)
3499 return 1; 3499 return 1;
3500} 3500}
3501 3501
3502#ifdef CONFIG_SHMEM
3502/** 3503/**
3503 * check_move_unevictable_page - check page for evictability and move to appropriate zone lru list 3504 * check_move_unevictable_page - check page for evictability and move to appropriate zone lru list
3504 * @page: page to check evictability and move to appropriate lru list 3505 * @page: page to check evictability and move to appropriate lru list
@@ -3509,6 +3510,8 @@ int page_evictable(struct page *page, struct vm_area_struct *vma)
3509 * 3510 *
3510 * Restrictions: zone->lru_lock must be held, page must be on LRU and must 3511 * Restrictions: zone->lru_lock must be held, page must be on LRU and must
3511 * have PageUnevictable set. 3512 * have PageUnevictable set.
3513 *
3514 * This function is only used for SysV IPC SHM_UNLOCK.
3512 */ 3515 */
3513static void check_move_unevictable_page(struct page *page, struct zone *zone) 3516static void check_move_unevictable_page(struct page *page, struct zone *zone)
3514{ 3517{
@@ -3545,6 +3548,8 @@ retry:
3545 * 3548 *
3546 * Scan all pages in mapping. Check unevictable pages for 3549 * Scan all pages in mapping. Check unevictable pages for
3547 * evictability and move them to the appropriate zone lru list. 3550 * evictability and move them to the appropriate zone lru list.
3551 *
3552 * This function is only used for SysV IPC SHM_UNLOCK.
3548 */ 3553 */
3549void scan_mapping_unevictable_pages(struct address_space *mapping) 3554void scan_mapping_unevictable_pages(struct address_space *mapping)
3550{ 3555{
@@ -3590,9 +3595,14 @@ void scan_mapping_unevictable_pages(struct address_space *mapping)
3590 pagevec_release(&pvec); 3595 pagevec_release(&pvec);
3591 3596
3592 count_vm_events(UNEVICTABLE_PGSCANNED, pg_scanned); 3597 count_vm_events(UNEVICTABLE_PGSCANNED, pg_scanned);
3598 cond_resched();
3593 } 3599 }
3594
3595} 3600}
3601#else
3602void scan_mapping_unevictable_pages(struct address_space *mapping)
3603{
3604}
3605#endif /* CONFIG_SHMEM */
3596 3606
3597static void warn_scan_unevictable_pages(void) 3607static void warn_scan_unevictable_pages(void)
3598{ 3608{