mm,page_alloc,cma: introduce a customisable threshold for allocating pages in cma

On some platforms the cma area can be half the entire system memory,
meaning that allocations start happening in the cma area immediately.
This leads to fragmentation and subsequent fatal cma_alloc failures.

We introduce an "alloc_in_cma_threshold" parameter which requires that
this many sixteenths of the free pages must be in cma before it will
try to use them. By default this is set to 12, but the previous
behaviour can be restored by setting it to 8 on startup.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
This commit is contained in:
David Plowman
2022-03-29 16:10:06 +01:00
committed by Dom Cobley
parent 70861e2cd6
commit bdc8172840

View File

@@ -206,6 +206,27 @@ EXPORT_SYMBOL(node_states);
gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK;
#define ALLOC_IN_CMA_THRESHOLD_MAX 16
#define ALLOC_IN_CMA_THRESHOLD_DEFAULT 12
static unsigned long _alloc_in_cma_threshold __read_mostly
= ALLOC_IN_CMA_THRESHOLD_DEFAULT;
static int __init alloc_in_cma_threshold_setup(char *buf)
{
unsigned long res;
if (kstrtoul(buf, 10, &res) < 0 ||
res > ALLOC_IN_CMA_THRESHOLD_MAX) {
pr_err("Bad alloc_cma_threshold value\n");
return 0;
}
_alloc_in_cma_threshold = res;
pr_info("Setting alloc_in_cma_threshold to %lu\n", res);
return 0;
}
early_param("alloc_in_cma_threshold", alloc_in_cma_threshold_setup);
/* /*
* A cached value of the page's pageblock's migratetype, used when the page is * A cached value of the page's pageblock's migratetype, used when the page is
* put on a pcplist. Used to avoid the pageblock migratetype lookup when * put on a pcplist. Used to avoid the pageblock migratetype lookup when
@@ -2097,12 +2118,13 @@ __rmqueue(struct zone *zone, unsigned int order, int migratetype,
if (IS_ENABLED(CONFIG_CMA)) { if (IS_ENABLED(CONFIG_CMA)) {
/* /*
* Balance movable allocations between regular and CMA areas by * Balance movable allocations between regular and CMA areas by
* allocating from CMA when over half of the zone's free memory * allocating from CMA when over more than a given proportion of
* is in the CMA area. * the zone's free memory is in the CMA area.
*/ */
if (alloc_flags & ALLOC_CMA && if (alloc_flags & ALLOC_CMA &&
zone_page_state(zone, NR_FREE_CMA_PAGES) > zone_page_state(zone, NR_FREE_CMA_PAGES) >
zone_page_state(zone, NR_FREE_PAGES) / 2) { zone_page_state(zone, NR_FREE_PAGES) / ALLOC_IN_CMA_THRESHOLD_MAX
* _alloc_in_cma_threshold) {
page = __rmqueue_cma_fallback(zone, order); page = __rmqueue_cma_fallback(zone, order);
if (page) if (page)
return page; return page;