|
13 | 13 | * |
14 | 14 | * The following locks and mutexes are used by kmemleak: |
15 | 15 | * |
16 | | - * - kmemleak_lock (raw_spinlock_t): protects the object_list modifications and |
17 | | - * accesses to the object_tree_root (or object_phys_tree_root). The |
18 | | - * object_list is the main list holding the metadata (struct kmemleak_object) |
19 | | - * for the allocated memory blocks. The object_tree_root and object_phys_tree_root |
20 | | - * are red black trees used to look-up metadata based on a pointer to the |
| 16 | + * - kmemleak_lock (raw_spinlock_t): protects the object_list as well as |
| 17 | + * del_state modifications and accesses to the object_tree_root (or |
| 18 | + * object_phys_tree_root). The object_list is the main list holding the |
| 19 | + * metadata (struct kmemleak_object) for the allocated memory blocks. |
| 20 | + * The object_tree_root and object_phys_tree_root are red |
| 21 | + * black trees used to look-up metadata based on a pointer to the |
21 | 22 | * corresponding memory block. The object_phys_tree_root is for objects |
22 | 23 | * allocated with physical address. The kmemleak_object structures are |
23 | 24 | * added to the object_list and object_tree_root (or object_phys_tree_root) |
@@ -147,6 +148,7 @@ struct kmemleak_object { |
147 | 148 | struct rcu_head rcu; /* object_list lockless traversal */ |
148 | 149 | /* object usage count; object freed when use_count == 0 */ |
149 | 150 | atomic_t use_count; |
| 151 | + unsigned int del_state; /* deletion state */ |
150 | 152 | unsigned long pointer; |
151 | 153 | size_t size; |
152 | 154 | /* pass surplus references to this pointer */ |
@@ -177,6 +179,11 @@ struct kmemleak_object { |
177 | 179 | /* flag set for object allocated with physical address */ |
178 | 180 | #define OBJECT_PHYS (1 << 4) |
179 | 181 |
|
| 182 | +/* set when __remove_object() called */ |
| 183 | +#define DELSTATE_REMOVED (1 << 0) |
| 184 | +/* set to temporarily prevent deletion from object_list */ |
| 185 | +#define DELSTATE_NO_DELETE (1 << 1) |
| 186 | + |
180 | 187 | #define HEX_PREFIX " " |
181 | 188 | /* number of bytes to print per line; must be 16 or 32 */ |
182 | 189 | #define HEX_ROW_SIZE 16 |
@@ -567,7 +574,9 @@ static void __remove_object(struct kmemleak_object *object) |
567 | 574 | rb_erase(&object->rb_node, object->flags & OBJECT_PHYS ? |
568 | 575 | &object_phys_tree_root : |
569 | 576 | &object_tree_root); |
570 | | - list_del_rcu(&object->object_list); |
| 577 | + if (!(object->del_state & DELSTATE_NO_DELETE)) |
| 578 | + list_del_rcu(&object->object_list); |
| 579 | + object->del_state |= DELSTATE_REMOVED; |
571 | 580 | } |
572 | 581 |
|
573 | 582 | /* |
@@ -634,6 +643,7 @@ static struct kmemleak_object *__create_object(unsigned long ptr, size_t size, |
634 | 643 | object->count = 0; /* white color initially */ |
635 | 644 | object->jiffies = jiffies; |
636 | 645 | object->checksum = 0; |
| 646 | + object->del_state = 0; |
637 | 647 |
|
638 | 648 | /* task information */ |
639 | 649 | if (in_hardirq()) { |
@@ -1473,9 +1483,22 @@ static void kmemleak_cond_resched(struct kmemleak_object *object) |
1473 | 1483 | if (!get_object(object)) |
1474 | 1484 | return; /* Try next object */ |
1475 | 1485 |
|
| 1486 | + raw_spin_lock_irq(&kmemleak_lock); |
| 1487 | + if (object->del_state & DELSTATE_REMOVED) |
| 1488 | + goto unlock_put; /* Object removed */ |
| 1489 | + object->del_state |= DELSTATE_NO_DELETE; |
| 1490 | + raw_spin_unlock_irq(&kmemleak_lock); |
| 1491 | + |
1476 | 1492 | rcu_read_unlock(); |
1477 | 1493 | cond_resched(); |
1478 | 1494 | rcu_read_lock(); |
| 1495 | + |
| 1496 | + raw_spin_lock_irq(&kmemleak_lock); |
| 1497 | + if (object->del_state & DELSTATE_REMOVED) |
| 1498 | + list_del_rcu(&object->object_list); |
| 1499 | + object->del_state &= ~DELSTATE_NO_DELETE; |
| 1500 | +unlock_put: |
| 1501 | + raw_spin_unlock_irq(&kmemleak_lock); |
1479 | 1502 | put_object(object); |
1480 | 1503 | } |
1481 | 1504 |
|
|
0 commit comments