⬢ DragonFlyBSD Kernel Audit
DF-4414 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/radeon/radeon_vm.c b/sys/dev/drm/radeon/radeon_vm.c
--- a/sys/dev/drm/radeon/radeon_vm.c
+++ b/sys/dev/drm/radeon/radeon_vm.c
@@ -1250,13 +1250,27 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
 	while (vm->va.rb_node) {
 		bo_va = container_of((void *)vm->va.rb_node, struct radeon_bo_va, it);
 #endif
-		r = radeon_bo_reserve(bo_va->bo, false);
+		/*
+		 * DFly interval-tree mock-up: the loop repeats the same
+		 * node until interval_tree_remove() succeeds, so the
+		 * reserve MUST make progress.  Use an uninterruptible
+		 * reserve (block until the holder releases instead of
+		 * returning -ERESTARTSYS to a signalled exiting thread,
+		 * which used to spin here forever), and bail out (leak
+		 * the bo_va, matching upstream's single-pass behaviour)
+		 * rather than livelock if it still fails.
+		 */
+		r = radeon_bo_reserve(bo_va->bo, true);
 		if (!r) {
 			interval_tree_remove(&bo_va->it, &vm->va);
 			list_del_init(&bo_va->bo_list);
 			radeon_bo_unreserve(bo_va->bo);
 			radeon_fence_unref(&bo_va->last_pt_update);
 			kfree(bo_va);
+		} else {
+			dev_err(rdev->dev,
+				"leaking bo_va in radeon_vm_fini (%d)\n", r);
+			break;
 		}
 	}