Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0eb69a0c authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky
Browse files

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: default avatarFrank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 646f919e
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -196,11 +196,11 @@ EXPORT_SYMBOL(airq_iv_release);
 */
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)
		return -1UL;
	spin_lock(&iv->lock);
	spin_lock_irqsave(&iv->lock, flags);
	bit = find_first_bit_inv(iv->avail, iv->bits);
	while (bit + num <= iv->bits) {
		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)
		bit = -1UL;
	spin_unlock(&iv->lock);
	spin_unlock_irqrestore(&iv->lock, flags);
	return bit;

}
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)
{
	unsigned long i;
	unsigned long i, flags;

	if (!iv->avail || num == 0)
		return;
	spin_lock(&iv->lock);
	spin_lock_irqsave(&iv->lock, flags);
	for (i = 0; i < num; i++) {
		/* Clear (possibly left over) interrupt bit */
		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))
			iv->end--;
	}
	spin_unlock(&iv->lock);
	spin_unlock_irqrestore(&iv->lock, flags);
}
EXPORT_SYMBOL(airq_iv_free);