mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-15 21:23:23 +00:00
firmware: arm_sdei: fix possible double-lock on hibernate error path
We call sdei_reregister_event() with sdei_list_lock held, if the register fails we call sdei_event_destroy() which also acquires sdei_list_lock thus creating A-A deadlock. Add '_llocked' to sdei_reregister_event(), to indicate the list lock is held, and add a _llocked variant of sdei_event_destroy(). Fixes: da351827240e ("firmware: arm_sdei: Add support for CPU and system power states") Signed-off-by: Liguang Zhang <zhangliguang@linux.alibaba.com> [expanded subject, added wrappers instead of duplicating contents] Signed-off-by: James Morse <james.morse@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
parent
6ded0b61cf
commit
c66d52b102
@ -280,13 +280,12 @@ static struct sdei_event *sdei_event_create(u32 event_num,
|
||||
return event;
|
||||
}
|
||||
|
||||
static void sdei_event_destroy(struct sdei_event *event)
|
||||
static void sdei_event_destroy_llocked(struct sdei_event *event)
|
||||
{
|
||||
lockdep_assert_held(&sdei_events_lock);
|
||||
lockdep_assert_held(&sdei_list_lock);
|
||||
|
||||
spin_lock(&sdei_list_lock);
|
||||
list_del(&event->list);
|
||||
spin_unlock(&sdei_list_lock);
|
||||
|
||||
if (event->type == SDEI_EVENT_TYPE_SHARED)
|
||||
kfree(event->registered);
|
||||
@ -296,6 +295,13 @@ static void sdei_event_destroy(struct sdei_event *event)
|
||||
kfree(event);
|
||||
}
|
||||
|
||||
static void sdei_event_destroy(struct sdei_event *event)
|
||||
{
|
||||
spin_lock(&sdei_list_lock);
|
||||
sdei_event_destroy_llocked(event);
|
||||
spin_unlock(&sdei_list_lock);
|
||||
}
|
||||
|
||||
static int sdei_api_get_version(u64 *version)
|
||||
{
|
||||
return invoke_sdei_fn(SDEI_1_0_FN_SDEI_VERSION, 0, 0, 0, 0, 0, version);
|
||||
@ -643,16 +649,17 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
|
||||
}
|
||||
EXPORT_SYMBOL(sdei_event_register);
|
||||
|
||||
static int sdei_reregister_event(struct sdei_event *event)
|
||||
static int sdei_reregister_event_llocked(struct sdei_event *event)
|
||||
{
|
||||
int err;
|
||||
|
||||
lockdep_assert_held(&sdei_events_lock);
|
||||
lockdep_assert_held(&sdei_list_lock);
|
||||
|
||||
err = _sdei_event_register(event);
|
||||
if (err) {
|
||||
pr_err("Failed to re-register event %u\n", event->event_num);
|
||||
sdei_event_destroy(event);
|
||||
sdei_event_destroy_llocked(event);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -681,7 +688,7 @@ static int sdei_reregister_shared(void)
|
||||
continue;
|
||||
|
||||
if (event->reregister) {
|
||||
err = sdei_reregister_event(event);
|
||||
err = sdei_reregister_event_llocked(event);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user