aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2012-01-04 09:28:45 -0500
committerChris Ball <cjb@laptop.org>2012-01-12 15:17:17 -0500
commit0db13fc2abbb0b1a8d8efee20dfbd7f3c5d54022 (patch)
tree9932b8a8bca14f536e9a23f905919d9ee9c1a10a /drivers/mmc/core
parent3abc1e804253add41990cbe1461e79c1165108e0 (diff)
mmc: fix a deadlock between system suspend and MMC block IO
Performing MMC block IO with simultaneous STR can lead to a deadlock: the mmc_pm_notify() function claims the host and then calls bus .remove() method, which lands in mmc_blk_remove(), which calls mmc_blk_remove_req() then it goes to -> mmc_cleanup_queue() -> kthread_stop(), which waits for the mmc-block thread to stop. If the mmc-block thread at that time is processing block requests, it will also try to claim the host in mmc_blk_issue_rq() and block there. This patch fixes the problem by calling .remove() before claiming the host. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Acked-by: Arindam Nath <arindam.nath@amd.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/core.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1da45e051328..bec0bf21c879 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2175,6 +2175,7 @@ void mmc_stop_host(struct mmc_host *host)
2175 2175
2176 mmc_bus_get(host); 2176 mmc_bus_get(host);
2177 if (host->bus_ops && !host->bus_dead) { 2177 if (host->bus_ops && !host->bus_dead) {
2178 /* Calling bus_ops->remove() with a claimed host can deadlock */
2178 if (host->bus_ops->remove) 2179 if (host->bus_ops->remove)
2179 host->bus_ops->remove(host); 2180 host->bus_ops->remove(host);
2180 2181
@@ -2398,7 +2399,9 @@ int mmc_suspend_host(struct mmc_host *host)
2398 if (err == -ENOSYS || !host->bus_ops->resume) { 2399 if (err == -ENOSYS || !host->bus_ops->resume) {
2399 /* 2400 /*
2400 * We simply "remove" the card in this case. 2401 * We simply "remove" the card in this case.
2401 * It will be redetected on resume. 2402 * It will be redetected on resume. (Calling
2403 * bus_ops->remove() with a claimed host can
2404 * deadlock.)
2402 */ 2405 */
2403 if (host->bus_ops->remove) 2406 if (host->bus_ops->remove)
2404 host->bus_ops->remove(host); 2407 host->bus_ops->remove(host);
@@ -2491,11 +2494,11 @@ int mmc_pm_notify(struct notifier_block *notify_block,
2491 if (!host->bus_ops || host->bus_ops->suspend) 2494 if (!host->bus_ops || host->bus_ops->suspend)
2492 break; 2495 break;
2493 2496
2494 mmc_claim_host(host); 2497 /* Calling bus_ops->remove() with a claimed host can deadlock */
2495
2496 if (host->bus_ops->remove) 2498 if (host->bus_ops->remove)
2497 host->bus_ops->remove(host); 2499 host->bus_ops->remove(host);
2498 2500
2501 mmc_claim_host(host);
2499 mmc_detach_bus(host); 2502 mmc_detach_bus(host);
2500 mmc_power_off(host); 2503 mmc_power_off(host);
2501 mmc_release_host(host); 2504 mmc_release_host(host);