diff options
Diffstat (limited to 'drivers/gpu/drm/drm_auth.c')
| -rw-r--r-- | drivers/gpu/drm/drm_auth.c | 96 | 
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);  |