34
34
#include <linux/spinlock.h>
35
35
#include <linux/ftrace.h>
36
36
#include <trace/events/lock.h>
37
+ #include <linux/hung_task.h>
37
38
38
39
static noinline void __down (struct semaphore * sem );
39
40
static noinline int __down_interruptible (struct semaphore * sem );
40
41
static noinline int __down_killable (struct semaphore * sem );
41
42
static noinline int __down_timeout (struct semaphore * sem , long timeout );
42
43
static noinline void __up (struct semaphore * sem , struct wake_q_head * wake_q );
43
44
45
+ #ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
46
+ static inline void hung_task_sem_set_holder (struct semaphore * sem )
47
+ {
48
+ WRITE_ONCE ((sem )-> last_holder , (unsigned long )current );
49
+ }
50
+
51
+ static inline void hung_task_sem_clear_if_holder (struct semaphore * sem )
52
+ {
53
+ if (READ_ONCE ((sem )-> last_holder ) == (unsigned long )current )
54
+ WRITE_ONCE ((sem )-> last_holder , 0UL );
55
+ }
56
+
57
+ unsigned long sem_last_holder (struct semaphore * sem )
58
+ {
59
+ return READ_ONCE (sem -> last_holder );
60
+ }
61
+ #else
62
+ static inline void hung_task_sem_set_holder (struct semaphore * sem )
63
+ {
64
+ }
65
+ static inline void hung_task_sem_clear_if_holder (struct semaphore * sem )
66
+ {
67
+ }
68
+ unsigned long sem_last_holder (struct semaphore * sem )
69
+ {
70
+ return 0UL ;
71
+ }
72
+ #endif
73
+
74
+ static inline void __sem_acquire (struct semaphore * sem )
75
+ {
76
+ sem -> count -- ;
77
+ hung_task_sem_set_holder (sem );
78
+ }
79
+
44
80
/**
45
81
* down - acquire the semaphore
46
82
* @sem: the semaphore to be acquired
@@ -59,7 +95,7 @@ void __sched down(struct semaphore *sem)
59
95
might_sleep ();
60
96
raw_spin_lock_irqsave (& sem -> lock , flags );
61
97
if (likely (sem -> count > 0 ))
62
- sem -> count -- ;
98
+ __sem_acquire ( sem ) ;
63
99
else
64
100
__down (sem );
65
101
raw_spin_unlock_irqrestore (& sem -> lock , flags );
@@ -83,7 +119,7 @@ int __sched down_interruptible(struct semaphore *sem)
83
119
might_sleep ();
84
120
raw_spin_lock_irqsave (& sem -> lock , flags );
85
121
if (likely (sem -> count > 0 ))
86
- sem -> count -- ;
122
+ __sem_acquire ( sem ) ;
87
123
else
88
124
result = __down_interruptible (sem );
89
125
raw_spin_unlock_irqrestore (& sem -> lock , flags );
@@ -110,7 +146,7 @@ int __sched down_killable(struct semaphore *sem)
110
146
might_sleep ();
111
147
raw_spin_lock_irqsave (& sem -> lock , flags );
112
148
if (likely (sem -> count > 0 ))
113
- sem -> count -- ;
149
+ __sem_acquire ( sem ) ;
114
150
else
115
151
result = __down_killable (sem );
116
152
raw_spin_unlock_irqrestore (& sem -> lock , flags );
@@ -140,7 +176,7 @@ int __sched down_trylock(struct semaphore *sem)
140
176
raw_spin_lock_irqsave (& sem -> lock , flags );
141
177
count = sem -> count - 1 ;
142
178
if (likely (count >= 0 ))
143
- sem -> count = count ;
179
+ __sem_acquire ( sem ) ;
144
180
raw_spin_unlock_irqrestore (& sem -> lock , flags );
145
181
146
182
return (count < 0 );
@@ -165,7 +201,7 @@ int __sched down_timeout(struct semaphore *sem, long timeout)
165
201
might_sleep ();
166
202
raw_spin_lock_irqsave (& sem -> lock , flags );
167
203
if (likely (sem -> count > 0 ))
168
- sem -> count -- ;
204
+ __sem_acquire ( sem ) ;
169
205
else
170
206
result = __down_timeout (sem , timeout );
171
207
raw_spin_unlock_irqrestore (& sem -> lock , flags );
@@ -187,6 +223,9 @@ void __sched up(struct semaphore *sem)
187
223
DEFINE_WAKE_Q (wake_q );
188
224
189
225
raw_spin_lock_irqsave (& sem -> lock , flags );
226
+
227
+ hung_task_sem_clear_if_holder (sem );
228
+
190
229
if (likely (list_empty (& sem -> wait_list )))
191
230
sem -> count ++ ;
192
231
else
@@ -228,8 +267,10 @@ static inline int __sched ___down_common(struct semaphore *sem, long state,
228
267
raw_spin_unlock_irq (& sem -> lock );
229
268
timeout = schedule_timeout (timeout );
230
269
raw_spin_lock_irq (& sem -> lock );
231
- if (waiter .up )
270
+ if (waiter .up ) {
271
+ hung_task_sem_set_holder (sem );
232
272
return 0 ;
273
+ }
233
274
}
234
275
235
276
timed_out :
@@ -246,10 +287,14 @@ static inline int __sched __down_common(struct semaphore *sem, long state,
246
287
{
247
288
int ret ;
248
289
290
+ hung_task_set_blocker (sem , BLOCKER_TYPE_SEM );
291
+
249
292
trace_contention_begin (sem , 0 );
250
293
ret = ___down_common (sem , state , timeout );
251
294
trace_contention_end (sem , ret );
252
295
296
+ hung_task_clear_blocker ();
297
+
253
298
return ret ;
254
299
}
255
300
0 commit comments