fix deadlock in drm_mode_obj_set_property_ioctl 77/177377/1
authorVladislav Andresov <v.andresov@partner.samsung.com>
Mon, 23 Apr 2018 22:11:08 +0000 (01:11 +0300)
committerVladislav Andresov <v.andresov@partner.samsung.com>
Fri, 27 Apr 2018 11:21:02 +0000 (14:21 +0300)
Change-Id: I558a2e00c077d6c19de82acb4214d39999034c7f
Signed-off-by: Vladislav Andresov <v.andresov@partner.samsung.com>
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 5e4bb4837bae7216cbdc8ea64b9ae2e7429646fa..6f65f06c37a0cb99aad17ff8f0d7c1d0e4e5e565 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 5ad036741b9945e4deb0336a9476f043a4fff94a..d12149296c9905baca2de1f1709121d726117fd1 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 6675b14284105cd639fb7fbb7ee9967cfcc38aa9..66db681c750dd376d12c05ab90ba273e7fa1deb5 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 11468ea4c335a066cfbe17f38bbd480e3ddcd399..2f7803f7aeb9a77684c5e111582ee4e8a8c2e540 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 94938d89347cf2f8860f617f28ab68d5134bacce..7bde5a9991cfabe065610dafcbbdd1575ee2a003 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_ */