Skip to content

Commit 0eb69a0

Browse files
Sebastian OttMartin Schwidefsky
authored andcommitted
s390/airq: silence lockdep warning
airq_iv_(alloc|free) is called by some users with interrupts enabled and by some with interrupts disabled which leads to the following lockdep warning: [ INFO: possible irq lock inversion dependency detected ] 3.14.0-15249-gbf29b7b-dirty #25 Not tainted --------------------------------------------------------- insmod/2108 just changed the state of lock: (&(&iv->lock)->rlock){+.....}, at: [<000000000046ee3e>] airq_iv_alloc+0x62/0x228 but this lock was taken by another, HARDIRQ-READ-safe lock in the past: (&info->lock){.-.-..} and interrupts could create inverse lock ordering between them. other info that might help us debug this: Possible interrupt unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&(&iv->lock)->rlock); local_irq_disable(); lock(&info->lock); lock(&(&iv->lock)->rlock); <Interrupt> lock(&info->lock); *** DEADLOCK *** Although this is a false alarm (since each airq user consistently calls these functions from the same context) fix this by ensuring that interrupts are disabled when the airq lock is held. Reported-by: Frank Blaschka <[email protected]> Signed-off-by: Sebastian Ott <[email protected]> Signed-off-by: Martin Schwidefsky <[email protected]>
1 parent 646f919 commit 0eb69a0

File tree

1 file changed

+6
-7
lines changed

1 file changed

+6
-7
lines changed

drivers/s390/cio/airq.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ EXPORT_SYMBOL(airq_iv_release);
196196
*/
197197
unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num)
198198
{
199-
unsigned long bit, i;
199+
unsigned long bit, i, flags;
200200

201201
if (!iv->avail || num == 0)
202202
return -1UL;
203-
spin_lock(&iv->lock);
203+
spin_lock_irqsave(&iv->lock, flags);
204204
bit = find_first_bit_inv(iv->avail, iv->bits);
205205
while (bit + num <= iv->bits) {
206206
for (i = 1; i < num; i++)
@@ -218,9 +218,8 @@ unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num)
218218
}
219219
if (bit + num > iv->bits)
220220
bit = -1UL;
221-
spin_unlock(&iv->lock);
221+
spin_unlock_irqrestore(&iv->lock, flags);
222222
return bit;
223-
224223
}
225224
EXPORT_SYMBOL(airq_iv_alloc);
226225

@@ -232,11 +231,11 @@ EXPORT_SYMBOL(airq_iv_alloc);
232231
*/
233232
void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num)
234233
{
235-
unsigned long i;
234+
unsigned long i, flags;
236235

237236
if (!iv->avail || num == 0)
238237
return;
239-
spin_lock(&iv->lock);
238+
spin_lock_irqsave(&iv->lock, flags);
240239
for (i = 0; i < num; i++) {
241240
/* Clear (possibly left over) interrupt bit */
242241
clear_bit_inv(bit + i, iv->vector);
@@ -248,7 +247,7 @@ void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num)
248247
while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail))
249248
iv->end--;
250249
}
251-
spin_unlock(&iv->lock);
250+
spin_unlock_irqrestore(&iv->lock, flags);
252251
}
253252
EXPORT_SYMBOL(airq_iv_free);
254253

0 commit comments

Comments
 (0)