powerpc/kernel: Block interrupts when updating TIDR
clear_thread_tidr() is called in interrupt context as a part of delayed
put of the task structure (i.e as a part of timer interrupt). To prevent
a deadlock, block interrupts when holding vas_thread_id_lock to set/
clear TIDR for a task.
Fixes: ec233ede4c ("powerpc: Add support for setting SPRN_TIDR")
Cc: stable@vger.kernel.org # v4.15+
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
committed by
Michael Ellerman
parent
902bdc5745
commit
384dfd627f
@@ -1515,14 +1515,15 @@ static int assign_thread_tidr(void)
|
|||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
int err;
|
int err;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if (!ida_pre_get(&vas_thread_ida, GFP_KERNEL))
|
if (!ida_pre_get(&vas_thread_ida, GFP_KERNEL))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock(&vas_thread_id_lock);
|
spin_lock_irqsave(&vas_thread_id_lock, flags);
|
||||||
err = ida_get_new_above(&vas_thread_ida, 1, &index);
|
err = ida_get_new_above(&vas_thread_ida, 1, &index);
|
||||||
spin_unlock(&vas_thread_id_lock);
|
spin_unlock_irqrestore(&vas_thread_id_lock, flags);
|
||||||
|
|
||||||
if (err == -EAGAIN)
|
if (err == -EAGAIN)
|
||||||
goto again;
|
goto again;
|
||||||
@@ -1530,9 +1531,9 @@ again:
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (index > MAX_THREAD_CONTEXT) {
|
if (index > MAX_THREAD_CONTEXT) {
|
||||||
spin_lock(&vas_thread_id_lock);
|
spin_lock_irqsave(&vas_thread_id_lock, flags);
|
||||||
ida_remove(&vas_thread_ida, index);
|
ida_remove(&vas_thread_ida, index);
|
||||||
spin_unlock(&vas_thread_id_lock);
|
spin_unlock_irqrestore(&vas_thread_id_lock, flags);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1541,9 +1542,11 @@ again:
|
|||||||
|
|
||||||
static void free_thread_tidr(int id)
|
static void free_thread_tidr(int id)
|
||||||
{
|
{
|
||||||
spin_lock(&vas_thread_id_lock);
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&vas_thread_id_lock, flags);
|
||||||
ida_remove(&vas_thread_ida, id);
|
ida_remove(&vas_thread_ida, id);
|
||||||
spin_unlock(&vas_thread_id_lock);
|
spin_unlock_irqrestore(&vas_thread_id_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user