diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-06-29 18:26:50 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-07-01 05:15:01 -0400 |
commit | baf27f9b17bf2f369f3865e38c41d2163e8d815d (patch) | |
tree | 169ee2fd851d2151cc9991d2cbdff700118ca51a | |
parent | d26e3af842023603747f1566caff5f471508bbd4 (diff) |
drm/i915: Break up the large vsnprintf() in print_error_buffers()
So it appears that I have encountered some bogosity when trying to call
i915_error_printf() with many arguments from print_error_buffers(). The
symptom is that the vsnprintf parser tries to interpret an integer arg
as a character string, the resulting OOPS indicating stack corruption.
Replacing the single call with its 13 format specifiers and arguments
with multiple calls to i915_error_printf() worked fine. This patch goes
one step further and introduced i915_error_puts() to pass the strings
simply.
It may not fix the root cause, but it does prevent my box from dying and
I think helps make print_error_buffers() more friendly.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=66077
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 109 |
1 files changed, 79 insertions, 30 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 04cf6c09710a..47d6c748057e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -647,41 +647,44 @@ static const char *purgeable_flag(int purgeable) | |||
647 | return purgeable ? " purgeable" : ""; | 647 | return purgeable ? " purgeable" : ""; |
648 | } | 648 | } |
649 | 649 | ||
650 | static void i915_error_vprintf(struct drm_i915_error_state_buf *e, | 650 | static bool __i915_error_ok(struct drm_i915_error_state_buf *e) |
651 | const char *f, va_list args) | ||
652 | { | 651 | { |
653 | unsigned len; | ||
654 | 652 | ||
655 | if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) { | 653 | if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) { |
656 | e->err = -ENOSPC; | 654 | e->err = -ENOSPC; |
657 | return; | 655 | return false; |
658 | } | 656 | } |
659 | 657 | ||
660 | if (e->bytes == e->size - 1 || e->err) | 658 | if (e->bytes == e->size - 1 || e->err) |
661 | return; | 659 | return false; |
662 | 660 | ||
663 | /* Seek the first printf which is hits start position */ | 661 | return true; |
664 | if (e->pos < e->start) { | 662 | } |
665 | len = vsnprintf(NULL, 0, f, args); | ||
666 | if (e->pos + len <= e->start) { | ||
667 | e->pos += len; | ||
668 | return; | ||
669 | } | ||
670 | 663 | ||
671 | /* First vsnprintf needs to fit in full for memmove*/ | 664 | static bool __i915_error_seek(struct drm_i915_error_state_buf *e, |
672 | if (len >= e->size) { | 665 | unsigned len) |
673 | e->err = -EIO; | 666 | { |
674 | return; | 667 | if (e->pos + len <= e->start) { |
675 | } | 668 | e->pos += len; |
669 | return false; | ||
676 | } | 670 | } |
677 | 671 | ||
678 | len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); | 672 | /* First vsnprintf needs to fit in its entirety for memmove */ |
679 | if (len >= e->size - e->bytes) | 673 | if (len >= e->size) { |
680 | len = e->size - e->bytes - 1; | 674 | e->err = -EIO; |
675 | return false; | ||
676 | } | ||
681 | 677 | ||
678 | return true; | ||
679 | } | ||
680 | |||
681 | static void __i915_error_advance(struct drm_i915_error_state_buf *e, | ||
682 | unsigned len) | ||
683 | { | ||
682 | /* If this is first printf in this window, adjust it so that | 684 | /* If this is first printf in this window, adjust it so that |
683 | * start position matches start of the buffer | 685 | * start position matches start of the buffer |
684 | */ | 686 | */ |
687 | |||
685 | if (e->pos < e->start) { | 688 | if (e->pos < e->start) { |
686 | const size_t off = e->start - e->pos; | 689 | const size_t off = e->start - e->pos; |
687 | 690 | ||
@@ -701,6 +704,51 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e, | |||
701 | e->pos += len; | 704 | e->pos += len; |
702 | } | 705 | } |
703 | 706 | ||
707 | static void i915_error_vprintf(struct drm_i915_error_state_buf *e, | ||
708 | const char *f, va_list args) | ||
709 | { | ||
710 | unsigned len; | ||
711 | |||
712 | if (!__i915_error_ok(e)) | ||
713 | return; | ||
714 | |||
715 | /* Seek the first printf which is hits start position */ | ||
716 | if (e->pos < e->start) { | ||
717 | len = vsnprintf(NULL, 0, f, args); | ||
718 | if (!__i915_error_seek(e, len)) | ||
719 | return; | ||
720 | } | ||
721 | |||
722 | len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); | ||
723 | if (len >= e->size - e->bytes) | ||
724 | len = e->size - e->bytes - 1; | ||
725 | |||
726 | __i915_error_advance(e, len); | ||
727 | } | ||
728 | |||
729 | static void i915_error_puts(struct drm_i915_error_state_buf *e, | ||
730 | const char *str) | ||
731 | { | ||
732 | unsigned len; | ||
733 | |||
734 | if (!__i915_error_ok(e)) | ||
735 | return; | ||
736 | |||
737 | len = strlen(str); | ||
738 | |||
739 | /* Seek the first printf which is hits start position */ | ||
740 | if (e->pos < e->start) { | ||
741 | if (!__i915_error_seek(e, len)) | ||
742 | return; | ||
743 | } | ||
744 | |||
745 | if (len >= e->size - e->bytes) | ||
746 | len = e->size - e->bytes - 1; | ||
747 | memcpy(e->buf + e->bytes, str, len); | ||
748 | |||
749 | __i915_error_advance(e, len); | ||
750 | } | ||
751 | |||
704 | void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) | 752 | void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) |
705 | { | 753 | { |
706 | va_list args; | 754 | va_list args; |
@@ -711,6 +759,7 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) | |||
711 | } | 759 | } |
712 | 760 | ||
713 | #define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) | 761 | #define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) |
762 | #define err_puts(e, s) i915_error_puts(e, s) | ||
714 | 763 | ||
715 | static void print_error_buffers(struct drm_i915_error_state_buf *m, | 764 | static void print_error_buffers(struct drm_i915_error_state_buf *m, |
716 | const char *name, | 765 | const char *name, |
@@ -720,26 +769,26 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m, | |||
720 | err_printf(m, "%s [%d]:\n", name, count); | 769 | err_printf(m, "%s [%d]:\n", name, count); |
721 | 770 | ||
722 | while (count--) { | 771 | while (count--) { |
723 | err_printf(m, " %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s", | 772 | err_printf(m, " %08x %8u %02x %02x %x %x", |
724 | err->gtt_offset, | 773 | err->gtt_offset, |
725 | err->size, | 774 | err->size, |
726 | err->read_domains, | 775 | err->read_domains, |
727 | err->write_domain, | 776 | err->write_domain, |
728 | err->rseqno, err->wseqno, | 777 | err->rseqno, err->wseqno); |
729 | pin_flag(err->pinned), | 778 | err_puts(m, pin_flag(err->pinned)); |
730 | tiling_flag(err->tiling), | 779 | err_puts(m, tiling_flag(err->tiling)); |
731 | dirty_flag(err->dirty), | 780 | err_puts(m, dirty_flag(err->dirty)); |
732 | purgeable_flag(err->purgeable), | 781 | err_puts(m, purgeable_flag(err->purgeable)); |
733 | err->ring != -1 ? " " : "", | 782 | err_puts(m, err->ring != -1 ? " " : ""); |
734 | ring_str(err->ring), | 783 | err_puts(m, ring_str(err->ring)); |
735 | cache_level_str(err->cache_level)); | 784 | err_puts(m, cache_level_str(err->cache_level)); |
736 | 785 | ||
737 | if (err->name) | 786 | if (err->name) |
738 | err_printf(m, " (name: %d)", err->name); | 787 | err_printf(m, " (name: %d)", err->name); |
739 | if (err->fence_reg != I915_FENCE_REG_NONE) | 788 | if (err->fence_reg != I915_FENCE_REG_NONE) |
740 | err_printf(m, " (fence: %d)", err->fence_reg); | 789 | err_printf(m, " (fence: %d)", err->fence_reg); |
741 | 790 | ||
742 | err_printf(m, "\n"); | 791 | err_puts(m, "\n"); |
743 | err++; | 792 | err++; |
744 | } | 793 | } |
745 | } | 794 | } |