A few callers need to serialise the destruction of their drm_mm_node and ensure it is removed from the drm_mm before freeing. However, to be completely sure that any access from another thread is complete before we free the struct, we require the RELEASE semantics of clear_bit_unlock(). This allows the conditional locking such as Thread A Thread B mutex_lock(mm_lock); if (drm_mm_node_allocated(node)) { drm_mm_node_remove(node); mutex_lock(mm_lock); mutex_unlock(mm_lock); if (drm_mm_node_allocated(node)) drm_mm_node_remove(node); mutex_unlock(mm_lock); } kfree(node); to serialise correctly without any lingering accesses from A to the freed node. Allocation / insertion of the node is assumed never to race with removal or eviction scanning.
Unified · Split
| @@ -424,9 +424,9 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) · 423 unmodified lines | ||
| 424 | 424 | |
| 425 | 425 | node->mm = mm; |
| 426 | 426 | |
| 427 | + __set_bit(DRM_MM_NODE_ALLOCATED_BIT, &node->flags); | |
| 427 | 428 | list_add(&node->node_list, &hole->node_list); |
| 428 | 429 | drm_mm_interval_tree_add_node(hole, node); |
| 429 | − __set_bit(DRM_MM_NODE_ALLOCATED_BIT, &node->flags); | |
| 430 | 430 | node->hole_size = 0; |
| 431 | 431 | |
| 432 | 432 | rm_hole(hole); |
| @@ -543,9 +543,9 @@ int drm_mm_insert_node_in_range(struct drm_mm * const mm, · 110 unmodified lines | ||
| 543 | 543 | node->color = color; |
| 544 | 544 | node->hole_size = 0; |
| 545 | 545 | |
| 546 | + __set_bit(DRM_MM_NODE_ALLOCATED_BIT, &node->flags); | |
| 546 | 547 | list_add(&node->node_list, &hole->node_list); |
| 547 | 548 | drm_mm_interval_tree_add_node(hole, node); |
| 548 | − __set_bit(DRM_MM_NODE_ALLOCATED_BIT, &node->flags); | |
| 549 | 549 | |
| 550 | 550 | rm_hole(hole); |
| 551 | 551 | if (adj_start > hole_start) |
| @@ -589,11 +589,12 @@ void drm_mm_remove_node(struct drm_mm_node *node) · 37 unmodified lines | ||
| 589 | 589 | |
| 590 | 590 | drm_mm_interval_tree_remove(node, &mm->interval_tree); |
| 591 | 591 | list_del(&node->node_list); |
| 592 | − __clear_bit(DRM_MM_NODE_ALLOCATED_BIT, &node->flags); | |
| 593 | 592 | |
| 594 | 593 | if (drm_mm_hole_follows(prev_node)) |
| 595 | 594 | rm_hole(prev_node); |
| 596 | 595 | add_hole(prev_node); |
| 596 | + | |
| 597 | + clear_bit_unlock(DRM_MM_NODE_ALLOCATED_BIT, &node->flags); | |
| 597 | 598 | } |
| 598 | 599 | EXPORT_SYMBOL(drm_mm_remove_node); |
| 599 | 600 | |
| @@ -614,6 +615,7 @@ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) · 14 unmodified lines | ||
| 614 | 615 | |
| 615 | 616 | *new = *old; |
| 616 | 617 | |
| 618 | + __set_bit(DRM_MM_NODE_ALLOCATED_BIT, &new->flags); | |
| 617 | 619 | list_replace(&old->node_list, &new->node_list); |
| 618 | 620 | rb_replace_node_cached(&old->rb, &new->rb, &mm->interval_tree); |
| 619 | 621 | |
| @@ -627,8 +629,7 @@ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) · 7 unmodified lines | ||
| 627 | 629 | &mm->holes_addr); |
| 628 | 630 | } |
| 629 | 631 | |
| 630 | − __clear_bit(DRM_MM_NODE_ALLOCATED_BIT, &old->flags); | |
| 631 | − __set_bit(DRM_MM_NODE_ALLOCATED_BIT, &new->flags); | |
| 632 | + clear_bit_unlock(DRM_MM_NODE_ALLOCATED_BIT, &old->flags); | |
| 632 | 633 | } |
| 633 | 634 | EXPORT_SYMBOL(drm_mm_replace_node); |
| 634 | 635 | |