mm: allocate CMA pages first for GFP_HIGHUSER_MOVABLE
authorCho KyongHo <pullip.cho@samsung.com>
Thu, 5 Jan 2017 01:23:07 +0000 (10:23 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:23:00 +0000 (20:23 +0300)
CMA pages are not actively used and tend to be remained unused because
the free list of CMA pages are only lookuped as the fallback of
movable page allocations. Large amount of free CMA pages causes
problems about unmovable page allocation failure as well as memory
unefficiency.
If free CMA pages are more than the low wmark, page reclamation does
not work for unmovable page allocations. This results in depletion of
free pages available for unmovable page allocations.
To prevent this impact by free CMA pages, we should always try to
consume all free CMA pages.

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

index ee8a4e79eddc03d016897ffd966d31c4fe762f34..e84f4909c16407f9b9a68b25136db2acaa17d97a 100644 (file)
@@ -2297,20 +2297,35 @@ do_steal:
 /*
  * Do the hard work of removing an element from the buddy allocator.
  * Call me with the zone->lock already held.
+ * If gfp mask of the page allocation has GFP_HIGHUSER_MOVABLE, @migratetype
+ * is changed from MIGRATE_MOVABLE to MIGRATE_CMA in rmqueue() to select the
+ * free list of MIGRATE_CMA. It helps depleting CMA free pages so that
+ * evaluation of watermark for unmovable page allocations is not too different
+ * from movable page allocations.
+ * If @migratetype is MIGRATE_CMA, it should be corrected to MIGRATE_MOVABLE
+ * after the free list of MIGRATE_CMA is searched to have a chance to search the
+ * free list of MIGRATE_MOVABLE. It also records correct migrate type in the
+ * trace as intended by the page allocation.
  */
 static struct page *__rmqueue(struct zone *zone, unsigned int order,
                                int migratetype)
 {
-       struct page *page;
+       struct page *page = NULL;
 
-retry:
-       page = __rmqueue_smallest(zone, order, migratetype);
-       if (unlikely(!page)) {
-               if (migratetype == MIGRATE_MOVABLE)
-                       page = __rmqueue_cma_fallback(zone, order);
+#ifdef CONFIG_CMA
+       if (migratetype == MIGRATE_CMA) {
+#else
+       if (migratetype == MIGRATE_MOVABLE) {
+#endif
+               page = __rmqueue_cma_fallback(zone, order);
+               migratetype = MIGRATE_MOVABLE;
+       }
 
-               if (!page && __rmqueue_fallback(zone, order, migratetype))
-                       goto retry;
+       while (!page) {
+               page = __rmqueue_smallest(zone, order, migratetype);
+               if (unlikely(!page) &&
+                   !__rmqueue_fallback(zone, order, migratetype))
+                       break;
        }
 
        trace_mm_page_alloc_zone_locked(page, order, migratetype);
@@ -2814,6 +2829,13 @@ struct page *rmqueue(struct zone *preferred_zone,
 {
        unsigned long flags;
        struct page *page;
+       int migratetype_rmqueue = migratetype;
+
+#ifdef CONFIG_CMA
+       if ((migratetype_rmqueue == MIGRATE_MOVABLE) &&
+           ((gfp_flags & GFP_HIGHUSER_MOVABLE) == GFP_HIGHUSER_MOVABLE))
+               migratetype_rmqueue = MIGRATE_CMA;
+#endif
 
        if (likely(order == 0)) {
                page = rmqueue_pcplist(preferred_zone, zone, order,
@@ -2836,7 +2858,7 @@ struct page *rmqueue(struct zone *preferred_zone,
                                trace_mm_page_alloc_zone_locked(page, order, migratetype);
                }
                if (!page)
-                       page = __rmqueue(zone, order, migratetype);
+                       page = __rmqueue(zone, order, migratetype_rmqueue);
        } while (page && check_new_pages(page, order));
        spin_unlock(&zone->lock);
        if (!page)
@@ -3701,7 +3723,8 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
                alloc_flags |= ALLOC_HARDER;
 
 #ifdef CONFIG_CMA
-       if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
+       if ((gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE) ||
+               ((gfp_mask & GFP_HIGHUSER_MOVABLE) == GFP_HIGHUSER_MOVABLE))
                alloc_flags |= ALLOC_CMA;
 #endif
        return alloc_flags;