diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index d99fb9e32..21271966b 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -208,6 +208,25 @@ static void free_vbuf(struct virtio_gpu_device *vgdev, kmem_cache_free(vgdev->vbufs, vbuf); } +/* + * Free a vbuf that never made it into the virtqueue. The caller handed + * over the references in vbuf->objs, which would otherwise have been + * dropped by the dequeue worker once the host completed the command, so + * release them here. If a fence was passed, the reservations are still + * locked and must be unlocked first. + */ +static void virtio_gpu_drop_vbuf(struct virtio_gpu_device *vgdev, + struct virtio_gpu_vbuffer *vbuf, + struct virtio_gpu_fence *fence) +{ + if (vbuf->objs) { + if (fence) + virtio_gpu_array_unlock_resv(vbuf->objs); + virtio_gpu_array_put_free(vbuf->objs); + } + free_vbuf(vgdev, vbuf); +} + void virtio_gpu_reclaim_vbufs(struct virtio_gpu_device *vgdev) { struct virtio_gpu_vbuffer *vbuf; @@ -437,9 +456,7 @@ static int virtio_gpu_queue_ctrl_sgs(struct virtio_gpu_device *vgdev, int ret, idx; if (!drm_dev_enter(vgdev->ddev, &idx)) { - if (fence && vbuf->objs) - virtio_gpu_array_unlock_resv(vbuf->objs); - free_vbuf(vgdev, vbuf); + virtio_gpu_drop_vbuf(vgdev, vbuf, fence); return -ENODEV; } @@ -459,9 +476,7 @@ static int virtio_gpu_queue_ctrl_sgs(struct virtio_gpu_device *vgdev, * synchronize_srcu() wait in drm_dev_unplug(). */ if (vgdev->vqs_released) { - if (fence && vbuf->objs) - virtio_gpu_array_unlock_resv(vbuf->objs); - free_vbuf(vgdev, vbuf); + virtio_gpu_drop_vbuf(vgdev, vbuf, fence); drm_dev_exit(idx); return -ENODEV; } @@ -542,8 +557,7 @@ static int virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev, sgt = vmalloc_to_sgt(vbuf->data_buf, vbuf->data_size, &sg_ents); if (!sgt) { - if (fence && vbuf->objs) - virtio_gpu_array_unlock_resv(vbuf->objs); + virtio_gpu_drop_vbuf(vgdev, vbuf, fence); return -ENOMEM; }