aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/exynos/exynos_drm_gem.c
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2013-12-20 05:16:24 -0500
committerInki Dae <inki.dae@samsung.com>2014-01-07 02:51:41 -0500
commit96f5421523dfdcfb67e66e0f51c4b64d2c12137c (patch)
tree6cbb770065605940e8d1d89b902c198a8dff4fb5 /drivers/gpu/drm/exynos/exynos_drm_gem.c
parentfe3c703c3d80bd4c2da0d47a7d56930926af7cbc (diff)
drm/exynos: use a new anon file for exynos gem mmaper
This patch resolves potential deadlock issue that can be incurred by changing file->f_op and filp->private_data to exynos specific mapper ops and gem object temporarily. To resolve this issue, this patch creates a new anon file dedicated to exynos specific mmaper, and making it used instead of existing one. Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_gem.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c74
1 files changed, 13 insertions, 61 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 1ade191d84f4..49b8c9b22902 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -338,46 +338,22 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
338 &args->offset); 338 &args->offset);
339} 339}
340 340
341static struct drm_file *exynos_drm_find_drm_file(struct drm_device *drm_dev, 341int exynos_drm_gem_mmap_buffer(struct file *filp,
342 struct file *filp)
343{
344 struct drm_file *file_priv;
345
346 /* find current process's drm_file from filelist. */
347 list_for_each_entry(file_priv, &drm_dev->filelist, lhead)
348 if (file_priv->filp == filp)
349 return file_priv;
350
351 WARN_ON(1);
352
353 return ERR_PTR(-EFAULT);
354}
355
356static int exynos_drm_gem_mmap_buffer(struct file *filp,
357 struct vm_area_struct *vma) 342 struct vm_area_struct *vma)
358{ 343{
359 struct drm_gem_object *obj = filp->private_data; 344 struct drm_gem_object *obj = filp->private_data;
360 struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 345 struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
361 struct drm_device *drm_dev = obj->dev; 346 struct drm_device *drm_dev = obj->dev;
362 struct exynos_drm_gem_buf *buffer; 347 struct exynos_drm_gem_buf *buffer;
363 struct drm_file *file_priv;
364 unsigned long vm_size; 348 unsigned long vm_size;
365 int ret; 349 int ret;
366 350
351 WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
352
367 vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; 353 vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
368 vma->vm_private_data = obj; 354 vma->vm_private_data = obj;
369 vma->vm_ops = drm_dev->driver->gem_vm_ops; 355 vma->vm_ops = drm_dev->driver->gem_vm_ops;
370 356
371 /* restore it to driver's fops. */
372 filp->f_op = fops_get(drm_dev->driver->fops);
373
374 file_priv = exynos_drm_find_drm_file(drm_dev, filp);
375 if (IS_ERR(file_priv))
376 return PTR_ERR(file_priv);
377
378 /* restore it to drm_file. */
379 filp->private_data = file_priv;
380
381 update_vm_cache_attr(exynos_gem_obj, vma); 357 update_vm_cache_attr(exynos_gem_obj, vma);
382 358
383 vm_size = vma->vm_end - vma->vm_start; 359 vm_size = vma->vm_end - vma->vm_start;
@@ -411,15 +387,13 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
411 return 0; 387 return 0;
412} 388}
413 389
414static const struct file_operations exynos_drm_gem_fops = {
415 .mmap = exynos_drm_gem_mmap_buffer,
416};
417
418int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, 390int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
419 struct drm_file *file_priv) 391 struct drm_file *file_priv)
420{ 392{
393 struct drm_exynos_file_private *exynos_file_priv;
421 struct drm_exynos_gem_mmap *args = data; 394 struct drm_exynos_gem_mmap *args = data;
422 struct drm_gem_object *obj; 395 struct drm_gem_object *obj;
396 struct file *anon_filp;
423 unsigned long addr; 397 unsigned long addr;
424 398
425 if (!(dev->driver->driver_features & DRIVER_GEM)) { 399 if (!(dev->driver->driver_features & DRIVER_GEM)) {
@@ -427,47 +401,25 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
427 return -ENODEV; 401 return -ENODEV;
428 } 402 }
429 403
404 mutex_lock(&dev->struct_mutex);
405
430 obj = drm_gem_object_lookup(dev, file_priv, args->handle); 406 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
431 if (!obj) { 407 if (!obj) {
432 DRM_ERROR("failed to lookup gem object.\n"); 408 DRM_ERROR("failed to lookup gem object.\n");
409 mutex_unlock(&dev->struct_mutex);
433 return -EINVAL; 410 return -EINVAL;
434 } 411 }
435 412
436 /* 413 exynos_file_priv = file_priv->driver_priv;
437 * We have to use gem object and its fops for specific mmaper, 414 anon_filp = exynos_file_priv->anon_filp;
438 * but vm_mmap() can deliver only filp. So we have to change 415 anon_filp->private_data = obj;
439 * filp->f_op and filp->private_data temporarily, then restore
440 * again. So it is important to keep lock until restoration the
441 * settings to prevent others from misuse of filp->f_op or
442 * filp->private_data.
443 */
444 mutex_lock(&dev->struct_mutex);
445
446 /*
447 * Set specific mmper's fops. And it will be restored by
448 * exynos_drm_gem_mmap_buffer to dev->driver->fops.
449 * This is used to call specific mapper temporarily.
450 */
451 file_priv->filp->f_op = &exynos_drm_gem_fops;
452
453 /*
454 * Set gem object to private_data so that specific mmaper
455 * can get the gem object. And it will be restored by
456 * exynos_drm_gem_mmap_buffer to drm_file.
457 */
458 file_priv->filp->private_data = obj;
459 416
460 addr = vm_mmap(file_priv->filp, 0, args->size, 417 addr = vm_mmap(anon_filp, 0, args->size, PROT_READ | PROT_WRITE,
461 PROT_READ | PROT_WRITE, MAP_SHARED, 0); 418 MAP_SHARED, 0);
462 419
463 drm_gem_object_unreference(obj); 420 drm_gem_object_unreference(obj);
464 421
465 if (IS_ERR_VALUE(addr)) { 422 if (IS_ERR_VALUE(addr)) {
466 /* check filp->f_op, filp->private_data are restored */
467 if (file_priv->filp->f_op == &exynos_drm_gem_fops) {
468 file_priv->filp->f_op = fops_get(dev->driver->fops);
469 file_priv->filp->private_data = file_priv;
470 }
471 mutex_unlock(&dev->struct_mutex); 423 mutex_unlock(&dev->struct_mutex);
472 return (int)addr; 424 return (int)addr;
473 } 425 }