diff options
Diffstat (limited to 'mm/cma.c')
-rw-r--r-- | mm/cma.c | 30 |
1 files changed, 28 insertions, 2 deletions
@@ -35,6 +35,7 @@ #include <linux/cma.h> #include <linux/highmem.h> #include <linux/io.h> +#include <linux/delay.h> #include <trace/events/cma.h> #include "cma.h" @@ -134,6 +135,10 @@ static int __init cma_activate_area(struct cma *cma) spin_lock_init(&cma->mem_head_lock); #endif + if (!PageHighMem(pfn_to_page(cma->base_pfn))) + kmemleak_free_part(__va(cma->base_pfn << PAGE_SHIFT), + cma->count << PAGE_SHIFT); + return 0; err: @@ -369,6 +374,7 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align) unsigned long bitmap_maxno, bitmap_no, bitmap_count; struct page *page = NULL; int ret; + int retry_after_sleep = 0; if (!cma || !cma->count) return NULL; @@ -379,6 +385,8 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align) if (!count) return NULL; + trace_cma_alloc_start(count, align); + mask = cma_bitmap_aligned_mask(cma, align); offset = cma_bitmap_aligned_offset(cma, align); bitmap_maxno = cma_bitmap_maxno(cma); @@ -390,8 +398,24 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align) bitmap_maxno, start, bitmap_count, mask, offset); if (bitmap_no >= bitmap_maxno) { - mutex_unlock(&cma->lock); - break; + if (retry_after_sleep < 2) { + start = 0; + /* + * Page may be momentarily pinned by some other + * process which has been scheduled out, eg. + * in exit path, during unmap call, or process + * fork and so cannot be freed there. Sleep + * for 100ms and retry twice to see if it has + * been freed later. + */ + mutex_unlock(&cma->lock); + msleep(100); + retry_after_sleep++; + continue; + } else { + mutex_unlock(&cma->lock); + break; + } } bitmap_set(cma->bitmap, bitmap_no, bitmap_count); /* @@ -416,6 +440,8 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align) pr_debug("%s(): memory range at %p is busy, retrying\n", __func__, pfn_to_page(pfn)); + + trace_cma_alloc_busy_retry(pfn, pfn_to_page(pfn), count, align); /* try again with a bit different memory target */ start = bitmap_no + mask + 1; } |