Skip to content

Commit

Permalink
powerpc/fscr: Enable interrupts earlier before calling get_user()
Browse files Browse the repository at this point in the history
The function get_user() can sleep while trying to fetch instruction
from user address space and causes the following warning from the
scheduler.

BUG: sleeping function called from invalid context

Though interrupts get enabled back but it happens bit later after
get_user() is called. This change moves enabling these interrupts
earlier covering the function get_user(). While at this, lets check
for kernel mode and crash as this interrupt should not have been
triggered from the kernel context.

Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
  • Loading branch information
Anshuman Khandual authored and Michael Ellerman committed Apr 10, 2018
1 parent 501a78c commit 709b973
Showing 1 changed file with 17 additions and 15 deletions.
32 changes: 17 additions & 15 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,22 @@ void facility_unavailable_exception(struct pt_regs *regs)
value = mfspr(SPRN_FSCR);

status = value >> 56;
if ((hv || status >= 2) &&
(status < ARRAY_SIZE(facility_strings)) &&
facility_strings[status])
facility = facility_strings[status];

/* We should not have taken this interrupt in kernel */
if (!user_mode(regs)) {
pr_emerg("Facility '%s' unavailable (%d) exception in kernel mode at %lx\n",
facility, status, regs->nip);
die("Unexpected facility unavailable exception", regs, SIGABRT);
}

/* We restore the interrupt state now */
if (!arch_irq_disabled_regs(regs))
local_irq_enable();

if (status == FSCR_DSCR_LG) {
/*
* User is accessing the DSCR register using the problem
Expand Down Expand Up @@ -1679,25 +1695,11 @@ void facility_unavailable_exception(struct pt_regs *regs)
return;
}

if ((hv || status >= 2) &&
(status < ARRAY_SIZE(facility_strings)) &&
facility_strings[status])
facility = facility_strings[status];

/* We restore the interrupt state now */
if (!arch_irq_disabled_regs(regs))
local_irq_enable();

pr_err_ratelimited("%sFacility '%s' unavailable (%d), exception at 0x%lx, MSR=%lx\n",
hv ? "Hypervisor " : "", facility, status, regs->nip, regs->msr);

out:
if (user_mode(regs)) {
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
return;
}

die("Unexpected facility unavailable exception", regs, SIGABRT);
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
}
#endif

Expand Down

0 comments on commit 709b973

Please sign in to comment.