diff options
author | Mel Gorman <mgorman@suse.de> | 2011-03-22 19:30:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-22 20:43:58 -0400 |
commit | 52c50567d8ab0a0a87f12cceaa4194967854f0bd (patch) | |
tree | 11644ba2fd533fdd39631254fc9cfc2699dfb8ae /mm | |
parent | c7a1fcd8e6e0c3c8f4f8f74fc926ff04da3bf7a7 (diff) |
mm: swap: unlock swapfile inode mutex before closing file on bad swapfiles
If an administrator tries to swapon a file backed by NFS, the inode mutex is
taken (as it is for any swapfile) but later identified to be a bad swapfile
due to the lack of bmap and tries to cleanup. During cleanup, an attempt is
made to close the file but with inode->i_mutex still held. Closing an NFS
file syncs it which tries to acquire the inode mutex leading to deadlock. If
lockdep is enabled the following appears on the console;
=============================================
[ INFO: possible recursive locking detected ]
2.6.38-rc8-autobuild #1
---------------------------------------------
swapon/2192 is trying to acquire lock:
(&sb->s_type->i_mutex_key#13){+.+.+.}, at: vfs_fsync_range+0x47/0x7c
but task is already holding lock:
(&sb->s_type->i_mutex_key#13){+.+.+.}, at: sys_swapon+0x28d/0xae7
other info that might help us debug this:
1 lock held by swapon/2192:
#0: (&sb->s_type->i_mutex_key#13){+.+.+.}, at: sys_swapon+0x28d/0xae7
stack backtrace:
Pid: 2192, comm: swapon Not tainted 2.6.38-rc8-autobuild #1
Call Trace:
__lock_acquire+0x2eb/0x1623
find_get_pages_tag+0x14a/0x174
pagevec_lookup_tag+0x25/0x2e
vfs_fsync_range+0x47/0x7c
lock_acquire+0xd3/0x100
vfs_fsync_range+0x47/0x7c
nfs_flush_one+0x0/0xdf [nfs]
mutex_lock_nested+0x40/0x2b1
vfs_fsync_range+0x47/0x7c
vfs_fsync_range+0x47/0x7c
vfs_fsync+0x1c/0x1e
nfs_file_flush+0x64/0x69 [nfs]
filp_close+0x43/0x72
sys_swapon+0xa39/0xae7
sysret_check+0x2e/0x69
system_call_fastpath+0x16/0x1b
This patch releases the mutex if its held before calling filep_close()
so swapon fails as expected without deadlock when the swapfile is backed
by NFS. If accepted for 2.6.39, it should also be considered a -stable
candidate for 2.6.38 and 2.6.37.
Signed-off-by: Mel Gorman <mgorman@suse.de>
Acked-by: Hugh Dickins <hughd@google.com>
Cc: <stable@kernel.org> [2.6.37+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/swapfile.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index 0341c5700e34..6d6d28c0a72f 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -2149,8 +2149,13 @@ bad_swap_2: | |||
2149 | p->flags = 0; | 2149 | p->flags = 0; |
2150 | spin_unlock(&swap_lock); | 2150 | spin_unlock(&swap_lock); |
2151 | vfree(swap_map); | 2151 | vfree(swap_map); |
2152 | if (swap_file) | 2152 | if (swap_file) { |
2153 | if (did_down) { | ||
2154 | mutex_unlock(&inode->i_mutex); | ||
2155 | did_down = 0; | ||
2156 | } | ||
2153 | filp_close(swap_file, NULL); | 2157 | filp_close(swap_file, NULL); |
2158 | } | ||
2154 | out: | 2159 | out: |
2155 | if (page && !IS_ERR(page)) { | 2160 | if (page && !IS_ERR(page)) { |
2156 | kunmap(page); | 2161 | kunmap(page); |