Commit 49ac825587f33afec8841b7fab2eb4db775014e6

Authored by KAMEZAWA Hiroyuki
Committed by Linus Torvalds
1 parent 4b20477f58

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: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Reported-by: Michal 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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 72 additions and 36 deletions Side-by-side Diff

include/linux/memory_hotplug.h
... ... @@ -70,6 +70,10 @@
70 70 extern int online_pages(unsigned long, unsigned long);
71 71 extern void __offline_isolated_pages(unsigned long, unsigned long);
72 72  
  73 +#ifdef CONFIG_MEMORY_HOTREMOVE
  74 +extern bool is_pageblock_removable_nolock(struct page *page);
  75 +#endif /* CONFIG_MEMORY_HOTREMOVE */
  76 +
73 77 /* reasonably generic interface to expand the physical pages in a zone */
74 78 extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn,
75 79 unsigned long nr_pages);
... ... @@ -602,27 +602,14 @@
602 602 /* Checks if this range of memory is likely to be hot-removable. */
603 603 int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
604 604 {
605   - int type;
606 605 struct page *page = pfn_to_page(start_pfn);
607 606 struct page *end_page = page + nr_pages;
608 607  
609 608 /* Check the starting page of each pageblock within the range */
610 609 for (; page < end_page; page = next_active_pageblock(page)) {
611   - type = get_pageblock_migratetype(page);
612   -
613   - /*
614   - * A pageblock containing MOVABLE or free pages is considered
615   - * removable
616   - */
617   - if (type != MIGRATE_MOVABLE && !pageblock_free(page))
  610 + if (!is_pageblock_removable_nolock(page))
618 611 return 0;
619   -
620   - /*
621   - * A pageblock starting with a PageReserved page is not
622   - * considered removable.
623   - */
624   - if (PageReserved(page))
625   - return 0;
  612 + cond_resched();
626 613 }
627 614  
628 615 /* All pageblocks in the memory block are likely to be hot-removable */
... ... @@ -5297,12 +5297,65 @@
5297 5297 * page allocater never alloc memory from ISOLATE block.
5298 5298 */
5299 5299  
  5300 +static int
  5301 +__count_immobile_pages(struct zone *zone, struct page *page, int count)
  5302 +{
  5303 + unsigned long pfn, iter, found;
  5304 + /*
  5305 + * For avoiding noise data, lru_add_drain_all() should be called
  5306 + * If ZONE_MOVABLE, the zone never contains immobile pages
  5307 + */
  5308 + if (zone_idx(zone) == ZONE_MOVABLE)
  5309 + return true;
  5310 +
  5311 + if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE)
  5312 + return true;
  5313 +
  5314 + pfn = page_to_pfn(page);
  5315 + for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) {
  5316 + unsigned long check = pfn + iter;
  5317 +
  5318 + if (!pfn_valid_within(check)) {
  5319 + iter++;
  5320 + continue;
  5321 + }
  5322 + page = pfn_to_page(check);
  5323 + if (!page_count(page)) {
  5324 + if (PageBuddy(page))
  5325 + iter += (1 << page_order(page)) - 1;
  5326 + continue;
  5327 + }
  5328 + if (!PageLRU(page))
  5329 + found++;
  5330 + /*
  5331 + * If there are RECLAIMABLE pages, we need to check it.
  5332 + * But now, memory offline itself doesn't call shrink_slab()
  5333 + * and it still to be fixed.
  5334 + */
  5335 + /*
  5336 + * If the page is not RAM, page_count()should be 0.
  5337 + * we don't need more check. This is an _used_ not-movable page.
  5338 + *
  5339 + * The problematic thing here is PG_reserved pages. PG_reserved
  5340 + * is set to both of a memory hole page and a _used_ kernel
  5341 + * page at boot.
  5342 + */
  5343 + if (found > count)
  5344 + return false;
  5345 + }
  5346 + return true;
  5347 +}
  5348 +
  5349 +bool is_pageblock_removable_nolock(struct page *page)
  5350 +{
  5351 + struct zone *zone = page_zone(page);
  5352 + return __count_immobile_pages(zone, page, 0);
  5353 +}
  5354 +
5300 5355 int set_migratetype_isolate(struct page *page)
5301 5356 {
5302 5357 struct zone *zone;
5303   - struct page *curr_page;
5304   - unsigned long flags, pfn, iter;
5305   - unsigned long immobile = 0;
  5358 + unsigned long flags, pfn;
5306 5359 struct memory_isolate_notify arg;
5307 5360 int notifier_ret;
5308 5361 int ret = -EBUSY;
... ... @@ -5312,11 +5365,6 @@
5312 5365 zone_idx = zone_idx(zone);
5313 5366  
5314 5367 spin_lock_irqsave(&zone->lock, flags);
5315   - if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE ||
5316   - zone_idx == ZONE_MOVABLE) {
5317   - ret = 0;
5318   - goto out;
5319   - }
5320 5368  
5321 5369 pfn = page_to_pfn(page);
5322 5370 arg.start_pfn = pfn;
5323 5371  
... ... @@ -5338,20 +5386,17 @@
5338 5386 notifier_ret = notifier_to_errno(notifier_ret);
5339 5387 if (notifier_ret)
5340 5388 goto out;
5341   -
5342   - for (iter = pfn; iter < (pfn + pageblock_nr_pages); iter++) {
5343   - if (!pfn_valid_within(pfn))
5344   - continue;
5345   -
5346   - curr_page = pfn_to_page(iter);
5347   - if (!page_count(curr_page) || PageLRU(curr_page))
5348   - continue;
5349   -
5350   - immobile++;
5351   - }
5352   -
5353   - if (arg.pages_found == immobile)
  5389 + /*
  5390 + * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
  5391 + * We just check MOVABLE pages.
  5392 + */
  5393 + if (__count_immobile_pages(zone, page, arg.pages_found))
5354 5394 ret = 0;
  5395 +
  5396 + /*
  5397 + * immobile means "not-on-lru" paes. If immobile is larger than
  5398 + * removable-by-driver pages reported by notifier, we'll fail.
  5399 + */
5355 5400  
5356 5401 out:
5357 5402 if (!ret) {