Commit 2b849570 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'stable/for-linus-3.6-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/mm

Pull frontswap updates from Konrad Rzeszutek Wilk:
 "Cleanups in code and documentation.  Little bit of refactoring for
  cleaner look."

* tag 'stable/for-linus-3.6-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/mm:
  mm/frontswap: cleanup doc and comment error
  mm: frontswap: remove unneeded headers
  mm: frontswap: split out function to clear a page out
  mm: frontswap: remove unnecessary check during initialization
  mm: frontswap: make all branches of if statement in put page consistent
  mm: frontswap: split frontswap_shrink further to simplify locking
  mm: frontswap: split out __frontswap_unuse_pages
  mm: frontswap: split out __frontswap_curr_pages
  mm: frontswap: trivial coding convention issues
  mm: frontswap: remove casting from function calls through ops structure
parents 62c4d9af 1d00015e
...@@ -25,7 +25,7 @@ with the specified swap device number (aka "type"). A "store" will ...@@ -25,7 +25,7 @@ with the specified swap device number (aka "type"). A "store" will
copy the page to transcendent memory and associate it with the type and copy the page to transcendent memory and associate it with the type and
offset associated with the page. A "load" will copy the page, if found, offset associated with the page. A "load" will copy the page, if found,
from transcendent memory into kernel memory, but will NOT remove the page from transcendent memory into kernel memory, but will NOT remove the page
from from transcendent memory. An "invalidate_page" will remove the page from transcendent memory. An "invalidate_page" will remove the page
from transcendent memory and an "invalidate_area" will remove ALL pages from transcendent memory and an "invalidate_area" will remove ALL pages
associated with the swap type (e.g., like swapoff) and notify the "device" associated with the swap type (e.g., like swapoff) and notify the "device"
to refuse further stores with that swap type. to refuse further stores with that swap type.
...@@ -99,7 +99,7 @@ server configured with a large amount of RAM... without pre-configuring ...@@ -99,7 +99,7 @@ server configured with a large amount of RAM... without pre-configuring
how much of the RAM is available for each of the clients! how much of the RAM is available for each of the clients!
In the virtual case, the whole point of virtualization is to statistically In the virtual case, the whole point of virtualization is to statistically
multiplex physical resources acrosst the varying demands of multiple multiplex physical resources across the varying demands of multiple
virtual machines. This is really hard to do with RAM and efforts to do virtual machines. This is really hard to do with RAM and efforts to do
it well with no kernel changes have essentially failed (except in some it well with no kernel changes have essentially failed (except in some
well-publicized special-case workloads). well-publicized special-case workloads).
......
...@@ -11,15 +11,11 @@ ...@@ -11,15 +11,11 @@
* This work is licensed under the terms of the GNU GPL, version 2. * This work is licensed under the terms of the GNU GPL, version 2.
*/ */
#include <linux/mm.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/swapops.h> #include <linux/swapops.h>
#include <linux/proc_fs.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/capability.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/frontswap.h> #include <linux/frontswap.h>
#include <linux/swapfile.h> #include <linux/swapfile.h>
...@@ -110,16 +106,21 @@ void __frontswap_init(unsigned type) ...@@ -110,16 +106,21 @@ void __frontswap_init(unsigned type)
BUG_ON(sis == NULL); BUG_ON(sis == NULL);
if (sis->frontswap_map == NULL) if (sis->frontswap_map == NULL)
return; return;
if (frontswap_enabled) frontswap_ops.init(type);
(*frontswap_ops.init)(type);
} }
EXPORT_SYMBOL(__frontswap_init); EXPORT_SYMBOL(__frontswap_init);
static inline void __frontswap_clear(struct swap_info_struct *sis, pgoff_t offset)
{
frontswap_clear(sis, offset);
atomic_dec(&sis->frontswap_pages);
}
/* /*
* "Store" data from a page to frontswap and associate it with the page's * "Store" data from a page to frontswap and associate it with the page's
* swaptype and offset. Page must be locked and in the swap cache. * swaptype and offset. Page must be locked and in the swap cache.
* If frontswap already contains a page with matching swaptype and * If frontswap already contains a page with matching swaptype and
* offset, the frontswap implmentation may either overwrite the data and * offset, the frontswap implementation may either overwrite the data and
* return success or invalidate the page from frontswap and return failure. * return success or invalidate the page from frontswap and return failure.
*/ */
int __frontswap_store(struct page *page) int __frontswap_store(struct page *page)
...@@ -134,22 +135,21 @@ int __frontswap_store(struct page *page) ...@@ -134,22 +135,21 @@ int __frontswap_store(struct page *page)
BUG_ON(sis == NULL); BUG_ON(sis == NULL);
if (frontswap_test(sis, offset)) if (frontswap_test(sis, offset))
dup = 1; dup = 1;
ret = (*frontswap_ops.store)(type, offset, page); ret = frontswap_ops.store(type, offset, page);
if (ret == 0) { if (ret == 0) {
frontswap_set(sis, offset); frontswap_set(sis, offset);
inc_frontswap_succ_stores(); inc_frontswap_succ_stores();
if (!dup) if (!dup)
atomic_inc(&sis->frontswap_pages); atomic_inc(&sis->frontswap_pages);
} else if (dup) { } else {
/* /*
failed dup always results in automatic invalidate of failed dup always results in automatic invalidate of
the (older) page from frontswap the (older) page from frontswap
*/ */
frontswap_clear(sis, offset);
atomic_dec(&sis->frontswap_pages);
inc_frontswap_failed_stores();
} else
inc_frontswap_failed_stores(); inc_frontswap_failed_stores();
if (dup)
__frontswap_clear(sis, offset);
}
if (frontswap_writethrough_enabled) if (frontswap_writethrough_enabled)
/* report failure so swap also writes to swap device */ /* report failure so swap also writes to swap device */
ret = -1; ret = -1;
...@@ -173,7 +173,7 @@ int __frontswap_load(struct page *page) ...@@ -173,7 +173,7 @@ int __frontswap_load(struct page *page)
BUG_ON(!PageLocked(page)); BUG_ON(!PageLocked(page));
BUG_ON(sis == NULL); BUG_ON(sis == NULL);
if (frontswap_test(sis, offset)) if (frontswap_test(sis, offset))
ret = (*frontswap_ops.load)(type, offset, page); ret = frontswap_ops.load(type, offset, page);
if (ret == 0) if (ret == 0)
inc_frontswap_loads(); inc_frontswap_loads();
return ret; return ret;
...@@ -190,9 +190,8 @@ void __frontswap_invalidate_page(unsigned type, pgoff_t offset) ...@@ -190,9 +190,8 @@ void __frontswap_invalidate_page(unsigned type, pgoff_t offset)
BUG_ON(sis == NULL); BUG_ON(sis == NULL);
if (frontswap_test(sis, offset)) { if (frontswap_test(sis, offset)) {
(*frontswap_ops.invalidate_page)(type, offset); frontswap_ops.invalidate_page(type, offset);
atomic_dec(&sis->frontswap_pages); __frontswap_clear(sis, offset);
frontswap_clear(sis, offset);
inc_frontswap_invalidates(); inc_frontswap_invalidates();
} }
} }
...@@ -209,67 +208,102 @@ void __frontswap_invalidate_area(unsigned type) ...@@ -209,67 +208,102 @@ void __frontswap_invalidate_area(unsigned type)
BUG_ON(sis == NULL); BUG_ON(sis == NULL);
if (sis->frontswap_map == NULL) if (sis->frontswap_map == NULL)
return; return;
(*frontswap_ops.invalidate_area)(type); frontswap_ops.invalidate_area(type);
atomic_set(&sis->frontswap_pages, 0); atomic_set(&sis->frontswap_pages, 0);
memset(sis->frontswap_map, 0, sis->max / sizeof(long)); memset(sis->frontswap_map, 0, sis->max / sizeof(long));
} }
EXPORT_SYMBOL(__frontswap_invalidate_area); EXPORT_SYMBOL(__frontswap_invalidate_area);
/* static unsigned long __frontswap_curr_pages(void)
* Frontswap, like a true swap device, may unnecessarily retain pages
* under certain circumstances; "shrink" frontswap is essentially a
* "partial swapoff" and works by calling try_to_unuse to attempt to
* unuse enough frontswap pages to attempt to -- subject to memory
* constraints -- reduce the number of pages in frontswap to the
* number given in the parameter target_pages.
*/
void frontswap_shrink(unsigned long target_pages)
{ {
struct swap_info_struct *si = NULL;
int si_frontswap_pages;
unsigned long total_pages = 0, total_pages_to_unuse;
unsigned long pages = 0, pages_to_unuse = 0;
int type; int type;
bool locked = false; unsigned long totalpages = 0;
struct swap_info_struct *si = NULL;
/* assert_spin_locked(&swap_lock);
* we don't want to hold swap_lock while doing a very
* lengthy try_to_unuse, but swap_list may change
* so restart scan from swap_list.head each time
*/
spin_lock(&swap_lock);
locked = true;
total_pages = 0;
for (type = swap_list.head; type >= 0; type = si->next) { for (type = swap_list.head; type >= 0; type = si->next) {
si = swap_info[type]; si = swap_info[type];
total_pages += atomic_read(&si->frontswap_pages); totalpages += atomic_read(&si->frontswap_pages);
} }
if (total_pages <= target_pages) return totalpages;
goto out; }
total_pages_to_unuse = total_pages - target_pages;
static int __frontswap_unuse_pages(unsigned long total, unsigned long *unused,
int *swapid)
{
int ret = -EINVAL;
struct swap_info_struct *si = NULL;
int si_frontswap_pages;
unsigned long total_pages_to_unuse = total;
unsigned long pages = 0, pages_to_unuse = 0;
int type;
assert_spin_locked(&swap_lock);
for (type = swap_list.head; type >= 0; type = si->next) { for (type = swap_list.head; type >= 0; type = si->next) {
si = swap_info[type]; si = swap_info[type];
si_frontswap_pages = atomic_read(&si->frontswap_pages); si_frontswap_pages = atomic_read(&si->frontswap_pages);
if (total_pages_to_unuse < si_frontswap_pages) if (total_pages_to_unuse < si_frontswap_pages) {
pages = pages_to_unuse = total_pages_to_unuse; pages = pages_to_unuse = total_pages_to_unuse;
else { } else {
pages = si_frontswap_pages; pages = si_frontswap_pages;
pages_to_unuse = 0; /* unuse all */ pages_to_unuse = 0; /* unuse all */
} }
/* ensure there is enough RAM to fetch pages from frontswap */ /* ensure there is enough RAM to fetch pages from frontswap */
if (security_vm_enough_memory_mm(current->mm, pages)) if (security_vm_enough_memory_mm(current->mm, pages)) {
ret = -ENOMEM;
continue; continue;
}
vm_unacct_memory(pages); vm_unacct_memory(pages);
*unused = pages_to_unuse;
*swapid = type;
ret = 0;
break; break;
} }
if (type < 0)
goto out; return ret;
locked = false; }
static int __frontswap_shrink(unsigned long target_pages,
unsigned long *pages_to_unuse,
int *type)
{
unsigned long total_pages = 0, total_pages_to_unuse;
assert_spin_locked(&swap_lock);
total_pages = __frontswap_curr_pages();
if (total_pages <= target_pages) {
/* Nothing to do */
*pages_to_unuse = 0;
return 0;
}
total_pages_to_unuse = total_pages - target_pages;
return __frontswap_unuse_pages(total_pages_to_unuse, pages_to_unuse, type);
}
/*
* Frontswap, like a true swap device, may unnecessarily retain pages
* under certain circumstances; "shrink" frontswap is essentially a
* "partial swapoff" and works by calling try_to_unuse to attempt to
* unuse enough frontswap pages to attempt to -- subject to memory
* constraints -- reduce the number of pages in frontswap to the
* number given in the parameter target_pages.
*/
void frontswap_shrink(unsigned long target_pages)
{
unsigned long pages_to_unuse = 0;
int type, ret;
/*
* we don't want to hold swap_lock while doing a very
* lengthy try_to_unuse, but swap_list may change
* so restart scan from swap_list.head each time
*/
spin_lock(&swap_lock);
ret = __frontswap_shrink(target_pages, &pages_to_unuse, &type);
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
try_to_unuse(type, true, pages_to_unuse); if (ret == 0 && pages_to_unuse)
out: try_to_unuse(type, true, pages_to_unuse);
if (locked)
spin_unlock(&swap_lock);
return; return;
} }
EXPORT_SYMBOL(frontswap_shrink); EXPORT_SYMBOL(frontswap_shrink);
...@@ -281,16 +315,12 @@ EXPORT_SYMBOL(frontswap_shrink); ...@@ -281,16 +315,12 @@ EXPORT_SYMBOL(frontswap_shrink);
*/ */
unsigned long frontswap_curr_pages(void) unsigned long frontswap_curr_pages(void)
{ {
int type;
unsigned long totalpages = 0; unsigned long totalpages = 0;
struct swap_info_struct *si = NULL;
spin_lock(&swap_lock); spin_lock(&swap_lock);
for (type = swap_list.head; type >= 0; type = si->next) { totalpages = __frontswap_curr_pages();
si = swap_info[type];
totalpages += atomic_read(&si->frontswap_pages);
}
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
return totalpages; return totalpages;
} }
EXPORT_SYMBOL(frontswap_curr_pages); EXPORT_SYMBOL(frontswap_curr_pages);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment