diff --git a/sys/dev/drm/drm_atomic_uapi.c b/sys/dev/drm/drm_atomic_uapi.c --- a/sys/dev/drm/drm_atomic_uapi.c +++ b/sys/dev/drm/drm_atomic_uapi.c @@ -1077,6 +1077,14 @@ for_each_new_crtc_in_state(state, crtc, crtc_state, i) { s32 __user *fence_ptr; + /* + * DF-1555: track whether the event below was allocated purely + * for the out-fence path; the setup_out_fence() error path + * needs this to free the event instead of leaking it (on + * DragonFly sync_file_create is a stub returning NULL, so the + * fence pointer is never attached). + */ + bool event_for_fence_only = false; fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc); @@ -1103,6 +1111,8 @@ crtc_state->event = NULL; return ret; } + } else if (crtc_state->event) { + event_for_fence_only = true; } if (fence_ptr) { @@ -1126,6 +1136,17 @@ ret = setup_out_fence(&f[(*num_fences)++], fence); if (ret) { dma_fence_put(fence); + /* + * DF-1555: setup_out_fence failed before + * crtc_state->event->base.fence was set; if we + * allocated the event only for the out-fence path + * it has neither fence nor file_priv set and + * complete_signaling() would skip freeing it. + */ + if (event_for_fence_only && crtc_state->event) { + drm_event_cancel_free(dev, &crtc_state->event->base); + crtc_state->event = NULL; + } return ret; }