⬢ DragonFlyBSD Kernel Audit
DF-5089 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/radeon/si_dma.c
+++ b/sys/dev/drm/radeon/si_dma.c
@@ -242,12 +242,22 @@ struct radeon_fence *si_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_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
 	num_loops = DIV_ROUND_UP(size_in_bytes, 0xfffff);
 	r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11);
 	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);
+	}