diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 50 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_stub.c | 39 |
2 files changed, 66 insertions, 23 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 6466cb5d8b1f..79478191404a 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) | |||
79 | */ | 79 | */ |
80 | int drm_open(struct inode *inode, struct file *filp) | 80 | int drm_open(struct inode *inode, struct file *filp) |
81 | { | 81 | { |
82 | struct drm_device *dev = NULL; | 82 | struct drm_device *dev; |
83 | int minor_id = iminor(inode); | ||
84 | struct drm_minor *minor; | 83 | struct drm_minor *minor; |
85 | int retcode = 0; | 84 | int retcode; |
86 | int need_setup = 0; | 85 | int need_setup = 0; |
87 | struct address_space *old_mapping; | 86 | struct address_space *old_mapping; |
88 | struct address_space *old_imapping; | 87 | struct address_space *old_imapping; |
89 | 88 | ||
90 | minor = idr_find(&drm_minors_idr, minor_id); | 89 | minor = drm_minor_acquire(iminor(inode)); |
91 | if (!minor) | 90 | if (IS_ERR(minor)) |
92 | return -ENODEV; | 91 | return PTR_ERR(minor); |
93 | |||
94 | if (!(dev = minor->dev)) | ||
95 | return -ENODEV; | ||
96 | 92 | ||
97 | if (drm_device_is_unplugged(dev)) | 93 | dev = minor->dev; |
98 | return -ENODEV; | 94 | if (drm_device_is_unplugged(dev)) { |
95 | retcode = -ENODEV; | ||
96 | goto err_release; | ||
97 | } | ||
99 | 98 | ||
100 | if (!dev->open_count++) | 99 | if (!dev->open_count++) |
101 | need_setup = 1; | 100 | need_setup = 1; |
@@ -128,6 +127,8 @@ err_undo: | |||
128 | dev->dev_mapping = old_mapping; | 127 | dev->dev_mapping = old_mapping; |
129 | mutex_unlock(&dev->struct_mutex); | 128 | mutex_unlock(&dev->struct_mutex); |
130 | dev->open_count--; | 129 | dev->open_count--; |
130 | err_release: | ||
131 | drm_minor_release(minor); | ||
131 | return retcode; | 132 | return retcode; |
132 | } | 133 | } |
133 | EXPORT_SYMBOL(drm_open); | 134 | EXPORT_SYMBOL(drm_open); |
@@ -143,33 +144,33 @@ EXPORT_SYMBOL(drm_open); | |||
143 | */ | 144 | */ |
144 | int drm_stub_open(struct inode *inode, struct file *filp) | 145 | int drm_stub_open(struct inode *inode, struct file *filp) |
145 | { | 146 | { |
146 | struct drm_device *dev = NULL; | 147 | struct drm_device *dev; |
147 | struct drm_minor *minor; | 148 | struct drm_minor *minor; |
148 | int minor_id = iminor(inode); | ||
149 | int err = -ENODEV; | 149 | int err = -ENODEV; |
150 | const struct file_operations *new_fops; | 150 | const struct file_operations *new_fops; |
151 | 151 | ||
152 | DRM_DEBUG("\n"); | 152 | DRM_DEBUG("\n"); |
153 | 153 | ||
154 | mutex_lock(&drm_global_mutex); | 154 | mutex_lock(&drm_global_mutex); |
155 | minor = idr_find(&drm_minors_idr, minor_id); | 155 | minor = drm_minor_acquire(iminor(inode)); |
156 | if (!minor) | 156 | if (IS_ERR(minor)) |
157 | goto out; | 157 | goto out_unlock; |
158 | |||
159 | if (!(dev = minor->dev)) | ||
160 | goto out; | ||
161 | 158 | ||
159 | dev = minor->dev; | ||
162 | if (drm_device_is_unplugged(dev)) | 160 | if (drm_device_is_unplugged(dev)) |
163 | goto out; | 161 | goto out_release; |
164 | 162 | ||
165 | new_fops = fops_get(dev->driver->fops); | 163 | new_fops = fops_get(dev->driver->fops); |
166 | if (!new_fops) | 164 | if (!new_fops) |
167 | goto out; | 165 | goto out_release; |
168 | 166 | ||
169 | replace_fops(filp, new_fops); | 167 | replace_fops(filp, new_fops); |
170 | if (filp->f_op->open) | 168 | if (filp->f_op->open) |
171 | err = filp->f_op->open(inode, filp); | 169 | err = filp->f_op->open(inode, filp); |
172 | out: | 170 | |
171 | out_release: | ||
172 | drm_minor_release(minor); | ||
173 | out_unlock: | ||
173 | mutex_unlock(&drm_global_mutex); | 174 | mutex_unlock(&drm_global_mutex); |
174 | return err; | 175 | return err; |
175 | } | 176 | } |
@@ -453,7 +454,8 @@ int drm_lastclose(struct drm_device * dev) | |||
453 | int drm_release(struct inode *inode, struct file *filp) | 454 | int drm_release(struct inode *inode, struct file *filp) |
454 | { | 455 | { |
455 | struct drm_file *file_priv = filp->private_data; | 456 | struct drm_file *file_priv = filp->private_data; |
456 | struct drm_device *dev = file_priv->minor->dev; | 457 | struct drm_minor *minor = file_priv->minor; |
458 | struct drm_device *dev = minor->dev; | ||
457 | int retcode = 0; | 459 | int retcode = 0; |
458 | 460 | ||
459 | mutex_lock(&drm_global_mutex); | 461 | mutex_lock(&drm_global_mutex); |
@@ -575,6 +577,8 @@ int drm_release(struct inode *inode, struct file *filp) | |||
575 | } | 577 | } |
576 | mutex_unlock(&drm_global_mutex); | 578 | mutex_unlock(&drm_global_mutex); |
577 | 579 | ||
580 | drm_minor_release(minor); | ||
581 | |||
578 | return retcode; | 582 | return retcode; |
579 | } | 583 | } |
580 | EXPORT_SYMBOL(drm_release); | 584 | EXPORT_SYMBOL(drm_release); |
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index f2f0249304b7..269048215e82 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) | |||
356 | } | 356 | } |
357 | 357 | ||
358 | /** | 358 | /** |
359 | * drm_minor_acquire - Acquire a DRM minor | ||
360 | * @minor_id: Minor ID of the DRM-minor | ||
361 | * | ||
362 | * Looks up the given minor-ID and returns the respective DRM-minor object. The | ||
363 | * refence-count of the underlying device is increased so you must release this | ||
364 | * object with drm_minor_release(). | ||
365 | * | ||
366 | * As long as you hold this minor, it is guaranteed that the object and the | ||
367 | * minor->dev pointer will stay valid! However, the device may get unplugged and | ||
368 | * unregistered while you hold the minor. | ||
369 | * | ||
370 | * Returns: | ||
371 | * Pointer to minor-object with increased device-refcount, or PTR_ERR on | ||
372 | * failure. | ||
373 | */ | ||
374 | struct drm_minor *drm_minor_acquire(unsigned int minor_id) | ||
375 | { | ||
376 | struct drm_minor *minor; | ||
377 | |||
378 | minor = idr_find(&drm_minors_idr, minor_id); | ||
379 | if (!minor) | ||
380 | return ERR_PTR(-ENODEV); | ||
381 | |||
382 | drm_dev_ref(minor->dev); | ||
383 | return minor; | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * drm_minor_release - Release DRM minor | ||
388 | * @minor: Pointer to DRM minor object | ||
389 | * | ||
390 | * Release a minor that was previously acquired via drm_minor_acquire(). | ||
391 | */ | ||
392 | void drm_minor_release(struct drm_minor *minor) | ||
393 | { | ||
394 | drm_dev_unref(minor->dev); | ||
395 | } | ||
396 | |||
397 | /** | ||
359 | * drm_put_minor - Destroy DRM minor | 398 | * drm_put_minor - Destroy DRM minor |
360 | * @minor: Minor to destroy | 399 | * @minor: Minor to destroy |
361 | * | 400 | * |