Skip to content

Commit f7426b9

Browse files
mszyprowtorvalds
authored andcommitted
mm: cma: adjust address limit to avoid hitting low/high memory boundary
Russell King recently noticed that limiting default CMA region only to low memory on ARM architecture causes serious memory management issues with machines having a lot of memory (which is mainly available as high memory). More information can be found the following thread: http://thread.gmane.org/gmane.linux.ports.arm.kernel/348441/ Those two patches removes this limit letting kernel to put default CMA region into high memory when this is possible (there is enough high memory available and architecture specific DMA limit fits). This should solve strange OOM issues on systems with lots of RAM (i.e. >1GiB) and large (>256M) CMA area. This patch (of 2): Automatically allocated regions should not cross low/high memory boundary, because such regions cannot be later correctly initialized due to spanning across two memory zones. This patch adds a check for this case and a simple code for moving region to low memory if automatically selected address might not fit completely into high memory. Signed-off-by: Marek Szyprowski <[email protected]> Acked-by: Michal Nazarewicz <[email protected]> Cc: Daniel Drake <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Russell King <[email protected]> Cc: Joonsoo Kim <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent d4932f9 commit f7426b9

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

mm/cma.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <linux/slab.h>
3333
#include <linux/log2.h>
3434
#include <linux/cma.h>
35+
#include <linux/highmem.h>
3536

3637
struct cma {
3738
unsigned long base_pfn;
@@ -163,6 +164,8 @@ int __init cma_declare_contiguous(phys_addr_t base,
163164
bool fixed, struct cma **res_cma)
164165
{
165166
struct cma *cma;
167+
phys_addr_t memblock_end = memblock_end_of_DRAM();
168+
phys_addr_t highmem_start = __pa(high_memory);
166169
int ret = 0;
167170

168171
pr_debug("%s(size %lx, base %08lx, limit %08lx alignment %08lx)\n",
@@ -196,6 +199,24 @@ int __init cma_declare_contiguous(phys_addr_t base,
196199
if (!IS_ALIGNED(size >> PAGE_SHIFT, 1 << order_per_bit))
197200
return -EINVAL;
198201

202+
/*
203+
* adjust limit to avoid crossing low/high memory boundary for
204+
* automatically allocated regions
205+
*/
206+
if (((limit == 0 || limit > memblock_end) &&
207+
(memblock_end - size < highmem_start &&
208+
memblock_end > highmem_start)) ||
209+
(!fixed && limit > highmem_start && limit - size < highmem_start)) {
210+
limit = highmem_start;
211+
}
212+
213+
if (fixed && base < highmem_start && base+size > highmem_start) {
214+
ret = -EINVAL;
215+
pr_err("Region at %08lx defined on low/high memory boundary (%08lx)\n",
216+
(unsigned long)base, (unsigned long)highmem_start);
217+
goto err;
218+
}
219+
199220
/* Reserve memory */
200221
if (base && fixed) {
201222
if (memblock_is_region_reserved(base, size) ||

0 commit comments

Comments
 (0)