Cleanups in code and documentation. Little bit of refactoring for cleaner look.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQEcBAABAgAGBQJQDWs9AAoJEFjIrFwIi8fJ6WwH/jOuuHD4nYxLp8CdMz1N02F9 LjDXIVz8EQz68uV2Z2KTmJPObpzIrkL/01GpvGCFJ8J3LRHGQbf8q0PDfIOsrBUU A0lViBuhccoS7Bj9dF+65aoJhtmImad3cSzfEKnA9cQX/PGY/UXdmP6mw/wLmCwu mQeUKH8zBXSD2xRQt12twm47pnjUwhFSu0iN32wEL9BlPSbq1p+6vuM3NNhnLOi4 FPi8+VkO1V6HOoM5ta8/wO3FDQHEnbdVk0u49jNZdUI3qesNjt7VDyQpWBKXoAm/ 0u7SU4AMwbBG4p2tbKXdD4foHFjWdshOxQRchsvklf32M1UTv38KDlc9n2o5neE= =Lm/R -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
2b84957026
|
@ -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
|
||||||
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).
|
||||||
|
|
150
mm/frontswap.c
150
mm/frontswap.c
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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,12 +208,79 @@ 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)
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
unsigned long totalpages = 0;
|
||||||
|
struct swap_info_struct *si = NULL;
|
||||||
|
|
||||||
|
assert_spin_locked(&swap_lock);
|
||||||
|
for (type = swap_list.head; type >= 0; type = si->next) {
|
||||||
|
si = swap_info[type];
|
||||||
|
totalpages += atomic_read(&si->frontswap_pages);
|
||||||
|
}
|
||||||
|
return totalpages;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
si = swap_info[type];
|
||||||
|
si_frontswap_pages = atomic_read(&si->frontswap_pages);
|
||||||
|
if (total_pages_to_unuse < si_frontswap_pages) {
|
||||||
|
pages = pages_to_unuse = total_pages_to_unuse;
|
||||||
|
} else {
|
||||||
|
pages = si_frontswap_pages;
|
||||||
|
pages_to_unuse = 0; /* unuse all */
|
||||||
|
}
|
||||||
|
/* ensure there is enough RAM to fetch pages from frontswap */
|
||||||
|
if (security_vm_enough_memory_mm(current->mm, pages)) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vm_unacct_memory(pages);
|
||||||
|
*unused = pages_to_unuse;
|
||||||
|
*swapid = type;
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
* Frontswap, like a true swap device, may unnecessarily retain pages
|
||||||
* under certain circumstances; "shrink" frontswap is essentially a
|
* under certain circumstances; "shrink" frontswap is essentially a
|
||||||
|
@ -225,12 +291,8 @@ EXPORT_SYMBOL(__frontswap_invalidate_area);
|
||||||
*/
|
*/
|
||||||
void frontswap_shrink(unsigned long target_pages)
|
void frontswap_shrink(unsigned long target_pages)
|
||||||
{
|
{
|
||||||
struct swap_info_struct *si = NULL;
|
unsigned long pages_to_unuse = 0;
|
||||||
int si_frontswap_pages;
|
int type, ret;
|
||||||
unsigned long total_pages = 0, total_pages_to_unuse;
|
|
||||||
unsigned long pages = 0, pages_to_unuse = 0;
|
|
||||||
int type;
|
|
||||||
bool locked = false;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we don't want to hold swap_lock while doing a very
|
* we don't want to hold swap_lock while doing a very
|
||||||
|
@ -238,38 +300,10 @@ void frontswap_shrink(unsigned long target_pages)
|
||||||
* so restart scan from swap_list.head each time
|
* so restart scan from swap_list.head each time
|
||||||
*/
|
*/
|
||||||
spin_lock(&swap_lock);
|
spin_lock(&swap_lock);
|
||||||
locked = true;
|
ret = __frontswap_shrink(target_pages, &pages_to_unuse, &type);
|
||||||
total_pages = 0;
|
|
||||||
for (type = swap_list.head; type >= 0; type = si->next) {
|
|
||||||
si = swap_info[type];
|
|
||||||
total_pages += atomic_read(&si->frontswap_pages);
|
|
||||||
}
|
|
||||||
if (total_pages <= target_pages)
|
|
||||||
goto out;
|
|
||||||
total_pages_to_unuse = total_pages - target_pages;
|
|
||||||
for (type = swap_list.head; type >= 0; type = si->next) {
|
|
||||||
si = swap_info[type];
|
|
||||||
si_frontswap_pages = atomic_read(&si->frontswap_pages);
|
|
||||||
if (total_pages_to_unuse < si_frontswap_pages)
|
|
||||||
pages = pages_to_unuse = total_pages_to_unuse;
|
|
||||||
else {
|
|
||||||
pages = si_frontswap_pages;
|
|
||||||
pages_to_unuse = 0; /* unuse all */
|
|
||||||
}
|
|
||||||
/* ensure there is enough RAM to fetch pages from frontswap */
|
|
||||||
if (security_vm_enough_memory_mm(current->mm, pages))
|
|
||||||
continue;
|
|
||||||
vm_unacct_memory(pages);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (type < 0)
|
|
||||||
goto out;
|
|
||||||
locked = false;
|
|
||||||
spin_unlock(&swap_lock);
|
spin_unlock(&swap_lock);
|
||||||
|
if (ret == 0 && pages_to_unuse)
|
||||||
try_to_unuse(type, true, pages_to_unuse);
|
try_to_unuse(type, true, pages_to_unuse);
|
||||||
out:
|
|
||||||
if (locked)
|
|
||||||
spin_unlock(&swap_lock);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(frontswap_shrink);
|
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);
|
||||||
|
|
Reference in New Issue