⬢ DragonFlyBSD Kernel Audit
DF-4871 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/radeon/r600_dma.c
+++ b/sys/dev/drm/radeon/r600_dma.c
@@ -454,12 +454,22 @@ struct radeon_fence *r600_copy_dma(struct radeon_device *rdev,
 
 	radeon_sync_create(&sync);
 
+	/* Sync with the resv before taking the ring lock: the waits inside
+	 * radeon_sync_resv() may sleep and must not hold rdev->ring_lock.
+	 */
+	r = radeon_sync_resv(rdev, &sync, resv, false);
+	if (r) {
+		DRM_ERROR("radeon: syncing before moving bo (%d).\n", r);
+		radeon_sync_free(rdev, &sync, NULL);
+		return ERR_PTR(r);
+	}
+
 	size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
 	num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFE);
 	r = radeon_ring_lock(rdev, ring, num_loops * 4 + 8);
 	if (r) {
 		DRM_ERROR("radeon: moving bo (%d).\n", r);
 		radeon_sync_free(rdev, &sync, NULL);
 		return ERR_PTR(r);
 	}
 
-	radeon_sync_resv(rdev, &sync, resv, false);
-	radeon_sync_rings(rdev, &sync, ring->idx);
+	r = radeon_sync_rings(rdev, &sync, ring->idx);
+	if (r) {
+		DRM_ERROR("radeon: failed to sync rings while moving bo (%d).\n", r);
+		radeon_ring_unlock_undo(rdev, ring);
+		radeon_sync_free(rdev, &sync, NULL);
+		return ERR_PTR(r);
+	}