Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
forked fromtorvalds/linux

Commit6f2b9b9

Browse files
jmbergIngo Molnar
authored and
Ingo Molnar
committed
timer: implement lockdep deadlock detection
This modifies the timer code in a way to allow lockdep to detectdeadlocks resulting from a lock being taken in the timer functionas well as around the del_timer_sync() call.Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
1 parent673f820 commit6f2b9b9

File tree

2 files changed

+141
-20
lines changed

2 files changed

+141
-20
lines changed

‎include/linux/timer.h‎

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include<linux/ktime.h>
66
#include<linux/stddef.h>
77
#include<linux/debugobjects.h>
8+
#include<linux/stringify.h>
89

910
structtvec_base;
1011

@@ -21,52 +22,126 @@ struct timer_list {
2122
charstart_comm[16];
2223
intstart_pid;
2324
#endif
25+
#ifdefCONFIG_LOCKDEP
26+
structlockdep_maplockdep_map;
27+
#endif
2428
};
2529

2630
externstructtvec_baseboot_tvec_bases;
2731

32+
#ifdefCONFIG_LOCKDEP
33+
/*
34+
* NB: because we have to copy the lockdep_map, setting the lockdep_map key
35+
* (second argument) here is required, otherwise it could be initialised to
36+
* the copy of the lockdep_map later! We use the pointer to and the string
37+
* "<file>:<line>" as the key resp. the name of the lockdep_map.
38+
*/
39+
#define__TIMER_LOCKDEP_MAP_INITIALIZER(_kn)\
40+
.lockdep_map = STATIC_LOCKDEP_MAP_INIT(_kn, &_kn),
41+
#else
42+
#define__TIMER_LOCKDEP_MAP_INITIALIZER(_kn)
43+
#endif
44+
2845
#defineTIMER_INITIALIZER(_function,_expires,_data) {\
2946
.entry = { .prev = TIMER_ENTRY_STATIC },\
3047
.function = (_function),\
3148
.expires = (_expires),\
3249
.data = (_data),\
3350
.base = &boot_tvec_bases,\
51+
__TIMER_LOCKDEP_MAP_INITIALIZER(\
52+
__FILE__ ":" __stringify(__LINE__))\
3453
}
3554

3655
#defineDEFINE_TIMER(_name,_function,_expires,_data)\
3756
struct timer_list _name =\
3857
TIMER_INITIALIZER(_function, _expires, _data)
3958

