Commit 49ac8255 authored by KAMEZAWA Hiroyuki's avatar KAMEZAWA Hiroyuki Committed by Linus Torvalds

memory hotplug: unify is_removable and offline detection code

Now, sysfs interface of memory hotplug shows whether the section is
removable or not.  But it checks only migrateype of pages and doesn't
check details of cluster of pages.

Next, memory hotplug's set_migratetype_isolate() has the same kind of
check, too.

This patch adds the function __count_unmovable_pages() and makes above 2
checks to use the same logic.  Then, is_removable and hotremove code uses
the same logic.  No changes in the hotremove logic itself.

TODO: need to find a way to check RECLAMABLE. But, considering bit,
      calling shrink_slab() against a range before starting memory hotremove
      sounds better. If so, this patch's logic doesn't need to be changed.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Reported-by: default avatarMichal Hocko <mhocko@suse.cz>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 4b20477f
......@@ -70,6 +70,10 @@ extern void online_page(struct page *page);
extern int online_pages(unsigned long, unsigned long);
extern void __offline_isolated_pages(unsigned long, unsigned long);
#ifdef CONFIG_MEMORY_HOTREMOVE
extern bool is_pageblock_removable_nolock(struct page *page);
#endif /* CONFIG_MEMORY_HOTREMOVE */
/* reasonably generic interface to expand the physical pages in a zone */
extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn,
unsigned long nr_pages);
......
......@@ -602,27 +602,14 @@ static struct page *next_active_pageblock(struct page *page)
/* Checks if this range of memory is likely to be hot-removable. */
int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
{
int type;
struct page *page = pfn_to_page(start_pfn);
struct page *end_page = page + nr_pages;
/* Check the starting page of each pageblock within the range */
for (; page < end_page; page = next_active_pageblock(page)) {
type = get_pageblock_migratetype(page);
/*
* A pageblock containing MOVABLE or free pages is considered
* removable
*/
if (type != MIGRATE_MOVABLE && !pageblock_free(page))
return 0;
/*
* A pageblock starting with a PageReserved page is not
* considered removable.
*/
if (PageReserved(page))
if (!is_pageblock_removable_nolock(page))
return 0;
cond_resched();
}
/* All pageblocks in the memory block are likely to be hot-removable */
......
......@@ -5297,12 +5297,65 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
* page allocater never alloc memory from ISOLATE block.
*/
static int
__count_immobile_pages(struct zone *zone, struct page *page, int count)
{
unsigned long pfn, iter, found;
/*
* For avoiding noise data, lru_add_drain_all() should be called
* If ZONE_MOVABLE, the zone never contains immobile pages
*/
if (zone_idx(zone) == ZONE_MOVABLE)
return true;
if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE)
return true;
pfn = page_to_pfn(page);
for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) {
unsigned long check = pfn + iter;
if (!pfn_valid_within(check)) {
iter++;
continue;
}
page = pfn_to_page(check);
if (!page_count(page)) {
if (PageBuddy(page))
iter += (1 << page_order(page)) - 1;
continue;
}
if (!PageLRU(page))
found++;
/*
* If there are RECLAIMABLE pages, we need to check it.
* But now, memory offline itself doesn't call shrink_slab()
* and it still to be fixed.
*/
/*
* If the page is not RAM, page_count()should be 0.
* we don't need more check. This is an _used_ not-movable page.
*
* The problematic thing here is PG_reserved pages. PG_reserved
* is set to both of a memory hole page and a _used_ kernel
* page at boot.
*/
if (found > count)
return false;
}
return true;
}
bool is_pageblock_removable_nolock(struct page *page)
{
struct zone *zone = page_zone(page);
return __count_immobile_pages(zone, page, 0);
}
int set_migratetype_isolate(struct page *page)
{
struct zone *zone;
struct page *curr_page;
unsigned long flags, pfn, iter;
unsigned long immobile = 0;
unsigned long flags, pfn;
struct memory_isolate_notify arg;
int notifier_ret;
int ret = -EBUSY;
......@@ -5312,11 +5365,6 @@ int set_migratetype_isolate(struct page *page)
zone_idx = zone_idx(zone);
spin_lock_irqsave(&zone->lock, flags);
if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE ||
zone_idx == ZONE_MOVABLE) {
ret = 0;
goto out;
}
pfn = page_to_pfn(page);
arg.start_pfn = pfn;
......@@ -5338,21 +5386,18 @@ int set_migratetype_isolate(struct page *page)
notifier_ret = notifier_to_errno(notifier_ret);
if (notifier_ret)
goto out;
for (iter = pfn; iter < (pfn + pageblock_nr_pages); iter++) {
if (!pfn_valid_within(pfn))
continue;
curr_page = pfn_to_page(iter);
if (!page_count(curr_page) || PageLRU(curr_page))
continue;
immobile++;
}
if (arg.pages_found == immobile)
/*
* FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
* We just check MOVABLE pages.
*/
if (__count_immobile_pages(zone, page, arg.pages_found))
ret = 0;
/*
* immobile means "not-on-lru" paes. If immobile is larger than
* removable-by-driver pages reported by notifier, we'll fail.
*/
out:
if (!ret) {
set_pageblock_migratetype(page, MIGRATE_ISOLATE);
......
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