fix deadlock in drm_mode_obj_set_property_ioctl 58/185858/1
authorVladislav Andresov <v.andresov@partner.samsung.com>
Mon, 23 Apr 2018 22:11:08 +0000 (01:11 +0300)
committerRahul Dadhich <r.dadhich@samsung.com>
Fri, 3 Aug 2018 05:00:05 +0000 (05:00 +0000)
Change-Id: I558a2e00c077d6c19de82acb4214d39999034c7f
Signed-off-by: Vladislav Andresov <v.andresov@partner.samsung.com>
(cherry picked from commit f6fd5336d495cf1f731c85d041e79cf3cf3a8e2b)

drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_modeset_lock.c
drivers/gpu/drm/vigs/vigs_fbdev.c
include/drm/drm_modeset_lock.h

index 5e4bb48..6f65f06 100644 (file)
@@ -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;
 }
index 5ad0367..d121492 100644 (file)
@@ -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);
index 6675b14..66db681 100644 (file)
@@ -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);
index 11468ea..2f7803f 100644 (file)
@@ -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;
 }
 
index 94938d8..7bde5a9 100644 (file)
@@ -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_ */