diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2010-08-26 15:44:17 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-08-26 19:10:16 -0400 |
commit | 7521473305f1379403b893a30ac09a2132dc1e25 (patch) | |
tree | 594d1c7f2807da61abb20aa3febe0ca159c3bdeb /drivers/gpu | |
parent | 5afda9e9a4625d771795a5f540fb202eec08a49c (diff) |
drm: mm: fix range restricted allocations
With the code cleanup in
7a6b2896f261894dde287d3faefa4b432cddca53 is the first bad commit
commit 7a6b2896f261894dde287d3faefa4b432cddca53
Author: Daniel Vetter <daniel.vetter@ffwll.ch>
Date: Fri Jul 2 15:02:15 2010 +0100
drm_mm: extract check_free_mm_node
I've botched up the range-restriction checks. The result is usually
an X server dying with SIGBUS in libpixman (software fallback rendering).
Change the code to adjust the start and end for range restricted
allocations. IMHO this even makes the code a bit clearer.
Fixes regression bug: https://bugs.freedesktop.org/show_bug.cgi?id=29738
Reported-by-Tested-by: Till MAtthiesen <entropy@everymail.net>
Acked-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/drm_mm.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index da99edc50888..a6bfc302ed90 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c | |||
@@ -285,21 +285,21 @@ void drm_mm_put_block(struct drm_mm_node *cur) | |||
285 | 285 | ||
286 | EXPORT_SYMBOL(drm_mm_put_block); | 286 | EXPORT_SYMBOL(drm_mm_put_block); |
287 | 287 | ||
288 | static int check_free_mm_node(struct drm_mm_node *entry, unsigned long size, | 288 | static int check_free_hole(unsigned long start, unsigned long end, |
289 | unsigned alignment) | 289 | unsigned long size, unsigned alignment) |
290 | { | 290 | { |
291 | unsigned wasted = 0; | 291 | unsigned wasted = 0; |
292 | 292 | ||
293 | if (entry->size < size) | 293 | if (end - start < size) |
294 | return 0; | 294 | return 0; |
295 | 295 | ||
296 | if (alignment) { | 296 | if (alignment) { |
297 | register unsigned tmp = entry->start % alignment; | 297 | unsigned tmp = start % alignment; |
298 | if (tmp) | 298 | if (tmp) |
299 | wasted = alignment - tmp; | 299 | wasted = alignment - tmp; |
300 | } | 300 | } |
301 | 301 | ||
302 | if (entry->size >= size + wasted) { | 302 | if (end >= start + size + wasted) { |
303 | return 1; | 303 | return 1; |
304 | } | 304 | } |
305 | 305 | ||
@@ -320,7 +320,8 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, | |||
320 | best_size = ~0UL; | 320 | best_size = ~0UL; |
321 | 321 | ||
322 | list_for_each_entry(entry, &mm->free_stack, free_stack) { | 322 | list_for_each_entry(entry, &mm->free_stack, free_stack) { |
323 | if (!check_free_mm_node(entry, size, alignment)) | 323 | if (!check_free_hole(entry->start, entry->start + entry->size, |
324 | size, alignment)) | ||
324 | continue; | 325 | continue; |
325 | 326 | ||
326 | if (!best_match) | 327 | if (!best_match) |
@@ -353,10 +354,12 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, | |||
353 | best_size = ~0UL; | 354 | best_size = ~0UL; |
354 | 355 | ||
355 | list_for_each_entry(entry, &mm->free_stack, free_stack) { | 356 | list_for_each_entry(entry, &mm->free_stack, free_stack) { |
356 | if (entry->start > end || (entry->start+entry->size) < start) | 357 | unsigned long adj_start = entry->start < start ? |
357 | continue; | 358 | start : entry->start; |
359 | unsigned long adj_end = entry->start + entry->size > end ? | ||
360 | end : entry->start + entry->size; | ||
358 | 361 | ||
359 | if (!check_free_mm_node(entry, size, alignment)) | 362 | if (!check_free_hole(adj_start, adj_end, size, alignment)) |
360 | continue; | 363 | continue; |
361 | 364 | ||
362 | if (!best_match) | 365 | if (!best_match) |
@@ -449,7 +452,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) | |||
449 | node->free_stack.prev = prev_free; | 452 | node->free_stack.prev = prev_free; |
450 | node->free_stack.next = next_free; | 453 | node->free_stack.next = next_free; |
451 | 454 | ||
452 | if (check_free_mm_node(node, mm->scan_size, mm->scan_alignment)) { | 455 | if (check_free_hole(node->start, node->start + node->size, |
456 | mm->scan_size, mm->scan_alignment)) { | ||
453 | mm->scan_hit_start = node->start; | 457 | mm->scan_hit_start = node->start; |
454 | mm->scan_hit_size = node->size; | 458 | mm->scan_hit_size = node->size; |
455 | 459 | ||