Skip to content

Commit c66d52b

Browse files
luanshi0212ctmarinas
authored andcommitted
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: da35182 ("firmware: arm_sdei: Add support for CPU and system power states") Signed-off-by: Liguang Zhang <[email protected]> [expanded subject, added wrappers instead of duplicating contents] Signed-off-by: James Morse <[email protected]> Signed-off-by: Catalin Marinas <[email protected]>
1 parent 6ded0b6 commit c66d52b

File tree

1 file changed

+13
-6
lines changed

1 file changed

+13
-6
lines changed

drivers/firmware/arm_sdei.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,13 +280,12 @@ static struct sdei_event *sdei_event_create(u32 event_num,
280280
return event;
281281
}
282282

283-
static void sdei_event_destroy(struct sdei_event *event)
283+
static void sdei_event_destroy_llocked(struct sdei_event *event)
284284
{
285285
lockdep_assert_held(&sdei_events_lock);
286+
lockdep_assert_held(&sdei_list_lock);
286287

287-
spin_lock(&sdei_list_lock);
288288
list_del(&event->list);
289-
spin_unlock(&sdei_list_lock);
290289

291290
if (event->type == SDEI_EVENT_TYPE_SHARED)
292291
kfree(event->registered);
@@ -296,6 +295,13 @@ static void sdei_event_destroy(struct sdei_event *event)
296295
kfree(event);
297296
}
298297

298+
static void sdei_event_destroy(struct sdei_event *event)
299+
{
300+
spin_lock(&sdei_list_lock);
301+
sdei_event_destroy_llocked(event);
302+
spin_unlock(&sdei_list_lock);
303+
}
304+
299305
static int sdei_api_get_version(u64 *version)
300306
{
301307
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)
643649
}
644650
EXPORT_SYMBOL(sdei_event_register);
645651

646-
static int sdei_reregister_event(struct sdei_event *event)
652+
static int sdei_reregister_event_llocked(struct sdei_event *event)
647653
{
648654
int err;
649655

650656
lockdep_assert_held(&sdei_events_lock);
657+
lockdep_assert_held(&sdei_list_lock);
651658

652659
err = _sdei_event_register(event);
653660
if (err) {
654661
pr_err("Failed to re-register event %u\n", event->event_num);
655-
sdei_event_destroy(event);
662+
sdei_event_destroy_llocked(event);
656663
return err;
657664
}
658665

@@ -681,7 +688,7 @@ static int sdei_reregister_shared(void)
681688
continue;
682689

683690
if (event->reregister) {
684-
err = sdei_reregister_event(event);
691+
err = sdei_reregister_event_llocked(event);
685692
if (err)
686693
break;
687694
}

0 commit comments

Comments
 (0)