drm: Protect the master management with a drm_device::master_mutex v3
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / gpu / drm / drm_stub.c
index fb514d2..5046180 100644 (file)
@@ -169,6 +169,7 @@ static void drm_master_destroy(struct kref *kref)
        struct drm_device *dev = master->minor->dev;
        struct drm_map_list *r_list, *list_temp;
 
+       mutex_lock(&dev->struct_mutex);
        if (dev->driver->master_destroy)
                dev->driver->master_destroy(dev, master);
 
@@ -196,6 +197,7 @@ static void drm_master_destroy(struct kref *kref)
 
        drm_ht_remove(&master->magiclist);
 
+       mutex_unlock(&dev->struct_mutex);
        kfree(master);
 }
 
@@ -211,19 +213,20 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
 {
        int ret = 0;
 
+       mutex_lock(&dev->master_mutex);
        if (file_priv->is_master)
-               return 0;
+               goto out_unlock;
 
-       if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
-               return -EINVAL;
-
-       if (!file_priv->master)
-               return -EINVAL;
+       if (file_priv->minor->master) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
 
-       if (file_priv->minor->master)
-               return -EINVAL;
+       if (!file_priv->master) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
 
-       mutex_lock(&dev->struct_mutex);
        file_priv->minor->master = drm_master_get(file_priv->master);
        file_priv->is_master = 1;
        if (dev->driver->master_set) {
@@ -233,27 +236,33 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
                        drm_master_put(&file_priv->minor->master);
                }
        }
-       mutex_unlock(&dev->struct_mutex);
 
+out_unlock:
+       mutex_unlock(&dev->master_mutex);
        return ret;
 }
 
 int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
+       int ret = -EINVAL;
+
+       mutex_lock(&dev->master_mutex);
        if (!file_priv->is_master)
-               return -EINVAL;
+               goto out_unlock;
 
        if (!file_priv->minor->master)
-               return -EINVAL;
+               goto out_unlock;
 
-       mutex_lock(&dev->struct_mutex);
+       ret = 0;
        if (dev->driver->master_drop)
                dev->driver->master_drop(dev, file_priv, false);
        drm_master_put(&file_priv->minor->master);
        file_priv->is_master = 0;
-       mutex_unlock(&dev->struct_mutex);
-       return 0;
+
+out_unlock:
+       mutex_unlock(&dev->master_mutex);
+       return ret;
 }
 
 static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
@@ -504,6 +513,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
        spin_lock_init(&dev->event_lock);
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);
+       mutex_init(&dev->master_mutex);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL);
@@ -556,6 +566,7 @@ err_minors:
        drm_put_minor(dev->control);
        drm_put_minor(dev->render);
        drm_put_minor(dev->primary);
+       mutex_destroy(&dev->master_mutex);
        kfree(dev);
        return NULL;
 }
@@ -585,6 +596,8 @@ void drm_dev_free(struct drm_device *dev)
        drm_fs_inode_free(dev->anon_inode);
 
        kfree(dev->devname);
+
+       mutex_destroy(&dev->master_mutex);
        kfree(dev);
 }
 EXPORT_SYMBOL(drm_dev_free);