diff options
author | Weijie Yang <weijie.yang@samsung.com> | 2014-02-06 15:04:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-06 16:48:51 -0500 |
commit | f893ab41e4dae2fe8991faf5d86d029068d1ef3a (patch) | |
tree | 6cde60539b7c64f11381a58d8c07112f0e7d5d5f /mm | |
parent | 579f82901f6f41256642936d7e632f3979ad76d4 (diff) |
mm/swap: fix race on swap_info reuse between swapoff and swapon
swapoff clear swap_info's SWP_USED flag prematurely and free its
resources after that. A concurrent swapon will reuse this swap_info
while its previous resources are not cleared completely.
These late freed resources are:
- p->percpu_cluster
- swap_cgroup_ctrl[type]
- block_device setting
- inode->i_flags &= ~S_SWAPFILE
This patch clears the SWP_USED flag after all its resources are freed,
so that swapon can reuse this swap_info by alloc_swap_info() safely.
[akpm@linux-foundation.org: tidy up code comment]
Signed-off-by: Weijie Yang <weijie.yang@samsung.com>
Acked-by: Hugh Dickins <hughd@google.com>
Cc: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: <stable@vger.kernel.org>
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 | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index c6c13b050a58..4a7f7e6992b6 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -1923,7 +1923,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) | |||
1923 | p->swap_map = NULL; | 1923 | p->swap_map = NULL; |
1924 | cluster_info = p->cluster_info; | 1924 | cluster_info = p->cluster_info; |
1925 | p->cluster_info = NULL; | 1925 | p->cluster_info = NULL; |
1926 | p->flags = 0; | ||
1927 | frontswap_map = frontswap_map_get(p); | 1926 | frontswap_map = frontswap_map_get(p); |
1928 | spin_unlock(&p->lock); | 1927 | spin_unlock(&p->lock); |
1929 | spin_unlock(&swap_lock); | 1928 | spin_unlock(&swap_lock); |
@@ -1949,6 +1948,16 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) | |||
1949 | mutex_unlock(&inode->i_mutex); | 1948 | mutex_unlock(&inode->i_mutex); |
1950 | } | 1949 | } |
1951 | filp_close(swap_file, NULL); | 1950 | filp_close(swap_file, NULL); |
1951 | |||
1952 | /* | ||
1953 | * Clear the SWP_USED flag after all resources are freed so that swapon | ||
1954 | * can reuse this swap_info in alloc_swap_info() safely. It is ok to | ||
1955 | * not hold p->lock after we cleared its SWP_WRITEOK. | ||
1956 | */ | ||
1957 | spin_lock(&swap_lock); | ||
1958 | p->flags = 0; | ||
1959 | spin_unlock(&swap_lock); | ||
1960 | |||
1952 | err = 0; | 1961 | err = 0; |
1953 | atomic_inc(&proc_poll_event); | 1962 | atomic_inc(&proc_poll_event); |
1954 | wake_up_interruptible(&proc_poll_wait); | 1963 | wake_up_interruptible(&proc_poll_wait); |