forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Signed-off-by: KAMEZAWA Hiroyuki <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
Showing
6 changed files
with
223 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#ifndef __LINUX_PAGEISOLATION_H | ||
#define __LINUX_PAGEISOLATION_H | ||
|
||
/* | ||
* Changes migrate type in [start_pfn, end_pfn) to be MIGRATE_ISOLATE. | ||
* If specified range includes migrate types other than MOVABLE, | ||
* this will fail with -EBUSY. | ||
* | ||
* For isolating all pages in the range finally, the caller have to | ||
* free all pages in the range. test_page_isolated() can be used for | ||
* test it. | ||
*/ | ||
extern int | ||
start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn); | ||
|
||
/* | ||
* Changes MIGRATE_ISOLATE to MIGRATE_MOVABLE. | ||
* target range is [start_pfn, end_pfn) | ||
*/ | ||
extern int | ||
undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn); | ||
|
||
/* | ||
* test all pages in [start_pfn, end_pfn)are isolated or not. | ||
*/ | ||
extern int | ||
test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn); | ||
|
||
/* | ||
* Internal funcs.Changes pageblock's migrate type. | ||
* Please use make_pagetype_isolated()/make_pagetype_movable(). | ||
*/ | ||
extern int set_migratetype_isolate(struct page *page); | ||
extern void unset_migratetype_isolate(struct page *page); | ||
|
||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/* | ||
* linux/mm/page_isolation.c | ||
*/ | ||
|
||
#include <stddef.h> | ||
#include <linux/mm.h> | ||
#include <linux/page-isolation.h> | ||
#include <linux/pageblock-flags.h> | ||
#include "internal.h" | ||
|
||
static inline struct page * | ||
__first_valid_page(unsigned long pfn, unsigned long nr_pages) | ||
{ | ||
int i; | ||
for (i = 0; i < nr_pages; i++) | ||
if (pfn_valid_within(pfn + i)) | ||
break; | ||
if (unlikely(i == nr_pages)) | ||
return NULL; | ||
return pfn_to_page(pfn + i); | ||
} | ||
|
||
/* | ||
* start_isolate_page_range() -- make page-allocation-type of range of pages | ||
* to be MIGRATE_ISOLATE. | ||
* @start_pfn: The lower PFN of the range to be isolated. | ||
* @end_pfn: The upper PFN of the range to be isolated. | ||
* | ||
* Making page-allocation-type to be MIGRATE_ISOLATE means free pages in | ||
* the range will never be allocated. Any free pages and pages freed in the | ||
* future will not be allocated again. | ||
* | ||
* start_pfn/end_pfn must be aligned to pageblock_order. | ||
* Returns 0 on success and -EBUSY if any part of range cannot be isolated. | ||
*/ | ||
int | ||
start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn) | ||
{ | ||
unsigned long pfn; | ||
unsigned long undo_pfn; | ||
struct page *page; | ||
|
||
BUG_ON((start_pfn) & (pageblock_nr_pages - 1)); | ||
BUG_ON((end_pfn) & (pageblock_nr_pages - 1)); | ||
|
||
for (pfn = start_pfn; | ||
pfn < end_pfn; | ||
pfn += pageblock_nr_pages) { | ||
page = __first_valid_page(pfn, pageblock_nr_pages); | ||
if (page && set_migratetype_isolate(page)) { | ||
undo_pfn = pfn; | ||
goto undo; | ||
} | ||
} | ||
return 0; | ||
undo: | ||
for (pfn = start_pfn; | ||
pfn <= undo_pfn; | ||
pfn += pageblock_nr_pages) | ||
unset_migratetype_isolate(pfn_to_page(pfn)); | ||
|
||
return -EBUSY; | ||
} | ||
|
||
/* | ||
* Make isolated pages available again. | ||
*/ | ||
int | ||
undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn) | ||
{ | ||
unsigned long pfn; | ||
struct page *page; | ||
BUG_ON((start_pfn) & (pageblock_nr_pages - 1)); | ||
BUG_ON((end_pfn) & (pageblock_nr_pages - 1)); | ||
for (pfn = start_pfn; | ||
pfn < end_pfn; | ||
pfn += pageblock_nr_pages) { | ||
page = __first_valid_page(pfn, pageblock_nr_pages); | ||
if (!page || get_pageblock_flags(page) != MIGRATE_ISOLATE) | ||
continue; | ||
unset_migratetype_isolate(page); | ||
} | ||
return 0; | ||
} | ||
/* | ||
* Test all pages in the range is free(means isolated) or not. | ||
* all pages in [start_pfn...end_pfn) must be in the same zone. | ||
* zone->lock must be held before call this. | ||
* | ||
* Returns 0 if all pages in the range is isolated. | ||
*/ | ||
static int | ||
__test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn) | ||
{ | ||
struct page *page; | ||
|
||
while (pfn < end_pfn) { | ||
if (!pfn_valid_within(pfn)) { | ||
pfn++; | ||
continue; | ||
} | ||
page = pfn_to_page(pfn); | ||
if (PageBuddy(page)) | ||
pfn += 1 << page_order(page); | ||
else if (page_count(page) == 0 && | ||
page_private(page) == MIGRATE_ISOLATE) | ||
pfn += 1; | ||
else | ||
break; | ||
} | ||
if (pfn < end_pfn) | ||
return 0; | ||
return 1; | ||
} | ||
|
||
int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn) | ||
{ | ||
unsigned long pfn; | ||
struct page *page; | ||
|
||
pfn = start_pfn; | ||
/* | ||
* Note: pageblock_nr_page != MAX_ORDER. Then, chunks of free page | ||
* is not aligned to pageblock_nr_pages. | ||
* Then we just check pagetype fist. | ||
*/ | ||
for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) { | ||
page = __first_valid_page(pfn, pageblock_nr_pages); | ||
if (page && get_pageblock_flags(page) != MIGRATE_ISOLATE) | ||
break; | ||
} | ||
if (pfn < end_pfn) | ||
return -EBUSY; | ||
/* Check all pages are free or Marked as ISOLATED */ | ||
if (__test_page_isolated_in_pageblock(start_pfn, end_pfn)) | ||
return 0; | ||
return -EBUSY; | ||
} |