From 6794d0e2d0962a24e1ed4945088916bb7a0fd786 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Mon, 11 Jul 2016 13:55:50 +0530 Subject: [PATCH] mmc: core: Fix deadlock in suspend & rescan path Due to deferred resume enabled -> | in system suspend | dpm_prepare | mmc_pm_notify with PREPARE_SUSPEND This will return from here and will not wait for mmc_rescan to complete. Because of above system has deadlocked in which => mmc_rescan after acquiring device's mutex_lock, has scheduled a work on WQ_FREEZABLE(bdi_wq) which will not run since system freeze state has already completed. This will only complete once tasks are unfreezed which means only after system resume is completed. And system suspend, is unpreparing the devices from dpm_prepared_list. During which this process is trying to acquire card->device's mutex lock which is held by above process. Thus a deadlock. Change-Id: I926bb3783e62892ce842e5d4da44a3c24c8f244d Signed-off-by: Ritesh Harjani --- drivers/mmc/core/core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 152a3e3b4f47..044dc352d5ab 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -3091,7 +3091,6 @@ int mmc_resume_bus(struct mmc_host *host) pr_debug("%s: Starting deferred resume\n", mmc_hostname(host)); spin_lock_irqsave(&host->lock, flags); host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME; - host->rescan_disable = 0; spin_unlock_irqrestore(&host->lock, flags); mmc_bus_get(host); @@ -4037,6 +4036,7 @@ EXPORT_SYMBOL(mmc_detect_card_removed); void mmc_rescan(struct work_struct *work) { + unsigned long flags; struct mmc_host *host = container_of(work, struct mmc_host, detect.work); @@ -4045,8 +4045,12 @@ void mmc_rescan(struct work_struct *work) host->trigger_card_event = false; } - if (host->rescan_disable) + spin_lock_irqsave(&host->lock, flags); + if (host->rescan_disable) { + spin_unlock_irqrestore(&host->lock, flags); return; + } + spin_unlock_irqrestore(&host->lock, flags); /* If there is a non-removable card registered, only scan once */ if ((host->caps & MMC_CAP_NONREMOVABLE) && host->rescan_entered) @@ -4293,10 +4297,6 @@ int mmc_pm_notify(struct notifier_block *notify_block, case PM_SUSPEND_PREPARE: case PM_RESTORE_PREPARE: spin_lock_irqsave(&host->lock, flags); - if (mmc_bus_needs_resume(host)) { - spin_unlock_irqrestore(&host->lock, flags); - break; - } host->rescan_disable = 1; spin_unlock_irqrestore(&host->lock, flags); cancel_delayed_work_sync(&host->detect);