1377 lines · 34.6 KB · C
RawDownload
	if (fixup && fixup(addr, state)) {		debug_objects_fixups++;		return true;	}	return false;} static void debug_object_is_on_stack(void *addr, int onstack){	int is_on_stack;	static int limit; 	if (limit > 4)		return; 	is_on_stack = object_is_on_stack(addr);	if (is_on_stack == onstack)		return; 	limit++;	if (is_on_stack)		pr_warn("object %p is on stack %p, but NOT annotated.\n", addr,			 task_stack_page(current));	else		pr_warn("object %p is NOT on stack %p, but annotated.\n", addr,			 task_stack_page(current)); 	WARN_ON(1);} static void__debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack){	enum debug_obj_state state;	bool check_stack = false;	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags; 	fill_pool(); 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (!obj) {		obj = alloc_object(addr, db, descr);		if (!obj) {			debug_objects_enabled = 0;			raw_spin_unlock_irqrestore(&db->lock, flags);			debug_objects_oom();			return;		}		check_stack = true;	} 	switch (obj->state) {	case ODEBUG_STATE_NONE:	case ODEBUG_STATE_INIT:	case ODEBUG_STATE_INACTIVE:		obj->state = ODEBUG_STATE_INIT;		break; 	case ODEBUG_STATE_ACTIVE:		state = obj->state;		raw_spin_unlock_irqrestore(&db->lock, flags);		debug_print_object(obj, "init");		debug_object_fixup(descr->fixup_init, addr, state);		return; 	case ODEBUG_STATE_DESTROYED:		raw_spin_unlock_irqrestore(&db->lock, flags);		debug_print_object(obj, "init");		return;	default:		break;	} 	raw_spin_unlock_irqrestore(&db->lock, flags);	if (check_stack)		debug_object_is_on_stack(addr, onstack);} /** * debug_object_init - debug checks when an object is initialized * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_init(void *addr, struct debug_obj_descr *descr){	if (!debug_objects_enabled)		return; 	__debug_object_init(addr, descr, 0);}EXPORT_SYMBOL_GPL(debug_object_init); /** * debug_object_init_on_stack - debug checks when an object on stack is *				initialized * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr){	if (!debug_objects_enabled)		return; 	__debug_object_init(addr, descr, 1);}EXPORT_SYMBOL_GPL(debug_object_init_on_stack); /** * debug_object_activate - debug checks when an object is activated * @addr:	address of the object * @descr:	pointer to an object specific debug description structure * Returns 0 for success, -EINVAL for check failed. */int debug_object_activate(void *addr, struct debug_obj_descr *descr){	enum debug_obj_state state;	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags;	int ret;	struct debug_obj o = { .object = addr,			       .state = ODEBUG_STATE_NOTAVAILABLE,			       .descr = descr }; 	if (!debug_objects_enabled)		return 0; 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (obj) {		bool print_object = false; 		switch (obj->state) {		case ODEBUG_STATE_INIT:		case ODEBUG_STATE_INACTIVE:			obj->state = ODEBUG_STATE_ACTIVE;			ret = 0;			break; 		case ODEBUG_STATE_ACTIVE:			state = obj->state;			raw_spin_unlock_irqrestore(&db->lock, flags);			debug_print_object(obj, "activate");			ret = debug_object_fixup(descr->fixup_activate, addr, state);			return ret ? 0 : -EINVAL; 		case ODEBUG_STATE_DESTROYED:			print_object = true;			ret = -EINVAL;			break;		default:			ret = 0;			break;		}		raw_spin_unlock_irqrestore(&db->lock, flags);		if (print_object)			debug_print_object(obj, "activate");		return ret;	} 	raw_spin_unlock_irqrestore(&db->lock, flags); 	/*	 * We are here when a static object is activated. We	 * let the type specific code confirm whether this is	 * true or not. if true, we just make sure that the	 * static object is tracked in the object tracker. If	 * not, this must be a bug, so we try to fix it up.	 */	if (descr->is_static_object && descr->is_static_object(addr)) {		/* track this static object */		debug_object_init(addr, descr);		debug_object_activate(addr, descr);	} else {		debug_print_object(&o, "activate");		ret = debug_object_fixup(descr->fixup_activate, addr,					ODEBUG_STATE_NOTAVAILABLE);		return ret ? 0 : -EINVAL;	}	return 0;}EXPORT_SYMBOL_GPL(debug_object_activate); /** * debug_object_deactivate - debug checks when an object is deactivated * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_deactivate(void *addr, struct debug_obj_descr *descr){	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags;	bool print_object = false; 	if (!debug_objects_enabled)		return; 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (obj) {		switch (obj->state) {		case ODEBUG_STATE_INIT:		case ODEBUG_STATE_INACTIVE:		case ODEBUG_STATE_ACTIVE:			if (!obj->astate)				obj->state = ODEBUG_STATE_INACTIVE;			else				print_object = true;			break; 		case ODEBUG_STATE_DESTROYED:			print_object = true;			break;		default:			break;		}	} 	raw_spin_unlock_irqrestore(&db->lock, flags);	if (!obj) {		struct debug_obj o = { .object = addr,				       .state = ODEBUG_STATE_NOTAVAILABLE,				       .descr = descr }; 		debug_print_object(&o, "deactivate");	} else if (print_object) {		debug_print_object(obj, "deactivate");	}}EXPORT_SYMBOL_GPL(debug_object_deactivate); /** * debug_object_destroy - debug checks when an object is destroyed * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_destroy(void *addr, struct debug_obj_descr *descr){	enum debug_obj_state state;	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags;	bool print_object = false; 	if (!debug_objects_enabled)		return; 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (!obj)		goto out_unlock; 	switch (obj->state) {	case ODEBUG_STATE_NONE:	case ODEBUG_STATE_INIT:	case ODEBUG_STATE_INACTIVE:		obj->state = ODEBUG_STATE_DESTROYED;		break;	case ODEBUG_STATE_ACTIVE:		state = obj->state;		raw_spin_unlock_irqrestore(&db->lock, flags);		debug_print_object(obj, "destroy");		debug_object_fixup(descr->fixup_destroy, addr, state);		return; 	case ODEBUG_STATE_DESTROYED:		print_object = true;		break;	default:		break;	}out_unlock:	raw_spin_unlock_irqrestore(&db->lock, flags);	if (print_object)		debug_print_object(obj, "destroy");}EXPORT_SYMBOL_GPL(debug_object_destroy); /** * debug_object_free - debug checks when an object is freed * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_free(void *addr, struct debug_obj_descr *descr){	enum debug_obj_state state;	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags; 	if (!debug_objects_enabled)		return; 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (!obj)		goto out_unlock; 	switch (obj->state) {	case ODEBUG_STATE_ACTIVE:		state = obj->state;		raw_spin_unlock_irqrestore(&db->lock, flags);		debug_print_object(obj, "free");		debug_object_fixup(descr->fixup_free, addr, state);		return;	default:		hlist_del(&obj->node);		raw_spin_unlock_irqrestore(&db->lock, flags);		free_object(obj);		return;	}out_unlock:	raw_spin_unlock_irqrestore(&db->lock, flags);}EXPORT_SYMBOL_GPL(debug_object_free); /** * debug_object_assert_init - debug checks when object should be init-ed * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_assert_init(void *addr, struct debug_obj_descr *descr){	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags; 	if (!debug_objects_enabled)		return; 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (!obj) {		struct debug_obj o = { .object = addr,				       .state = ODEBUG_STATE_NOTAVAILABLE,				       .descr = descr }; 		raw_spin_unlock_irqrestore(&db->lock, flags);		/*		 * Maybe the object is static, and we let the type specific		 * code confirm. Track this static object if true, else invoke		 * fixup.		 */		if (descr->is_static_object && descr->is_static_object(addr)) {			/* Track this static object */			debug_object_init(addr, descr);		} else {			debug_print_object(&o, "assert_init");			debug_object_fixup(descr->fixup_assert_init, addr,					   ODEBUG_STATE_NOTAVAILABLE);		}		return;	} 	raw_spin_unlock_irqrestore(&db->lock, flags);}EXPORT_SYMBOL_GPL(debug_object_assert_init); /** * debug_object_active_state - debug checks object usage state machine * @addr:	address of the object * @descr:	pointer to an object specific debug description structure * @expect:	expected state * @next:	state to move to if expected state is found */voiddebug_object_active_state(void *addr, struct debug_obj_descr *descr,			  unsigned int expect, unsigned int next){	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags;	bool print_object = false; 	if (!debug_objects_enabled)		return; 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (obj) {		switch (obj->state) {		case ODEBUG_STATE_ACTIVE:			if (obj->astate == expect)				obj->astate = next;			else				print_object = true;			break; 		default:			print_object = true;			break;		}	} 	raw_spin_unlock_irqrestore(&db->lock, flags);	if (!obj) {		struct debug_obj o = { .object = addr,				       .state = ODEBUG_STATE_NOTAVAILABLE,				       .descr = descr }; 		debug_print_object(&o, "active_state");	} else if (print_object) {		debug_print_object(obj, "active_state");	}}EXPORT_SYMBOL_GPL(debug_object_active_state); #ifdef CONFIG_DEBUG_OBJECTS_FREEstatic void __debug_check_no_obj_freed(const void *address, unsigned long size){	unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;	struct debug_obj_descr *descr;	enum debug_obj_state state;	struct debug_bucket *db;	struct hlist_node *tmp;	struct debug_obj *obj;	int cnt, objs_checked = 0; 	saddr = (unsigned long) address;	eaddr = saddr + size;	paddr = saddr & ODEBUG_CHUNK_MASK;	chunks = ((eaddr - paddr) + (ODEBUG_CHUNK_SIZE - 1));	chunks >>= ODEBUG_CHUNK_SHIFT; 	for (;chunks > 0; chunks--, paddr += ODEBUG_CHUNK_SIZE) {		db = get_bucket(paddr); repeat:		cnt = 0;		raw_spin_lock_irqsave(&db->lock, flags);		hlist_for_each_entry_safe(obj, tmp, &db->list, node) {			cnt++;			oaddr = (unsigned long) obj->object;			if (oaddr < saddr || oaddr >= eaddr)				continue; 			switch (obj->state) {			case ODEBUG_STATE_ACTIVE:				descr = obj->descr;				state = obj->state;				raw_spin_unlock_irqrestore(&db->lock, flags);				debug_print_object(obj, "free");				debug_object_fixup(descr->fixup_free,						   (void *) oaddr, state);				goto repeat;			default:				hlist_del(&obj->node);				__free_object(obj);				break;			}		}		raw_spin_unlock_irqrestore(&db->lock, flags); 		if (cnt > debug_objects_maxchain)			debug_objects_maxchain = cnt; 		objs_checked += cnt;	} 	if (objs_checked > debug_objects_maxchecked)		debug_objects_maxchecked = objs_checked; 	/* Schedule work to actually kmem_cache_free() objects */	if (!READ_ONCE(obj_freeing) && READ_ONCE(obj_nr_tofree)) {		WRITE_ONCE(obj_freeing, true);		schedule_delayed_work(&debug_obj_work, ODEBUG_FREE_WORK_DELAY);	}} void debug_check_no_obj_freed(const void *address, unsigned long size){	if (debug_objects_enabled)		__debug_check_no_obj_freed(address, size);}#endif

Lines 501–1000 of 1377. Previous lines