debugobjects: Make debug_object_activate() return status

In order to better respond to things like duplicate invocations
of call_rcu(), RCU needs to see the status of a call to
debug_object_activate().  This would allow RCU to leak the callback in
order to avoid adding freelist-reuse mischief to the duplicate invoations.
This commit therefore makes debug_object_activate() return status,
zero for success and -EINVAL for failure.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Sedat Dilek <sedat.dilek@gmail.com>
Cc: Davidlohr Bueso <davidlohr.bueso@hp.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
This commit is contained in:
Paul E. McKenney 2013-04-23 12:51:11 -07:00
parent 15100df81f
commit b778ae2536
2 changed files with 17 additions and 9 deletions

View File

@ -63,7 +63,7 @@ struct debug_obj_descr {
extern void debug_object_init (void *addr, struct debug_obj_descr *descr); extern void debug_object_init (void *addr, struct debug_obj_descr *descr);
extern void extern void
debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr); debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr);
extern void debug_object_activate (void *addr, struct debug_obj_descr *descr); extern int debug_object_activate (void *addr, struct debug_obj_descr *descr);
extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr); extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr);
extern void debug_object_destroy (void *addr, struct debug_obj_descr *descr); extern void debug_object_destroy (void *addr, struct debug_obj_descr *descr);
extern void debug_object_free (void *addr, struct debug_obj_descr *descr); extern void debug_object_free (void *addr, struct debug_obj_descr *descr);
@ -85,8 +85,8 @@ static inline void
debug_object_init (void *addr, struct debug_obj_descr *descr) { } debug_object_init (void *addr, struct debug_obj_descr *descr) { }
static inline void static inline void
debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) { } debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) { }
static inline void static inline int
debug_object_activate (void *addr, struct debug_obj_descr *descr) { } debug_object_activate (void *addr, struct debug_obj_descr *descr) { return 0; }
static inline void static inline void
debug_object_deactivate(void *addr, struct debug_obj_descr *descr) { } debug_object_deactivate(void *addr, struct debug_obj_descr *descr) { }
static inline void static inline void

View File

@ -381,19 +381,21 @@ void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr)
* debug_object_activate - debug checks when an object is activated * debug_object_activate - debug checks when an object is activated
* @addr: address of the object * @addr: address of the object
* @descr: pointer to an object specific debug description structure * @descr: pointer to an object specific debug description structure
* Returns 0 for success, -EINVAL for check failed.
*/ */
void debug_object_activate(void *addr, struct debug_obj_descr *descr) int debug_object_activate(void *addr, struct debug_obj_descr *descr)
{ {
enum debug_obj_state state; enum debug_obj_state state;
struct debug_bucket *db; struct debug_bucket *db;
struct debug_obj *obj; struct debug_obj *obj;
unsigned long flags; unsigned long flags;
int ret;
struct debug_obj o = { .object = addr, struct debug_obj o = { .object = addr,
.state = ODEBUG_STATE_NOTAVAILABLE, .state = ODEBUG_STATE_NOTAVAILABLE,
.descr = descr }; .descr = descr };
if (!debug_objects_enabled) if (!debug_objects_enabled)
return; return 0;
db = get_bucket((unsigned long) addr); db = get_bucket((unsigned long) addr);
@ -405,23 +407,26 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr)
case ODEBUG_STATE_INIT: case ODEBUG_STATE_INIT:
case ODEBUG_STATE_INACTIVE: case ODEBUG_STATE_INACTIVE:
obj->state = ODEBUG_STATE_ACTIVE; obj->state = ODEBUG_STATE_ACTIVE;
ret = 0;
break; break;
case ODEBUG_STATE_ACTIVE: case ODEBUG_STATE_ACTIVE:
debug_print_object(obj, "activate"); debug_print_object(obj, "activate");
state = obj->state; state = obj->state;
raw_spin_unlock_irqrestore(&db->lock, flags); raw_spin_unlock_irqrestore(&db->lock, flags);
debug_object_fixup(descr->fixup_activate, addr, state); ret = debug_object_fixup(descr->fixup_activate, addr, state);
return; return ret ? -EINVAL : 0;
case ODEBUG_STATE_DESTROYED: case ODEBUG_STATE_DESTROYED:
debug_print_object(obj, "activate"); debug_print_object(obj, "activate");
ret = -EINVAL;
break; break;
default: default:
ret = 0;
break; break;
} }
raw_spin_unlock_irqrestore(&db->lock, flags); raw_spin_unlock_irqrestore(&db->lock, flags);
return; return ret;
} }
raw_spin_unlock_irqrestore(&db->lock, flags); raw_spin_unlock_irqrestore(&db->lock, flags);
@ -431,8 +436,11 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr)
* true or not. * true or not.
*/ */
if (debug_object_fixup(descr->fixup_activate, addr, if (debug_object_fixup(descr->fixup_activate, addr,
ODEBUG_STATE_NOTAVAILABLE)) ODEBUG_STATE_NOTAVAILABLE)) {
debug_print_object(&o, "activate"); debug_print_object(&o, "activate");
return -EINVAL;
}
return 0;
} }
/** /**