diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 37 |
1 files changed, 20 insertions, 17 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index bbf7ce4ead99..e1de47576143 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -364,6 +364,11 @@ static struct drm_mode_object *_object_find(struct drm_device *dev, if (obj && obj->type == DRM_MODE_OBJECT_BLOB) obj = NULL; + + if (obj && obj->free_cb) { + if (!kref_get_unless_zero(&obj->refcount)) + obj = NULL; + } mutex_unlock(&dev->mode_config.idr_mutex); return obj; @@ -495,11 +500,8 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, mutex_lock(&dev->mode_config.fb_lock); obj = _object_find(dev, id, DRM_MODE_OBJECT_FB); - if (obj) { + if (obj) fb = obj_to_fb(obj); - if (!kref_get_unless_zero(&fb->base.refcount)) - fb = NULL; - } mutex_unlock(&dev->mode_config.fb_lock); return fb; @@ -3474,37 +3476,38 @@ int drm_mode_rmfb(struct drm_device *dev, { struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fbl = NULL; - struct drm_mode_object *obj; uint32_t *id = data; int found = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; + fb = drm_framebuffer_lookup(dev, *id); + if (!fb) + return -ENOENT; + mutex_lock(&file_priv->fbs_lock); - mutex_lock(&dev->mode_config.fb_lock); - obj = _object_find(dev, *id, DRM_MODE_OBJECT_FB); - if (!obj) - goto fail_lookup; - fb = obj_to_fb(obj); list_for_each_entry(fbl, &file_priv->fbs, filp_head) if (fb == fbl) found = 1; - if (!found) - goto fail_lookup; + if (!found) { + mutex_unlock(&file_priv->fbs_lock); + goto fail_unref; + } list_del_init(&fb->filp_head); - mutex_unlock(&dev->mode_config.fb_lock); mutex_unlock(&file_priv->fbs_lock); + /* we now own the reference that was stored in the fbs list */ drm_framebuffer_unreference(fb); - return 0; + /* drop the reference we picked up in framebuffer lookup */ + drm_framebuffer_unreference(fb); -fail_lookup: - mutex_unlock(&dev->mode_config.fb_lock); - mutex_unlock(&file_priv->fbs_lock); + return 0; +fail_unref: + drm_framebuffer_unreference(fb); return -ENOENT; } |