diff options
| -rw-r--r-- | mm/kmemleak.c | 69 |
1 files changed, 41 insertions, 28 deletions
diff --git a/mm/kmemleak.c b/mm/kmemleak.c index c17dbc76fb72..b18d9ca578b9 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c | |||
| @@ -123,6 +123,9 @@ struct kmemleak_scan_area { | |||
| 123 | size_t length; | 123 | size_t length; |
| 124 | }; | 124 | }; |
| 125 | 125 | ||
| 126 | #define KMEMLEAK_GREY 0 | ||
| 127 | #define KMEMLEAK_BLACK -1 | ||
| 128 | |||
| 126 | /* | 129 | /* |
| 127 | * Structure holding the metadata for each allocated memory block. | 130 | * Structure holding the metadata for each allocated memory block. |
| 128 | * Modifications to such objects should be made while holding the | 131 | * Modifications to such objects should be made while holding the |
| @@ -310,17 +313,19 @@ static void hex_dump_object(struct seq_file *seq, | |||
| 310 | */ | 313 | */ |
| 311 | static bool color_white(const struct kmemleak_object *object) | 314 | static bool color_white(const struct kmemleak_object *object) |
| 312 | { | 315 | { |
| 313 | return object->count != -1 && object->count < object->min_count; | 316 | return object->count != KMEMLEAK_BLACK && |
| 317 | object->count < object->min_count; | ||
| 314 | } | 318 | } |
| 315 | 319 | ||
| 316 | static bool color_gray(const struct kmemleak_object *object) | 320 | static bool color_gray(const struct kmemleak_object *object) |
| 317 | { | 321 | { |
| 318 | return object->min_count != -1 && object->count >= object->min_count; | 322 | return object->min_count != KMEMLEAK_BLACK && |
| 323 | object->count >= object->min_count; | ||
| 319 | } | 324 | } |
| 320 | 325 | ||
| 321 | static bool color_black(const struct kmemleak_object *object) | 326 | static bool color_black(const struct kmemleak_object *object) |
| 322 | { | 327 | { |
| 323 | return object->min_count == -1; | 328 | return object->min_count == KMEMLEAK_BLACK; |
| 324 | } | 329 | } |
| 325 | 330 | ||
| 326 | /* | 331 | /* |
| @@ -661,47 +666,55 @@ static void delete_object_part(unsigned long ptr, size_t size) | |||
| 661 | 666 | ||
| 662 | put_object(object); | 667 | put_object(object); |
| 663 | } | 668 | } |
| 664 | /* | 669 | |
| 665 | * Make a object permanently as gray-colored so that it can no longer be | 670 | static void __paint_it(struct kmemleak_object *object, int color) |
| 666 | * reported as a leak. This is used in general to mark a false positive. | 671 | { |
| 667 | */ | 672 | object->min_count = color; |
| 668 | static void make_gray_object(unsigned long ptr) | 673 | if (color == KMEMLEAK_BLACK) |
| 674 | object->flags |= OBJECT_NO_SCAN; | ||
| 675 | } | ||
| 676 | |||
| 677 | static void paint_it(struct kmemleak_object *object, int color) | ||
| 669 | { | 678 | { |
| 670 | unsigned long flags; | 679 | unsigned long flags; |
| 680 | |||
| 681 | spin_lock_irqsave(&object->lock, flags); | ||
| 682 | __paint_it(object, color); | ||
| 683 | spin_unlock_irqrestore(&object->lock, flags); | ||
| 684 | } | ||
| 685 | |||
| 686 | static void paint_ptr(unsigned long ptr, int color) | ||
| 687 | { | ||
| 671 | struct kmemleak_object *object; | 688 | struct kmemleak_object *object; |
| 672 | 689 | ||
| 673 | object = find_and_get_object(ptr, 0); | 690 | object = find_and_get_object(ptr, 0); |
| 674 | if (!object) { | 691 | if (!object) { |
| 675 | kmemleak_warn("Graying unknown object at 0x%08lx\n", ptr); | 692 | kmemleak_warn("Trying to color unknown object " |
| 693 | "at 0x%08lx as %s\n", ptr, | ||
| 694 | (color == KMEMLEAK_GREY) ? "Grey" : | ||
| 695 | (color == KMEMLEAK_BLACK) ? "Black" : "Unknown"); | ||
| 676 | return; | 696 | return; |
| 677 | } | 697 | } |
| 678 | 698 | paint_it(object, color); | |
| 679 | spin_lock_irqsave(&object->lock, flags); | ||
| 680 | object->min_count = 0; | ||
| 681 | spin_unlock_irqrestore(&object->lock, flags); | ||
| 682 | put_object(object); | 699 | put_object(object); |
| 683 | } | 700 | } |
| 684 | 701 | ||
| 685 | /* | 702 | /* |
| 703 | * Make a object permanently as gray-colored so that it can no longer be | ||
| 704 | * reported as a leak. This is used in general to mark a false positive. | ||
| 705 | */ | ||
| 706 | static void make_gray_object(unsigned long ptr) | ||
| 707 | { | ||
| 708 | paint_ptr(ptr, KMEMLEAK_GREY); | ||
| 709 | } | ||
| 710 | |||
| 711 | /* | ||
| 686 | * Mark the object as black-colored so that it is ignored from scans and | 712 | * Mark the object as black-colored so that it is ignored from scans and |
| 687 | * reporting. | 713 | * reporting. |
| 688 | */ | 714 | */ |
| 689 | static void make_black_object(unsigned long ptr) | 715 | static void make_black_object(unsigned long ptr) |
| 690 | { | 716 | { |
| 691 | unsigned long flags; | 717 | paint_ptr(ptr, KMEMLEAK_BLACK); |
| 692 | struct kmemleak_object *object; | ||
| 693 | |||
| 694 | object = find_and_get_object(ptr, 0); | ||
| 695 | if (!object) { | ||
| 696 | kmemleak_warn("Blacking unknown object at 0x%08lx\n", ptr); | ||
| 697 | return; | ||
| 698 | } | ||
| 699 | |||
| 700 | spin_lock_irqsave(&object->lock, flags); | ||
| 701 | object->min_count = -1; | ||
| 702 | object->flags |= OBJECT_NO_SCAN; | ||
| 703 | spin_unlock_irqrestore(&object->lock, flags); | ||
| 704 | put_object(object); | ||
| 705 | } | 718 | } |
| 706 | 719 | ||
| 707 | /* | 720 | /* |
| @@ -1436,7 +1449,7 @@ static void kmemleak_clear(void) | |||
| 1436 | spin_lock_irqsave(&object->lock, flags); | 1449 | spin_lock_irqsave(&object->lock, flags); |
| 1437 | if ((object->flags & OBJECT_REPORTED) && | 1450 | if ((object->flags & OBJECT_REPORTED) && |
| 1438 | unreferenced_object(object)) | 1451 | unreferenced_object(object)) |
| 1439 | object->min_count = 0; | 1452 | __paint_it(object, KMEMLEAK_GREY); |
| 1440 | spin_unlock_irqrestore(&object->lock, flags); | 1453 | spin_unlock_irqrestore(&object->lock, flags); |
| 1441 | } | 1454 | } |
| 1442 | rcu_read_unlock(); | 1455 | rcu_read_unlock(); |
