diff options
author | Florian Mickler <florian@mickler.org> | 2009-04-06 16:55:41 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-04-08 13:18:19 -0400 |
commit | 2bc43b5cf5158a26fa1328234795abed2dff5275 (patch) | |
tree | 0965b8d142a1a1c70d65be61f5478807fb8daff0 | |
parent | 5b40f871158da7aaccff442645dae8b97c2e4d50 (diff) |
drm/i915: Fix use of uninitialized var in 40a5f0de
i915_gem_put_relocs_to_user returned an uninitialized value which
got returned to userspace. This caused libdrm in my setup to never
get out of a do{}while() loop retrying i915_gem_execbuffer.
result was hanging X, overheating of cpu and 2-3gb of logfile-spam.
This patch adresses the issue by
1. initializing vars in this file where necessary
2. correcting wrongly interpreted return values of copy_[from/to]_user
Signed-off-by: Florian Mickler <florian@mickler.org>
[anholt: cleanups of unnecessary changes, consistency in APIs]
Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 33ab07b0d712..6f7d0e27036f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -141,15 +141,18 @@ fast_shmem_read(struct page **pages, | |||
141 | int length) | 141 | int length) |
142 | { | 142 | { |
143 | char __iomem *vaddr; | 143 | char __iomem *vaddr; |
144 | int ret; | 144 | int unwritten; |
145 | 145 | ||
146 | vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0); | 146 | vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0); |
147 | if (vaddr == NULL) | 147 | if (vaddr == NULL) |
148 | return -ENOMEM; | 148 | return -ENOMEM; |
149 | ret = __copy_to_user_inatomic(data, vaddr + page_offset, length); | 149 | unwritten = __copy_to_user_inatomic(data, vaddr + page_offset, length); |
150 | kunmap_atomic(vaddr, KM_USER0); | 150 | kunmap_atomic(vaddr, KM_USER0); |
151 | 151 | ||
152 | return ret; | 152 | if (unwritten) |
153 | return -EFAULT; | ||
154 | |||
155 | return 0; | ||
153 | } | 156 | } |
154 | 157 | ||
155 | static inline int | 158 | static inline int |
@@ -3000,13 +3003,13 @@ i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list, | |||
3000 | drm_free(*relocs, reloc_count * sizeof(**relocs), | 3003 | drm_free(*relocs, reloc_count * sizeof(**relocs), |
3001 | DRM_MEM_DRIVER); | 3004 | DRM_MEM_DRIVER); |
3002 | *relocs = NULL; | 3005 | *relocs = NULL; |
3003 | return ret; | 3006 | return -EFAULT; |
3004 | } | 3007 | } |
3005 | 3008 | ||
3006 | reloc_index += exec_list[i].relocation_count; | 3009 | reloc_index += exec_list[i].relocation_count; |
3007 | } | 3010 | } |
3008 | 3011 | ||
3009 | return ret; | 3012 | return 0; |
3010 | } | 3013 | } |
3011 | 3014 | ||
3012 | static int | 3015 | static int |
@@ -3015,23 +3018,28 @@ i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object *exec_list, | |||
3015 | struct drm_i915_gem_relocation_entry *relocs) | 3018 | struct drm_i915_gem_relocation_entry *relocs) |
3016 | { | 3019 | { |
3017 | uint32_t reloc_count = 0, i; | 3020 | uint32_t reloc_count = 0, i; |
3018 | int ret; | 3021 | int ret = 0; |
3019 | 3022 | ||
3020 | for (i = 0; i < buffer_count; i++) { | 3023 | for (i = 0; i < buffer_count; i++) { |
3021 | struct drm_i915_gem_relocation_entry __user *user_relocs; | 3024 | struct drm_i915_gem_relocation_entry __user *user_relocs; |
3025 | int unwritten; | ||
3022 | 3026 | ||
3023 | user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr; | 3027 | user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr; |
3024 | 3028 | ||
3025 | if (ret == 0) { | 3029 | unwritten = copy_to_user(user_relocs, |
3026 | ret = copy_to_user(user_relocs, | 3030 | &relocs[reloc_count], |
3027 | &relocs[reloc_count], | 3031 | exec_list[i].relocation_count * |
3028 | exec_list[i].relocation_count * | 3032 | sizeof(*relocs)); |
3029 | sizeof(*relocs)); | 3033 | |
3034 | if (unwritten) { | ||
3035 | ret = -EFAULT; | ||
3036 | goto err; | ||
3030 | } | 3037 | } |
3031 | 3038 | ||
3032 | reloc_count += exec_list[i].relocation_count; | 3039 | reloc_count += exec_list[i].relocation_count; |
3033 | } | 3040 | } |
3034 | 3041 | ||
3042 | err: | ||
3035 | drm_free(relocs, reloc_count * sizeof(*relocs), DRM_MEM_DRIVER); | 3043 | drm_free(relocs, reloc_count * sizeof(*relocs), DRM_MEM_DRIVER); |
3036 | 3044 | ||
3037 | return ret; | 3045 | return ret; |
@@ -3306,10 +3314,12 @@ err: | |||
3306 | (uintptr_t) args->buffers_ptr, | 3314 | (uintptr_t) args->buffers_ptr, |
3307 | exec_list, | 3315 | exec_list, |
3308 | sizeof(*exec_list) * args->buffer_count); | 3316 | sizeof(*exec_list) * args->buffer_count); |
3309 | if (ret) | 3317 | if (ret) { |
3318 | ret = -EFAULT; | ||
3310 | DRM_ERROR("failed to copy %d exec entries " | 3319 | DRM_ERROR("failed to copy %d exec entries " |
3311 | "back to user (%d)\n", | 3320 | "back to user (%d)\n", |
3312 | args->buffer_count, ret); | 3321 | args->buffer_count, ret); |
3322 | } | ||
3313 | } | 3323 | } |
3314 | 3324 | ||
3315 | /* Copy the updated relocations out regardless of current error | 3325 | /* Copy the updated relocations out regardless of current error |