Avoid clobbering adjacent blocks if they happen to expire earlier and amalgamate together to form the requested hole. In passing this fixes a regression from commit ea7b1dd44867e9cd6bac67e7c9fc3f128b5b255c Author: Daniel Vetter <daniel.vetter@xxxxxxxx> Date: Fri Feb 18 17:59:12 2011 +0100 drm: mm: track free areas implicitly which swaps the end address for size (with a potential overflow) and effectively causes the eviction code to clobber almost all earlier buffers above the evictee. Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Cc: Daniel Vetter <daniel.vetter@xxxxxxxx> --- drivers/gpu/drm/drm_mm.c | 58 +++++++++++++++++++++++++--------------------- include/drm/drm_mm.h | 2 +- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 7103aa3..c93729c 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -421,6 +421,25 @@ static int check_free_hole(unsigned long start, unsigned long end, return end >= start + size; } +static int adjust_free_hole(unsigned long *start, unsigned long *end, + unsigned long size, unsigned alignment) +{ + if (*end - *start < size) + return 0; + + if (alignment) { + unsigned tmp = *start % alignment; + if (tmp) + *start += alignment - tmp; + } + + if (*end - *start < size) + return 0; + + *end = *start + size; + return 1; +} + struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, unsigned long size, unsigned alignment, @@ -545,7 +564,7 @@ void drm_mm_init_scan(struct drm_mm *mm, mm->scan_size = size; mm->scanned_blocks = 0; mm->scan_hit_start = 0; - mm->scan_hit_size = 0; + mm->scan_hit_end = 0; mm->scan_check_range = 0; mm->prev_scanned_node = NULL; } @@ -572,7 +591,7 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm, mm->scan_size = size; mm->scanned_blocks = 0; mm->scan_hit_start = 0; - mm->scan_hit_size = 0; + mm->scan_hit_end = 0; mm->scan_start = start; mm->scan_end = end; mm->scan_check_range = 1; @@ -591,8 +610,6 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) struct drm_mm *mm = node->mm; struct drm_mm_node *prev_node; unsigned long hole_start, hole_end; - unsigned long adj_start; - unsigned long adj_end; mm->scanned_blocks++; @@ -612,24 +629,21 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) hole_start = drm_mm_hole_node_start(prev_node); hole_end = drm_mm_hole_node_end(prev_node); - adj_start = hole_start; - adj_end = hole_end; - if (mm->color_adjust) - mm->color_adjust(prev_node, mm->scan_color, &adj_start, &adj_end); + mm->color_adjust(prev_node, mm->scan_color, + &hole_start, &hole_end); if (mm->scan_check_range) { - if (adj_start < mm->scan_start) - adj_start = mm->scan_start; - if (adj_end > mm->scan_end) - adj_end = mm->scan_end; + if (hole_start < mm->scan_start) + hole_start = mm->scan_start; + if (hole_end > mm->scan_end) + hole_end = mm->scan_end; } - if (check_free_hole(adj_start, adj_end, - mm->scan_size, mm->scan_alignment)) { + if (adjust_free_hole(&hole_start, &hole_end, + mm->scan_size, mm->scan_alignment)) { mm->scan_hit_start = hole_start; - mm->scan_hit_size = hole_end; - + mm->scan_hit_end = hole_end; return 1; } @@ -668,16 +682,8 @@ int drm_mm_scan_remove_block(struct drm_mm_node *node) INIT_LIST_HEAD(&node->node_list); list_add(&node->node_list, &prev_node->node_list); - /* Only need to check for containement because start&size for the - * complete resulting free block (not just the desired part) is - * stored. */ - if (node->start >= mm->scan_hit_start && - node->start + node->size - <= mm->scan_hit_start + mm->scan_hit_size) { - return 1; - } - - return 0; + return (node->start + node->size >= mm->scan_hit_start && + node->start <= mm->scan_hit_end); } EXPORT_SYMBOL(drm_mm_scan_remove_block); diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 9a08a45..9e06ca1 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -70,7 +70,7 @@ struct drm_mm { unsigned long scan_color; unsigned long scan_size; unsigned long scan_hit_start; - unsigned scan_hit_size; + unsigned long scan_hit_end; unsigned scanned_blocks; unsigned long scan_start; unsigned long scan_end; -- 1.7.10.4 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel