diff mbox

[37/48] staging: etnaviv: avoid pinning pages in CMA

Message ID 1443182280-15868-38-git-send-email-l.stach@pengutronix.de (mailing list archive)
State New, archived
Headers show

Commit Message

Lucas Stach Sept. 25, 2015, 11:57 a.m. UTC
From: Russell King <rmk+kernel@arm.linux.org.uk>

The CMA memory area is shared between CMA and other users.  In order to
allow CMA to work, non-CMA allocations in this area must be for movable
pages, so that a CMA allocation can reclaim its memory from other users
when required.

Page cache backed allocations, such as pages allocated via shmem, are by
default marked as "movable" allocations, which means that they can come
from the CMA region.

However, in etnaviv's case, we allocate shmem pages, and then we pin
these pages for the life of the buffer.  This prevents the pages being
reclaimed, and causes CMA failures.

new_inode() in fs/inode.c even says:

 * Allocates a new inode for given superblock. The default gfp_mask
 * for allocations related to inode->i_mapping is GFP_HIGHUSER_MOVABLE.
 * If HIGHMEM pages are unsuitable or it is known that pages allocated
 * for the page cache are not reclaimable or migratable,
 * mapping_set_gfp_mask() must be called with suitable flags on the
 * newly created inode's mapping

Etnaviv shmem pages are not reclaimable nor migratable once they're
pinned, so etnaviv is not conforming with this requirement.  Change the
gfp_mask to GFP_HIGHUSER, so we can still allocate from highmem, but not
from the CMA area.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
diff mbox

Patch

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 2518f897fdd8..5c2462d6130d 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -640,6 +640,19 @@  static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev,
 	} else {
 		to_etnaviv_bo(obj)->ops = &etnaviv_gem_shmem_ops;
 		ret = drm_gem_object_init(dev, obj, size);
+		if (ret == 0) {
+			struct address_space *mapping;
+
+			/*
+			 * Our buffers are kept pinned, so allocating them
+			 * from the MOVABLE zone is a really bad idea, and
+			 * conflicts with CMA.  See coments above new_inode()
+			 * why this is required _and_ expected if you're
+			 * going to pin these pages.
+			 */
+			mapping = file_inode(obj->filp)->i_mapping;
+			mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
+		}
 	}
 
 	if (ret)