Commit a5d8e467f83f6672104f276223a88e3b50cbd375

Authored by Mathieu Desnoyers
Committed by Paul E. McKenney
1 parent d822ed1094

Debugobjects transition check

Implement a basic state machine checker in the debugobjects.

This state machine checker detects races and inconsistencies within the "active"
life of a debugobject. The checker only keeps track of the current state; all
the state machine logic is kept at the object instance level.

The checker works by adding a supplementary "unsigned int astate" field to the
debug_obj structure. It keeps track of the current "active state" of the object.

The only constraints that are imposed on the states by the debugobjects system
is that:

- activation of an object sets the current active state to 0,
- deactivation of an object expects the current active state to be 0.

For the rest of the states, the state mapping is determined by the specific
object instance. Therefore, the logic keeping track of the state machine is
within the specialized instance, without any need to know about it at the
debugobject level.

The current object active state is changed by calling:

debug_object_active_state(addr, descr, expect, next)

where "expect" is the expected state and "next" is the next state to move to if
the expected state is found. A warning is generated if the expected is not
found.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: David S. Miller <davem@davemloft.net>
CC: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
CC: akpm@linux-foundation.org
CC: mingo@elte.hu
CC: laijs@cn.fujitsu.com
CC: dipankar@in.ibm.com
CC: josh@joshtriplett.org
CC: dvhltc@us.ibm.com
CC: niv@us.ibm.com
CC: peterz@infradead.org
CC: rostedt@goodmis.org
CC: Valdis.Kletnieks@vt.edu
CC: dhowells@redhat.com
CC: eric.dumazet@gmail.com
CC: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

Showing 2 changed files with 67 additions and 3 deletions Side-by-side Diff

include/linux/debugobjects.h
... ... @@ -20,12 +20,14 @@
20 20 * struct debug_obj - representaion of an tracked object
21 21 * @node: hlist node to link the object into the tracker list
22 22 * @state: tracked object state
  23 + * @astate: current active state
23 24 * @object: pointer to the real object
24 25 * @descr: pointer to an object type specific debug description structure
25 26 */
26 27 struct debug_obj {
27 28 struct hlist_node node;
28 29 enum debug_obj_state state;
  30 + unsigned int astate;
29 31 void *object;
30 32 struct debug_obj_descr *descr;
31 33 };
... ... @@ -59,6 +61,15 @@
59 61 extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr);
60 62 extern void debug_object_destroy (void *addr, struct debug_obj_descr *descr);
61 63 extern void debug_object_free (void *addr, struct debug_obj_descr *descr);
  64 +
  65 +/*
  66 + * Active state:
  67 + * - Set at 0 upon initialization.
  68 + * - Must return to 0 before deactivation.
  69 + */
  70 +extern void
  71 +debug_object_active_state(void *addr, struct debug_obj_descr *descr,
  72 + unsigned int expect, unsigned int next);
62 73  
63 74 extern void debug_objects_early_init(void);
64 75 extern void debug_objects_mem_init(void);
... ... @@ -141,6 +141,7 @@
141 141 obj->object = addr;
142 142 obj->descr = descr;
143 143 obj->state = ODEBUG_STATE_NONE;
  144 + obj->astate = 0;
144 145 hlist_del(&obj->node);
145 146  
146 147 hlist_add_head(&obj->node, &b->list);
... ... @@ -252,8 +253,10 @@
252 253  
253 254 if (limit < 5 && obj->descr != descr_test) {
254 255 limit++;
255   - WARN(1, KERN_ERR "ODEBUG: %s %s object type: %s\n", msg,
256   - obj_states[obj->state], obj->descr->name);
  256 + WARN(1, KERN_ERR "ODEBUG: %s %s (active state %u) "
  257 + "object type: %s\n",
  258 + msg, obj_states[obj->state], obj->astate,
  259 + obj->descr->name);
257 260 }
258 261 debug_objects_warnings++;
259 262 }
... ... @@ -447,7 +450,10 @@
447 450 case ODEBUG_STATE_INIT:
448 451 case ODEBUG_STATE_INACTIVE:
449 452 case ODEBUG_STATE_ACTIVE:
450   - obj->state = ODEBUG_STATE_INACTIVE;
  453 + if (!obj->astate)
  454 + obj->state = ODEBUG_STATE_INACTIVE;
  455 + else
  456 + debug_print_object(obj, "deactivate");
451 457 break;
452 458  
453 459 case ODEBUG_STATE_DESTROYED:
... ... @@ -550,6 +556,53 @@
550 556 return;
551 557 }
552 558 out_unlock:
  559 + raw_spin_unlock_irqrestore(&db->lock, flags);
  560 +}
  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 +
553 606 raw_spin_unlock_irqrestore(&db->lock, flags);
554 607 }
555 608