mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
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 <frank.blaschka@de.ibm.com> Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
646f919e93
commit
0eb69a0c58
@ -196,11 +196,11 @@ EXPORT_SYMBOL(airq_iv_release);
|
|||||||
*/
|
*/
|
||||||
unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num)
|
unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num)
|
||||||
{
|
{
|
||||||
unsigned long bit, i;
|
unsigned long bit, i, flags;
|
||||||
|
|
||||||
if (!iv->avail || num == 0)
|
if (!iv->avail || num == 0)
|
||||||
return -1UL;
|
return -1UL;
|
||||||
spin_lock(&iv->lock);
|
spin_lock_irqsave(&iv->lock, flags);
|
||||||
bit = find_first_bit_inv(iv->avail, iv->bits);
|
bit = find_first_bit_inv(iv->avail, iv->bits);
|
||||||
while (bit + num <= iv->bits) {
|
while (bit + num <= iv->bits) {
|
||||||
for (i = 1; i < num; i++)
|
for (i = 1; i < num; i++)
|
||||||
@ -218,9 +218,8 @@ unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num)
|
|||||||
}
|
}
|
||||||
if (bit + num > iv->bits)
|
if (bit + num > iv->bits)
|
||||||
bit = -1UL;
|
bit = -1UL;
|
||||||
spin_unlock(&iv->lock);
|
spin_unlock_irqrestore(&iv->lock, flags);
|
||||||
return bit;
|
return bit;
|
||||||
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(airq_iv_alloc);
|
EXPORT_SYMBOL(airq_iv_alloc);
|
||||||
|
|
||||||
@ -232,11 +231,11 @@ EXPORT_SYMBOL(airq_iv_alloc);
|
|||||||
*/
|
*/
|
||||||
void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num)
|
void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num)
|
||||||
{
|
{
|
||||||
unsigned long i;
|
unsigned long i, flags;
|
||||||
|
|
||||||
if (!iv->avail || num == 0)
|
if (!iv->avail || num == 0)
|
||||||
return;
|
return;
|
||||||
spin_lock(&iv->lock);
|
spin_lock_irqsave(&iv->lock, flags);
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
/* Clear (possibly left over) interrupt bit */
|
/* Clear (possibly left over) interrupt bit */
|
||||||
clear_bit_inv(bit + i, iv->vector);
|
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)
|
|||||||
while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail))
|
while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail))
|
||||||
iv->end--;
|
iv->end--;
|
||||||
}
|
}
|
||||||
spin_unlock(&iv->lock);
|
spin_unlock_irqrestore(&iv->lock, flags);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(airq_iv_free);
|
EXPORT_SYMBOL(airq_iv_free);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user