mmc: add module parameter to set whether cards are assumed removable

Some people run general-purpose distribution kernels on netbooks with
a card that is physically non-removable or logically non-removable
(e.g. used for /home) and cannot be cleanly unmounted during suspend.
Add a module parameter to set whether cards are assumed removable or
non-removable, with the default set by CONFIG_MMC_UNSAFE_RESUME.

In general, it is not possible to tell whether a card present in an MMC
slot after resume is the same that was there before suspend.  So there are
two possible behaviours, each of which will cause data loss in some cases:

CONFIG_MMC_UNSAFE_RESUME=n (default): Cards are assumed to be removed
during suspend.  Any filesystem on them must be unmounted before suspend;
otherwise, buffered writes will be lost.

CONFIG_MMC_UNSAFE_RESUME=y: Cards are assumed to remain present during
suspend.  They must not be swapped during suspend; otherwise, buffered
writes will be flushed to the wrong card.

Currently the choice is made at compile time and this allows that to be
overridden at module load time.

Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Cc: Wouter van Heyst <larstiq@larstiq.dyndns.org>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Ben Hutchings 2009-12-14 18:01:29 -08:00 committed by Linus Torvalds
parent c78402e95d
commit bd68e0838f
5 changed files with 23 additions and 43 deletions

View File

@ -3,7 +3,7 @@
# #
config MMC_UNSAFE_RESUME config MMC_UNSAFE_RESUME
bool "Allow unsafe resume (DANGEROUS)" bool "Assume MMC/SD cards are non-removable (DANGEROUS)"
help help
If you say Y here, the MMC layer will assume that all cards If you say Y here, the MMC layer will assume that all cards
stayed in their respective slots during the suspend. The stayed in their respective slots during the suspend. The
@ -14,3 +14,5 @@ config MMC_UNSAFE_RESUME
This option is usually just for embedded systems which use This option is usually just for embedded systems which use
a MMC/SD card for rootfs. Most people should say N here. a MMC/SD card for rootfs. Most people should say N here.
This option sets a default which can be overridden by the
module parameter "removable=0" or "removable=1".

View File

@ -47,6 +47,22 @@ static struct workqueue_struct *workqueue;
int use_spi_crc = 1; int use_spi_crc = 1;
module_param(use_spi_crc, bool, 0); module_param(use_spi_crc, bool, 0);
/*
* We normally treat cards as removed during suspend if they are not
* known to be on a non-removable bus, to avoid the risk of writing
* back data to a different card after resume. Allow this to be
* overridden if necessary.
*/
#ifdef CONFIG_MMC_UNSAFE_RESUME
int mmc_assume_removable;
#else
int mmc_assume_removable = 1;
#endif
module_param_named(removable, mmc_assume_removable, bool, 0644);
MODULE_PARM_DESC(
removable,
"MMC/SD cards are removable and may be removed during suspend");
/* /*
* Internal function. Schedule delayed work in the MMC work queue. * Internal function. Schedule delayed work in the MMC work queue.
*/ */

View File

@ -54,7 +54,9 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
int mmc_attach_sd(struct mmc_host *host, u32 ocr); int mmc_attach_sd(struct mmc_host *host, u32 ocr);
int mmc_attach_sdio(struct mmc_host *host, u32 ocr); int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
/* Module parameters */
extern int use_spi_crc; extern int use_spi_crc;
extern int mmc_assume_removable;
/* Debugfs information for hosts and cards */ /* Debugfs information for hosts and cards */
void mmc_add_host_debugfs(struct mmc_host *host); void mmc_add_host_debugfs(struct mmc_host *host);

View File

@ -602,25 +602,6 @@ static int mmc_awake(struct mmc_host *host)
return err; return err;
} }
#ifdef CONFIG_MMC_UNSAFE_RESUME
static const struct mmc_bus_ops mmc_ops = {
.awake = mmc_awake,
.sleep = mmc_sleep,
.remove = mmc_remove,
.detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
.power_restore = mmc_power_restore,
};
static void mmc_attach_bus_ops(struct mmc_host *host)
{
mmc_attach_bus(host, &mmc_ops);
}
#else
static const struct mmc_bus_ops mmc_ops = { static const struct mmc_bus_ops mmc_ops = {
.awake = mmc_awake, .awake = mmc_awake,
.sleep = mmc_sleep, .sleep = mmc_sleep,
@ -645,15 +626,13 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
{ {
const struct mmc_bus_ops *bus_ops; const struct mmc_bus_ops *bus_ops;
if (host->caps & MMC_CAP_NONREMOVABLE) if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
bus_ops = &mmc_ops_unsafe; bus_ops = &mmc_ops_unsafe;
else else
bus_ops = &mmc_ops; bus_ops = &mmc_ops;
mmc_attach_bus(host, bus_ops); mmc_attach_bus(host, bus_ops);
} }
#endif
/* /*
* Starting point for MMC card init. * Starting point for MMC card init.
*/ */

View File

@ -606,23 +606,6 @@ static void mmc_sd_power_restore(struct mmc_host *host)
mmc_release_host(host); mmc_release_host(host);
} }
#ifdef CONFIG_MMC_UNSAFE_RESUME
static const struct mmc_bus_ops mmc_sd_ops = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
.suspend = mmc_sd_suspend,
.resume = mmc_sd_resume,
.power_restore = mmc_sd_power_restore,
};
static void mmc_sd_attach_bus_ops(struct mmc_host *host)
{
mmc_attach_bus(host, &mmc_sd_ops);
}
#else
static const struct mmc_bus_ops mmc_sd_ops = { static const struct mmc_bus_ops mmc_sd_ops = {
.remove = mmc_sd_remove, .remove = mmc_sd_remove,
.detect = mmc_sd_detect, .detect = mmc_sd_detect,
@ -643,15 +626,13 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
{ {
const struct mmc_bus_ops *bus_ops; const struct mmc_bus_ops *bus_ops;
if (host->caps & MMC_CAP_NONREMOVABLE) if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
bus_ops = &mmc_sd_ops_unsafe; bus_ops = &mmc_sd_ops_unsafe;
else else
bus_ops = &mmc_sd_ops; bus_ops = &mmc_sd_ops;
mmc_attach_bus(host, bus_ops); mmc_attach_bus(host, bus_ops);
} }
#endif
/* /*
* Starting point for SD card init. * Starting point for SD card init.
*/ */