aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2009-03-11 15:30:04 -0400
committerEric Anholt <eric@anholt.net>2009-03-27 17:47:34 -0400
commit201361a54ed187d8595a283e3a4ddb213bc8323b (patch)
tree12a5d23a45f72f8bd917161735d55985654b52e0 /drivers/gpu
parenteb01459fbbccb4ca0b879cbfc97e33ac6eabf975 (diff)
drm/i915: Fix lock order reversal with cliprects and cmdbuf in non-DRI2 paths.
This introduces allocation in the batch submission path that wasn't there previously, but these are compatibility paths so we care about simplicity more than performance. kernel.org bug #12419. Signed-off-by: Eric Anholt <eric@anholt.net> Reviewed-by: Keith Packard <keithp@keithp.com> Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c107
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c27
3 files changed, 97 insertions, 39 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 6d21b9e48b89..ae83fe0ab374 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -356,7 +356,7 @@ static int validate_cmd(int cmd)
356 return ret; 356 return ret;
357} 357}
358 358
359static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwords) 359static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
360{ 360{
361 drm_i915_private_t *dev_priv = dev->dev_private; 361 drm_i915_private_t *dev_priv = dev->dev_private;
362 int i; 362 int i;
@@ -370,8 +370,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
370 for (i = 0; i < dwords;) { 370 for (i = 0; i < dwords;) {
371 int cmd, sz; 371 int cmd, sz;
372 372
373 if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) 373 cmd = buffer[i];
374 return -EINVAL;
375 374
376 if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) 375 if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
377 return -EINVAL; 376 return -EINVAL;
@@ -379,11 +378,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
379 OUT_RING(cmd); 378 OUT_RING(cmd);
380 379
381 while (++i, --sz) { 380 while (++i, --sz) {
382 if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], 381 OUT_RING(buffer[i]);
383 sizeof(cmd))) {
384 return -EINVAL;
385 }
386 OUT_RING(cmd);
387 } 382 }
388 } 383 }
389 384
@@ -397,17 +392,13 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
397 392
398int 393int
399i915_emit_box(struct drm_device *dev, 394i915_emit_box(struct drm_device *dev,
400 struct drm_clip_rect __user *boxes, 395 struct drm_clip_rect *boxes,
401 int i, int DR1, int DR4) 396 int i, int DR1, int DR4)
402{ 397{
403 drm_i915_private_t *dev_priv = dev->dev_private; 398 drm_i915_private_t *dev_priv = dev->dev_private;
404 struct drm_clip_rect box; 399 struct drm_clip_rect box = boxes[i];
405 RING_LOCALS; 400 RING_LOCALS;
406 401
407 if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
408 return -EFAULT;
409 }
410
411 if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { 402 if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
412 DRM_ERROR("Bad box %d,%d..%d,%d\n", 403 DRM_ERROR("Bad box %d,%d..%d,%d\n",
413 box.x1, box.y1, box.x2, box.y2); 404 box.x1, box.y1, box.x2, box.y2);
@@ -460,7 +451,9 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
460} 451}
461 452
462static int i915_dispatch_cmdbuffer(struct drm_device * dev, 453static int i915_dispatch_cmdbuffer(struct drm_device * dev,
463 drm_i915_cmdbuffer_t * cmd) 454 drm_i915_cmdbuffer_t *cmd,
455 struct drm_clip_rect *cliprects,
456 void *cmdbuf)
464{ 457{
465 int nbox = cmd->num_cliprects; 458 int nbox = cmd->num_cliprects;
466 int i = 0, count, ret; 459 int i = 0, count, ret;
@@ -476,13 +469,13 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
476 469
477 for (i = 0; i < count; i++) { 470 for (i = 0; i < count; i++) {
478 if (i < nbox) { 471 if (i < nbox) {
479 ret = i915_emit_box(dev, cmd->cliprects, i, 472 ret = i915_emit_box(dev, cliprects, i,
480 cmd->DR1, cmd->DR4); 473 cmd->DR1, cmd->DR4);
481 if (ret) 474 if (ret)
482 return ret; 475 return ret;
483 } 476 }
484 477
485 ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4); 478 ret = i915_emit_cmds(dev, cmdbuf, cmd->sz / 4);
486 if (ret) 479 if (ret)
487 return ret; 480 return ret;
488 } 481 }
@@ -492,10 +485,10 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
492} 485}
493 486
494static int i915_dispatch_batchbuffer(struct drm_device * dev, 487static int i915_dispatch_batchbuffer(struct drm_device * dev,
495 drm_i915_batchbuffer_t * batch) 488 drm_i915_batchbuffer_t * batch,
489 struct drm_clip_rect *cliprects)
496{ 490{
497 drm_i915_private_t *dev_priv = dev->dev_private; 491 drm_i915_private_t *dev_priv = dev->dev_private;
498 struct drm_clip_rect __user *boxes = batch->cliprects;
499 int nbox = batch->num_cliprects; 492 int nbox = batch->num_cliprects;
500 int i = 0, count; 493 int i = 0, count;
501 RING_LOCALS; 494 RING_LOCALS;
@@ -511,7 +504,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
511 504
512 for (i = 0; i < count; i++) { 505 for (i = 0; i < count; i++) {
513 if (i < nbox) { 506 if (i < nbox) {
514 int ret = i915_emit_box(dev, boxes, i, 507 int ret = i915_emit_box(dev, cliprects, i,
515 batch->DR1, batch->DR4); 508 batch->DR1, batch->DR4);
516 if (ret) 509 if (ret)
517 return ret; 510 return ret;
@@ -626,6 +619,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
626 master_priv->sarea_priv; 619 master_priv->sarea_priv;
627 drm_i915_batchbuffer_t *batch = data; 620 drm_i915_batchbuffer_t *batch = data;
628 int ret; 621 int ret;
622 struct drm_clip_rect *cliprects = NULL;
629 623
630 if (!dev_priv->allow_batchbuffer) { 624 if (!dev_priv->allow_batchbuffer) {
631 DRM_ERROR("Batchbuffer ioctl disabled\n"); 625 DRM_ERROR("Batchbuffer ioctl disabled\n");
@@ -637,17 +631,35 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
637 631
638 RING_LOCK_TEST_WITH_RETURN(dev, file_priv); 632 RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
639 633
640 if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects, 634 if (batch->num_cliprects < 0)
641 batch->num_cliprects * 635 return -EINVAL;
642 sizeof(struct drm_clip_rect))) 636
643 return -EFAULT; 637 if (batch->num_cliprects) {
638 cliprects = drm_calloc(batch->num_cliprects,
639 sizeof(struct drm_clip_rect),
640 DRM_MEM_DRIVER);
641 if (cliprects == NULL)
642 return -ENOMEM;
643
644 ret = copy_from_user(cliprects, batch->cliprects,
645 batch->num_cliprects *
646 sizeof(struct drm_clip_rect));
647 if (ret != 0)
648 goto fail_free;
649 }
644 650
645 mutex_lock(&dev->struct_mutex); 651 mutex_lock(&dev->struct_mutex);
646 ret = i915_dispatch_batchbuffer(dev, batch); 652 ret = i915_dispatch_batchbuffer(dev, batch, cliprects);
647 mutex_unlock(&dev->struct_mutex); 653 mutex_unlock(&dev->struct_mutex);
648 654
649 if (sarea_priv) 655 if (sarea_priv)
650 sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); 656 sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
657
658fail_free:
659 drm_free(cliprects,
660 batch->num_cliprects * sizeof(struct drm_clip_rect),
661 DRM_MEM_DRIVER);
662
651 return ret; 663 return ret;
652} 664}
653 665
@@ -659,6 +671,8 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
659 drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) 671 drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
660 master_priv->sarea_priv; 672 master_priv->sarea_priv;
661 drm_i915_cmdbuffer_t *cmdbuf = data; 673 drm_i915_cmdbuffer_t *cmdbuf = data;
674 struct drm_clip_rect *cliprects = NULL;
675 void *batch_data;
662 int ret; 676 int ret;
663 677
664 DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", 678 DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
@@ -666,25 +680,50 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
666 680
667 RING_LOCK_TEST_WITH_RETURN(dev, file_priv); 681 RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
668 682
669 if (cmdbuf->num_cliprects && 683 if (cmdbuf->num_cliprects < 0)
670 DRM_VERIFYAREA_READ(cmdbuf->cliprects, 684 return -EINVAL;
671 cmdbuf->num_cliprects * 685
672 sizeof(struct drm_clip_rect))) { 686 batch_data = drm_alloc(cmdbuf->sz, DRM_MEM_DRIVER);
673 DRM_ERROR("Fault accessing cliprects\n"); 687 if (batch_data == NULL)
674 return -EFAULT; 688 return -ENOMEM;
689
690 ret = copy_from_user(batch_data, cmdbuf->buf, cmdbuf->sz);
691 if (ret != 0)
692 goto fail_batch_free;
693
694 if (cmdbuf->num_cliprects) {
695 cliprects = drm_calloc(cmdbuf->num_cliprects,
696 sizeof(struct drm_clip_rect),
697 DRM_MEM_DRIVER);
698 if (cliprects == NULL)
699 goto fail_batch_free;
700
701 ret = copy_from_user(cliprects, cmdbuf->cliprects,
702 cmdbuf->num_cliprects *
703 sizeof(struct drm_clip_rect));
704 if (ret != 0)
705 goto fail_clip_free;
675 } 706 }
676 707
677 mutex_lock(&dev->struct_mutex); 708 mutex_lock(&dev->struct_mutex);
678 ret = i915_dispatch_cmdbuffer(dev, cmdbuf); 709 ret = i915_dispatch_cmdbuffer(dev, cmdbuf, cliprects, batch_data);
679 mutex_unlock(&dev->struct_mutex); 710 mutex_unlock(&dev->struct_mutex);
680 if (ret) { 711 if (ret) {
681 DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); 712 DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
682 return ret; 713 goto fail_batch_free;
683 } 714 }
684 715
685 if (sarea_priv) 716 if (sarea_priv)
686 sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); 717 sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
687 return 0; 718
719fail_batch_free:
720 drm_free(batch_data, cmdbuf->sz, DRM_MEM_DRIVER);
721fail_clip_free:
722 drm_free(cliprects,
723 cmdbuf->num_cliprects * sizeof(struct drm_clip_rect),
724 DRM_MEM_DRIVER);
725
726 return ret;
688} 727}
689 728
690static int i915_flip_bufs(struct drm_device *dev, void *data, 729static int i915_flip_bufs(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 75e33844146b..2c02ce6b2b98 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -520,7 +520,7 @@ extern int i915_driver_device_is_agp(struct drm_device * dev);
520extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, 520extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
521 unsigned long arg); 521 unsigned long arg);
522extern int i915_emit_box(struct drm_device *dev, 522extern int i915_emit_box(struct drm_device *dev,
523 struct drm_clip_rect __user *boxes, 523 struct drm_clip_rect *boxes,
524 int i, int DR1, int DR4); 524 int i, int DR1, int DR4);
525 525
526/* i915_irq.c */ 526/* i915_irq.c */
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 010af908bdb6..2bda15197cce 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2891,11 +2891,10 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
2891static int 2891static int
2892i915_dispatch_gem_execbuffer(struct drm_device *dev, 2892i915_dispatch_gem_execbuffer(struct drm_device *dev,
2893 struct drm_i915_gem_execbuffer *exec, 2893 struct drm_i915_gem_execbuffer *exec,
2894 struct drm_clip_rect *cliprects,
2894 uint64_t exec_offset) 2895 uint64_t exec_offset)
2895{ 2896{
2896 drm_i915_private_t *dev_priv = dev->dev_private; 2897 drm_i915_private_t *dev_priv = dev->dev_private;
2897 struct drm_clip_rect __user *boxes = (struct drm_clip_rect __user *)
2898 (uintptr_t) exec->cliprects_ptr;
2899 int nbox = exec->num_cliprects; 2898 int nbox = exec->num_cliprects;
2900 int i = 0, count; 2899 int i = 0, count;
2901 uint32_t exec_start, exec_len; 2900 uint32_t exec_start, exec_len;
@@ -2916,7 +2915,7 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev,
2916 2915
2917 for (i = 0; i < count; i++) { 2916 for (i = 0; i < count; i++) {
2918 if (i < nbox) { 2917 if (i < nbox) {
2919 int ret = i915_emit_box(dev, boxes, i, 2918 int ret = i915_emit_box(dev, cliprects, i,
2920 exec->DR1, exec->DR4); 2919 exec->DR1, exec->DR4);
2921 if (ret) 2920 if (ret)
2922 return ret; 2921 return ret;
@@ -2983,6 +2982,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
2983 struct drm_gem_object **object_list = NULL; 2982 struct drm_gem_object **object_list = NULL;
2984 struct drm_gem_object *batch_obj; 2983 struct drm_gem_object *batch_obj;
2985 struct drm_i915_gem_object *obj_priv; 2984 struct drm_i915_gem_object *obj_priv;
2985 struct drm_clip_rect *cliprects = NULL;
2986 int ret, i, pinned = 0; 2986 int ret, i, pinned = 0;
2987 uint64_t exec_offset; 2987 uint64_t exec_offset;
2988 uint32_t seqno, flush_domains; 2988 uint32_t seqno, flush_domains;
@@ -3019,6 +3019,23 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
3019 goto pre_mutex_err; 3019 goto pre_mutex_err;
3020 } 3020 }
3021 3021
3022 if (args->num_cliprects != 0) {
3023 cliprects = drm_calloc(args->num_cliprects, sizeof(*cliprects),
3024 DRM_MEM_DRIVER);
3025 if (cliprects == NULL)
3026 goto pre_mutex_err;
3027
3028 ret = copy_from_user(cliprects,
3029 (struct drm_clip_rect __user *)
3030 (uintptr_t) args->cliprects_ptr,
3031 sizeof(*cliprects) * args->num_cliprects);
3032 if (ret != 0) {
3033 DRM_ERROR("copy %d cliprects failed: %d\n",
3034 args->num_cliprects, ret);
3035 goto pre_mutex_err;
3036 }
3037 }
3038
3022 mutex_lock(&dev->struct_mutex); 3039 mutex_lock(&dev->struct_mutex);
3023 3040
3024 i915_verify_inactive(dev, __FILE__, __LINE__); 3041 i915_verify_inactive(dev, __FILE__, __LINE__);
@@ -3155,7 +3172,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
3155#endif 3172#endif
3156 3173
3157 /* Exec the batchbuffer */ 3174 /* Exec the batchbuffer */
3158 ret = i915_dispatch_gem_execbuffer(dev, args, exec_offset); 3175 ret = i915_dispatch_gem_execbuffer(dev, args, cliprects, exec_offset);
3159 if (ret) { 3176 if (ret) {
3160 DRM_ERROR("dispatch failed %d\n", ret); 3177 DRM_ERROR("dispatch failed %d\n", ret);
3161 goto err; 3178 goto err;
@@ -3224,6 +3241,8 @@ pre_mutex_err:
3224 DRM_MEM_DRIVER); 3241 DRM_MEM_DRIVER);
3225 drm_free(exec_list, sizeof(*exec_list) * args->buffer_count, 3242 drm_free(exec_list, sizeof(*exec_list) * args->buffer_count,
3226 DRM_MEM_DRIVER); 3243 DRM_MEM_DRIVER);
3244 drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects,
3245 DRM_MEM_DRIVER);
3227 3246
3228 return ret; 3247 return ret;
3229} 3248}