diff mbox

drm/exynos: fix deadlock issue at mmap

Message ID 1379932951-9089-1-git-send-email-inki.dae@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Inki Dae Sept. 23, 2013, 10:42 a.m. UTC
This patch fixes the deadlock issue when another process requested
mmap system call.

This issue can incur the deadlock if another process sharing the same
file called mmap system call between ->f_op pointer chaning and restoring.

So this patch calls down_write(&mm->mmap_sem) before do_mmap_pgoff
call and then up_write(&mm->mmap_sem) after do_mmap_pg_off call
so that when another process called mmap system call, the process
can wait for up_write() call until the ->f_op pointer is restored.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_gem.c |   20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

Comments

Inki Dae Sept. 24, 2013, 4:58 a.m. UTC | #1
Please, ignore this patch. This patch has still some problems. I will post
it later.

Thanks,
Inki Dae

> -----Original Message-----
> From: Inki Dae [mailto:inki.dae@samsung.com]
> Sent: Monday, September 23, 2013 7:43 PM
> To: airlied@linux.ie; dri-devel@lists.freedesktop.org
> Cc: Inki Dae; Kyungmin Park
> Subject: [PATCH] drm/exynos: fix deadlock issue at mmap
> 
> This patch fixes the deadlock issue when another process requested
> mmap system call.
> 
> This issue can incur the deadlock if another process sharing the same
> file called mmap system call between ->f_op pointer chaning and restoring.
> 
> So this patch calls down_write(&mm->mmap_sem) before do_mmap_pgoff
> call and then up_write(&mm->mmap_sem) after do_mmap_pg_off call
> so that when another process called mmap system call, the process
> can wait for up_write() call until the ->f_op pointer is restored.
> 
> Signed-off-by: Inki Dae <inki.dae@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  drivers/gpu/drm/exynos/exynos_drm_gem.c |   20 ++++++++++++++++++--
>  1 file changed, 18 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c
> b/drivers/gpu/drm/exynos/exynos_drm_gem.c
> index 49f9cd2..779c2d7 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
> @@ -13,6 +13,7 @@
>  #include <drm/drm_vma_manager.h>
> 
>  #include <linux/shmem_fs.h>
> +#include <linux/security.h>
>  #include <drm/exynos_drm.h>
> 
>  #include "exynos_drm_drv.h"
> @@ -420,6 +421,7 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev,
> void *data,
>  {
>  	struct drm_exynos_gem_mmap *args = data;
>  	struct drm_gem_object *obj;
> +	struct mm_struct *mm = current->mm;
>  	unsigned long addr;
> 
>  	if (!(dev->driver->driver_features & DRIVER_GEM)) {
> @@ -433,6 +435,8 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev,
> void *data,
>  		return -EINVAL;
>  	}
> 
> +	down_write(&mm->mmap_sem);
> +
>  	/*
>  	 * We have to use gem object and its fops for specific mmaper,
>  	 * but vm_mmap() can deliver only filp. So we have to change
> @@ -457,8 +461,17 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev,
> void *data,
>  	 */
>  	file_priv->filp->private_data = obj;
> 
> -	addr = vm_mmap(file_priv->filp, 0, args->size,
> -			PROT_READ | PROT_WRITE, MAP_SHARED, 0);
> +	addr = security_mmap_file(file_priv->filp, PROT_READ | PROT_WRITE,
> +					MAP_SHARED);
> +	if (!addr) {
> +		unsigned long populate;
> +
> +		addr = do_mmap_pgoff(file_priv->filp, 0, args->size,
> +					PROT_READ | PROT_WRITE,
> +					MAP_SHARED, 0, &populate);
> +		if (populate)
> +			mm_populate(addr, populate);
> +	}
> 
>  	drm_gem_object_unreference(obj);
> 
> @@ -469,10 +482,13 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device
*dev,
> void *data,
>  			file_priv->filp->private_data = file_priv;
>  		}
>  		mutex_unlock(&dev->struct_mutex);
> +		up_write(&mm->mmap_sem);
> +
>  		return (int)addr;
>  	}
> 
>  	mutex_unlock(&dev->struct_mutex);
> +	up_write(&mm->mmap_sem);
> 
>  	args->mapped = addr;
> 
> --
> 1.7.9.5
diff mbox

Patch

diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 49f9cd2..779c2d7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -13,6 +13,7 @@ 
 #include <drm/drm_vma_manager.h>
 
 #include <linux/shmem_fs.h>
+#include <linux/security.h>
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
@@ -420,6 +421,7 @@  int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_exynos_gem_mmap *args = data;
 	struct drm_gem_object *obj;
+	struct mm_struct *mm = current->mm;
 	unsigned long addr;
 
 	if (!(dev->driver->driver_features & DRIVER_GEM)) {
@@ -433,6 +435,8 @@  int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
 		return -EINVAL;
 	}
 
+	down_write(&mm->mmap_sem);
+
 	/*
 	 * We have to use gem object and its fops for specific mmaper,
 	 * but vm_mmap() can deliver only filp. So we have to change
@@ -457,8 +461,17 @@  int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
 	 */
 	file_priv->filp->private_data = obj;
 
-	addr = vm_mmap(file_priv->filp, 0, args->size,
-			PROT_READ | PROT_WRITE, MAP_SHARED, 0);
+	addr = security_mmap_file(file_priv->filp, PROT_READ | PROT_WRITE,
+					MAP_SHARED);
+	if (!addr) {
+		unsigned long populate;
+
+		addr = do_mmap_pgoff(file_priv->filp, 0, args->size,
+					PROT_READ | PROT_WRITE,
+					MAP_SHARED, 0, &populate);
+		if (populate)
+			mm_populate(addr, populate);
+	}
 
 	drm_gem_object_unreference(obj);
 
@@ -469,10 +482,13 @@  int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
 			file_priv->filp->private_data = file_priv;
 		}
 		mutex_unlock(&dev->struct_mutex);
+		up_write(&mm->mmap_sem);
+
 		return (int)addr;
 	}
 
 	mutex_unlock(&dev->struct_mutex);
+	up_write(&mm->mmap_sem);
 
 	args->mapped = addr;