drm: add minor-lookup/release helpers
Instead of accessing drm_minors_idr directly, this adds a small helper to hide the internals. This will help us later to remove the drm_global_mutex requirement for minor-lookup. Furthermore, this also makes sure that minor->dev is always valid and takes a reference-count to the device as long as the minor is used in an open-file. This way, "struct file*"->private_data->dev is guaranteed to be valid (which it has to, as we cannot reset it). Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
099d1c290e
commit
1616c525b9
|
@ -79,23 +79,22 @@ static int drm_setup(struct drm_device * dev)
|
||||||
*/
|
*/
|
||||||
int drm_open(struct inode *inode, struct file *filp)
|
int drm_open(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = NULL;
|
struct drm_device *dev;
|
||||||
int minor_id = iminor(inode);
|
|
||||||
struct drm_minor *minor;
|
struct drm_minor *minor;
|
||||||
int retcode = 0;
|
int retcode;
|
||||||
int need_setup = 0;
|
int need_setup = 0;
|
||||||
struct address_space *old_mapping;
|
struct address_space *old_mapping;
|
||||||
struct address_space *old_imapping;
|
struct address_space *old_imapping;
|
||||||
|
|
||||||
minor = idr_find(&drm_minors_idr, minor_id);
|
minor = drm_minor_acquire(iminor(inode));
|
||||||
if (!minor)
|
if (IS_ERR(minor))
|
||||||
return -ENODEV;
|
return PTR_ERR(minor);
|
||||||
|
|
||||||
if (!(dev = minor->dev))
|
dev = minor->dev;
|
||||||
return -ENODEV;
|
if (drm_device_is_unplugged(dev)) {
|
||||||
|
retcode = -ENODEV;
|
||||||
if (drm_device_is_unplugged(dev))
|
goto err_release;
|
||||||
return -ENODEV;
|
}
|
||||||
|
|
||||||
if (!dev->open_count++)
|
if (!dev->open_count++)
|
||||||
need_setup = 1;
|
need_setup = 1;
|
||||||
|
@ -128,6 +127,8 @@ err_undo:
|
||||||
dev->dev_mapping = old_mapping;
|
dev->dev_mapping = old_mapping;
|
||||||
mutex_unlock(&dev->struct_mutex);
|
mutex_unlock(&dev->struct_mutex);
|
||||||
dev->open_count--;
|
dev->open_count--;
|
||||||
|
err_release:
|
||||||
|
drm_minor_release(minor);
|
||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_open);
|
EXPORT_SYMBOL(drm_open);
|
||||||
|
@ -143,33 +144,33 @@ EXPORT_SYMBOL(drm_open);
|
||||||
*/
|
*/
|
||||||
int drm_stub_open(struct inode *inode, struct file *filp)
|
int drm_stub_open(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = NULL;
|
struct drm_device *dev;
|
||||||
struct drm_minor *minor;
|
struct drm_minor *minor;
|
||||||
int minor_id = iminor(inode);
|
|
||||||
int err = -ENODEV;
|
int err = -ENODEV;
|
||||||
const struct file_operations *new_fops;
|
const struct file_operations *new_fops;
|
||||||
|
|
||||||
DRM_DEBUG("\n");
|
DRM_DEBUG("\n");
|
||||||
|
|
||||||
mutex_lock(&drm_global_mutex);
|
mutex_lock(&drm_global_mutex);
|
||||||
minor = idr_find(&drm_minors_idr, minor_id);
|
minor = drm_minor_acquire(iminor(inode));
|
||||||
if (!minor)
|
if (IS_ERR(minor))
|
||||||
goto out;
|
goto out_unlock;
|
||||||
|
|
||||||
if (!(dev = minor->dev))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
|
dev = minor->dev;
|
||||||
if (drm_device_is_unplugged(dev))
|
if (drm_device_is_unplugged(dev))
|
||||||
goto out;
|
goto out_release;
|
||||||
|
|
||||||
new_fops = fops_get(dev->driver->fops);
|
new_fops = fops_get(dev->driver->fops);
|
||||||
if (!new_fops)
|
if (!new_fops)
|
||||||
goto out;
|
goto out_release;
|
||||||
|
|
||||||
replace_fops(filp, new_fops);
|
replace_fops(filp, new_fops);
|
||||||
if (filp->f_op->open)
|
if (filp->f_op->open)
|
||||||
err = filp->f_op->open(inode, filp);
|
err = filp->f_op->open(inode, filp);
|
||||||
out:
|
|
||||||
|
out_release:
|
||||||
|
drm_minor_release(minor);
|
||||||
|
out_unlock:
|
||||||
mutex_unlock(&drm_global_mutex);
|
mutex_unlock(&drm_global_mutex);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -453,7 +454,8 @@ int drm_lastclose(struct drm_device * dev)
|
||||||
int drm_release(struct inode *inode, struct file *filp)
|
int drm_release(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct drm_file *file_priv = filp->private_data;
|
struct drm_file *file_priv = filp->private_data;
|
||||||
struct drm_device *dev = file_priv->minor->dev;
|
struct drm_minor *minor = file_priv->minor;
|
||||||
|
struct drm_device *dev = minor->dev;
|
||||||
int retcode = 0;
|
int retcode = 0;
|
||||||
|
|
||||||
mutex_lock(&drm_global_mutex);
|
mutex_lock(&drm_global_mutex);
|
||||||
|
@ -575,6 +577,8 @@ int drm_release(struct inode *inode, struct file *filp)
|
||||||
}
|
}
|
||||||
mutex_unlock(&drm_global_mutex);
|
mutex_unlock(&drm_global_mutex);
|
||||||
|
|
||||||
|
drm_minor_release(minor);
|
||||||
|
|
||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_release);
|
EXPORT_SYMBOL(drm_release);
|
||||||
|
|
|
@ -355,6 +355,45 @@ static void drm_unplug_minor(struct drm_minor *minor)
|
||||||
idr_remove(&drm_minors_idr, minor->index);
|
idr_remove(&drm_minors_idr, minor->index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_minor_acquire - Acquire a DRM minor
|
||||||
|
* @minor_id: Minor ID of the DRM-minor
|
||||||
|
*
|
||||||
|
* Looks up the given minor-ID and returns the respective DRM-minor object. The
|
||||||
|
* refence-count of the underlying device is increased so you must release this
|
||||||
|
* object with drm_minor_release().
|
||||||
|
*
|
||||||
|
* As long as you hold this minor, it is guaranteed that the object and the
|
||||||
|
* minor->dev pointer will stay valid! However, the device may get unplugged and
|
||||||
|
* unregistered while you hold the minor.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Pointer to minor-object with increased device-refcount, or PTR_ERR on
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
struct drm_minor *drm_minor_acquire(unsigned int minor_id)
|
||||||
|
{
|
||||||
|
struct drm_minor *minor;
|
||||||
|
|
||||||
|
minor = idr_find(&drm_minors_idr, minor_id);
|
||||||
|
if (!minor)
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
|
drm_dev_ref(minor->dev);
|
||||||
|
return minor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_minor_release - Release DRM minor
|
||||||
|
* @minor: Pointer to DRM minor object
|
||||||
|
*
|
||||||
|
* Release a minor that was previously acquired via drm_minor_acquire().
|
||||||
|
*/
|
||||||
|
void drm_minor_release(struct drm_minor *minor)
|
||||||
|
{
|
||||||
|
drm_dev_unref(minor->dev);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_put_minor - Destroy DRM minor
|
* drm_put_minor - Destroy DRM minor
|
||||||
* @minor: Minor to destroy
|
* @minor: Minor to destroy
|
||||||
|
|
|
@ -1672,6 +1672,10 @@ void drm_dev_ref(struct drm_device *dev);
|
||||||
void drm_dev_unref(struct drm_device *dev);
|
void drm_dev_unref(struct drm_device *dev);
|
||||||
int drm_dev_register(struct drm_device *dev, unsigned long flags);
|
int drm_dev_register(struct drm_device *dev, unsigned long flags);
|
||||||
void drm_dev_unregister(struct drm_device *dev);
|
void drm_dev_unregister(struct drm_device *dev);
|
||||||
|
|
||||||
|
struct drm_minor *drm_minor_acquire(unsigned int minor_id);
|
||||||
|
void drm_minor_release(struct drm_minor *minor);
|
||||||
|
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
/* PCI section */
|
/* PCI section */
|
||||||
|
|
Loading…
Reference in New Issue