summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2014-01-29 10:49:19 +0100
committerDavid Herrmann <dh.herrmann@gmail.com>2014-03-16 12:25:17 +0100
commit1616c525b98deb34b8f4b02eccf0ae3a1310fa27 (patch)
treed28625fe2ae686919c757df8ec6b8940e0d46d22 /drivers/gpu/drm
parent099d1c290e2ebc3b798961a6c177c3aef5f0b789 (diff)
downloadlinux-0-day-1616c525b98deb34b8f4b02eccf0ae3a1310fa27.tar.gz
linux-0-day-1616c525b98deb34b8f4b02eccf0ae3a1310fa27.tar.xz
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>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/drm_fops.c50
-rw-r--r--drivers/gpu/drm/drm_stub.c39
2 files changed, 66 insertions, 23 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 6466cb5d8b1ff..79478191404ad 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -79,23 +79,22 @@ static int drm_setup(struct drm_device * dev)
*/
int drm_open(struct inode *inode, struct file *filp)
{
- struct drm_device *dev = NULL;
- int minor_id = iminor(inode);
+ struct drm_device *dev;
struct drm_minor *minor;
- int retcode = 0;
+ int retcode;
int need_setup = 0;
struct address_space *old_mapping;
struct address_space *old_imapping;
- minor = idr_find(&drm_minors_idr, minor_id);
- if (!minor)
- return -ENODEV;
-
- if (!(dev = minor->dev))
- return -ENODEV;
+ minor = drm_minor_acquire(iminor(inode));
+ if (IS_ERR(minor))
+ return PTR_ERR(minor);
- if (drm_device_is_unplugged(dev))
- return -ENODEV;
+ dev = minor->dev;
+ if (drm_device_is_unplugged(dev)) {
+ retcode = -ENODEV;
+ goto err_release;
+ }
if (!dev->open_count++)
need_setup = 1;
@@ -128,6 +127,8 @@ err_undo:
dev->dev_mapping = old_mapping;
mutex_unlock(&dev->struct_mutex);
dev->open_count--;
+err_release:
+ drm_minor_release(minor);
return retcode;
}
EXPORT_SYMBOL(drm_open);
@@ -143,33 +144,33 @@ EXPORT_SYMBOL(drm_open);
*/
int drm_stub_open(struct inode *inode, struct file *filp)
{
- struct drm_device *dev = NULL;
+ struct drm_device *dev;
struct drm_minor *minor;
- int minor_id = iminor(inode);
int err = -ENODEV;
const struct file_operations *new_fops;
DRM_DEBUG("\n");
mutex_lock(&drm_global_mutex);
- minor = idr_find(&drm_minors_idr, minor_id);
- if (!minor)
- goto out;
-
- if (!(dev = minor->dev))
- goto out;
+ minor = drm_minor_acquire(iminor(inode));
+ if (IS_ERR(minor))
+ goto out_unlock;
+ dev = minor->dev;
if (drm_device_is_unplugged(dev))
- goto out;
+ goto out_release;
new_fops = fops_get(dev->driver->fops);
if (!new_fops)
- goto out;
+ goto out_release;
replace_fops(filp, new_fops);
if (filp->f_op->open)
err = filp->f_op->open(inode, filp);
-out:
+
+out_release:
+ drm_minor_release(minor);
+out_unlock:
mutex_unlock(&drm_global_mutex);
return err;
}
@@ -453,7 +454,8 @@ int drm_lastclose(struct drm_device * dev)
int drm_release(struct inode *inode, struct file *filp)
{
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;
mutex_lock(&drm_global_mutex);
@@ -575,6 +577,8 @@ int drm_release(struct inode *inode, struct file *filp)
}
mutex_unlock(&drm_global_mutex);
+ drm_minor_release(minor);
+
return retcode;
}
EXPORT_SYMBOL(drm_release);
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index f2f0249304b71..269048215e826 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -356,6 +356,45 @@ static void drm_unplug_minor(struct drm_minor *minor)
}
/**
+ * 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
* @minor: Minor to destroy
*