⬢ DragonFlyBSD Kernel Audit
DF-4584 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/radeon/radeon.h b/sys/dev/drm/radeon/radeon.h
index 1111111..2222222 100644
--- a/sys/dev/drm/radeon/radeon.h
+++ b/sys/dev/drm/radeon/radeon.h
@@ -2404,6 +2404,7 @@ struct radeon_device {
 	bool				needs_reset, in_reset;
 	bool				fictitious_range_registered;
 	struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES];
+	struct lock			surface_regs_lock; /* serializes get/clear_surface_reg */
 	const struct firmware *me_fw;	/* all family ME firmware */
 	const struct firmware *pfp_fw;	/* r6/700 PFP firmware */
 	const struct firmware *rlc_fw;	/* r6/700 RLC firmware */
diff --git a/sys/dev/drm/radeon/radeon_device.c b/sys/dev/drm/radeon/radeon_device.c
index 1111111..2222222 100644
--- a/sys/dev/drm/radeon/radeon_device.c
+++ b/sys/dev/drm/radeon/radeon_device.c
@@ -1319,6 +1319,7 @@ int radeon_device_init(struct radeon_device *rdev,
 	atomic_set(&rdev->ih.lock, 0);
 	lockinit(&rdev->gem.mutex, "radeon_gemmtx", 0, LK_CANRECURSE);
+	lockinit(&rdev->surface_regs_lock, "radeon_surflk", 0, 0);
 	lockinit(&rdev->pm.mutex, "drdpmm", 0, LK_CANRECURSE);
 	lockinit(&rdev->gpu_clock_mutex, "radeon_clockmtx", 0, LK_CANRECURSE);
 	lockinit(&rdev->srbm_mutex, "radeon_srbm_mutex", 0, LK_CANRECURSE);
diff --git a/sys/dev/drm/radeon/radeon_object.c b/sys/dev/drm/radeon/radeon_object.c
index 1111111..2222222 100644
--- a/sys/dev/drm/radeon/radeon_object.c
+++ b/sys/dev/drm/radeon/radeon_object.c
@@ -611,12 +611,15 @@ int radeon_bo_get_surface_reg(struct radeon_bo *bo)
 	lockdep_assert_held(&bo->tbo.resv->lock.base);
 
 	if (!bo->tiling_flags)
 		return 0;
 
+	/* The registry is device-global and steal touches OTHER BOs
+	 * (reg->bo), which are not covered by this BO's reservation.
+	 * Serialize against concurrent get/clear incl. the destroy path. */
+	lockmgr(&rdev->surface_regs_lock, LK_EXCLUSIVE);
+
 	if (bo->surface_reg >= 0) {
 		reg = &rdev->surface_regs[bo->surface_reg];
 		i = bo->surface_reg;
 		goto out;
 	}
@@ -644,9 +647,11 @@ int radeon_bo_get_surface_reg(struct radeon_bo *bo)
 	bo->surface_reg = i;
 	reg->bo = bo;
 
 out:
 	radeon_set_surface_reg(rdev, i, bo->tiling_flags, bo->pitch,
 			       bo->tbo.mem.start << PAGE_SHIFT,
 			       bo->tbo.num_pages << PAGE_SHIFT);
+	lockmgr(&rdev->surface_regs_lock, LK_RELEASE);
 	return 0;
 }
 
@@ -662,11 +667,14 @@ static void radeon_bo_clear_surface_reg(struct radeon_bo *bo)
 	if (bo->surface_reg == -1)
 		return;
 
+	/* Serialize against radeon_bo_get_surface_reg()'s steal scan,
+	 * which dereferences reg->bo of this (possibly dying) BO. */
+	lockmgr(&rdev->surface_regs_lock, LK_EXCLUSIVE);
 	reg = &rdev->surface_regs[bo->surface_reg];
 	radeon_clear_surface_reg(rdev, bo->surface_reg);
 
 	reg->bo = NULL;
 	bo->surface_reg = -1;
+	lockmgr(&rdev->surface_regs_lock, LK_RELEASE);
 }
 
 int radeon_bo_set_tiling_flags(struct radeon_bo *bo,