aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_auth.c')
-rw-r--r--drivers/gpu/drm/drm_auth.c96
1 files changed, 70 insertions, 26 deletions
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index b59b26a71ad5..60a6b21474b1 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -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)
@@ -61,6 +61,36 @@
* 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);
@@ -344,22 +379,6 @@ out:
}
/**
- * 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);