Root/mm/page_isolation.c

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

Archive Download this file



interactive