diff options
| author | John W. Linville <linville@tuxdriver.com> | 2012-09-07 15:07:55 -0400 | 
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2012-09-07 15:07:55 -0400 | 
| commit | fac805f8c198092de9a2842efd7f5022e2937b18 (patch) | |
| tree | 7557809c373f97a343c427d8fded0696060394ce /mm/page_isolation.c | |
| parent | 2461c7d60f9f3821274e4acf9019cba8b82c94b5 (diff) | |
| parent | f10723841e624c0726c70356b31d91befed01dd6 (diff) | |
| download | olio-linux-3.10-fac805f8c198092de9a2842efd7f5022e2937b18.tar.xz olio-linux-3.10-fac805f8c198092de9a2842efd7f5022e2937b18.zip  | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
Diffstat (limited to 'mm/page_isolation.c')
| -rw-r--r-- | mm/page_isolation.c | 93 | 
1 files changed, 93 insertions, 0 deletions
diff --git a/mm/page_isolation.c b/mm/page_isolation.c index c9f04774f2b..247d1f17573 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -5,8 +5,101 @@  #include <linux/mm.h>  #include <linux/page-isolation.h>  #include <linux/pageblock-flags.h> +#include <linux/memory.h>  #include "internal.h" +/* called while holding zone->lock */ +static void set_pageblock_isolate(struct page *page) +{ +	if (get_pageblock_migratetype(page) == MIGRATE_ISOLATE) +		return; + +	set_pageblock_migratetype(page, MIGRATE_ISOLATE); +	page_zone(page)->nr_pageblock_isolate++; +} + +/* called while holding zone->lock */ +static void restore_pageblock_isolate(struct page *page, int migratetype) +{ +	struct zone *zone = page_zone(page); +	if (WARN_ON(get_pageblock_migratetype(page) != MIGRATE_ISOLATE)) +		return; + +	BUG_ON(zone->nr_pageblock_isolate <= 0); +	set_pageblock_migratetype(page, migratetype); +	zone->nr_pageblock_isolate--; +} + +int set_migratetype_isolate(struct page *page) +{ +	struct zone *zone; +	unsigned long flags, pfn; +	struct memory_isolate_notify arg; +	int notifier_ret; +	int ret = -EBUSY; + +	zone = page_zone(page); + +	spin_lock_irqsave(&zone->lock, flags); + +	pfn = page_to_pfn(page); +	arg.start_pfn = pfn; +	arg.nr_pages = pageblock_nr_pages; +	arg.pages_found = 0; + +	/* +	 * It may be possible to isolate a pageblock even if the +	 * migratetype is not MIGRATE_MOVABLE. The memory isolation +	 * notifier chain is used by balloon drivers to return the +	 * number of pages in a range that are held by the balloon +	 * driver to shrink memory. If all the pages are accounted for +	 * by balloons, are free, or on the LRU, isolation can continue. +	 * Later, for example, when memory hotplug notifier runs, these +	 * pages reported as "can be isolated" should be isolated(freed) +	 * by the balloon driver through the memory notifier chain. +	 */ +	notifier_ret = memory_isolate_notify(MEM_ISOLATE_COUNT, &arg); +	notifier_ret = notifier_to_errno(notifier_ret); +	if (notifier_ret) +		goto out; +	/* +	 * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself. +	 * We just check MOVABLE pages. +	 */ +	if (!has_unmovable_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_isolate(page); +		move_freepages_block(zone, page, MIGRATE_ISOLATE); +	} + +	spin_unlock_irqrestore(&zone->lock, flags); +	if (!ret) +		drain_all_pages(); +	return ret; +} + +void unset_migratetype_isolate(struct page *page, unsigned migratetype) +{ +	struct zone *zone; +	unsigned long flags; +	zone = page_zone(page); +	spin_lock_irqsave(&zone->lock, flags); +	if (get_pageblock_migratetype(page) != MIGRATE_ISOLATE) +		goto out; +	move_freepages_block(zone, page, migratetype); +	restore_pageblock_isolate(page, migratetype); +out: +	spin_unlock_irqrestore(&zone->lock, flags); +} +  static inline struct page *  __first_valid_page(unsigned long pfn, unsigned long nr_pages)  {  |