diff options
author | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | 2007-10-16 04:26:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:02 -0400 |
commit | a5d76b54a3f3a40385d7f76069a2feac9f1bad63 (patch) | |
tree | f58c432a4224b3be032bd4a4afa79dfa55d198a6 /mm/page_isolation.c | |
parent | 75884fb1c6388f3713ddcca662f3647b3129aaeb (diff) |
memory unplug: page isolation
Implement generic chunk-of-pages isolation method by using page grouping ops.
This patch add MIGRATE_ISOLATE to MIGRATE_TYPES. By this
- MIGRATE_TYPES increases.
- bitmap for migratetype is enlarged.
pages of MIGRATE_ISOLATE migratetype will not be allocated even if it is free.
By this, you can isolated *freed* pages from users. How-to-free pages is not
a purpose of this patch. You may use reclaim and migrate codes to free pages.
If start_isolate_page_range(start,end) is called,
- migratetype of the range turns to be MIGRATE_ISOLATE if
its type is MIGRATE_MOVABLE. (*) this check can be updated if other
memory reclaiming works make progress.
- MIGRATE_ISOLATE is not on migratetype fallback list.
- All free pages and will-be-freed pages are isolated.
To check all pages in the range are isolated or not, use test_pages_isolated(),
To cancel isolation, use undo_isolate_page_range().
Changes V6 -> V7
- removed unnecessary #ifdef
There are HOLES_IN_ZONE handling codes...I'm glad if we can remove them..
Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
Signed-off-by: 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>
Diffstat (limited to 'mm/page_isolation.c')
-rw-r--r-- | mm/page_isolation.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/mm/page_isolation.c b/mm/page_isolation.c new file mode 100644 index 000000000000..8f92a29695cc --- /dev/null +++ b/mm/page_isolation.c | |||
@@ -0,0 +1,138 @@ | |||
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 | |||
11 | static 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 | */ | ||
36 | int | ||
37 | start_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; | ||
56 | undo: | ||
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 | */ | ||
68 | int | ||
69 | undo_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_flags(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 | */ | ||
92 | static 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 | |||
116 | int 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_flags(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 | } | ||