Merge tag 'defconfig-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / gpu / drm / drm_auth.c
index b59b26a..60a6b21 100644 (file)
@@ -52,7 +52,7 @@
  *
  * In addition only one &drm_master can be the current master for a &drm_device.
  * It can be switched through the DROP_MASTER and SET_MASTER IOCTL, or
- * implicitly through closing/openeing the primary device node. See also
+ * implicitly through closing/opening the primary device node. See also
  * drm_is_current_master().
  *
  * Clients can authenticate against the current master (if it matches their own)
  * trusted clients.
  */
 
+static bool drm_is_current_master_locked(struct drm_file *fpriv)
+{
+       lockdep_assert_once(lockdep_is_held(&fpriv->master_lookup_lock) ||
+                           lockdep_is_held(&fpriv->minor->dev->master_mutex));
+
+       return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
+}
+
+/**
+ * drm_is_current_master - checks whether @priv is the current master
+ * @fpriv: DRM file private
+ *
+ * Checks whether @fpriv is current master on its device. This decides whether a
+ * client is allowed to run DRM_MASTER IOCTLs.
+ *
+ * Most of the modern IOCTL which require DRM_MASTER are for kernel modesetting
+ * - the current master is assumed to own the non-shareable display hardware.
+ */
+bool drm_is_current_master(struct drm_file *fpriv)
+{
+       bool ret;
+
+       spin_lock(&fpriv->master_lookup_lock);
+       ret = drm_is_current_master_locked(fpriv);
+       spin_unlock(&fpriv->master_lookup_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_is_current_master);
+
 int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_auth *auth = data;
@@ -135,16 +165,18 @@ static void drm_set_master(struct drm_device *dev, struct drm_file *fpriv,
 static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
 {
        struct drm_master *old_master;
+       struct drm_master *new_master;
 
        lockdep_assert_held_once(&dev->master_mutex);
 
        WARN_ON(fpriv->is_master);
        old_master = fpriv->master;
-       fpriv->master = drm_master_create(dev);
-       if (!fpriv->master) {
-               fpriv->master = old_master;
+       new_master = drm_master_create(dev);
+       if (!new_master)
                return -ENOMEM;
-       }
+       spin_lock(&fpriv->master_lookup_lock);
+       fpriv->master = new_master;
+       spin_unlock(&fpriv->master_lookup_lock);
 
        fpriv->is_master = 1;
        fpriv->authenticated = 1;
@@ -223,7 +255,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
        if (ret)
                goto out_unlock;
 
-       if (drm_is_current_master(file_priv))
+       if (drm_is_current_master_locked(file_priv))
                goto out_unlock;
 
        if (dev->master) {
@@ -272,7 +304,7 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
        if (ret)
                goto out_unlock;
 
-       if (!drm_is_current_master(file_priv)) {
+       if (!drm_is_current_master_locked(file_priv)) {
                ret = -EINVAL;
                goto out_unlock;
        }
@@ -303,10 +335,13 @@ int drm_master_open(struct drm_file *file_priv)
         * any master object for render clients
         */
        mutex_lock(&dev->master_mutex);
-       if (!dev->master)
+       if (!dev->master) {
                ret = drm_new_set_master(dev, file_priv);
-       else
+       } else {
+               spin_lock(&file_priv->master_lookup_lock);
                file_priv->master = drm_master_get(dev->master);
+               spin_unlock(&file_priv->master_lookup_lock);
+       }
        mutex_unlock(&dev->master_mutex);
 
        return ret;
@@ -322,7 +357,7 @@ void drm_master_release(struct drm_file *file_priv)
        if (file_priv->magic)
                idr_remove(&file_priv->master->magic_map, file_priv->magic);
 
-       if (!drm_is_current_master(file_priv))
+       if (!drm_is_current_master_locked(file_priv))
                goto out;
 
        drm_legacy_lock_master_cleanup(dev, master);
@@ -343,22 +378,6 @@ out:
        mutex_unlock(&dev->master_mutex);
 }
 
-/**
- * drm_is_current_master - checks whether @priv is the current master
- * @fpriv: DRM file private
- *
- * Checks whether @fpriv is current master on its device. This decides whether a
- * client is allowed to run DRM_MASTER IOCTLs.
- *
- * Most of the modern IOCTL which require DRM_MASTER are for kernel modesetting
- * - the current master is assumed to own the non-shareable display hardware.
- */
-bool drm_is_current_master(struct drm_file *fpriv)
-{
-       return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
-}
-EXPORT_SYMBOL(drm_is_current_master);
-
 /**
  * drm_master_get - reference a master pointer
  * @master: &struct drm_master
@@ -372,6 +391,31 @@ struct drm_master *drm_master_get(struct drm_master *master)
 }
 EXPORT_SYMBOL(drm_master_get);
 
+/**
+ * drm_file_get_master - reference &drm_file.master of @file_priv
+ * @file_priv: DRM file private
+ *
+ * Increments the reference count of @file_priv's &drm_file.master and returns
+ * the &drm_file.master. If @file_priv has no &drm_file.master, returns NULL.
+ *
+ * Master pointers returned from this function should be unreferenced using
+ * drm_master_put().
+ */
+struct drm_master *drm_file_get_master(struct drm_file *file_priv)
+{
+       struct drm_master *master = NULL;
+
+       spin_lock(&file_priv->master_lookup_lock);
+       if (!file_priv->master)
+               goto unlock;
+       master = drm_master_get(file_priv->master);
+
+unlock:
+       spin_unlock(&file_priv->master_lookup_lock);
+       return master;
+}
+EXPORT_SYMBOL(drm_file_get_master);
+
 static void drm_master_destroy(struct kref *kref)
 {
        struct drm_master *master = container_of(kref, struct drm_master, refcount);