linux/mm/page_isolation.c
<<
>>
Prefs
   1/*
   2 * linux/mm/page_isolation.c
   3 */
   4
   5#include <stddef.h>
   6#include <linux/mm.h>
   7#include <linux/page-isolation.h>
   8#include <linux/pageblock-flags.h>
   9#include "internal.h"
  10
  11static inline struct page *
  12__first_valid_page(unsigned long pfn, unsigned long nr_pages)
  13{
  14        int i;
  15        for (i = 0; i < nr_pages; i++)
  16                if (pfn_valid_within(pfn + i))
  17                        break;
  18        if (unlikely(i == nr_pages))
  19                return NULL;
  20        return pfn_to_page(pfn + i);
  21}
  22
  23/*
  24 * start_isolate_page_range() -- make page-allocation-type of range of pages
  25 * to be MIGRATE_ISOLATE.
  26 * @start_pfn: The lower PFN of the range to be isolated.
  27 * @end_pfn: The upper PFN of the range to be isolated.
  28 *
  29 * Making page-allocation-type to be MIGRATE_ISOLATE means free pages in
  30 * the range will never be allocated. Any free pages and pages freed in the
  31 * future will not be allocated again.
  32 *
  33 * start_pfn/end_pfn must be aligned to pageblock_order.
  34 * Returns 0 on success and -EBUSY if any part of range cannot be isolated.
  35 */
  36int
  37start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn)
  38{
  39        unsigned long pfn;
  40        unsigned long undo_pfn;
  41        struct page *page;
  42
  43        BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
  44        BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
  45
  46        for (pfn = start_pfn;
  47             pfn < end_pfn;
  48             pfn += pageblock_nr_pages) {
  49                page = __first_valid_page(pfn, pageblock_nr_pages);
  50                if (page && set_migratetype_isolate(page)) {
  51                        undo_pfn = pfn;
  52                        goto undo;
  53                }
  54        }
  55        return 0;
  56undo:
  57        for (pfn = start_pfn;
  58             pfn < undo_pfn;
  59             pfn += pageblock_nr_pages)
  60                unset_migratetype_isolate(pfn_to_page(pfn));
  61
  62        return -EBUSY;
  63}
  64
  65/*
  66 * Make isolated pages available again.
  67 */
  68int
  69undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn)
  70{
  71        unsigned long pfn;
  72        struct page *page;
  73        BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
  74        BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
  75        for (pfn = start_pfn;
  76             pfn < end_pfn;
  77             pfn += pageblock_nr_pages) {
  78                page = __first_valid_page(pfn, pageblock_nr_pages);
  79                if (!page || get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
  80                        continue;
  81                unset_migratetype_isolate(page);
  82        }
  83        return 0;
  84}
  85/*
  86 * Test all pages in the range is free(means isolated) or not.
  87 * all pages in [start_pfn...end_pfn) must be in the same zone.
  88 * zone->lock must be held before call this.
  89 *
  90 * Returns 0 if all pages in the range is isolated.
  91 */
  92static int
  93__test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn)
  94{
  95        struct page *page;
  96
  97        while (pfn < end_pfn) {
  98                if (!pfn_valid_within(pfn)) {
  99                        pfn++;
 100                        continue;
 101                }
 102                page = pfn_to_page(pfn);
 103                if (PageBuddy(page))
 104                        pfn += 1 << page_order(page);
 105                else if (page_count(page) == 0 &&
 106                                page_private(page) == MIGRATE_ISOLATE)
 107                        pfn += 1;
 108                else
 109                        break;
 110        }
 111        if (pfn < end_pfn)
 112                return 0;
 113        return 1;
 114}
 115
 116int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
 117{
 118        unsigned long pfn;
 119        struct page *page;
 120
 121        pfn = start_pfn;
 122        /*
 123         * Note: pageblock_nr_page != MAX_ORDER. Then, chunks of free page
 124         * is not aligned to pageblock_nr_pages.
 125         * Then we just check pagetype fist.
 126         */
 127        for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
 128                page = __first_valid_page(pfn, pageblock_nr_pages);
 129                if (page && get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
 130                        break;
 131        }
 132        if (pfn < end_pfn)
 133                return -EBUSY;
 134        /* Check all pages are free or Marked as ISOLATED */
 135        if (__test_page_isolated_in_pageblock(start_pfn, end_pfn))
 136                return 0;
 137        return -EBUSY;
 138}
 139
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.