/* * linux/mm/compaction.c * * Memory compaction for the reduction of external fragmentation. Note that * this heavily depends upon page migration to do all the real heavy * lifting * * Copyright IBM Corp. 2007-2010 Mel Gorman <mel@csn.ul.ie> */#include <linux/swap.h>#include <linux/migrate.h>#include <linux/compaction.h>#include <linux/mm_inline.h>#include <linux/backing-dev.h>#include <linux/sysctl.h>#include <linux/sysfs.h>#include "internal.h" #if defined CONFIG_COMPACTION || defined CONFIG_CMA #define CREATE_TRACE_POINTS#include <trace/events/compaction.h> static unsigned long release_freepages(struct list_head *freelist){ struct page *page, *next; unsigned long count = 0; list_for_each_entry_safe(page, next, freelist, lru) { list_del(&page->lru); __free_page(page); count++; } return count;} static void map_pages(struct list_head *list){ struct page *page; list_for_each_entry(page, list, lru) { arch_alloc_page(page, 0); kernel_map_pages(page, 1, 1); }} static inline bool migrate_async_suitable(int migratetype){ return is_migrate_cma(migratetype) || migratetype == MIGRATE_MOVABLE;} /* * Isolate free pages onto a private freelist. Caller must hold zone->lock. * If @strict is true, will abort returning 0 on any invalid PFNs or non-free * pages inside of the pageblock (even though it may still end up isolating * some pages). */static unsigned long isolate_freepages_block(unsigned long blockpfn, unsigned long end_pfn, struct list_head *freelist, bool strict){ int nr_scanned = 0, total_isolated = 0; struct page *cursor; cursor = pfn_to_page(blockpfn); /* Isolate free pages. This assumes the block is valid */ for (; blockpfn < end_pfn; blockpfn++, cursor++) { int isolated, i; struct page *page = cursor; if (!pfn_valid_within(blockpfn)) { if (strict) return 0; continue; } nr_scanned++; if (!PageBuddy(page)) { if (strict) return 0; continue; } /* Found a free page, break it into order-0 pages */ isolated = split_free_page(page); if (!isolated && strict) return 0; total_isolated += isolated; for (i = 0; i < isolated; i++) { list_add(&page->lru, freelist); page++; } /* If a page was split, advance to the end of it */ if (isolated) { blockpfn += isolated - 1; cursor += isolated - 1; } } trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated); return total_isolated;} /** * isolate_freepages_range() - isolate free pages. * @start_pfn: The first PFN to start isolating. * @end_pfn: The one-past-last PFN. * * Non-free pages, invalid PFNs, or zone boundaries within the * [start_pfn, end_pfn) range are considered errors, cause function to * undo its actions and return zero. * * Otherwise, function returns one-past-the-last PFN of isolated page * (which may be greater then end_pfn if end fell in a middle of * a free page). */unsigned longisolate_freepages_range(unsigned long start_pfn, unsigned long end_pfn){ unsigned long isolated, pfn, block_end_pfn, flags; struct zone *zone = NULL; LIST_HEAD(freelist); if (pfn_valid(start_pfn)) zone = page_zone(pfn_to_page(start_pfn)); for (pfn = start_pfn; pfn < end_pfn; pfn += isolated) { if (!pfn_valid(pfn) || zone != page_zone(pfn_to_page(pfn))) break; /* * On subsequent iterations ALIGN() is actually not needed, * but we keep it that we not to complicate the code. */ block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages); block_end_pfn = min(block_end_pfn, end_pfn); spin_lock_irqsave(&zone->lock, flags); isolated = isolate_freepages_block(pfn, block_end_pfn, &freelist, true); spin_unlock_irqrestore(&zone->lock, flags); /* * In strict mode, isolate_freepages_block() returns 0 if * there are any holes in the block (ie. invalid PFNs or * non-free pages). */ if (!isolated) break; /* * If we managed to isolate pages, it is always (1 << n) * * pageblock_nr_pages for some non-negative n. (Max order * page may span two pageblocks). */ } /* split_free_page does not map the pages */ map_pages(&freelist); if (pfn < end_pfn) { /* Loop terminated early, cleanup. */ release_freepages(&freelist); return 0; } /* We don't use freelists for anything. */ return pfn;} /* Update the number of anon and file isolated pages in the zone */static void acct_isolated(struct zone *zone, struct compact_control *cc){ struct page *page; unsigned int count[2] = { 0, }; list_for_each_entry(page, &cc->migratepages, lru) count[!!page_is_file_cache(page)]++; __mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]); __mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);} /* Similar to reclaim, but different enough that they don't share logic */static bool too_many_isolated(struct zone *zone){ unsigned long active, inactive, isolated; inactive = zone_page_state(zone, NR_INACTIVE_FILE) + zone_page_state(zone, NR_INACTIVE_ANON); active = zone_page_state(zone, NR_ACTIVE_FILE) + zone_page_state(zone, NR_ACTIVE_ANON); isolated = zone_page_state(zone, NR_ISOLATED_FILE) + zone_page_state(zone, NR_ISOLATED_ANON); return isolated > (inactive + active) / 2;} /** * isolate_migratepages_range() - isolate all migrate-able pages in range. * @zone: Zone pages are in. * @cc: Compaction control structure. * @low_pfn: The first PFN of the range. * @end_pfn: The one-past-the-last PFN of the range. * * Isolate all pages that can be migrated from the range specified by * [low_pfn, end_pfn). Returns zero if there is a fatal signal * pending), otherwise PFN of the first page that was not scanned * (which may be both less, equal to or more then end_pfn). * * Assumes that cc->migratepages is empty and cc->nr_migratepages is * zero. * * Apart from cc->migratepages and cc->nr_migratetypes this function * does not modify any cc's fields, in particular it does not modify * (or read for that matter) cc->migrate_pfn. */unsigned longisolate_migratepages_range(struct zone *zone, struct compact_control *cc, unsigned long low_pfn, unsigned long end_pfn){ unsigned long last_pageblock_nr = 0, pageblock_nr; unsigned long nr_scanned = 0, nr_isolated = 0; struct list_head *migratelist = &cc->migratepages; isolate_mode_t mode = 0; struct lruvec *lruvec; /* * Ensure that there are not too many pages isolated from the LRU * list by either parallel reclaimers or compaction. If there are, * delay for some time until fewer pages are isolated */ while (unlikely(too_many_isolated(zone))) { /* async migration should just abort */ if (!cc->sync) return 0; congestion_wait(BLK_RW_ASYNC, HZ/10); if (fatal_signal_pending(current)) return 0; } /* Time to isolate some pages for migration */ cond_resched(); spin_lock_irq(&zone->lru_lock); for (; low_pfn < end_pfn; low_pfn++) { struct page *page; bool locked = true; /* give a chance to irqs before checking need_resched() */ if (!((low_pfn+1) % SWAP_CLUSTER_MAX)) { spin_unlock_irq(&zone->lru_lock); locked = false; } if (need_resched() || spin_is_contended(&zone->lru_lock)) { if (locked) spin_unlock_irq(&zone->lru_lock); cond_resched(); spin_lock_irq(&zone->lru_lock); if (fatal_signal_pending(current)) break; } else if (!locked) spin_lock_irq(&zone->lru_lock); /* * migrate_pfn does not necessarily start aligned to a * pageblock. Ensure that pfn_valid is called when moving * into a new MAX_ORDER_NR_PAGES range in case of large * memory holes within the zone */ if ((low_pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) { if (!pfn_valid(low_pfn)) { low_pfn += MAX_ORDER_NR_PAGES - 1; continue; } } if (!pfn_valid_within(low_pfn)) continue; nr_scanned++; /* * Get the page and ensure the page is within the same zone. * See the comment in isolate_freepages about overlapping * nodes. It is deliberate that the new zone lock is not taken * as memory compaction should not move pages between nodes. */ page = pfn_to_page(low_pfn); if (page_zone(page) != zone) continue; /* Skip if free */ if (PageBuddy(page)) continue; /* * For async migration, also only scan in MOVABLE blocks. Async * migration is optimistic to see if the minimum amount of work * satisfies the allocation */ pageblock_nr = low_pfn >> pageblock_order; if (!cc->sync && last_pageblock_nr != pageblock_nr && !migrate_async_suitable(get_pageblock_migratetype(page))) { low_pfn += pageblock_nr_pages; low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1; last_pageblock_nr = pageblock_nr; continue; } if (!PageLRU(page)) continue; /* * PageLRU is set, and lru_lock excludes isolation, * splitting and collapsing (collapsing has already * happened if PageLRU is set). */ if (PageTransHuge(page)) { low_pfn += (1 << compound_order(page)) - 1; continue; } if (!cc->sync) mode |= ISOLATE_ASYNC_MIGRATE; lruvec = mem_cgroup_page_lruvec(page, zone); /* Try isolate the page */ if (__isolate_lru_page(page, mode) != 0) continue; VM_BUG_ON(PageTransCompound(page)); /* Successfully isolated */ del_page_from_lru_list(page, lruvec, page_lru(page)); list_add(&page->lru, migratelist); cc->nr_migratepages++; nr_isolated++; /* Avoid isolating too much */ if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) { ++low_pfn; break; } } acct_isolated(zone, cc); spin_unlock_irq(&zone->lru_lock); trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated); return low_pfn;} #endif /* CONFIG_COMPACTION || CONFIG_CMA */#ifdef CONFIG_COMPACTION /* Returns true if the page is within a block suitable for migration to */static bool suitable_migration_target(struct page *page){ int migratetype = get_pageblock_migratetype(page); /* Don't interfere with memory hot-remove or the min_free_kbytes blocks */ if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE) return false; /* If the page is a large free page, then allow migration */ if (PageBuddy(page) && page_order(page) >= pageblock_order) return true; /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */ if (migrate_async_suitable(migratetype)) return true; /* Otherwise skip the block */ return false;} /* * Based on information in the current compact_control, find blocks * suitable for isolating free pages from and then isolate them. */static void isolate_freepages(struct zone *zone, struct compact_control *cc){ struct page *page; unsigned long high_pfn, low_pfn, pfn, zone_end_pfn, end_pfn; unsigned long flags; int nr_freepages = cc->nr_freepages; struct list_head *freelist = &cc->freepages; /* * Initialise the free scanner. The starting point is where we last * scanned from (or the end of the zone if starting). The low point * is the end of the pageblock the migration scanner is using. */ pfn = cc->free_pfn; low_pfn = cc->migrate_pfn + pageblock_nr_pages; /* * Take care that if the migration scanner is at the end of the zone * that the free scanner does not accidentally move to the next zone * in the next isolation cycle. */ high_pfn = min(low_pfn, pfn); zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; /* * Isolate free pages until enough are available to migrate the * pages on cc->migratepages. We stop searching if the migrate * and free page scanners meet or enough free pages are isolated. */ for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages; pfn -= pageblock_nr_pages) { unsigned long isolated; if (!pfn_valid(pfn)) continue; /* * Check for overlapping nodes/zones. It's possible on some * configurations to have a setup like * node0 node1 node0 * i.e. it's possible that all pages within a zones range of * pages do not belong to a single zone. */ page = pfn_to_page(pfn); if (page_zone(page) != zone) continue; /* Check the block is suitable for migration */ if (!suitable_migration_target(page)) continue; /* * Found a block suitable for isolating free pages from. Now * we disabled interrupts, double check things are ok and * isolate the pages. This is to minimise the time IRQs * are disabled */ isolated = 0; spin_lock_irqsave(&zone->lock, flags); if (suitable_migration_target(page)) { end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn); isolated = isolate_freepages_block(pfn, end_pfn, freelist, false); nr_freepages += isolated; } spin_unlock_irqrestore(&zone->lock, flags); /* * Record the highest PFN we isolated pages from. When next * looking for free pages, the search will restart here as * page migration may have returned some pages to the allocator */ if (isolated) high_pfn = max(high_pfn, pfn); } /* split_free_page does not map the pages */ map_pages(freelist); cc->free_pfn = high_pfn; cc->nr_freepages = nr_freepages;} /* * This is a migrate-callback that "allocates" freepages by taking pages * from the isolated freelists in the block we are migrating to. */static struct page *compaction_alloc(struct page *migratepage, unsigned long data, int **result){ struct compact_control *cc = (struct compact_control *)data; struct page *freepage; /* Isolate free pages if necessary */ if (list_empty(&cc->freepages)) { isolate_freepages(cc->zone, cc); if (list_empty(&cc->freepages)) return NULL; } freepage = list_entry(cc->freepages.next, struct page, lru); list_del(&freepage->lru); cc->nr_freepages--; return freepage;} Lines 1–500 of 906. Load more
/* * linux/mm/compaction.c * * Memory compaction for the reduction of external fragmentation. Note that * this heavily depends upon page migration to do all the real heavy * lifting * * Copyright IBM Corp. 2007-2010 Mel Gorman <mel@csn.ul.ie> */ #include <linux/swap.h> #include <linux/migrate.h> #include <linux/compaction.h> #include <linux/mm_inline.h> #include <linux/backing-dev.h> #include <linux/sysctl.h> #include <linux/sysfs.h> #include "internal.h" #if defined CONFIG_COMPACTION || defined CONFIG_CMA #define CREATE_TRACE_POINTS #include <trace/events/compaction.h> static unsigned long release_freepages(struct list_head *freelist) { struct page *page, *next; unsigned long count = 0; list_for_each_entry_safe(page, next, freelist, lru) { list_del(&page->lru); __free_page(page); count++; } return count; } static void map_pages(struct list_head *list) { struct page *page; list_for_each_entry(page, list, lru) { arch_alloc_page(page, 0); kernel_map_pages(page, 1, 1); } } static inline bool migrate_async_suitable(int migratetype) { return is_migrate_cma(migratetype) || migratetype == MIGRATE_MOVABLE; } /* * Isolate free pages onto a private freelist. Caller must hold zone->lock. * If @strict is true, will abort returning 0 on any invalid PFNs or non-free * pages inside of the pageblock (even though it may still end up isolating * some pages). */ static unsigned long isolate_freepages_block(unsigned long blockpfn, unsigned long end_pfn, struct list_head *freelist, bool strict) { int nr_scanned = 0, total_isolated = 0; struct page *cursor; cursor = pfn_to_page(blockpfn); /* Isolate free pages. This assumes the block is valid */ for (; blockpfn < end_pfn; blockpfn++, cursor++) { int isolated, i; struct page *page = cursor; if (!pfn_valid_within(blockpfn)) { if (strict) return 0; continue; } nr_scanned++; if (!PageBuddy(page)) { if (strict) return 0; continue; } /* Found a free page, break it into order-0 pages */ isolated = split_free_page(page); if (!isolated && strict) return 0; total_isolated += isolated; for (i = 0; i < isolated; i++) { list_add(&page->lru, freelist); page++; } /* If a page was split, advance to the end of it */ if (isolated) { blockpfn += isolated - 1; cursor += isolated - 1; } } trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated); return total_isolated; } /** * isolate_freepages_range() - isolate free pages. * @start_pfn: The first PFN to start isolating. * @end_pfn: The one-past-last PFN. * * Non-free pages, invalid PFNs, or zone boundaries within the * [start_pfn, end_pfn) range are considered errors, cause function to * undo its actions and return zero. * * Otherwise, function returns one-past-the-last PFN of isolated page * (which may be greater then end_pfn if end fell in a middle of * a free page). */ unsigned long isolate_freepages_range(unsigned long start_pfn, unsigned long end_pfn) { unsigned long isolated, pfn, block_end_pfn, flags; struct zone *zone = NULL; LIST_HEAD(freelist); if (pfn_valid(start_pfn)) zone = page_zone(pfn_to_page(start_pfn)); for (pfn = start_pfn; pfn < end_pfn; pfn += isolated) { if (!pfn_valid(pfn) || zone != page_zone(pfn_to_page(pfn))) break; /* * On subsequent iterations ALIGN() is actually not needed, * but we keep it that we not to complicate the code. */ block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages); block_end_pfn = min(block_end_pfn, end_pfn); spin_lock_irqsave(&zone->lock, flags); isolated = isolate_freepages_block(pfn, block_end_pfn, &freelist, true); spin_unlock_irqrestore(&zone->lock, flags); /* * In strict mode, isolate_freepages_block() returns 0 if * there are any holes in the block (ie. invalid PFNs or * non-free pages). */ if (!isolated) break; /* * If we managed to isolate pages, it is always (1 << n) * * pageblock_nr_pages for some non-negative n. (Max order * page may span two pageblocks). */ } /* split_free_page does not map the pages */ map_pages(&freelist); if (pfn < end_pfn) { /* Loop terminated early, cleanup. */ release_freepages(&freelist); return 0; } /* We don't use freelists for anything. */ return pfn; } /* Update the number of anon and file isolated pages in the zone */ static void acct_isolated(struct zone *zone, struct compact_control *cc) { struct page *page; unsigned int count[2] = { 0, }; list_for_each_entry(page, &cc->migratepages, lru) count[!!page_is_file_cache(page)]++; __mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]); __mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]); } /* Similar to reclaim, but different enough that they don't share logic */ static bool too_many_isolated(struct zone *zone) { unsigned long active, inactive, isolated; inactive = zone_page_state(zone, NR_INACTIVE_FILE) + zone_page_state(zone, NR_INACTIVE_ANON); active = zone_page_state(zone, NR_ACTIVE_FILE) + zone_page_state(zone, NR_ACTIVE_ANON); isolated = zone_page_state(zone, NR_ISOLATED_FILE) + zone_page_state(zone, NR_ISOLATED_ANON); return isolated > (inactive + active) / 2; } /** * isolate_migratepages_range() - isolate all migrate-able pages in range. * @zone: Zone pages are in. * @cc: Compaction control structure. * @low_pfn: The first PFN of the range. * @end_pfn: The one-past-the-last PFN of the range. * * Isolate all pages that can be migrated from the range specified by * [low_pfn, end_pfn). Returns zero if there is a fatal signal * pending), otherwise PFN of the first page that was not scanned * (which may be both less, equal to or more then end_pfn). * * Assumes that cc->migratepages is empty and cc->nr_migratepages is * zero. * * Apart from cc->migratepages and cc->nr_migratetypes this function * does not modify any cc's fields, in particular it does not modify * (or read for that matter) cc->migrate_pfn. */ unsigned long isolate_migratepages_range(struct zone *zone, struct compact_control *cc, unsigned long low_pfn, unsigned long end_pfn) { unsigned long last_pageblock_nr = 0, pageblock_nr; unsigned long nr_scanned = 0, nr_isolated = 0; struct list_head *migratelist = &cc->migratepages; isolate_mode_t mode = 0; struct lruvec *lruvec; /* * Ensure that there are not too many pages isolated from the LRU * list by either parallel reclaimers or compaction. If there are, * delay for some time until fewer pages are isolated */ while (unlikely(too_many_isolated(zone))) { /* async migration should just abort */ if (!cc->sync) return 0; congestion_wait(BLK_RW_ASYNC, HZ/10); if (fatal_signal_pending(current)) return 0; } /* Time to isolate some pages for migration */ cond_resched(); spin_lock_irq(&zone->lru_lock); for (; low_pfn < end_pfn; low_pfn++) { struct page *page; bool locked = true; /* give a chance to irqs before checking need_resched() */ if (!((low_pfn+1) % SWAP_CLUSTER_MAX)) { spin_unlock_irq(&zone->lru_lock); locked = false; } if (need_resched() || spin_is_contended(&zone->lru_lock)) { if (locked) spin_unlock_irq(&zone->lru_lock); cond_resched(); spin_lock_irq(&zone->lru_lock); if (fatal_signal_pending(current)) break; } else if (!locked) spin_lock_irq(&zone->lru_lock); /* * migrate_pfn does not necessarily start aligned to a * pageblock. Ensure that pfn_valid is called when moving * into a new MAX_ORDER_NR_PAGES range in case of large * memory holes within the zone */ if ((low_pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) { if (!pfn_valid(low_pfn)) { low_pfn += MAX_ORDER_NR_PAGES - 1; continue; } } if (!pfn_valid_within(low_pfn)) continue; nr_scanned++; /* * Get the page and ensure the page is within the same zone. * See the comment in isolate_freepages about overlapping * nodes. It is deliberate that the new zone lock is not taken * as memory compaction should not move pages between nodes. */ page = pfn_to_page(low_pfn); if (page_zone(page) != zone) continue; /* Skip if free */ if (PageBuddy(page)) continue; /* * For async migration, also only scan in MOVABLE blocks. Async * migration is optimistic to see if the minimum amount of work * satisfies the allocation */ pageblock_nr = low_pfn >> pageblock_order; if (!cc->sync && last_pageblock_nr != pageblock_nr && !migrate_async_suitable(get_pageblock_migratetype(page))) { low_pfn += pageblock_nr_pages; low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1; last_pageblock_nr = pageblock_nr; continue; } if (!PageLRU(page)) continue; /* * PageLRU is set, and lru_lock excludes isolation, * splitting and collapsing (collapsing has already * happened if PageLRU is set). */ if (PageTransHuge(page)) { low_pfn += (1 << compound_order(page)) - 1; continue; } if (!cc->sync) mode |= ISOLATE_ASYNC_MIGRATE; lruvec = mem_cgroup_page_lruvec(page, zone); /* Try isolate the page */ if (__isolate_lru_page(page, mode) != 0) continue; VM_BUG_ON(PageTransCompound(page)); /* Successfully isolated */ del_page_from_lru_list(page, lruvec, page_lru(page)); list_add(&page->lru, migratelist); cc->nr_migratepages++; nr_isolated++; /* Avoid isolating too much */ if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) { ++low_pfn; break; } } acct_isolated(zone, cc); spin_unlock_irq(&zone->lru_lock); trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated); return low_pfn; } #endif /* CONFIG_COMPACTION || CONFIG_CMA */ #ifdef CONFIG_COMPACTION /* Returns true if the page is within a block suitable for migration to */ static bool suitable_migration_target(struct page *page) { int migratetype = get_pageblock_migratetype(page); /* Don't interfere with memory hot-remove or the min_free_kbytes blocks */ if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE) return false; /* If the page is a large free page, then allow migration */ if (PageBuddy(page) && page_order(page) >= pageblock_order) return true; /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */ if (migrate_async_suitable(migratetype)) return true; /* Otherwise skip the block */ return false; } /* * Based on information in the current compact_control, find blocks * suitable for isolating free pages from and then isolate them. */ static void isolate_freepages(struct zone *zone, struct compact_control *cc) { struct page *page; unsigned long high_pfn, low_pfn, pfn, zone_end_pfn, end_pfn; unsigned long flags; int nr_freepages = cc->nr_freepages; struct list_head *freelist = &cc->freepages; /* * Initialise the free scanner. The starting point is where we last * scanned from (or the end of the zone if starting). The low point * is the end of the pageblock the migration scanner is using. */ pfn = cc->free_pfn; low_pfn = cc->migrate_pfn + pageblock_nr_pages; /* * Take care that if the migration scanner is at the end of the zone * that the free scanner does not accidentally move to the next zone * in the next isolation cycle. */ high_pfn = min(low_pfn, pfn); zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; /* * Isolate free pages until enough are available to migrate the * pages on cc->migratepages. We stop searching if the migrate * and free page scanners meet or enough free pages are isolated. */ for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages; pfn -= pageblock_nr_pages) { unsigned long isolated; if (!pfn_valid(pfn)) continue; /* * Check for overlapping nodes/zones. It's possible on some * configurations to have a setup like * node0 node1 node0 * i.e. it's possible that all pages within a zones range of * pages do not belong to a single zone. */ page = pfn_to_page(pfn); if (page_zone(page) != zone) continue; /* Check the block is suitable for migration */ if (!suitable_migration_target(page)) continue; /* * Found a block suitable for isolating free pages from. Now * we disabled interrupts, double check things are ok and * isolate the pages. This is to minimise the time IRQs * are disabled */ isolated = 0; spin_lock_irqsave(&zone->lock, flags); if (suitable_migration_target(page)) { end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn); isolated = isolate_freepages_block(pfn, end_pfn, freelist, false); nr_freepages += isolated; } spin_unlock_irqrestore(&zone->lock, flags); /* * Record the highest PFN we isolated pages from. When next * looking for free pages, the search will restart here as * page migration may have returned some pages to the allocator */ if (isolated) high_pfn = max(high_pfn, pfn); } /* split_free_page does not map the pages */ map_pages(freelist); cc->free_pfn = high_pfn; cc->nr_freepages = nr_freepages; } /* * This is a migrate-callback that "allocates" freepages by taking pages * from the isolated freelists in the block we are migrating to. */ static struct page *compaction_alloc(struct page *migratepage, unsigned long data, int **result) { struct compact_control *cc = (struct compact_control *)data; struct page *freepage; /* Isolate free pages if necessary */ if (list_empty(&cc->freepages)) { isolate_freepages(cc->zone, cc); if (list_empty(&cc->freepages)) return NULL; } freepage = list_entry(cc->freepages.next, struct page, lru); list_del(&freepage->lru); cc->nr_freepages--; return freepage; }