aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2018-03-21 05:18:38 -0400
committerThomas Hellstrom <thellstrom@vmware.com>2018-03-21 05:52:01 -0400
commit73a88250b70954a8f27c2444e1c2411bba3c29d9 (patch)
treed4347a5a40c693af235e082bac3f7affeeb8b593
parent140bcaa23a1c37b694910424075a15e009120dbe (diff)
drm/vmwgfx: Fix a destoy-while-held mutex problem.
When validating legacy surfaces, the backup bo might be destroyed at surface validate time. However, the kms resource validation code may have the bo reserved, so we will destroy a locked mutex. While there shouldn't be any other users of that mutex when it is destroyed, it causes a lock leak and thus throws a lockdep error. Fix this by having the kms resource validation code hold a reference to the bo while we have it reserved. We do this by introducing a validation context which might come in handy when the kms code is extended to validate multiple resources or buffers. Cc: <stable@vger.kernel.org> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com>
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c28
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h12
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c5
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c5
4 files changed, 34 insertions, 16 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index b3d62aa01a9b..3c824fd7cbf3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -31,7 +31,6 @@
31#include <drm/drm_atomic_helper.h> 31#include <drm/drm_atomic_helper.h>
32#include <drm/drm_rect.h> 32#include <drm/drm_rect.h>
33 33
34
35/* Might need a hrtimer here? */ 34/* Might need a hrtimer here? */
36#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) 35#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
37 36
@@ -2517,9 +2516,12 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv,
2517 * Helper to be used if an error forces the caller to undo the actions of 2516 * Helper to be used if an error forces the caller to undo the actions of
2518 * vmw_kms_helper_resource_prepare. 2517 * vmw_kms_helper_resource_prepare.
2519 */ 2518 */
2520void vmw_kms_helper_resource_revert(struct vmw_resource *res) 2519void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx)
2521{ 2520{
2522 vmw_kms_helper_buffer_revert(res->backup); 2521 struct vmw_resource *res = ctx->res;
2522
2523 vmw_kms_helper_buffer_revert(ctx->buf);
2524 vmw_dmabuf_unreference(&ctx->buf);
2523 vmw_resource_unreserve(res, false, NULL, 0); 2525 vmw_resource_unreserve(res, false, NULL, 0);
2524 mutex_unlock(&res->dev_priv->cmdbuf_mutex); 2526 mutex_unlock(&res->dev_priv->cmdbuf_mutex);
2525} 2527}
@@ -2536,10 +2538,14 @@ void vmw_kms_helper_resource_revert(struct vmw_resource *res)
2536 * interrupted by a signal. 2538 * interrupted by a signal.
2537 */ 2539 */
2538int vmw_kms_helper_resource_prepare(struct vmw_resource *res, 2540int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
2539 bool interruptible) 2541 bool interruptible,
2542 struct vmw_validation_ctx *ctx)
2540{ 2543{
2541 int ret = 0; 2544 int ret = 0;
2542 2545
2546 ctx->buf = NULL;
2547 ctx->res = res;
2548
2543 if (interruptible) 2549 if (interruptible)
2544 ret = mutex_lock_interruptible(&res->dev_priv->cmdbuf_mutex); 2550 ret = mutex_lock_interruptible(&res->dev_priv->cmdbuf_mutex);
2545 else 2551 else
@@ -2558,6 +2564,8 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
2558 res->dev_priv->has_mob); 2564 res->dev_priv->has_mob);
2559 if (ret) 2565 if (ret)
2560 goto out_unreserve; 2566 goto out_unreserve;
2567
2568 ctx->buf = vmw_dmabuf_reference(res->backup);
2561 } 2569 }
2562 ret = vmw_resource_validate(res); 2570 ret = vmw_resource_validate(res);
2563 if (ret) 2571 if (ret)
@@ -2565,7 +2573,7 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
2565 return 0; 2573 return 0;
2566 2574
2567out_revert: 2575out_revert:
2568 vmw_kms_helper_buffer_revert(res->backup); 2576 vmw_kms_helper_buffer_revert(ctx->buf);
2569out_unreserve: 2577out_unreserve:
2570 vmw_resource_unreserve(res, false, NULL, 0); 2578 vmw_resource_unreserve(res, false, NULL, 0);
2571out_unlock: 2579out_unlock:
@@ -2581,11 +2589,13 @@ out_unlock:
2581 * @out_fence: Optional pointer to a fence pointer. If non-NULL, a 2589 * @out_fence: Optional pointer to a fence pointer. If non-NULL, a
2582 * ref-counted fence pointer is returned here. 2590 * ref-counted fence pointer is returned here.
2583 */ 2591 */
2584void vmw_kms_helper_resource_finish(struct vmw_resource *res, 2592void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx,
2585 struct vmw_fence_obj **out_fence) 2593 struct vmw_fence_obj **out_fence)
2586{ 2594{
2587 if (res->backup || out_fence) 2595 struct vmw_resource *res = ctx->res;
2588 vmw_kms_helper_buffer_finish(res->dev_priv, NULL, res->backup, 2596
2597 if (ctx->buf || out_fence)
2598 vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf,
2589 out_fence, NULL); 2599 out_fence, NULL);
2590 2600
2591 vmw_resource_unreserve(res, false, NULL, 0); 2601 vmw_resource_unreserve(res, false, NULL, 0);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 948362c43c73..3d2ca280eaa7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -240,6 +240,11 @@ struct vmw_display_unit {
240 int set_gui_y; 240 int set_gui_y;
241}; 241};
242 242
243struct vmw_validation_ctx {
244 struct vmw_resource *res;
245 struct vmw_dma_buffer *buf;
246};
247
243#define vmw_crtc_to_du(x) \ 248#define vmw_crtc_to_du(x) \
244 container_of(x, struct vmw_display_unit, crtc) 249 container_of(x, struct vmw_display_unit, crtc)
245#define vmw_connector_to_du(x) \ 250#define vmw_connector_to_du(x) \
@@ -296,9 +301,10 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv,
296 struct drm_vmw_fence_rep __user * 301 struct drm_vmw_fence_rep __user *
297 user_fence_rep); 302 user_fence_rep);
298int vmw_kms_helper_resource_prepare(struct vmw_resource *res, 303int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
299 bool interruptible); 304 bool interruptible,
300void vmw_kms_helper_resource_revert(struct vmw_resource *res); 305 struct vmw_validation_ctx *ctx);
301void vmw_kms_helper_resource_finish(struct vmw_resource *res, 306void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx);
307void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx,
302 struct vmw_fence_obj **out_fence); 308 struct vmw_fence_obj **out_fence);
303int vmw_kms_readback(struct vmw_private *dev_priv, 309int vmw_kms_readback(struct vmw_private *dev_priv,
304 struct drm_file *file_priv, 310 struct drm_file *file_priv,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 63a4cd794b73..3ec9eae831b8 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -909,12 +909,13 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
909 struct vmw_framebuffer_surface *vfbs = 909 struct vmw_framebuffer_surface *vfbs =
910 container_of(framebuffer, typeof(*vfbs), base); 910 container_of(framebuffer, typeof(*vfbs), base);
911 struct vmw_kms_sou_surface_dirty sdirty; 911 struct vmw_kms_sou_surface_dirty sdirty;
912 struct vmw_validation_ctx ctx;
912 int ret; 913 int ret;
913 914
914 if (!srf) 915 if (!srf)
915 srf = &vfbs->surface->res; 916 srf = &vfbs->surface->res;
916 917
917 ret = vmw_kms_helper_resource_prepare(srf, true); 918 ret = vmw_kms_helper_resource_prepare(srf, true, &ctx);
918 if (ret) 919 if (ret)
919 return ret; 920 return ret;
920 921
@@ -933,7 +934,7 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
933 ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 934 ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
934 dest_x, dest_y, num_clips, inc, 935 dest_x, dest_y, num_clips, inc,
935 &sdirty.base); 936 &sdirty.base);
936 vmw_kms_helper_resource_finish(srf, out_fence); 937 vmw_kms_helper_resource_finish(&ctx, out_fence);
937 938
938 return ret; 939 return ret;
939} 940}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index b68d74888ab1..6b969e5dea2a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -980,12 +980,13 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
980 struct vmw_framebuffer_surface *vfbs = 980 struct vmw_framebuffer_surface *vfbs =
981 container_of(framebuffer, typeof(*vfbs), base); 981 container_of(framebuffer, typeof(*vfbs), base);
982 struct vmw_stdu_dirty sdirty; 982 struct vmw_stdu_dirty sdirty;
983 struct vmw_validation_ctx ctx;
983 int ret; 984 int ret;
984 985
985 if (!srf) 986 if (!srf)
986 srf = &vfbs->surface->res; 987 srf = &vfbs->surface->res;
987 988
988 ret = vmw_kms_helper_resource_prepare(srf, true); 989 ret = vmw_kms_helper_resource_prepare(srf, true, &ctx);
989 if (ret) 990 if (ret)
990 return ret; 991 return ret;
991 992
@@ -1008,7 +1009,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
1008 dest_x, dest_y, num_clips, inc, 1009 dest_x, dest_y, num_clips, inc,
1009 &sdirty.base); 1010 &sdirty.base);
1010out_finish: 1011out_finish:
1011 vmw_kms_helper_resource_finish(srf, out_fence); 1012 vmw_kms_helper_resource_finish(&ctx, out_fence);
1012 1013
1013 return ret; 1014 return ret;
1014} 1015}