[PATCH 1/2 v3] drm/exynos: added userptr limit ioctl.

Inki Dae inki.dae at samsung.com
Tue May 8 23:17:38 PDT 2012


this ioctl is used to limit user-desired userptr size as pre-defined
and also could be accessed by only root user.

with userptr feature, unprivileged user can allocate all the pages on system,
so the amount of free physical pages will be very limited. if the VMAs
within user address space was locked, the pages couldn't be swapped out so
it may result in significant degradation of system performance. so this
feature would be used to avoid such situation.

Signed-off-by: Inki Dae <inki.dae at samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_drv.c |    6 ++++++
 drivers/gpu/drm/exynos/exynos_drm_drv.h |    6 ++++++
 drivers/gpu/drm/exynos/exynos_drm_gem.c |   22 ++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_gem.h |    3 +++
 include/drm/exynos_drm.h                |   17 +++++++++++++++++
 5 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 9d3204c..1e68ec2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -64,6 +64,9 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 		return -ENOMEM;
 	}
 
+	/* maximum size of userptr is limited to 16MB as default. */
+	private->userptr_limit = SZ_16M;
+
 	INIT_LIST_HEAD(&private->pageflip_event_list);
 	dev->dev_private = (void *)private;
 
@@ -221,6 +224,9 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
 			exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
 			exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
+	DRM_IOCTL_DEF_DRV(EXYNOS_USER_LIMIT,
+			exynos_drm_gem_user_limit_ioctl, DRM_MASTER |
+			DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
 			DRM_UNLOCKED | DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index c82c90c..b38ed6f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -235,6 +235,12 @@ struct exynos_drm_private {
 	 * this array is used to be aware of which crtc did it request vblank.
 	 */
 	struct drm_crtc *crtc[MAX_CRTC];
+
+	/*
+	 * maximum size of allocation by userptr feature.
+	 * - as default, this has 16MB and only root user can change it.
+	 */
+	unsigned long userptr_limit;
 };
 
 /*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index fc91293..e6abb66 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -33,6 +33,8 @@
 #include "exynos_drm_gem.h"
 #include "exynos_drm_buf.h"
 
+#define USERPTR_MAX_SIZE		SZ_64M
+
 static unsigned int convert_to_vm_err_msg(int msg)
 {
 	unsigned int out_msg;
@@ -630,6 +632,26 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
 	return 0;
 }
 
+int exynos_drm_gem_user_limit_ioctl(struct drm_device *dev, void *data,
+				      struct drm_file *filp)
+{
+	struct exynos_drm_private *priv = dev->dev_private;
+	struct drm_exynos_user_limit *limit = data;
+
+	if (limit->userptr_limit < PAGE_SIZE ||
+			limit->userptr_limit > USERPTR_MAX_SIZE) {
+		DRM_DEBUG_KMS("invalid userptr_limit size.\n");
+		return -EINVAL;
+	}
+
+	if (priv->userptr_limit == limit->userptr_limit)
+		return 0;
+
+	priv->userptr_limit = limit->userptr_limit;
+
+	return 0;
+}
+
 int exynos_drm_gem_init_object(struct drm_gem_object *obj)
 {
 	DRM_DEBUG_KMS("%s\n", __FILE__);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index 14d038b..3334c9f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -78,6 +78,9 @@ struct exynos_drm_gem_obj {
 
 struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
 
+int exynos_drm_gem_user_limit_ioctl(struct drm_device *dev, void *data,
+				      struct drm_file *filp);
+
 /* destroy a buffer with gem object */
 void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
 
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index 54c97e8..52465dc 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -92,6 +92,19 @@ struct drm_exynos_gem_info {
 };
 
 /**
+ * A structure to userptr limited information.
+ *
+ * @userptr_limit: maximum size to userptr buffer.
+ *	the buffer could be allocated by unprivileged user using malloc()
+ *	and the size of the buffer would be limited as userptr_limit value.
+ * @pad: just padding to be 64-bit aligned.
+ */
+struct drm_exynos_user_limit {
+	unsigned int userptr_limit;
+	unsigned int pad;
+};
+
+/**
  * A structure for user connection request of virtual display.
  *
  * @connection: indicate whether doing connetion or not by user.
@@ -162,6 +175,7 @@ struct drm_exynos_g2d_exec {
 #define DRM_EXYNOS_GEM_MMAP		0x02
 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
 #define DRM_EXYNOS_GEM_GET		0x04
+#define DRM_EXYNOS_USER_LIMIT		0x05
 #define DRM_EXYNOS_PLANE_SET_ZPOS	0x06
 #define DRM_EXYNOS_VIDI_CONNECTION	0x07
 
@@ -182,6 +196,9 @@ struct drm_exynos_g2d_exec {
 #define DRM_IOCTL_EXYNOS_GEM_GET	DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_GEM_GET,	struct drm_exynos_gem_info)
 
+#define DRM_IOCTL_EXYNOS_USER_LIMIT	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_USER_LIMIT,	struct drm_exynos_user_limit)
+
 #define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS	DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
 
-- 
1.7.4.1



More information about the dri-devel mailing list