mm: restrict cma pages to GFP_HIGHUSER_MOVABLE
authorCho KyongHo <pullip.cho@samsung.com>
Thu, 5 Jan 2017 12:25:29 +0000 (21:25 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:23:00 +0000 (20:23 +0300)
pcp list of MIGRATE_MOVABLE can have CMA pages and the free pages in
the list are ready for allocation with __GFP_MOVABLE. Since CMA pages
should be allocated only if GFP_HIGHUSER_MOVABLE is specified, it is
required to verify if the selected page in the pcp list is proper for
allocation according to gfp mask.

Change-Id: I5c74d74edc6adce293a3db59abdbb1acf4a01c14
Signed-off-by: Cho KyongHo <pullip.cho@samsung.com>
mm/page_alloc.c

index e84f4909c16407f9b9a68b25136db2acaa17d97a..585acf44b23f28b37dc7ce6d9afba790ac288781 100644 (file)
@@ -2788,6 +2788,25 @@ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype,
                else
                        page = list_first_entry(list, struct page, lru);
 
+               /*
+                * If the head or the tail page in the pcp list is CMA page and
+                * the gfp flags is not GFP_HIGHUSER_MOVABLE, do not allocate a
+                * page from the pcp list. The free list of MIGRATE_CMA is a
+                * special case of the free list of MIGRATE_MOVABLE and the
+                * pages from the free list of MIGRATE_CMA are pushed to the pcp
+                * list of MIGRATE_MOVABLE. Since the pcp list of
+                * MIGRATE_MOVABLE is selected if the gfp flags has GFP_MOVABLE,
+                * we should avoid the case that a cma page in the pcp list of
+                * MIGRATE_MOVABLE is allocated to a movable allocation without
+                * GFP_HIGHUSER_MOVABLE.
+                * If this is the case, allocate a movable page from the free
+                * list of MIGRATE_MOVABLE instead of pcp list of
+                * MIGRATE_MOVABLE.
+                */
+#ifdef CONFIG_CMA
+               if (is_migrate_cma_page(page) && (migratetype != MIGRATE_CMA))
+                       return NULL;
+#endif
                list_del(&page->lru);
                pcp->count--;
        } while (check_new_pcp(page));
@@ -2798,7 +2817,8 @@ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype,
 /* Lock and remove page from the per-cpu list */
 static struct page *rmqueue_pcplist(struct zone *preferred_zone,
                        struct zone *zone, unsigned int order,
-                       gfp_t gfp_flags, int migratetype)
+                       gfp_t gfp_flags, int migratetype,
+                       int migratetype_rmqueue)
 {
        struct per_cpu_pages *pcp;
        struct list_head *list;
@@ -2809,7 +2829,7 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone,
        local_irq_save(flags);
        pcp = &this_cpu_ptr(zone->pageset)->pcp;
        list = &pcp->lists[migratetype];
-       page = __rmqueue_pcplist(zone,  migratetype, cold, pcp, list);
+       page = __rmqueue_pcplist(zone,  migratetype_rmqueue, cold, pcp, list);
        if (page) {
                __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
                zone_statistics(preferred_zone, zone);
@@ -2836,11 +2856,18 @@ struct page *rmqueue(struct zone *preferred_zone,
            ((gfp_flags & GFP_HIGHUSER_MOVABLE) == GFP_HIGHUSER_MOVABLE))
                migratetype_rmqueue = MIGRATE_CMA;
 #endif
-
        if (likely(order == 0)) {
                page = rmqueue_pcplist(preferred_zone, zone, order,
-                               gfp_flags, migratetype);
-               goto out;
+                               gfp_flags, migratetype, migratetype_rmqueue);
+               /*
+                * Allocation with GFP_MOVABLE and !GFP_HIGHMEM will have
+                * another chance of page allocation from the free list.
+                * See the comment in __rmqueue_pcplist().
+                */
+#ifdef CONFIG_CMA
+               if (likely(page) || (migratetype_rmqueue != MIGRATE_MOVABLE))
+#endif
+                       goto out;
        }
 
        /*