diff options
author | Omar Sandoval <osandov@fb.com> | 2018-05-25 17:47:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-05-25 21:12:10 -0400 |
commit | 7cbf319234adaa4518a28c8c523d3330e06638f0 (patch) | |
tree | c25ce860d1ba8ac686456d181acca73048d3a1a5 /mm/swapfile.c | |
parent | 62d18ecfa64137349fac9c5817784fbd48b54f48 (diff) |
mm: fix nr_rotate_swap leak in swapon() error case
If swapon() fails after incrementing nr_rotate_swap, we don't decrement
it and thus effectively leak it. Make sure we decrement it if we
incremented it.
Link: http://lkml.kernel.org/r/b6fe6b879f17fa68eee6cbd876f459f6e5e33495.1526491581.git.osandov@fb.com
Fixes: 81a0298bdfab ("mm, swap: don't use VMA based swap readahead if HDD is used as swap")
Signed-off-by: Omar Sandoval <osandov@fb.com>
Reviewed-by: Rik van Riel <riel@surriel.com>
Reviewed-by: "Huang, Ying" <ying.huang@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/swapfile.c')
-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 cc2cf04d9018..78a015fcec3b 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -3112,6 +3112,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) | |||
3112 | unsigned long *frontswap_map = NULL; | 3112 | unsigned long *frontswap_map = NULL; |
3113 | struct page *page = NULL; | 3113 | struct page *page = NULL; |
3114 | struct inode *inode = NULL; | 3114 | struct inode *inode = NULL; |
3115 | bool inced_nr_rotate_swap = false; | ||
3115 | 3116 | ||
3116 | if (swap_flags & ~SWAP_FLAGS_VALID) | 3117 | if (swap_flags & ~SWAP_FLAGS_VALID) |
3117 | return -EINVAL; | 3118 | return -EINVAL; |
@@ -3215,8 +3216,10 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) | |||
3215 | cluster = per_cpu_ptr(p->percpu_cluster, cpu); | 3216 | cluster = per_cpu_ptr(p->percpu_cluster, cpu); |
3216 | cluster_set_null(&cluster->index); | 3217 | cluster_set_null(&cluster->index); |
3217 | } | 3218 | } |
3218 | } else | 3219 | } else { |
3219 | atomic_inc(&nr_rotate_swap); | 3220 | atomic_inc(&nr_rotate_swap); |
3221 | inced_nr_rotate_swap = true; | ||
3222 | } | ||
3220 | 3223 | ||
3221 | error = swap_cgroup_swapon(p->type, maxpages); | 3224 | error = swap_cgroup_swapon(p->type, maxpages); |
3222 | if (error) | 3225 | if (error) |
@@ -3307,6 +3310,8 @@ bad_swap: | |||
3307 | vfree(swap_map); | 3310 | vfree(swap_map); |
3308 | kvfree(cluster_info); | 3311 | kvfree(cluster_info); |
3309 | kvfree(frontswap_map); | 3312 | kvfree(frontswap_map); |
3313 | if (inced_nr_rotate_swap) | ||
3314 | atomic_dec(&nr_rotate_swap); | ||
3310 | if (swap_file) { | 3315 | if (swap_file) { |
3311 | if (inode && S_ISREG(inode->i_mode)) { | 3316 | if (inode && S_ISREG(inode->i_mode)) { |
3312 | inode_unlock(inode); | 3317 | inode_unlock(inode); |