summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>2014-02-14 19:34:17 +0100
committerChanho Park <chanho61.park@samsung.com>2014-11-18 11:47:01 +0900
commitcfeefb8237d985d9223679f012531842183df408 (patch)
tree824b95c887aab945913cd7c63cb3e82135b91a0a
parent61a99174639217a543d05464369a48e02a08b82f (diff)
downloadlinux-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.h5
-rw-r--r--mm/page_alloc.c10
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);