From a839ed599343541edd84a37691376636d835079f Mon Sep 17 00:00:00 2001 From: Vladislav Andresov Date: Tue, 24 Apr 2018 01:11:08 +0300 Subject: [PATCH] fix deadlock in drm_mode_obj_set_property_ioctl Change-Id: I558a2e00c077d6c19de82acb4214d39999034c7f Signed-off-by: Vladislav Andresov (cherry picked from commit f6fd5336d495cf1f731c85d041e79cf3cf3a8e2b) --- drivers/gpu/drm/drm_crtc.c | 2 ++ drivers/gpu/drm/drm_fb_helper.c | 14 ++++++++++---- drivers/gpu/drm/drm_modeset_lock.c | 18 ++++++++++++++++++ drivers/gpu/drm/vigs/vigs_fbdev.c | 14 ++++++++++---- include/drm/drm_modeset_lock.h | 5 +++++ 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5e4bb48..6f65f06 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4966,6 +4966,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, return -EINVAL; drm_modeset_lock_all(dev); + drm_modeset_set_locker_all(dev, current); arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); if (!arg_obj) { @@ -5010,6 +5011,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, drm_property_change_valid_put(property, ref); out: + drm_modeset_set_locker_all(dev, NULL); drm_modeset_unlock_all(dev); return ret; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 5ad0367..d121492 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1294,14 +1294,18 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, struct drm_mode_set *modeset; int ret = 0; int i; + bool need_lock = current != drm_modeset_get_locker_all(dev); if (oops_in_progress) return -EBUSY; - drm_modeset_lock_all(dev); + if (need_lock) { + drm_modeset_lock_all(dev); + } + if (!drm_fb_helper_is_bound(fb_helper)) { - drm_modeset_unlock_all(dev); - return -EBUSY; + ret = -EBUSY; + goto unlock; } if (fb_helper->atomic) { @@ -1324,7 +1328,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, } } unlock: - drm_modeset_unlock_all(dev); + if (need_lock) { + drm_modeset_unlock_all(dev); + } return ret; } EXPORT_SYMBOL(drm_fb_helper_pan_display); diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 6675b14..66db681 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -455,3 +455,21 @@ int drm_modeset_lock_all_crtcs(struct drm_device *dev, return 0; } EXPORT_SYMBOL(drm_modeset_lock_all_crtcs); + +struct task_struct *drm_modeset_get_locker_all(struct drm_device *dev) +{ +#if defined(CONFIG_MUTEX_SPIN_ON_OWNER) + return ((struct mutex *)&dev->mode_config.mutex)->owner; +#endif + return NULL; +} +EXPORT_SYMBOL(drm_modeset_get_locker_all); + +void drm_modeset_set_locker_all(struct drm_device *dev, + struct task_struct *locker) +{ +#if defined(CONFIG_MUTEX_SPIN_ON_OWNER) + ((struct mutex *)&dev->mode_config.mutex)->owner = locker; +#endif +} +EXPORT_SYMBOL(drm_modeset_set_locker_all); diff --git a/drivers/gpu/drm/vigs/vigs_fbdev.c b/drivers/gpu/drm/vigs/vigs_fbdev.c index 11468ea..2f7803f 100644 --- a/drivers/gpu/drm/vigs/vigs_fbdev.c +++ b/drivers/gpu/drm/vigs/vigs_fbdev.c @@ -125,11 +125,15 @@ static int vigs_fbdev_setcmap(struct fb_cmap *cmap, struct fb_info *fbi) struct drm_crtc *crtc; int i, j, ret = 0; int start; + bool need_lock = current != drm_modeset_get_locker_all(dev); + + if (need_lock) { + drm_modeset_lock_all(dev); + } - drm_modeset_lock_all(dev); if (!vigs_fbdev_helper_is_bound(fb_helper)) { - drm_modeset_unlock_all(dev); - return -EBUSY; + ret = -EBUSY; + goto out; } for (i = 0; i < fb_helper->crtc_count; i++) { @@ -166,7 +170,9 @@ static int vigs_fbdev_setcmap(struct fb_cmap *cmap, struct fb_info *fbi) } out: - drm_modeset_unlock_all(dev); + if (need_lock) { + drm_modeset_unlock_all(dev); + } return ret; } diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 94938d8..7bde5a9 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -141,4 +141,9 @@ drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc); int drm_modeset_lock_all_crtcs(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +struct task_struct *drm_modeset_get_locker_all(struct drm_device *dev); + +void drm_modeset_set_locker_all(struct drm_device *dev, + struct task_struct *locker); + #endif /* DRM_MODESET_LOCK_H_ */ -- 2.7.4