aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2014-08-06 07:02:51 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-08-08 11:43:58 -0400
commite2fcdaa9c951c51d558fea2cc020d89b382d702e (patch)
tree2e283076bfb6efdb99aa24f8c92809e0333659f4
parent692ef70c016b5035ad1942ccc2bc4040aa290044 (diff)
drm/i915: Free pending page flip events at .preclose()
If there are pending page flips when the fd gets closed those page flips may have events associated to them. When the page flip eventually completes it will queue the event to file_priv->event_list, but that may be too late and file_priv->event_list has already been cleaned up. Thus we leak a bit of kernel memory in the form of the event structure. To avoid such problems clear out such pending events from intel_crtc->unpin_work at ->preclose(). Any event that already made it to file_priv->event_list will get cleaned up by the drm_release_events() a bit later. We can ignore the file_priv->event_space accounting since file_priv is going away. This is already how drm core deals with pending vblank events, which are maintained by the drm core. What saves us from a total disaster (ie. dereferencing and alrady freed file_priv) is the fact that the fb descruction triggers a modeset and there we wait for pending flips. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c3
-rw-r--r--drivers/gpu/drm/i915/intel_display.c22
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
3 files changed, 26 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 2e7f03ad5ee2..c965698a8bac 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1981,6 +1981,9 @@ void i915_driver_preclose(struct drm_device *dev, struct drm_file *file)
1981 i915_gem_context_close(dev, file); 1981 i915_gem_context_close(dev, file);
1982 i915_gem_release(dev, file); 1982 i915_gem_release(dev, file);
1983 mutex_unlock(&dev->struct_mutex); 1983 mutex_unlock(&dev->struct_mutex);
1984
1985 if (drm_core_check_feature(dev, DRIVER_MODESET))
1986 intel_modeset_preclose(dev, file);
1984} 1987}
1985 1988
1986void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) 1989void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f32a94544940..24295694e493 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13470,3 +13470,25 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
13470 err_printf(m, " VSYNC: %08x\n", error->transcoder[i].vsync); 13470 err_printf(m, " VSYNC: %08x\n", error->transcoder[i].vsync);
13471 } 13471 }
13472} 13472}
13473
13474void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file)
13475{
13476 struct intel_crtc *crtc;
13477
13478 for_each_intel_crtc(dev, crtc) {
13479 struct intel_unpin_work *work;
13480 unsigned long irqflags;
13481
13482 spin_lock_irqsave(&dev->event_lock, irqflags);
13483
13484 work = crtc->unpin_work;
13485
13486 if (work && work->event &&
13487 work->event->base.file_priv == file) {
13488 kfree(work->event);
13489 work->event = NULL;
13490 }
13491
13492 spin_unlock_irqrestore(&dev->event_lock, irqflags);
13493 }
13494}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 79782094c8f9..666ca8a044ea 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -892,6 +892,7 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
892 struct intel_crtc_config *pipe_config); 892 struct intel_crtc_config *pipe_config);
893int intel_format_to_fourcc(int format); 893int intel_format_to_fourcc(int format);
894void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); 894void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
895void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
895 896
896/* intel_dp.c */ 897/* intel_dp.c */
897void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); 898void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);