commit 4b23a68f9536 ("mm/page_alloc: protect PCP lists with a spinlock") fallback freeing page to free_one_page() if pcp trylock failed. This make MIGRATE_CMA be able to fallback and be stolen whole pageblock by MIGRATE_UNMOVABLE in the page allocation. PCP free is fine because free_pcppages_bulk() will always get migratetype again before freeing the page, thus this only happen when someone tried to put CMA page in to other MIGRATE_TYPE's freelist. Fixes: 4b23a68f9536 ("mm/page_alloc: protect PCP lists with a spinlock") Reported-by: Joe Liu <joe.liu@xxxxxxxxxxxx> Signed-off-by: Lecopzer Chen <lecopzer.chen@xxxxxxxxxxxx> Cc: Mark-pk Tsai <mark-pk.tsai@xxxxxxxxxxxx> Cc: Joe Liu <joe.liu@xxxxxxxxxxxx> --- mm/page_alloc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 452459836b71..0ea88c031838 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2428,6 +2428,14 @@ void free_unref_page(struct page *page, unsigned int order) free_unref_page_commit(zone, pcp, page, migratetype, order); pcp_spin_unlock(pcp); } else { +#ifdef CONFIG_CMA + /* + * CMA must be back to its freelist. Otherwise CMA pageblock may + * be stolen by fallback flow while getting free page. + */ + if (get_pcppage_migratetype(page) == MIGRATE_CMA) + migratetype = MIGRATE_CMA; +#endif free_one_page(zone, page, pfn, order, migratetype, FPI_NONE); } pcp_trylock_finish(UP_flags); -- 2.18.0