Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965080AbaGDHx5 (ORCPT ); Fri, 4 Jul 2014 03:53:57 -0400 Received: from lgeamrelo01.lge.com ([156.147.1.125]:43564 "EHLO lgeamrelo01.lge.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752035AbaGDHxI (ORCPT ); Fri, 4 Jul 2014 03:53:08 -0400 X-Original-SENDERIP: 10.177.220.145 X-Original-MAILFROM: iamjoonsoo.kim@lge.com From: Joonsoo Kim To: Andrew Morton Cc: "Kirill A. Shutemov" , Rik van Riel , Peter Zijlstra , Mel Gorman , Johannes Weiner , Minchan Kim , Yasuaki Ishimatsu , Zhang Yanfei , "Srivatsa S. Bhat" , Tang Chen , Naoya Horiguchi , Bartlomiej Zolnierkiewicz , Wen Congyang , Marek Szyprowski , Michal Nazarewicz , Laura Abbott , Heesub Shin , "Aneesh Kumar K.V" , Ritesh Harjani , t.stanislaws@samsung.com, Gioh Kim , linux-mm@kvack.org, linux-kernel@vger.kernel.org, Joonsoo Kim Subject: [PATCH 09/10] mm/page_alloc: fix possible wrongly calculated freepage counter Date: Fri, 4 Jul 2014 16:57:54 +0900 Message-Id: <1404460675-24456-10-git-send-email-iamjoonsoo.kim@lge.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1404460675-24456-1-git-send-email-iamjoonsoo.kim@lge.com> References: <1404460675-24456-1-git-send-email-iamjoonsoo.kim@lge.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When isolating/unisolating some pageblock, we add/sub number of pages returend by move_freepages_block() to calculate number of freepage. But, this value is invalid for calculation, because it means number of pages in buddy list of that migratetype rather than number of *moved* pages. So number of freepage could be incorrect more and more whenever calling these functions. And, there is one more counting problem on __test_page_isolated_in_pageblock(). move_freepages() is called, but missed to fixup number of freepage. I think that counting should be done in move_freepages(), otherwise, another future user to this function also missed to fixup number of freepage again. Now, we have proper infrastructure, get_onbuddy_migratetype(), which can be used to get current migratetype of buddy list. So fix this situation. Signed-off-by: Joonsoo Kim --- mm/page_alloc.c | 37 ++++++++++++++++++++++++++++++++++--- mm/page_isolation.c | 12 +++--------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d9fb8bb..80c9bd8 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -465,6 +465,33 @@ static inline void clear_page_guard(struct zone *zone, struct page *page, unsigned int order, int migratetype) {} #endif +static inline void count_freepage_nr(struct page *page, int order, + int *nr_isolate, int *nr_cma, int *nr_others) +{ + int nr = 1 << order; + int migratetype = get_onbuddy_migratetype(page); + + if (is_migrate_isolate(migratetype)) + *nr_isolate += nr; + else if (is_migrate_cma(migratetype)) + *nr_cma += nr; + else + *nr_others += nr; +} + +static void fixup_freepage_nr(struct zone *zone, int migratetype, + int nr_isolate, int nr_cma, int nr_others) +{ + int nr_free = nr_cma + nr_others; + + if (is_migrate_isolate(migratetype)) { + __mod_zone_page_state(zone, NR_FREE_PAGES, -nr_free); + __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, -nr_cma); + } else { + __mod_zone_freepage_state(zone, nr_isolate, migratetype); + } +} + static inline void set_page_order(struct page *page, unsigned int order, int migratetype) { @@ -619,6 +646,7 @@ static inline void __free_one_page(struct page *page, buddy = page + (buddy_idx - page_idx); if (!page_is_buddy(page, buddy, order)) break; + /* * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page, * merge with it and move up one order. @@ -1062,7 +1090,7 @@ int move_freepages(struct zone *zone, { struct page *page; unsigned long order; - int pages_moved = 0; + int nr_pages = 0, nr_isolate = 0, nr_cma = 0, nr_others = 0; #ifndef CONFIG_HOLES_IN_ZONE /* @@ -1090,14 +1118,17 @@ int move_freepages(struct zone *zone, } order = page_order(page); + count_freepage_nr(page, order, + &nr_isolate, &nr_cma, &nr_others); list_move(&page->lru, &zone->free_area[order].free_list[migratetype]); set_onbuddy_migratetype(page, migratetype); page += 1 << order; - pages_moved += 1 << order; + nr_pages += 1 << order; } - return pages_moved; + fixup_freepage_nr(zone, migratetype, nr_isolate, nr_cma, nr_others); + return nr_pages; } int move_freepages_block(struct zone *zone, struct page *page, diff --git a/mm/page_isolation.c b/mm/page_isolation.c index 6e4e86b..62676de 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -56,14 +56,9 @@ int set_migratetype_isolate(struct page *page, bool skip_hwpoisoned_pages) out: if (!ret) { - unsigned long nr_pages; - int migratetype = get_pageblock_migratetype(page); - set_pageblock_migratetype(page, MIGRATE_ISOLATE); zone->nr_isolate_pageblock++; - nr_pages = move_freepages_block(zone, page, MIGRATE_ISOLATE); - - __mod_zone_freepage_state(zone, -nr_pages, migratetype); + move_freepages_block(zone, page, MIGRATE_ISOLATE); } spin_unlock_irqrestore(&zone->lock, flags); @@ -75,14 +70,13 @@ out: void unset_migratetype_isolate(struct page *page, unsigned migratetype) { struct zone *zone; - unsigned long flags, nr_pages; + unsigned long flags; zone = page_zone(page); spin_lock_irqsave(&zone->lock, flags); if (get_pageblock_migratetype(page) != MIGRATE_ISOLATE) goto out; - nr_pages = move_freepages_block(zone, page, migratetype); - __mod_zone_freepage_state(zone, nr_pages, migratetype); + move_freepages_block(zone, page, migratetype); set_pageblock_migratetype(page, migratetype); zone->nr_isolate_pageblock--; out: -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/