summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiam Mark <lmark@codeaurora.org>2015-10-23 12:14:11 -0700
committerJeevan Shriram <jshriram@codeaurora.org>2016-05-18 13:38:15 -0700
commit2ef8479273158dd0f48faafa1f00eec10297aaae (patch)
tree3d14fdfebcef6b8e0fe943c0b5a445f10397d447
parentb9d51a0b437e08fbce76cfc57a1151594672e62c (diff)
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: Susheel Khiani <skhiani@codeaurora.org> Signed-off-by: Liam Mark <lmark@codeaurora.org>
-rw-r--r--mm/cma.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/mm/cma.c b/mm/cma.c
index cb2987bbb1e6..9ff71db72bc5 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -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"
@@ -373,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;
@@ -396,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);
/*