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

Commit 384dfd62 authored by Sukadev Bhattiprolu's avatar Sukadev Bhattiprolu Committed by Michael Ellerman
Browse files

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: ec233ede ("powerpc: Add support for setting SPRN_TIDR")
Cc: stable@vger.kernel.org # v4.15+
Signed-off-by: default avatarSukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 902bdc57
Loading
Loading
Loading
Loading
+9 −6
Original line number Original line Diff line number Diff line
@@ -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 @@ static int assign_thread_tidr(void)
		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 @@ static int assign_thread_tidr(void)


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);
}
}


/*
/*