tmpfs: fix race between umount and swapoff
authorHugh Dickins <hughd@google.com>
Wed, 11 May 2011 22:13:37 +0000 (15:13 -0700)
committerSteve Conklin <sconklin@canonical.com>
Thu, 2 Jun 2011 19:23:22 +0000 (14:23 -0500)
commit8b9bf6c112af397345bff61a54e04f18ae64086d
tree0d048c90567fdf357fd7a8d36433fff649f05c3c
parent650d5d06c51b137e6b1e5bb186eec5dbfa906057
tmpfs: fix race between umount and swapoff

BugLink: http://bugs.launchpad.net/bugs/788691

commit 778dd893ae785c5fd505dac30b5fc40aae188bf1 upstream.

The use of igrab() in swapoff's shmem_unuse_inode() is just as vulnerable
to umount as that in shmem_writepage().

Fix this instance by extending the protection of shmem_swaplist_mutex
right across shmem_unuse_inode(): while it's on the list, the inode cannot
be evicted (and the filesystem cannot be unmounted) without
shmem_evict_inode() taking that mutex to remove it from the list.

But since shmem_writepage() might take that mutex, we should avoid making
memory allocations or memcg charges while holding it: prepare them at the
outer level in shmem_unuse().  When mem_cgroup_cache_charge() was
originally placed, we didn't know until that point that the page from swap
was actually a shmem page; but nowadays it's noted in the swap_map, so
we're safe to charge upfront.  For the radix_tree, do as is done in
shmem_getpage(): preload upfront, but don't pin to the cpu; so we make a
habit of refreshing the node pool, but might dip into GFP_NOWAIT reserves
on occasion if subsequently preempted.

With the allocation and charge moved out from shmem_unuse_inode(),
we can also hold index map and info->lock over from finding the entry.

Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Konstantin Khlebnikov <khlebnikov@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Steve Conklin <sconklin@canonical.com>
mm/shmem.c