diff options
Diffstat (limited to 'lib/debugobjects.c')
-rw-r--r-- | lib/debugobjects.c | 64 |
1 files changed, 59 insertions, 5 deletions
diff --git a/lib/debugobjects.c b/lib/debugobjects.c index a9a8996d286a..deebcc57d4e6 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/seq_file.h> | 13 | #include <linux/seq_file.h> |
14 | #include <linux/debugfs.h> | 14 | #include <linux/debugfs.h> |
15 | #include <linux/slab.h> | ||
15 | #include <linux/hash.h> | 16 | #include <linux/hash.h> |
16 | 17 | ||
17 | #define ODEBUG_HASH_BITS 14 | 18 | #define ODEBUG_HASH_BITS 14 |
@@ -140,6 +141,7 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr) | |||
140 | obj->object = addr; | 141 | obj->object = addr; |
141 | obj->descr = descr; | 142 | obj->descr = descr; |
142 | obj->state = ODEBUG_STATE_NONE; | 143 | obj->state = ODEBUG_STATE_NONE; |
144 | obj->astate = 0; | ||
143 | hlist_del(&obj->node); | 145 | hlist_del(&obj->node); |
144 | 146 | ||
145 | hlist_add_head(&obj->node, &b->list); | 147 | hlist_add_head(&obj->node, &b->list); |
@@ -251,8 +253,10 @@ static void debug_print_object(struct debug_obj *obj, char *msg) | |||
251 | 253 | ||
252 | if (limit < 5 && obj->descr != descr_test) { | 254 | if (limit < 5 && obj->descr != descr_test) { |
253 | limit++; | 255 | limit++; |
254 | WARN(1, KERN_ERR "ODEBUG: %s %s object type: %s\n", msg, | 256 | WARN(1, KERN_ERR "ODEBUG: %s %s (active state %u) " |
255 | obj_states[obj->state], obj->descr->name); | 257 | "object type: %s\n", |
258 | msg, obj_states[obj->state], obj->astate, | ||
259 | obj->descr->name); | ||
256 | } | 260 | } |
257 | debug_objects_warnings++; | 261 | debug_objects_warnings++; |
258 | } | 262 | } |
@@ -446,7 +450,10 @@ void debug_object_deactivate(void *addr, struct debug_obj_descr *descr) | |||
446 | case ODEBUG_STATE_INIT: | 450 | case ODEBUG_STATE_INIT: |
447 | case ODEBUG_STATE_INACTIVE: | 451 | case ODEBUG_STATE_INACTIVE: |
448 | case ODEBUG_STATE_ACTIVE: | 452 | case ODEBUG_STATE_ACTIVE: |
449 | obj->state = ODEBUG_STATE_INACTIVE; | 453 | if (!obj->astate) |
454 | obj->state = ODEBUG_STATE_INACTIVE; | ||
455 | else | ||
456 | debug_print_object(obj, "deactivate"); | ||
450 | break; | 457 | break; |
451 | 458 | ||
452 | case ODEBUG_STATE_DESTROYED: | 459 | case ODEBUG_STATE_DESTROYED: |
@@ -552,6 +559,53 @@ out_unlock: | |||
552 | raw_spin_unlock_irqrestore(&db->lock, flags); | 559 | raw_spin_unlock_irqrestore(&db->lock, flags); |
553 | } | 560 | } |
554 | 561 | ||
562 | /** | ||
563 | * debug_object_active_state - debug checks object usage state machine | ||
564 | * @addr: address of the object | ||
565 | * @descr: pointer to an object specific debug description structure | ||
566 | * @expect: expected state | ||
567 | * @next: state to move to if expected state is found | ||
568 | */ | ||
569 | void | ||
570 | debug_object_active_state(void *addr, struct debug_obj_descr *descr, | ||
571 | unsigned int expect, unsigned int next) | ||
572 | { | ||
573 | struct debug_bucket *db; | ||
574 | struct debug_obj *obj; | ||
575 | unsigned long flags; | ||
576 | |||
577 | if (!debug_objects_enabled) | ||
578 | return; | ||
579 | |||
580 | db = get_bucket((unsigned long) addr); | ||
581 | |||
582 | raw_spin_lock_irqsave(&db->lock, flags); | ||
583 | |||
584 | obj = lookup_object(addr, db); | ||
585 | if (obj) { | ||
586 | switch (obj->state) { | ||
587 | case ODEBUG_STATE_ACTIVE: | ||
588 | if (obj->astate == expect) | ||
589 | obj->astate = next; | ||
590 | else | ||
591 | debug_print_object(obj, "active_state"); | ||
592 | break; | ||
593 | |||
594 | default: | ||
595 | debug_print_object(obj, "active_state"); | ||
596 | break; | ||
597 | } | ||
598 | } else { | ||
599 | struct debug_obj o = { .object = addr, | ||
600 | .state = ODEBUG_STATE_NOTAVAILABLE, | ||
601 | .descr = descr }; | ||
602 | |||
603 | debug_print_object(&o, "active_state"); | ||
604 | } | ||
605 | |||
606 | raw_spin_unlock_irqrestore(&db->lock, flags); | ||
607 | } | ||
608 | |||
555 | #ifdef CONFIG_DEBUG_OBJECTS_FREE | 609 | #ifdef CONFIG_DEBUG_OBJECTS_FREE |
556 | static void __debug_check_no_obj_freed(const void *address, unsigned long size) | 610 | static void __debug_check_no_obj_freed(const void *address, unsigned long size) |
557 | { | 611 | { |
@@ -773,7 +827,7 @@ static int __init fixup_free(void *addr, enum debug_obj_state state) | |||
773 | } | 827 | } |
774 | } | 828 | } |
775 | 829 | ||
776 | static int | 830 | static int __init |
777 | check_results(void *addr, enum debug_obj_state state, int fixups, int warnings) | 831 | check_results(void *addr, enum debug_obj_state state, int fixups, int warnings) |
778 | { | 832 | { |
779 | struct debug_bucket *db; | 833 | struct debug_bucket *db; |
@@ -916,7 +970,7 @@ void __init debug_objects_early_init(void) | |||
916 | /* | 970 | /* |
917 | * Convert the statically allocated objects to dynamic ones: | 971 | * Convert the statically allocated objects to dynamic ones: |
918 | */ | 972 | */ |
919 | static int debug_objects_replace_static_objects(void) | 973 | static int __init debug_objects_replace_static_objects(void) |
920 | { | 974 | { |
921 | struct debug_bucket *db = obj_hash; | 975 | struct debug_bucket *db = obj_hash; |
922 | struct hlist_node *node, *tmp; | 976 | struct hlist_node *node, *tmp; |