mutex_unlock(&dev->mode_config.idr_mutex);
 }
 
+/**
+ * drm_mode_object_find - look up a drm object with static lifetime
+ * @dev: drm device
+ * @id: id of the mode object
+ * @type: type of the mode object
+ *
+ * Note that framebuffers cannot be looked up with this functions - since those
+ * are reference counted, they need special treatment.
+ */
 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
                uint32_t id, uint32_t type)
 {
        struct drm_mode_object *obj = NULL;
 
+       /* Framebuffers are reference counted and need their own lookup
+        * function.*/
+       WARN_ON(type == DRM_MODE_OBJECT_FB);
+
        mutex_lock(&dev->mode_config.idr_mutex);
        obj = idr_find(&dev->mode_config.crtc_idr, id);
        if (!obj || (obj->type != type) || (obj->id != id))
        fb->funcs->destroy(fb);
 }
 
+/**
+ * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
+ * @dev: drm device
+ * @id: id of the fb object
+ *
+ * If successful, this grabs an additional reference to the framebuffer -
+ * callers need to make sure to eventually unreference the returned framebuffer
+ * again.
+ */
+struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
+                                              uint32_t id)
+{
+       struct drm_mode_object *obj = NULL;
+       struct drm_framebuffer *fb;
+
+       mutex_lock(&dev->mode_config.fb_lock);
+
+       mutex_lock(&dev->mode_config.idr_mutex);
+       obj = idr_find(&dev->mode_config.crtc_idr, id);
+       if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
+               fb = NULL;
+       else
+               fb = obj_to_fb(obj);
+       mutex_unlock(&dev->mode_config.idr_mutex);
+
+       if (fb)
+               kref_get(&fb->refcount);
+
+       mutex_unlock(&dev->mode_config.fb_lock);
+
+       return fb;
+}
+EXPORT_SYMBOL(drm_framebuffer_lookup);
+
 /**
  * drm_framebuffer_unreference - unref a framebuffer
  * @fb: framebuffer to unref
        }
        crtc = obj_to_crtc(obj);
 
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, plane_req->fb_id,
-                                  DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
+       if (!fb) {
                DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
                              plane_req->fb_id);
                ret = -ENOENT;
                goto out;
        }
-       fb = obj_to_fb(obj);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        /* Check whether this plane supports the fb pixel format. */
        for (i = 0; i < plane->format_count; i++)
                        }
                        fb = crtc->fb;
                } else {
-                       mutex_lock(&dev->mode_config.fb_lock);
-                       obj = drm_mode_object_find(dev, crtc_req->fb_id,
-                                                  DRM_MODE_OBJECT_FB);
-                       mutex_unlock(&dev->mode_config.fb_lock);
-                       if (!obj) {
+                       fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
+                       if (!fb) {
                                DRM_DEBUG_KMS("Unknown FB ID%d\n",
                                                crtc_req->fb_id);
                                ret = -EINVAL;
                                goto out;
                        }
-                       fb = obj_to_fb(obj);
+                       /* fb is protect by the mode_config lock, so drop the
+                        * ref immediately */
+                       drm_framebuffer_unreference(fb);
                }
 
                mode = drm_mode_create(dev);
 int drm_mode_rmfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv)
 {
-       struct drm_mode_object *obj;
        struct drm_framebuffer *fb = NULL;
        struct drm_framebuffer *fbl = NULL;
        uint32_t *id = data;
                return -EINVAL;
 
        drm_modeset_lock_all(dev);
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
-       /* TODO check that we really get a framebuffer back. */
-       if (!obj) {
-               mutex_unlock(&dev->mode_config.fb_lock);
+       fb = drm_framebuffer_lookup(dev, *id);
+       if (!fb) {
                ret = -EINVAL;
                goto out;
        }
-       fb = obj_to_fb(obj);
-       mutex_unlock(&dev->mode_config.fb_lock);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        mutex_lock(&file_priv->fbs_lock);
        list_for_each_entry(fbl, &file_priv->fbs, filp_head)
                   void *data, struct drm_file *file_priv)
 {
        struct drm_mode_fb_cmd *r = data;
-       struct drm_mode_object *obj;
        struct drm_framebuffer *fb;
        int ret = 0;
 
                return -EINVAL;
 
        drm_modeset_lock_all(dev);
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, r->fb_id);
+       if (!fb) {
                ret = -EINVAL;
                goto out;
        }
-       fb = obj_to_fb(obj);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        r->height = fb->height;
        r->width = fb->width;
        struct drm_clip_rect __user *clips_ptr;
        struct drm_clip_rect *clips = NULL;
        struct drm_mode_fb_dirty_cmd *r = data;
-       struct drm_mode_object *obj;
        struct drm_framebuffer *fb;
        unsigned flags;
        int num_clips;
                return -EINVAL;
 
        drm_modeset_lock_all(dev);
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, r->fb_id);
+       if (!fb) {
                ret = -EINVAL;
                goto out_err1;
        }
-       fb = obj_to_fb(obj);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        num_clips = r->num_clips;
        clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
        if (crtc->funcs->page_flip == NULL)
                goto out;
 
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj)
+       fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
+       if (!fb)
                goto out;
-       fb = obj_to_fb(obj);
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
        hdisplay = crtc->mode.hdisplay;
        vdisplay = crtc->mode.vdisplay;
 
        struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct drm_vmw_rect __user *clips_ptr;
        struct drm_vmw_rect *clips = NULL;
-       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb;
        struct vmw_framebuffer *vfb;
        struct vmw_resource *res;
        uint32_t num_clips;
 
        drm_modeset_lock_all(dev);
 
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, arg->fb_id);
+       if (!fb) {
                DRM_ERROR("Invalid framebuffer id.\n");
                ret = -EINVAL;
                goto out_no_fb;
        }
-       vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
+       vfb = vmw_framebuffer_to_vfb(fb);
 
        ret = ttm_read_lock(&vmaster->lock, true);
        if (unlikely(ret != 0))
        struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct drm_vmw_rect __user *clips_ptr;
        struct drm_vmw_rect *clips = NULL;
-       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb;
        struct vmw_framebuffer *vfb;
        uint32_t num_clips;
        int ret;
 
        drm_modeset_lock_all(dev);
 
-       mutex_lock(&dev->mode_config.fb_lock);
-       obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
-       mutex_unlock(&dev->mode_config.fb_lock);
-       if (!obj) {
+       fb = drm_framebuffer_lookup(dev, arg->fb_id);
+       if (!fb) {
                DRM_ERROR("Invalid framebuffer id.\n");
                ret = -EINVAL;
                goto out_no_fb;
        }
+       /* fb is protect by the mode_config lock, so drop the ref immediately */
+       drm_framebuffer_unreference(fb);
 
-       vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
+       vfb = vmw_framebuffer_to_vfb(fb);
        if (!vfb->dmabuf) {
                DRM_ERROR("Framebuffer not dmabuf backed.\n");
                ret = -EINVAL;