⬢ DragonFlyBSD Kernel Audit
DF-4437 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/drm_plane.c
+++ b/sys/dev/drm/drm_plane.c
@@ -1018,6 +1018,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	struct drm_pending_vblank_event *e = NULL;
 	u32 target_vblank = page_flip->sequence;
 	struct drm_modeset_acquire_ctx ctx;
+	bool vblank_ref_held = false;
 	int ret = -EINVAL;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -1087,6 +1088,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 
 	drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
 retry:
+	if (crtc->funcs->page_flip_target && !vblank_ref_held) {
+		ret = drm_crtc_vblank_get(crtc);
+		if (ret)
+			goto out;
+		vblank_ref_held = true;
+	}
+
 	ret = drm_modeset_lock(&crtc->mutex, &ctx);
 	if (ret)
 		goto out;
@@ -1178,6 +1187,11 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	if (plane->old_fb)
 		drm_framebuffer_put(plane->old_fb);
 	plane->old_fb = NULL;
+	if (vblank_ref_held) {
+		drm_crtc_vblank_put(crtc);
+		vblank_ref_held = false;
+	}
 
 	if (ret == -EDEADLK) {
 		ret = drm_modeset_backoff(&ctx);
@@ -1192,9 +1206,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 
 	drm_modeset_drop_locks(&ctx);
 	drm_modeset_acquire_fini(&ctx);
-
-	if (ret && crtc->funcs->page_flip_target)
-		drm_crtc_vblank_put(crtc);
 
 	return ret;
 }