From 7eaceaccab5f40bbfda044629a6298616aeaed50 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 10 Mar 2011 08:52:07 +0100 Subject: block: remove per-queue plugging Code has been converted over to the new explicit on-stack plugging, and delay users have been converted to use the new API for that. So lets kill off the old plugging along with aops->sync_page(). Signed-off-by: Jens Axboe --- mm/swapfile.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 07a458d72fa..7ceea78ceb2 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -94,39 +94,6 @@ __try_to_reclaim_swap(struct swap_info_struct *si, unsigned long offset) return ret; } -/* - * We need this because the bdev->unplug_fn can sleep and we cannot - * hold swap_lock while calling the unplug_fn. And swap_lock - * cannot be turned into a mutex. - */ -static DECLARE_RWSEM(swap_unplug_sem); - -void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page) -{ - swp_entry_t entry; - - down_read(&swap_unplug_sem); - entry.val = page_private(page); - if (PageSwapCache(page)) { - struct block_device *bdev = swap_info[swp_type(entry)]->bdev; - struct backing_dev_info *bdi; - - /* - * If the page is removed from swapcache from under us (with a - * racy try_to_unuse/swapoff) we need an additional reference - * count to avoid reading garbage from page_private(page) above. - * If the WARN_ON triggers during a swapoff it maybe the race - * condition and it's harmless. However if it triggers without - * swapoff it signals a problem. - */ - WARN_ON(page_count(page) <= 1); - - bdi = bdev->bd_inode->i_mapping->backing_dev_info; - blk_run_backing_dev(bdi, page); - } - up_read(&swap_unplug_sem); -} - /* * swapon tell device that all the old swap contents can be discarded, * to allow the swap device to optimize its wear-levelling. @@ -1643,10 +1610,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) goto out_dput; } - /* wait for any unplug function to finish */ - down_write(&swap_unplug_sem); - up_write(&swap_unplug_sem); - destroy_swap_extents(p); if (p->flags & SWP_CONTINUED) free_swap_count_continuations(p); -- cgit v1.2.3-70-g09d2 From 52c50567d8ab0a0a87f12cceaa4194967854f0bd Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Tue, 22 Mar 2011 16:30:08 -0700 Subject: 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 Acked-by: Hugh Dickins Cc: [2.6.37+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 0341c5700e3..6d6d28c0a72 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2149,8 +2149,13 @@ bad_swap_2: p->flags = 0; spin_unlock(&swap_lock); vfree(swap_map); - if (swap_file) + if (swap_file) { + if (did_down) { + mutex_unlock(&inode->i_mutex); + did_down = 0; + } filp_close(swap_file, NULL); + } out: if (page && !IS_ERR(page)) { kunmap(page); -- cgit v1.2.3-70-g09d2 From 803d0c8351b47b72b8b018457a33b342557b90a2 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:14 -0700 Subject: sys_swapon: use vzalloc() instead of vmalloc/memset This patch series refactors the sys_swapon function. sys_swapon is currently a very large function, with 313 lines (more than 12 25-line screens), which can make it a bit hard to read. This patch series reduces this size by half, by extracting large chunks of related code to new helper functions. One of these chunks of code was nearly identical to the part of sys_swapoff which is used in case of a failure return from try_to_unuse(), so this patch series also makes both share the same code. As a side effect of all this refactoring, the compiled code gets a bit smaller (from v1 of this patch series): text data bss dec hex filename 14012 944 276 15232 3b80 mm/swapfile.o.before 13941 944 276 15161 3b39 mm/swapfile.o.after This patch: Use vzalloc() instead of vmalloc/memset. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: Jesper Juhl Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 6d6d28c0a72..99eb5048b7a 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2047,13 +2047,12 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) goto bad_swap; /* OK, set up the swap map and apply the bad block list */ - swap_map = vmalloc(maxpages); + swap_map = vzalloc(maxpages); if (!swap_map) { error = -ENOMEM; goto bad_swap; } - memset(swap_map, 0, maxpages); nr_good_pages = maxpages - 1; /* omit header page */ for (i = 0; i < swap_header->info.nr_badpages; i++) { -- cgit v1.2.3-70-g09d2 From 80b0df12b808bf8e8391afae1b43f5e529f76d89 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:15 -0700 Subject: sys_swapon: remove changelog from function comment Changelogs belong in the git history instead of in the source code. Also, "The swapon system call" is redundant with "SYSCALL_DEFINE2(swapon, ...)". Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: Jesper Juhl Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton [ Gaah. That's a _historical_ comment. But the patch-series depends on removal ] Signed-off-by: Linus Torvalds --- mm/swapfile.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 99eb5048b7a..97146447093 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1844,11 +1844,6 @@ static int __init max_swapfiles_check(void) late_initcall(max_swapfiles_check); #endif -/* - * Written 01/25/92 by Simmule Turner, heavily changed by Linus. - * - * The swapon system call - */ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; -- cgit v1.2.3-70-g09d2 From e8e6c2ec403ecfaa226857d8204344c98fe12b7b Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:16 -0700 Subject: sys_swapon: do not depend on "type" after allocation Within sys_swapon, after the swap_info entry has been allocated, we always have type == p->type and swap_info[type] == p. Use this fact to reduce the dependency on the "type" local variable within the function, as a preparation to move the allocation of the swap_info entry to a separate function. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 97146447093..5238d8d15d7 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1927,7 +1927,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) for (i = 0; i < nr_swapfiles; i++) { struct swap_info_struct *q = swap_info[i]; - if (i == type || !q->swap_file) + if (q == p || !q->swap_file) continue; if (mapping == q->swap_file->f_mapping) goto bad_swap; @@ -2062,7 +2062,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } } - error = swap_cgroup_swapon(type, maxpages); + error = swap_cgroup_swapon(p->type, maxpages); if (error) goto bad_swap; @@ -2120,9 +2120,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } p->next = i; if (prev < 0) - swap_list.head = swap_list.next = type; + swap_list.head = swap_list.next = p->type; else - swap_info[prev]->next = type; + swap_info[prev]->next = p->type; spin_unlock(&swap_lock); mutex_unlock(&swapon_mutex); atomic_inc(&proc_poll_event); @@ -2136,7 +2136,7 @@ bad_swap: blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); } destroy_swap_extents(p); - swap_cgroup_swapoff(type); + swap_cgroup_swapoff(p->type); bad_swap_2: spin_lock(&swap_lock); p->swap_file = NULL; -- cgit v1.2.3-70-g09d2 From 53cbb2435f161f2a8b36af8f6d2c46dc59d0d757 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:17 -0700 Subject: sys_swapon: separate swap_info allocation Move the swap_info allocation to its own function. Only code movement, no functional changes. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 57 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 20 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 5238d8d15d7..6d1c3c67ae6 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1844,33 +1844,15 @@ static int __init max_swapfiles_check(void) late_initcall(max_swapfiles_check); #endif -SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) +static struct swap_info_struct *alloc_swap_info(void) { struct swap_info_struct *p; - char *name = NULL; - struct block_device *bdev = NULL; - struct file *swap_file = NULL; - struct address_space *mapping; unsigned int type; - int i, prev; int error; - union swap_header *swap_header; - unsigned int nr_good_pages; - int nr_extents = 0; - sector_t span; - unsigned long maxpages; - unsigned long swapfilepages; - unsigned char *swap_map = NULL; - struct page *page = NULL; - struct inode *inode = NULL; - int did_down = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) - return -ENOMEM; + return ERR_PTR(-ENOMEM); spin_lock(&swap_lock); for (type = 0; type < nr_swapfiles; type++) { @@ -1906,6 +1888,41 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) p->next = -1; spin_unlock(&swap_lock); + return p; + +out: + return ERR_PTR(error); +} + +SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) +{ + struct swap_info_struct *p; + char *name = NULL; + struct block_device *bdev = NULL; + struct file *swap_file = NULL; + struct address_space *mapping; + int i, prev; + int error; + union swap_header *swap_header; + unsigned int nr_good_pages; + int nr_extents = 0; + sector_t span; + unsigned long maxpages; + unsigned long swapfilepages; + unsigned char *swap_map = NULL; + struct page *page = NULL; + struct inode *inode = NULL; + int did_down = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + p = alloc_swap_info(); + if (IS_ERR(p)) { + error = PTR_ERR(p); + goto out; + } + name = getname(specialfile); error = PTR_ERR(name); if (IS_ERR(name)) { -- cgit v1.2.3-70-g09d2 From 2542e5134d2c19a9e6a4e641ef78cac6bccebd9b Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:18 -0700 Subject: sys_swapon: simplify error return from swap_info allocation At this point in sys_swapon, there is nothing to free. Return directly instead of jumping to the cleanup block at the end of the function. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 6d1c3c67ae6..4d457d699c1 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1918,10 +1918,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) return -EPERM; p = alloc_swap_info(); - if (IS_ERR(p)) { - error = PTR_ERR(p); - goto out; - } + if (IS_ERR(p)) + return PTR_ERR(p); name = getname(specialfile); error = PTR_ERR(name); -- cgit v1.2.3-70-g09d2 From 730c0581c82dbc5be2f41a2d85bde6bad11bc8a4 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:19 -0700 Subject: sys_swapon: simplify error flow in alloc_swap_info() Since there is no cleanup to do, there is no reason to jump to a label. Return directly instead. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 4d457d699c1..4d89c4c9336 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1848,7 +1848,6 @@ static struct swap_info_struct *alloc_swap_info(void) { struct swap_info_struct *p; unsigned int type; - int error; p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) @@ -1859,11 +1858,10 @@ static struct swap_info_struct *alloc_swap_info(void) if (!(swap_info[type]->flags & SWP_USED)) break; } - error = -EPERM; if (type >= MAX_SWAPFILES) { spin_unlock(&swap_lock); kfree(p); - goto out; + return ERR_PTR(-EPERM); } if (type >= nr_swapfiles) { p->type = type; @@ -1889,9 +1887,6 @@ static struct swap_info_struct *alloc_swap_info(void) spin_unlock(&swap_lock); return p; - -out: - return ERR_PTR(error); } SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) -- cgit v1.2.3-70-g09d2 From 28b36bd741bd44db30e12b1048a659aa346e9b76 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:20 -0700 Subject: sys_swapon: remove initial value of name variable Now there is nothing which jumps to the cleanup blocks before the name variable is set. There is no need to set it initially to NULL anymore. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 4d89c4c9336..6f25ece88c4 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1892,7 +1892,7 @@ static struct swap_info_struct *alloc_swap_info(void) SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; - char *name = NULL; + char *name; struct block_device *bdev = NULL; struct file *swap_file = NULL; struct address_space *mapping; -- cgit v1.2.3-70-g09d2 From 83ef99befc324803a54cf2a5fab5a322df3a99d6 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:21 -0700 Subject: sys_swapon: remove did_down variable Since mutex_lock(&inode->i_mutex) is called just after setting inode, did_down is always equivalent to (inode && S_ISREG(inode->i_mode)). Use this fact to remove the did_down variable. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 6f25ece88c4..b261e55e0b8 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1907,7 +1907,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) unsigned char *swap_map = NULL; struct page *page = NULL; struct inode *inode = NULL; - int did_down = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1962,7 +1961,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } else if (S_ISREG(inode->i_mode)) { p->bdev = inode->i_sb->s_bdev; mutex_lock(&inode->i_mutex); - did_down = 1; if (IS_SWAPFILE(inode)) { error = -EBUSY; goto bad_swap; @@ -2154,10 +2152,8 @@ bad_swap_2: spin_unlock(&swap_lock); vfree(swap_map); if (swap_file) { - if (did_down) { + if (inode && S_ISREG(inode->i_mode)) mutex_unlock(&inode->i_mutex); - did_down = 0; - } filp_close(swap_file, NULL); } out: @@ -2167,7 +2163,7 @@ out: } if (name) putname(name); - if (did_down) { + if (inode && S_ISREG(inode->i_mode)) { if (!error) inode->i_flags |= S_SWAPFILE; mutex_unlock(&inode->i_mutex); -- cgit v1.2.3-70-g09d2 From 7de7fb6b3422e6d1dac00666a992834085e745dc Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:22 -0700 Subject: sys_swapon: move setting of error nearer use Move the setting of the error variable nearer the goto in a few places. Avoids calling PTR_ERR() if not IS_ERR() in two places, and makes the error condition more explicit in two other places. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Jesper Juhl Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index b261e55e0b8..e4dc94996c5 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1916,14 +1916,14 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) return PTR_ERR(p); name = getname(specialfile); - error = PTR_ERR(name); if (IS_ERR(name)) { + error = PTR_ERR(name); name = NULL; goto bad_swap_2; } swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0); - error = PTR_ERR(swap_file); if (IS_ERR(swap_file)) { + error = PTR_ERR(swap_file); swap_file = NULL; goto bad_swap_2; } @@ -1932,17 +1932,17 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) mapping = swap_file->f_mapping; inode = mapping->host; - error = -EBUSY; for (i = 0; i < nr_swapfiles; i++) { struct swap_info_struct *q = swap_info[i]; if (q == p || !q->swap_file) continue; - if (mapping == q->swap_file->f_mapping) + if (mapping == q->swap_file->f_mapping) { + error = -EBUSY; goto bad_swap; + } } - error = -EINVAL; if (S_ISBLK(inode->i_mode)) { bdev = bdgrab(I_BDEV(inode)); error = blkdev_get(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL, @@ -1966,6 +1966,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) goto bad_swap; } } else { + error = -EINVAL; goto bad_swap; } -- cgit v1.2.3-70-g09d2 From f2090d2df51d7cdb2f952dcfdcd8baaac0aec444 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:23 -0700 Subject: sys_swapon: remove bdev variable The bdev variable is always equivalent to (S_ISBLK(inode->i_mode) ? p->bdev : NULL), as long as it being set is moved to a bit earlier. Use this fact to remove the bdev variable. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index e4dc94996c5..a314d42c0fa 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1893,7 +1893,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; char *name; - struct block_device *bdev = NULL; struct file *swap_file = NULL; struct address_space *mapping; int i, prev; @@ -1944,19 +1943,19 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } if (S_ISBLK(inode->i_mode)) { - bdev = bdgrab(I_BDEV(inode)); - error = blkdev_get(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL, + p->bdev = bdgrab(I_BDEV(inode)); + error = blkdev_get(p->bdev, + FMODE_READ | FMODE_WRITE | FMODE_EXCL, sys_swapon); if (error < 0) { - bdev = NULL; + p->bdev = NULL; error = -EINVAL; goto bad_swap; } - p->old_block_size = block_size(bdev); - error = set_blocksize(bdev, PAGE_SIZE); + p->old_block_size = block_size(p->bdev); + error = set_blocksize(p->bdev, PAGE_SIZE); if (error < 0) goto bad_swap; - p->bdev = bdev; p->flags |= SWP_BLKDEV; } else if (S_ISREG(inode->i_mode)) { p->bdev = inode->i_sb->s_bdev; @@ -2140,9 +2139,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = 0; goto out; bad_swap: - if (bdev) { - set_blocksize(bdev, p->old_block_size); - blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); + if (S_ISBLK(inode->i_mode) && p->bdev) { + set_blocksize(p->bdev, p->old_block_size); + blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); } destroy_swap_extents(p); swap_cgroup_swapoff(p->type); -- cgit v1.2.3-70-g09d2 From 9b01c350af4fb00fe2ab66ff9bf16058c50b69bd Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:24 -0700 Subject: sys_swapon: do only cleanup in the cleanup blocks The only way error is 0 in the cleanup blocks is when the function is returning successfully. In this case, the cleanup blocks were setting S_SWAPFILE in the S_ISREG case. But this is not a cleanup. Move the setting of S_SWAPFILE to just before the "goto out;" to make this more clear. At this point, we do not need to test for inode because it will never be NULL. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index a314d42c0fa..e356e5e7031 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2136,6 +2136,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) atomic_inc(&proc_poll_event); wake_up_interruptible(&proc_poll_wait); + if (S_ISREG(inode->i_mode)) + inode->i_flags |= S_SWAPFILE; error = 0; goto out; bad_swap: @@ -2163,11 +2165,8 @@ out: } if (name) putname(name); - if (inode && S_ISREG(inode->i_mode)) { - if (!error) - inode->i_flags |= S_SWAPFILE; + if (inode && S_ISREG(inode->i_mode)) mutex_unlock(&inode->i_mutex); - } return error; } -- cgit v1.2.3-70-g09d2 From bd69010b042a60ca41a890df1b10019e94746c2f Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:25 -0700 Subject: sys_swapon: use a single error label sys_swapon currently has two error labels, bad_swap and bad_swap_2. bad_swap does the same as bad_swap_2 plus destroy_swap_extents() and swap_cgroup_swapoff(); both are noops in the places where bad_swap_2 is jumped to. With a single extra test for inode (matching the one in the S_ISREG case below), all the error paths in the function can go to bad_swap. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index e356e5e7031..14590775212 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1918,13 +1918,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) if (IS_ERR(name)) { error = PTR_ERR(name); name = NULL; - goto bad_swap_2; + goto bad_swap; } swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0); if (IS_ERR(swap_file)) { error = PTR_ERR(swap_file); swap_file = NULL; - goto bad_swap_2; + goto bad_swap; } p->swap_file = swap_file; @@ -2141,13 +2141,12 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = 0; goto out; bad_swap: - if (S_ISBLK(inode->i_mode) && p->bdev) { + if (inode && S_ISBLK(inode->i_mode) && p->bdev) { set_blocksize(p->bdev, p->old_block_size); blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); } destroy_swap_extents(p); swap_cgroup_swapoff(p->type); -bad_swap_2: spin_lock(&swap_lock); p->swap_file = NULL; p->flags = 0; -- cgit v1.2.3-70-g09d2 From 4d0e1e10752ca487d83d1ab2a1d4ae6d664e1cc0 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:26 -0700 Subject: sys_swapon: separate bdev claim and inode lock Move the code which claims the bdev (S_ISBLK) or locks the inode (S_ISREG) to a separate function. Only code movement, no functional changes. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 64 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 25 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 14590775212..fc687b234eb 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1889,6 +1889,43 @@ static struct swap_info_struct *alloc_swap_info(void) return p; } +static int claim_swapfile(struct swap_info_struct *p, struct inode *inode) +{ + int error; + + if (S_ISBLK(inode->i_mode)) { + p->bdev = bdgrab(I_BDEV(inode)); + error = blkdev_get(p->bdev, + FMODE_READ | FMODE_WRITE | FMODE_EXCL, + sys_swapon); + if (error < 0) { + p->bdev = NULL; + error = -EINVAL; + goto bad_swap; + } + p->old_block_size = block_size(p->bdev); + error = set_blocksize(p->bdev, PAGE_SIZE); + if (error < 0) + goto bad_swap; + p->flags |= SWP_BLKDEV; + } else if (S_ISREG(inode->i_mode)) { + p->bdev = inode->i_sb->s_bdev; + mutex_lock(&inode->i_mutex); + if (IS_SWAPFILE(inode)) { + error = -EBUSY; + goto bad_swap; + } + } else { + error = -EINVAL; + goto bad_swap; + } + + return 0; + +bad_swap: + return error; +} + SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; @@ -1942,32 +1979,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } } - if (S_ISBLK(inode->i_mode)) { - p->bdev = bdgrab(I_BDEV(inode)); - error = blkdev_get(p->bdev, - FMODE_READ | FMODE_WRITE | FMODE_EXCL, - sys_swapon); - if (error < 0) { - p->bdev = NULL; - error = -EINVAL; - goto bad_swap; - } - p->old_block_size = block_size(p->bdev); - error = set_blocksize(p->bdev, PAGE_SIZE); - if (error < 0) - goto bad_swap; - p->flags |= SWP_BLKDEV; - } else if (S_ISREG(inode->i_mode)) { - p->bdev = inode->i_sb->s_bdev; - mutex_lock(&inode->i_mutex); - if (IS_SWAPFILE(inode)) { - error = -EBUSY; - goto bad_swap; - } - } else { - error = -EINVAL; + error = claim_swapfile(p, inode); + if (unlikely(error)) goto bad_swap; - } swapfilepages = i_size_read(inode) >> PAGE_SHIFT; -- cgit v1.2.3-70-g09d2 From 87ade72a799a9a895b4a60918c32b43d3dfc3324 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:27 -0700 Subject: sys_swapon: simplify error flow in claim_swapfile() Since there is no cleanup to do, there is no reason to jump to a label. Return directly instead. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index fc687b234eb..61a604c12a9 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1900,30 +1900,22 @@ static int claim_swapfile(struct swap_info_struct *p, struct inode *inode) sys_swapon); if (error < 0) { p->bdev = NULL; - error = -EINVAL; - goto bad_swap; + return -EINVAL; } p->old_block_size = block_size(p->bdev); error = set_blocksize(p->bdev, PAGE_SIZE); if (error < 0) - goto bad_swap; + return error; p->flags |= SWP_BLKDEV; } else if (S_ISREG(inode->i_mode)) { p->bdev = inode->i_sb->s_bdev; mutex_lock(&inode->i_mutex); - if (IS_SWAPFILE(inode)) { - error = -EBUSY; - goto bad_swap; - } - } else { - error = -EINVAL; - goto bad_swap; - } + if (IS_SWAPFILE(inode)) + return -EBUSY; + } else + return -EINVAL; return 0; - -bad_swap: - return error; } SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) -- cgit v1.2.3-70-g09d2 From 5de771e41f0fc2243c39585357b73f0ff757b280 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:28 -0700 Subject: sys_swapon: move setting of swapfilepages near use There is no reason I can see to read inode->i_size long before it is needed. Move its read to just before it is needed, to reduce the variable lifetime. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Jesper Juhl Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 61a604c12a9..4dade515b08 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1975,8 +1975,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) if (unlikely(error)) goto bad_swap; - swapfilepages = i_size_read(inode) >> PAGE_SHIFT; - /* * Read the swap header. */ @@ -2045,6 +2043,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = -EINVAL; if (!maxpages) goto bad_swap; + swapfilepages = i_size_read(inode) >> PAGE_SHIFT; if (swapfilepages && maxpages > swapfilepages) { printk(KERN_WARNING "Swap area shorter than signature indicates\n"); -- cgit v1.2.3-70-g09d2 From ca8bd38bf6f05481c4155fc444178151884f65d0 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:29 -0700 Subject: sys_swapon: separate parsing of swapfile header Move the code which parses and checks the swapfile header (except for the bad block list) to a separate function. Only code movement, no functional changes. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 140 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 62 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 4dade515b08..5e13bff1764 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1918,6 +1918,82 @@ static int claim_swapfile(struct swap_info_struct *p, struct inode *inode) return 0; } +static unsigned long read_swap_header(struct swap_info_struct *p, + union swap_header *swap_header, + struct inode *inode) +{ + int i; + unsigned long maxpages; + unsigned long swapfilepages; + + if (memcmp("SWAPSPACE2", swap_header->magic.magic, 10)) { + printk(KERN_ERR "Unable to find swap-space signature\n"); + goto bad_swap; + } + + /* swap partition endianess hack... */ + if (swab32(swap_header->info.version) == 1) { + swab32s(&swap_header->info.version); + swab32s(&swap_header->info.last_page); + swab32s(&swap_header->info.nr_badpages); + for (i = 0; i < swap_header->info.nr_badpages; i++) + swab32s(&swap_header->info.badpages[i]); + } + /* Check the swap header's sub-version */ + if (swap_header->info.version != 1) { + printk(KERN_WARNING + "Unable to handle swap header version %d\n", + swap_header->info.version); + goto bad_swap; + } + + p->lowest_bit = 1; + p->cluster_next = 1; + p->cluster_nr = 0; + + /* + * Find out how many pages are allowed for a single swap + * device. There are two limiting factors: 1) the number of + * bits for the swap offset in the swp_entry_t type and + * 2) the number of bits in the a swap pte as defined by + * the different architectures. In order to find the + * largest possible bit mask a swap entry with swap type 0 + * and swap offset ~0UL is created, encoded to a swap pte, + * decoded to a swp_entry_t again and finally the swap + * offset is extracted. This will mask all the bits from + * the initial ~0UL mask that can't be encoded in either + * the swp_entry_t or the architecture definition of a + * swap pte. + */ + maxpages = swp_offset(pte_to_swp_entry( + swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1; + if (maxpages > swap_header->info.last_page) { + maxpages = swap_header->info.last_page + 1; + /* p->max is an unsigned int: don't overflow it */ + if ((unsigned int)maxpages == 0) + maxpages = UINT_MAX; + } + p->highest_bit = maxpages - 1; + + if (!maxpages) + goto bad_swap; + swapfilepages = i_size_read(inode) >> PAGE_SHIFT; + if (swapfilepages && maxpages > swapfilepages) { + printk(KERN_WARNING + "Swap area shorter than signature indicates\n"); + goto bad_swap; + } + if (swap_header->info.nr_badpages && S_ISREG(inode->i_mode)) + goto bad_swap; + if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES) + goto bad_swap; + + return maxpages; + +bad_swap: + return 0; +} + SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; @@ -1931,7 +2007,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) int nr_extents = 0; sector_t span; unsigned long maxpages; - unsigned long swapfilepages; unsigned char *swap_map = NULL; struct page *page = NULL; struct inode *inode = NULL; @@ -1989,71 +2064,12 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } swap_header = kmap(page); - if (memcmp("SWAPSPACE2", swap_header->magic.magic, 10)) { - printk(KERN_ERR "Unable to find swap-space signature\n"); + maxpages = read_swap_header(p, swap_header, inode); + if (unlikely(!maxpages)) { error = -EINVAL; goto bad_swap; } - /* swap partition endianess hack... */ - if (swab32(swap_header->info.version) == 1) { - swab32s(&swap_header->info.version); - swab32s(&swap_header->info.last_page); - swab32s(&swap_header->info.nr_badpages); - for (i = 0; i < swap_header->info.nr_badpages; i++) - swab32s(&swap_header->info.badpages[i]); - } - /* Check the swap header's sub-version */ - if (swap_header->info.version != 1) { - printk(KERN_WARNING - "Unable to handle swap header version %d\n", - swap_header->info.version); - error = -EINVAL; - goto bad_swap; - } - - p->lowest_bit = 1; - p->cluster_next = 1; - p->cluster_nr = 0; - - /* - * Find out how many pages are allowed for a single swap - * device. There are two limiting factors: 1) the number of - * bits for the swap offset in the swp_entry_t type and - * 2) the number of bits in the a swap pte as defined by - * the different architectures. In order to find the - * largest possible bit mask a swap entry with swap type 0 - * and swap offset ~0UL is created, encoded to a swap pte, - * decoded to a swp_entry_t again and finally the swap - * offset is extracted. This will mask all the bits from - * the initial ~0UL mask that can't be encoded in either - * the swp_entry_t or the architecture definition of a - * swap pte. - */ - maxpages = swp_offset(pte_to_swp_entry( - swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1; - if (maxpages > swap_header->info.last_page) { - maxpages = swap_header->info.last_page + 1; - /* p->max is an unsigned int: don't overflow it */ - if ((unsigned int)maxpages == 0) - maxpages = UINT_MAX; - } - p->highest_bit = maxpages - 1; - - error = -EINVAL; - if (!maxpages) - goto bad_swap; - swapfilepages = i_size_read(inode) >> PAGE_SHIFT; - if (swapfilepages && maxpages > swapfilepages) { - printk(KERN_WARNING - "Swap area shorter than signature indicates\n"); - goto bad_swap; - } - if (swap_header->info.nr_badpages && S_ISREG(inode->i_mode)) - goto bad_swap; - if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES) - goto bad_swap; - /* OK, set up the swap map and apply the bad block list */ swap_map = vzalloc(maxpages); if (!swap_map) { -- cgit v1.2.3-70-g09d2 From 38719025384cf7121331bd6d41c062d3c5f7bb91 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:30 -0700 Subject: sys_swapon: simplify error flow in read_swap_header() Since there is no cleanup to do, there is no reason to jump to a label. Return directly instead. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 5e13bff1764..058a9dfefef 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1928,7 +1928,7 @@ static unsigned long read_swap_header(struct swap_info_struct *p, if (memcmp("SWAPSPACE2", swap_header->magic.magic, 10)) { printk(KERN_ERR "Unable to find swap-space signature\n"); - goto bad_swap; + return 0; } /* swap partition endianess hack... */ @@ -1944,7 +1944,7 @@ static unsigned long read_swap_header(struct swap_info_struct *p, printk(KERN_WARNING "Unable to handle swap header version %d\n", swap_header->info.version); - goto bad_swap; + return 0; } p->lowest_bit = 1; @@ -1976,22 +1976,19 @@ static unsigned long read_swap_header(struct swap_info_struct *p, p->highest_bit = maxpages - 1; if (!maxpages) - goto bad_swap; + return 0; swapfilepages = i_size_read(inode) >> PAGE_SHIFT; if (swapfilepages && maxpages > swapfilepages) { printk(KERN_WARNING "Swap area shorter than signature indicates\n"); - goto bad_swap; + return 0; } if (swap_header->info.nr_badpages && S_ISREG(inode->i_mode)) - goto bad_swap; + return 0; if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES) - goto bad_swap; + return 0; return maxpages; - -bad_swap: - return 0; } SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) -- cgit v1.2.3-70-g09d2 From 1421ef3cd15b87ef949e965efeb1e527479d3f75 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:31 -0700 Subject: sys_swapon: call swap_cgroup_swapon() earlier The call to swap_cgroup_swapon is in the middle of loading the swap map and extents. As it only does memory allocation and does not depend on the swapfile layout (map/extents), it can be called earlier (or later). Move it to just after the allocation of swap_map, since it is conceptually similar (allocates a map). Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 058a9dfefef..10f2b33805f 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2074,6 +2074,10 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) goto bad_swap; } + error = swap_cgroup_swapon(p->type, maxpages); + if (error) + goto bad_swap; + nr_good_pages = maxpages - 1; /* omit header page */ for (i = 0; i < swap_header->info.nr_badpages; i++) { @@ -2088,10 +2092,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } } - error = swap_cgroup_swapon(p->type, maxpages); - if (error) - goto bad_swap; - if (nr_good_pages) { swap_map[0] = SWAP_MAP_BAD; p->max = maxpages; -- cgit v1.2.3-70-g09d2 From 915d4d7bc0d719f2f0907273c01967d38751c625 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:32 -0700 Subject: sys_swapon: separate parsing of bad blocks and extents Move the code which parses the bad block list and the extents to a separate function. Only code movement, no functional changes. This change uses the fact that, after the success path, nr_good_pages == p->pages. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 83 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 29 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 10f2b33805f..a0f39f9dc5a 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1991,6 +1991,54 @@ static unsigned long read_swap_header(struct swap_info_struct *p, return maxpages; } +static int setup_swap_map_and_extents(struct swap_info_struct *p, + union swap_header *swap_header, + unsigned char *swap_map, + unsigned long maxpages, + sector_t *span) +{ + int i; + int error; + unsigned int nr_good_pages; + int nr_extents; + + nr_good_pages = maxpages - 1; /* omit header page */ + + for (i = 0; i < swap_header->info.nr_badpages; i++) { + unsigned int page_nr = swap_header->info.badpages[i]; + if (page_nr == 0 || page_nr > swap_header->info.last_page) { + error = -EINVAL; + goto bad_swap; + } + if (page_nr < maxpages) { + swap_map[page_nr] = SWAP_MAP_BAD; + nr_good_pages--; + } + } + + if (nr_good_pages) { + swap_map[0] = SWAP_MAP_BAD; + p->max = maxpages; + p->pages = nr_good_pages; + nr_extents = setup_swap_extents(p, span); + if (nr_extents < 0) { + error = nr_extents; + goto bad_swap; + } + nr_good_pages = p->pages; + } + if (!nr_good_pages) { + printk(KERN_WARNING "Empty swap-file\n"); + error = -EINVAL; + goto bad_swap; + } + + return nr_extents; + +bad_swap: + return error; +} + SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; @@ -2001,7 +2049,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) int error; union swap_header *swap_header; unsigned int nr_good_pages; - int nr_extents = 0; + int nr_extents; sector_t span; unsigned long maxpages; unsigned char *swap_map = NULL; @@ -2078,36 +2126,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) if (error) goto bad_swap; - nr_good_pages = maxpages - 1; /* omit header page */ - - for (i = 0; i < swap_header->info.nr_badpages; i++) { - unsigned int page_nr = swap_header->info.badpages[i]; - if (page_nr == 0 || page_nr > swap_header->info.last_page) { - error = -EINVAL; - goto bad_swap; - } - if (page_nr < maxpages) { - swap_map[page_nr] = SWAP_MAP_BAD; - nr_good_pages--; - } - } - - if (nr_good_pages) { - swap_map[0] = SWAP_MAP_BAD; - p->max = maxpages; - p->pages = nr_good_pages; - nr_extents = setup_swap_extents(p, &span); - if (nr_extents < 0) { - error = nr_extents; - goto bad_swap; - } - nr_good_pages = p->pages; - } - if (!nr_good_pages) { - printk(KERN_WARNING "Empty swap-file\n"); - error = -EINVAL; + nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map, + maxpages, &span); + if (unlikely(nr_extents < 0)) { + error = nr_extents; goto bad_swap; } + nr_good_pages = p->pages; if (p->bdev) { if (blk_queue_nonrot(bdev_get_queue(p->bdev))) { -- cgit v1.2.3-70-g09d2 From bdb8e3f68320f897de3f3a4c363fe2802037f21d Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:33 -0700 Subject: sys_swapon: simplify error flow in setup_swap_map_and_extents() Since there is no cleanup to do, there is no reason to jump to a label. Return directly instead. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index a0f39f9dc5a..be0d0a28690 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1998,7 +1998,6 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, sector_t *span) { int i; - int error; unsigned int nr_good_pages; int nr_extents; @@ -2006,10 +2005,8 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, for (i = 0; i < swap_header->info.nr_badpages; i++) { unsigned int page_nr = swap_header->info.badpages[i]; - if (page_nr == 0 || page_nr > swap_header->info.last_page) { - error = -EINVAL; - goto bad_swap; - } + if (page_nr == 0 || page_nr > swap_header->info.last_page) + return -EINVAL; if (page_nr < maxpages) { swap_map[page_nr] = SWAP_MAP_BAD; nr_good_pages--; @@ -2021,22 +2018,16 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, p->max = maxpages; p->pages = nr_good_pages; nr_extents = setup_swap_extents(p, span); - if (nr_extents < 0) { - error = nr_extents; - goto bad_swap; - } + if (nr_extents < 0) + return nr_extents; nr_good_pages = p->pages; } if (!nr_good_pages) { printk(KERN_WARNING "Empty swap-file\n"); - error = -EINVAL; - goto bad_swap; + return -EINVAL; } return nr_extents; - -bad_swap: - return error; } SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) -- cgit v1.2.3-70-g09d2 From 9c8100ef26ba9012b8677a383179a0cf169fc7f3 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:34 -0700 Subject: sys_swapon: remove nr_good_pages variable It still exists within setup_swap_map_and_extents(), but after it nr_good_pages == p->pages. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index be0d0a28690..9e3613b9161 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2039,7 +2039,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) int i, prev; int error; union swap_header *swap_header; - unsigned int nr_good_pages; int nr_extents; sector_t span; unsigned long maxpages; @@ -2123,7 +2122,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = nr_extents; goto bad_swap; } - nr_good_pages = p->pages; if (p->bdev) { if (blk_queue_nonrot(bdev_get_queue(p->bdev))) { @@ -2143,12 +2141,12 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) p->prio = --least_priority; p->swap_map = swap_map; p->flags |= SWP_WRITEOK; - nr_swap_pages += nr_good_pages; - total_swap_pages += nr_good_pages; + nr_swap_pages += p->pages; + total_swap_pages += p->pages; printk(KERN_INFO "Adding %uk swap on %s. " "Priority:%d extents:%d across:%lluk %s%s\n", - nr_good_pages<<(PAGE_SHIFT-10), name, p->prio, + p->pages<<(PAGE_SHIFT-10), name, p->prio, nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10), (p->flags & SWP_SOLIDSTATE) ? "SS" : "", (p->flags & SWP_DISCARDABLE) ? "D" : ""); -- cgit v1.2.3-70-g09d2 From c69dbfb84e88503468b6c481aecdb48d76ad5bc6 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:35 -0700 Subject: sys_swapon: move printk outside lock The block in sys_swapon which does the final adjustments to the swap_info_struct and to swap_list is the same as the block which re-inserts it again at sys_swapoff on failure of try_to_unuse(). To be able to make both share the same code, move the printk() call in the middle of it to just after it. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 9e3613b9161..df3dc7a3c2e 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2144,13 +2144,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) nr_swap_pages += p->pages; total_swap_pages += p->pages; - printk(KERN_INFO "Adding %uk swap on %s. " - "Priority:%d extents:%d across:%lluk %s%s\n", - p->pages<<(PAGE_SHIFT-10), name, p->prio, - nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10), - (p->flags & SWP_SOLIDSTATE) ? "SS" : "", - (p->flags & SWP_DISCARDABLE) ? "D" : ""); - /* insert swap space into swap_list: */ prev = -1; for (i = swap_list.head; i >= 0; i = swap_info[i]->next) { @@ -2164,6 +2157,14 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) else swap_info[prev]->next = p->type; spin_unlock(&swap_lock); + + printk(KERN_INFO "Adding %uk swap on %s. " + "Priority:%d extents:%d across:%lluk %s%s\n", + p->pages<<(PAGE_SHIFT-10), name, p->prio, + nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10), + (p->flags & SWP_SOLIDSTATE) ? "SS" : "", + (p->flags & SWP_DISCARDABLE) ? "D" : ""); + mutex_unlock(&swapon_mutex); atomic_inc(&proc_poll_event); wake_up_interruptible(&proc_poll_wait); -- cgit v1.2.3-70-g09d2 From c6a2b64ba5d09a1e281e85988ffd650655fa0f39 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:36 -0700 Subject: sys_swapoff: change order to match sys_swapon The block in sys_swapon which does the final adjustments to the swap_info_struct and to swap_list is the same as the block which re-inserts it again at sys_swapoff on failure of try_to_unuse(), except for the order of the operations within the lock. Since the order should not matter, arbitrarily change sys_swapoff to match sys_swapon, in preparation to making both share the same code. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index df3dc7a3c2e..465d972f4c7 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1625,6 +1625,10 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) spin_lock(&swap_lock); if (p->prio < 0) p->prio = --least_priority; + p->flags |= SWP_WRITEOK; + nr_swap_pages += p->pages; + total_swap_pages += p->pages; + prev = -1; for (i = swap_list.head; i >= 0; i = swap_info[i]->next) { if (p->prio >= swap_info[i]->prio) @@ -1636,9 +1640,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) swap_list.head = swap_list.next = type; else swap_info[prev]->next = type; - nr_swap_pages += p->pages; - total_swap_pages += p->pages; - p->flags |= SWP_WRITEOK; spin_unlock(&swap_lock); goto out_dput; } -- cgit v1.2.3-70-g09d2 From 40531542e2832419566c997af0808513f6f2815d Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:37 -0700 Subject: sys_swapon: separate final enabling of the swapfile The block in sys_swapon which does the final adjustments to the swap_info_struct and to swap_list is the same as the block which re-inserts it again at sys_swapoff on failure of try_to_unuse(). Move this code to a separate function, and use it both in sys_swapon and sys_swapoff. Signed-off-by: Cesar Eduardo Barros Tested-by: Eric B Munson Acked-by: Eric B Munson Reviewed-by: Pekka Enberg Reviewed-by: KAMEZAWA Hiroyuki Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 84 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 42 insertions(+), 42 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 465d972f4c7..7243044c413 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1550,6 +1550,36 @@ bad_bmap: goto out; } +static void enable_swap_info(struct swap_info_struct *p, int prio, + unsigned char *swap_map) +{ + int i, prev; + + spin_lock(&swap_lock); + if (prio >= 0) + p->prio = prio; + else + p->prio = --least_priority; + p->swap_map = swap_map; + p->flags |= SWP_WRITEOK; + nr_swap_pages += p->pages; + total_swap_pages += p->pages; + + /* insert swap space into swap_list: */ + prev = -1; + for (i = swap_list.head; i >= 0; i = swap_info[i]->next) { + if (p->prio >= swap_info[i]->prio) + break; + prev = i; + } + p->next = i; + if (prev < 0) + swap_list.head = swap_list.next = p->type; + else + swap_info[prev]->next = p->type; + spin_unlock(&swap_lock); +} + SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) { struct swap_info_struct *p = NULL; @@ -1621,26 +1651,14 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) current->flags &= ~PF_OOM_ORIGIN; if (err) { + /* + * reading p->prio and p->swap_map outside the lock is + * safe here because only sys_swapon and sys_swapoff + * change them, and there can be no other sys_swapon or + * sys_swapoff for this swap_info_struct at this point. + */ /* re-insert swap space back into swap_list */ - spin_lock(&swap_lock); - if (p->prio < 0) - p->prio = --least_priority; - p->flags |= SWP_WRITEOK; - nr_swap_pages += p->pages; - total_swap_pages += p->pages; - - prev = -1; - for (i = swap_list.head; i >= 0; i = swap_info[i]->next) { - if (p->prio >= swap_info[i]->prio) - break; - prev = i; - } - p->next = i; - if (prev < 0) - swap_list.head = swap_list.next = type; - else - swap_info[prev]->next = type; - spin_unlock(&swap_lock); + enable_swap_info(p, p->prio, p->swap_map); goto out_dput; } @@ -2037,7 +2055,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) char *name; struct file *swap_file = NULL; struct address_space *mapping; - int i, prev; + int i; + int prio; int error; union swap_header *swap_header; int nr_extents; @@ -2134,30 +2153,11 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } mutex_lock(&swapon_mutex); - spin_lock(&swap_lock); + prio = -1; if (swap_flags & SWAP_FLAG_PREFER) - p->prio = + prio = (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT; - else - p->prio = --least_priority; - p->swap_map = swap_map; - p->flags |= SWP_WRITEOK; - nr_swap_pages += p->pages; - total_swap_pages += p->pages; - - /* insert swap space into swap_list: */ - prev = -1; - for (i = swap_list.head; i >= 0; i = swap_info[i]->next) { - if (p->prio >= swap_info[i]->prio) - break; - prev = i; - } - p->next = i; - if (prev < 0) - swap_list.head = swap_list.next = p->type; - else - swap_info[prev]->next = p->type; - spin_unlock(&swap_lock); + enable_swap_info(p, prio, swap_map); printk(KERN_INFO "Adding %uk swap on %s. " "Priority:%d extents:%d across:%lluk %s%s\n", -- cgit v1.2.3-70-g09d2 From 24b8ff7c27d9e975540656e377de44a2a181a01f Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 16:33:38 -0700 Subject: mm: remove inline from scan_swap_map() scan_swap_map() is a large function (224 lines), with several loops and a complex control flow involving several gotos. Given all that, it is a bit silly that it is marked as inline. The compiler agrees with me: on a x86-64 compile, it did not inline the function. Remove the "inline" and let the compiler decide instead. Signed-off-by: Cesar Eduardo Barros Reviewed-by: Pekka Enberg Reviewed-by: KOSAKI Motohiro Reviewed-by: KAMEZAWA Hiroyuki Reviewed-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index 7243044c413..aafcf3611b3 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -212,8 +212,8 @@ static int wait_for_discard(void *word) #define SWAPFILE_CLUSTER 256 #define LATENCY_LIMIT 256 -static inline unsigned long scan_swap_map(struct swap_info_struct *si, - unsigned char usage) +static unsigned long scan_swap_map(struct swap_info_struct *si, + unsigned char usage) { unsigned long offset; unsigned long scan_base; -- cgit v1.2.3-70-g09d2 From 2130781e2aaab66e5a9f2fdc8af35da0153f405c Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 22 Mar 2011 23:03:13 -0300 Subject: sys_swapon: fix inode locking A conflict between 52c50567d8ab ("mm: swap: unlock swapfile inode mutex before closing file on bad swapfiles") and 83ef99befc32 ("sys_swapon: remove did_down variable") caused a double unlock of the inode mutex (once in bad_swap: before the filp_close, once at the end just before returning). The patch which added the extra unlock cleared did_down to avoid unlocking twice, but the other patch removed the did_down variable. To fix, set inode to NULL after the first unlock, since it will be used after that point only for the final unlock. While checking this patch, I found a path which could unlock without locking, in case the same inode was added as a swapfile twice. To fix, move the setting of the inode variable further down, to just before claim_swapfile, which will lock the inode before doing anything else. Cc: Mel Gorman Cc: Hugh Dickins Cc: Eric B Munson Cc: KAMEZAWA Hiroyuki Cc: Andrew Morton Signed-off-by: Cesar Eduardo Barros Signed-off-by: Linus Torvalds --- mm/swapfile.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/swapfile.c b/mm/swapfile.c index aafcf3611b3..71b42ec55b7 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2088,7 +2088,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) p->swap_file = swap_file; mapping = swap_file->f_mapping; - inode = mapping->host; for (i = 0; i < nr_swapfiles; i++) { struct swap_info_struct *q = swap_info[i]; @@ -2101,6 +2100,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } } + inode = mapping->host; + /* If S_ISREG(inode->i_mode) will do mutex_lock(&inode->i_mutex); */ error = claim_swapfile(p, inode); if (unlikely(error)) goto bad_swap; @@ -2187,8 +2188,10 @@ bad_swap: spin_unlock(&swap_lock); vfree(swap_map); if (swap_file) { - if (inode && S_ISREG(inode->i_mode)) + if (inode && S_ISREG(inode->i_mode)) { mutex_unlock(&inode->i_mutex); + inode = NULL; + } filp_close(swap_file, NULL); } out: -- cgit v1.2.3-70-g09d2 From 56039efa18f2530fc23e8ef19e716b65ee2a1d1e Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Wed, 23 Mar 2011 16:42:19 -0700 Subject: memcg: fix ugly initialization of return value is in caller Remove initialization of vaiable in caller of memory cgroup function. Actually, it's return value of memcg function but it's initialized in caller. Some memory cgroup uses following style to bring the result of start function to the end function for avoiding races. mem_cgroup_start_A(&(*ptr)) /* Something very complicated can happen here. */ mem_cgroup_end_A(*ptr) In some calls, *ptr should be initialized to NULL be caller. But it's ugly. This patch fixes that *ptr is initialized by _start function. Signed-off-by: KAMEZAWA Hiroyuki Acked-by: Johannes Weiner Acked-by: Daisuke Nishimura Cc: Balbir Singh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memcontrol.c | 8 ++++++-- mm/memory.c | 2 +- mm/migrate.c | 2 +- mm/swapfile.c | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'mm/swapfile.c') diff --git a/mm/memcontrol.c b/mm/memcontrol.c index e1ee6ad9c97..b56bd74b486 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2475,7 +2475,7 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm, /* shmem */ if (PageSwapCache(page)) { - struct mem_cgroup *mem = NULL; + struct mem_cgroup *mem; ret = mem_cgroup_try_charge_swapin(mm, page, gfp_mask, &mem); if (!ret) @@ -2501,6 +2501,8 @@ int mem_cgroup_try_charge_swapin(struct mm_struct *mm, struct mem_cgroup *mem; int ret; + *ptr = NULL; + if (mem_cgroup_disabled()) return 0; @@ -2916,6 +2918,8 @@ int mem_cgroup_prepare_migration(struct page *page, enum charge_type ctype; int ret = 0; + *ptr = NULL; + VM_BUG_ON(PageTransHuge(page)); if (mem_cgroup_disabled()) return 0; @@ -3058,7 +3062,7 @@ int mem_cgroup_shmem_charge_fallback(struct page *page, struct mm_struct *mm, gfp_t gfp_mask) { - struct mem_cgroup *mem = NULL; + struct mem_cgroup *mem; int ret; if (mem_cgroup_disabled()) diff --git a/mm/memory.c b/mm/memory.c index 615be5127ce..20d5f7499ce 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2767,7 +2767,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, swp_entry_t entry; pte_t pte; int locked; - struct mem_cgroup *ptr = NULL; + struct mem_cgroup *ptr; int exclusive = 0; int ret = 0; diff --git a/mm/migrate.c b/mm/migrate.c index 89e5c3fe8bb..b0406d739ea 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -633,7 +633,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, struct page *newpage = get_new_page(page, private, &result); int remap_swapcache = 1; int charge = 0; - struct mem_cgroup *mem = NULL; + struct mem_cgroup *mem; struct anon_vma *anon_vma = NULL; if (!newpage) diff --git a/mm/swapfile.c b/mm/swapfile.c index 71b42ec55b7..039e6167763 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -880,7 +880,7 @@ unsigned int count_swap_pages(int type, int free) static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr, swp_entry_t entry, struct page *page) { - struct mem_cgroup *ptr = NULL; + struct mem_cgroup *ptr; spinlock_t *ptl; pte_t *pte; int ret = 1; -- cgit v1.2.3-70-g09d2