40-
voidinit_timer(structtimer_list*timer);
41-
voidinit_timer_deferrable(structtimer_list*timer);
59+
voidinit_timer_key(structtimer_list*timer,
60+
constchar*name,
61+
structlock_class_key*key);
62+
voidinit_timer_deferrable_key(structtimer_list*timer,
63+
constchar*name,
64+
structlock_class_key*key);
65+
66+
#ifdefCONFIG_LOCKDEP
67+
#defineinit_timer(timer)\
68+
do {\
69+
static struct lock_class_key __key;\
70+
init_timer_key((timer), #timer, &__key);\
71+
} while (0)
72+
73+
#defineinit_timer_deferrable(timer)\
74+
do {\
75+
static struct lock_class_key __key;\
76+
init_timer_deferrable_key((timer), #timer, &__key);\
77+
} while (0)
78+
79+
#defineinit_timer_on_stack(timer)\
80+
do {\
81+
static struct lock_class_key __key;\
82+
init_timer_on_stack_key((timer), #timer, &__key);\
83+
} while (0)
84+
85+
#definesetup_timer(timer,fn,data)\
86+
do {\
87+
static struct lock_class_key __key;\
88+
setup_timer_key((timer), #timer, &__key, (fn), (data));\
89+
} while (0)
90+
91+
#definesetup_timer_on_stack(timer,fn,data)\
92+
do {\
93+
static struct lock_class_key __key;\
94+
setup_timer_on_stack_key((timer), #timer, &__key,\
95+
(fn), (data));\
96+
} while (0)
97+
#else
98+
#defineinit_timer(timer)\
99+
init_timer_key((timer), NULL, NULL)
100+
#defineinit_timer_deferrable(timer)\
101+
init_timer_deferrable_key((timer), NULL, NULL)
102+
#defineinit_timer_on_stack(timer)\
103+
init_timer_on_stack_key((timer), NULL, NULL)
104+
#definesetup_timer(timer,fn,data)\
105+
setup_timer_key((timer), NULL, NULL, (fn), (data))
106+
#definesetup_timer_on_stack(timer,fn,data)\
107+
setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
108+
#endif
42109

43110
#ifdefCONFIG_DEBUG_OBJECTS_TIMERS
44-
externvoidinit_timer_on_stack(structtimer_list*timer);
111+
externvoidinit_timer_on_stack_key(structtimer_list*timer,
112+
constchar*name,
113+
structlock_class_key*key);
45114
externvoiddestroy_timer_on_stack(structtimer_list*timer);
46115
#else
47116
staticinlinevoiddestroy_timer_on_stack(structtimer_list*timer) { }
48-
staticinlinevoidinit_timer_on_stack(structtimer_list*timer)
117+
staticinlinevoidinit_timer_on_stack_key(structtimer_list*timer,
118+
constchar*name,
119+
structlock_class_key*key)
49120
{
50-
init_timer(timer);
121+
init_timer_key(timer,name,key);
51122
}
52123
#endif
53124

54-
staticinlinevoidsetup_timer(structtimer_list*timer,
125+
staticinlinevoidsetup_timer_key(structtimer_list*timer,
126+
constchar*name,
127+
structlock_class_key*key,
55128
void (*function)(unsigned long),
56129
unsigned longdata)
57130
{
58131
timer->function=function;
59132
timer->data=data;
60-
init_timer(timer);
133+
init_timer_key(timer,name,key);
61134
}
62135

63-
staticinlinevoidsetup_timer_on_stack(structtimer_list*timer,
136+
staticinlinevoidsetup_timer_on_stack_key(structtimer_list*timer,
137+
constchar*name,
138+
structlock_class_key*key,
64139
void (*function)(unsigned long),
65140
unsigned longdata)
66141
{
67142
timer->function=function;
68143
timer->data=data;
69-
init_timer_on_stack(timer);
144+
init_timer_on_stack_key(timer,name,key);
70145
}
71146

72147
/**

‎kernel/timer.c‎

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -491,14 +491,18 @@ static inline void debug_timer_free(struct timer_list *timer)
491491
debug_object_free(timer,&timer_debug_descr);
492492
}
493493

494-
staticvoid__init_timer(structtimer_list*timer);
494+
staticvoid__init_timer(structtimer_list*timer,
495+
constchar*name,
496+
structlock_class_key*key);
495497

496-
voidinit_timer_on_stack(structtimer_list*timer)
498+
voidinit_timer_on_stack_key(structtimer_list*timer,
499+
constchar*name,
500+
structlock_class_key*key)
497501
{
498502
debug_object_init_on_stack(timer,&timer_debug_descr);
499-
__init_timer(timer);
503+
__init_timer(timer,name,key);
500504
}
501-
EXPORT_SYMBOL_GPL(init_timer_on_stack);
505+
EXPORT_SYMBOL_GPL(init_timer_on_stack_key);
502506

503507
voiddestroy_timer_on_stack(structtimer_list*timer)
504508
{
@@ -512,7 +516,9 @@ static inline void debug_timer_activate(struct timer_list *timer) { }
512516
staticinlinevoiddebug_timer_deactivate(structtimer_list*timer) { }
513517
#endif
514518

515-
staticvoid__init_timer(structtimer_list*timer)
519+
staticvoid__init_timer(structtimer_list*timer,
520+
constchar*name,
521+
structlock_class_key*key)
516522
{
517523
timer->entry.next=NULL;
518524
timer->base=__raw_get_cpu_var(tvec_bases);
@@ -521,6 +527,7 @@ static void __init_timer(struct timer_list *timer)
521527
timer->start_pid=-1;
522528
memset(timer->start_comm,0,TASK_COMM_LEN);
523529
#endif
530+
lockdep_init_map(&timer->lockdep_map,name,key,0);
524531
}
525532

526533
/**
@@ -530,19 +537,23 @@ static void __init_timer(struct timer_list *timer)
530537
* init_timer() must be done to a timer prior calling *any* of the
531538
* other timer functions.
532539
*/
533-
voidinit_timer(structtimer_list*timer)
540+
voidinit_timer_key(structtimer_list*timer,
541+
constchar*name,
542+
structlock_class_key*key)
534543
{
535544
debug_timer_init(timer);
536-
__init_timer(timer);
545+
__init_timer(timer,name,key);
537546
}
538-
EXPORT_SYMBOL(init_timer);
547+
EXPORT_SYMBOL(init_timer_key);
539548

540-
voidinit_timer_deferrable(structtimer_list*timer)
549+
voidinit_timer_deferrable_key(structtimer_list*timer,
550+
constchar*name,
551+
structlock_class_key*key)
541552
{
542-
init_timer(timer);
553+
init_timer_key(timer,name,key);
543554
timer_set_deferrable(timer);
544555
}
545-
EXPORT_SYMBOL(init_timer_deferrable);
556+
EXPORT_SYMBOL(init_timer_deferrable_key);
546557

547558
staticinlinevoiddetach_timer(structtimer_list*timer,
548559
intclear_pending)
@@ -789,6 +800,15 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
789800
*/
790801
intdel_timer_sync(structtimer_list*timer)
791802
{
803+
#ifdefCONFIG_LOCKDEP
804+
unsigned longflags;
805+
806+
local_irq_save(flags);
807+
lock_map_acquire(&timer->lockdep_map);
808+
lock_map_release(&timer->lockdep_map);
809+
local_irq_restore(flags);
810+
#endif
811+
792812
for (;;) {
793813
intret=try_to_del_timer_sync(timer);
794814
if (ret >=0)
@@ -861,10 +881,36 @@ static inline void __run_timers(struct tvec_base *base)
861881

862882
set_running_timer(base,timer);
863883
detach_timer(timer,1);
884+
864885
spin_unlock_irq(&base->lock);
865886
{
866887
intpreempt_count=preempt_count();
888+
889+
#ifdefCONFIG_LOCKDEP
890+
/*
891+
* It is permissible to free the timer from
892+
* inside the function that is called from
893+
* it, this we need to take into account for
894+
* lockdep too. To avoid bogus "held lock
895+
* freed" warnings as well as problems when
896+
* looking into timer->lockdep_map, make a
897+
* copy and use that here.
898+
*/
899+
structlockdep_maplockdep_map=
900+
timer->lockdep_map;
901+
#endif
902+
/*
903+
* Couple the lock chain with the lock chain at
904+
* del_timer_sync() by acquiring the lock_map
905+
* around the fn() call here and in
906+
* del_timer_sync().
907+
*/
908+
lock_map_acquire(&lockdep_map);
909+
867910
fn(data);
911+
912+
lock_map_release(&lockdep_map);
913+
868914
if (preempt_count!=preempt_count()) {
869915
printk(KERN_ERR"huh, entered %p "
870916
"with preempt_count %08x, exited"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp