diff options
author | Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> | 2014-02-14 19:34:17 +0100 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-11-18 11:47:01 +0900 |
commit | cfeefb8237d985d9223679f012531842183df408 (patch) | |
tree | 824b95c887aab945913cd7c63cb3e82135b91a0a | |
parent | 61a99174639217a543d05464369a48e02a08b82f (diff) | |
download | linux-3.10-cfeefb8237d985d9223679f012531842183df408.tar.gz linux-3.10-cfeefb8237d985d9223679f012531842183df408.tar.bz2 linux-3.10-cfeefb8237d985d9223679f012531842183df408.zip |
mm/page_alloc: fix freeing of MIGRATE_RESERVE migratetype pages
Pages allocated from MIGRATE_RESERVE migratetype pageblocks
are not freed back to MIGRATE_RESERVE migratetype free
lists in free_pcppages_bulk()->__free_one_page() if we got
to free_pcppages_bulk() through drain_[zone_]pages().
The freeing through free_hot_cold_page() is okay because
freepage migratetype is set to pageblock migratetype before
calling free_pcppages_bulk(). If pages of MIGRATE_RESERVE
migratetype end up on the free lists of other migratetype
whole Reserved pageblock may be later changed to the other
migratetype in __rmqueue_fallback() and it will be never
changed back to be a Reserved pageblock. Fix the issue by
preserving freepage migratetype as a pageblock migratetype
(instead of overriding it to the requested migratetype)
for MIGRATE_RESERVE migratetype pages in rmqueue_bulk().
The problem was introduced in v2.6.31 by commit ed0ae21
("page allocator: do not call get_pageblock_migratetype()
more than necessary").
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Reported-by: Yong-Taek Lee <ytk.lee@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Hugh Dickins <hughd@google.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Change-Id: I1d4ab2a3241387160dd376b0ead864cd2b0c59f0
-rw-r--r-- | include/linux/mmzone.h | 5 | ||||
-rw-r--r-- | mm/page_alloc.c | 10 |
2 files changed, 12 insertions, 3 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 5c76737d836..dc40e42e685 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -63,6 +63,11 @@ enum { MIGRATE_TYPES }; +static inline bool is_migrate_reserve(int migratetype) +{ + return unlikely(migratetype == MIGRATE_RESERVE); +} + #ifdef CONFIG_CMA # define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA) #else diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0cbd0ed9579..0072c03dcde 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1140,7 +1140,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, unsigned long count, struct list_head *list, int migratetype, int cold) { - int mt = migratetype, i; + int mt, i; spin_lock(&zone->lock); for (i = 0; i < count; ++i) { @@ -1161,9 +1161,13 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, list_add(&page->lru, list); else list_add_tail(&page->lru, list); + mt = get_pageblock_migratetype(page); if (IS_ENABLED(CONFIG_CMA)) { - mt = get_pageblock_migratetype(page); - if (!is_migrate_cma(mt) && !is_migrate_isolate(mt)) + if (!is_migrate_cma(mt) && !is_migrate_isolate(mt) && + !is_migrate_reserve(mt)) + mt = migratetype; + } else { + if (!is_migrate_reserve(mt)) mt = migratetype; } set_freepage_migratetype(page, mt); |