Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 263a20e2 authored by Liam Mark's avatar Liam Mark
Browse files

mm: cma: sleep between retries in cma_alloc



Port support from 3.10 for retrying cma allocations
to 3.18 to help resolve cma allocation failures.

It was observed that CMA pages are sometimes getting
pinned down by BG processes scheduled out in their exit
path. Since BG processes have lower priority they end up
getting less time slice by scheduler there by consuming
more time to free up CMA pages.

Also when a process is being forked copy_one_pte
may create copy-on-write mappings, when this is done
the page _count and page _mapcount are each
incremented sequentially. If the process is context
switched out after incrementing the _count but before
incrementing the _mapcount then the page will appear
temporarily pinned.

So instead of failing to allocate and directly
returning an error on the CMA allocation path we do 2
retries, with sleeps, to give the system an opportunity
to unpin any pinned pages.

Change-Id: I022a9341f8ee44f281c7cb34769695843e97d684
Signed-off-by: default avatarSusheel Khiani <skhiani@codeaurora.org>
Signed-off-by: default avatarLiam Mark <lmark@codeaurora.org>
parent 8ca03863
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <linux/log2.h>
#include <linux/cma.h>
#include <linux/highmem.h>
#include <linux/delay.h>

struct cma {
	unsigned long	base_pfn;
@@ -344,6 +345,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;
@@ -363,9 +365,25 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align)
		bitmap_no = bitmap_find_next_zero_area(cma->bitmap,
				bitmap_maxno, start, bitmap_count, mask);
		if (bitmap_no >= bitmap_maxno) {
			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);
		/*
		 * It's safe to drop the lock here. We've marked this region for