af54aed94b
Revert commitbb01b64cfa
("mm/balloon_compaction.c: enqueue zero page to balloon device")' Zeroing ballon pages is rather time consuming, especially when a lot of pages are in flight. E.g. 7GB worth of ballooned memory takes 2.8s with __GFP_ZERO while it takes ~491ms without it. The original commit argued that zeroing will help ksmd to merge these pages on the host but this argument is assuming that the host actually marks balloon pages for ksm which is not universally true. So we pay performance penalty for something that even might not be used in the end which is wrong. The host can zero out pages on its own when there is a need. [mhocko@kernel.org: new changelog text] Link: http://lkml.kernel.org/r/1501761557-9758-1-git-send-email-wei.w.wang@intel.com Fixes:bb01b64cfa
("mm/balloon_compaction.c: enqueue zero page to balloon device") Signed-off-by: Wei Wang <wei.w.wang@intel.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Acked-by: Michal Hocko <mhocko@suse.com> Cc: zhenwei.pi <zhenwei.pi@youruncloud.com> Cc: David Hildenbrand <david@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
156 lines
4.7 KiB
C
156 lines
4.7 KiB
C
/*
|
|
* mm/balloon_compaction.c
|
|
*
|
|
* Common interface for making balloon pages movable by compaction.
|
|
*
|
|
* Copyright (C) 2012, Red Hat, Inc. Rafael Aquini <aquini@redhat.com>
|
|
*/
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/export.h>
|
|
#include <linux/balloon_compaction.h>
|
|
|
|
/*
|
|
* balloon_page_enqueue - allocates a new page and inserts it into the balloon
|
|
* page list.
|
|
* @b_dev_info: balloon device descriptor where we will insert a new page to
|
|
*
|
|
* Driver must call it to properly allocate a new enlisted balloon page
|
|
* before definitively removing it from the guest system.
|
|
* This function returns the page address for the recently enqueued page or
|
|
* NULL in the case we fail to allocate a new page this turn.
|
|
*/
|
|
struct page *balloon_page_enqueue(struct balloon_dev_info *b_dev_info)
|
|
{
|
|
unsigned long flags;
|
|
struct page *page = alloc_page(balloon_mapping_gfp_mask() |
|
|
__GFP_NOMEMALLOC | __GFP_NORETRY);
|
|
if (!page)
|
|
return NULL;
|
|
|
|
/*
|
|
* Block others from accessing the 'page' when we get around to
|
|
* establishing additional references. We should be the only one
|
|
* holding a reference to the 'page' at this point.
|
|
*/
|
|
BUG_ON(!trylock_page(page));
|
|
spin_lock_irqsave(&b_dev_info->pages_lock, flags);
|
|
balloon_page_insert(b_dev_info, page);
|
|
__count_vm_event(BALLOON_INFLATE);
|
|
spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
|
|
unlock_page(page);
|
|
return page;
|
|
}
|
|
EXPORT_SYMBOL_GPL(balloon_page_enqueue);
|
|
|
|
/*
|
|
* balloon_page_dequeue - removes a page from balloon's page list and returns
|
|
* the its address to allow the driver release the page.
|
|
* @b_dev_info: balloon device decriptor where we will grab a page from.
|
|
*
|
|
* Driver must call it to properly de-allocate a previous enlisted balloon page
|
|
* before definetively releasing it back to the guest system.
|
|
* This function returns the page address for the recently dequeued page or
|
|
* NULL in the case we find balloon's page list temporarily empty due to
|
|
* compaction isolated pages.
|
|
*/
|
|
struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info)
|
|
{
|
|
struct page *page, *tmp;
|
|
unsigned long flags;
|
|
bool dequeued_page;
|
|
|
|
dequeued_page = false;
|
|
spin_lock_irqsave(&b_dev_info->pages_lock, flags);
|
|
list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) {
|
|
/*
|
|
* Block others from accessing the 'page' while we get around
|
|
* establishing additional references and preparing the 'page'
|
|
* to be released by the balloon driver.
|
|
*/
|
|
if (trylock_page(page)) {
|
|
#ifdef CONFIG_BALLOON_COMPACTION
|
|
if (PageIsolated(page)) {
|
|
/* raced with isolation */
|
|
unlock_page(page);
|
|
continue;
|
|
}
|
|
#endif
|
|
balloon_page_delete(page);
|
|
__count_vm_event(BALLOON_DEFLATE);
|
|
unlock_page(page);
|
|
dequeued_page = true;
|
|
break;
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
|
|
|
|
if (!dequeued_page) {
|
|
/*
|
|
* If we are unable to dequeue a balloon page because the page
|
|
* list is empty and there is no isolated pages, then something
|
|
* went out of track and some balloon pages are lost.
|
|
* BUG() here, otherwise the balloon driver may get stuck into
|
|
* an infinite loop while attempting to release all its pages.
|
|
*/
|
|
spin_lock_irqsave(&b_dev_info->pages_lock, flags);
|
|
if (unlikely(list_empty(&b_dev_info->pages) &&
|
|
!b_dev_info->isolated_pages))
|
|
BUG();
|
|
spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
|
|
page = NULL;
|
|
}
|
|
return page;
|
|
}
|
|
EXPORT_SYMBOL_GPL(balloon_page_dequeue);
|
|
|
|
#ifdef CONFIG_BALLOON_COMPACTION
|
|
|
|
bool balloon_page_isolate(struct page *page, isolate_mode_t mode)
|
|
|
|
{
|
|
struct balloon_dev_info *b_dev_info = balloon_page_device(page);
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&b_dev_info->pages_lock, flags);
|
|
list_del(&page->lru);
|
|
b_dev_info->isolated_pages++;
|
|
spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
|
|
|
|
return true;
|
|
}
|
|
|
|
void balloon_page_putback(struct page *page)
|
|
{
|
|
struct balloon_dev_info *b_dev_info = balloon_page_device(page);
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&b_dev_info->pages_lock, flags);
|
|
list_add(&page->lru, &b_dev_info->pages);
|
|
b_dev_info->isolated_pages--;
|
|
spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
|
|
}
|
|
|
|
|
|
/* move_to_new_page() counterpart for a ballooned page */
|
|
int balloon_page_migrate(struct address_space *mapping,
|
|
struct page *newpage, struct page *page,
|
|
enum migrate_mode mode)
|
|
{
|
|
struct balloon_dev_info *balloon = balloon_page_device(page);
|
|
|
|
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
|
VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
|
|
|
|
return balloon->migratepage(balloon, newpage, page, mode);
|
|
}
|
|
|
|
const struct address_space_operations balloon_aops = {
|
|
.migratepage = balloon_page_migrate,
|
|
.isolate_page = balloon_page_isolate,
|
|
.putback_page = balloon_page_putback,
|
|
};
|
|
EXPORT_SYMBOL_GPL(balloon_aops);
|
|
|
|
#endif /* CONFIG_BALLOON_COMPACTION */
|