diff options
author | Hugh Dickins <hughd@google.com> | 2012-01-20 17:34:19 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-23 11:38:48 -0500 |
commit | 85046579bde15e532983438f86b36856e358f417 (patch) | |
tree | 9b80b31791e63520277617a5abe85692dc480cd0 /ipc | |
parent | cb78edfdcef5259ac9e9088bd63810d21299928d (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>
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/shm.c | 37 |
1 files changed, 22 insertions, 15 deletions
@@ -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: |