summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Taysom <taysom@chromium.org>2013-06-04 14:42:40 -0700
committerChris Ball <cjb@laptop.org>2013-06-27 11:23:15 -0400
commitfdfa20c1631210d0ca218689204682ea80e170e3 (patch)
treedade6a1b5ed6321f870c59e8e7e6a7f2b29558b9
parente2f6aac6a88138851f81372c5cecc9562aab9352 (diff)
mmc: reordered shutdown sequence in mmc_bld_remove_req
We had a multi-partition SD-Card with two ext2 file systems. The partition table was getting overwritten by a race between the card removal and the unmount of the 2nd ext2 partition. What was observed: 1. Suspend/resume would call to remove the device. The clearing of the device information is done asynchronously. 2. A request is made to unmount the file system (this is called after the removal has started). 3. The remapping table was cleared by the asynchronous part of the device removal. 4. A write request to the super block (block 0 of the partition) was sent down and instead of being remapped to the partition offset, it was remapped to block 0 of the device which is where the partition table is located. 5. Write was queued and written resulting in the overwriting of the partition table with the ext2 super block. 6. The mmc_queue is cleaned up. The mmc card device driver used to access SD cards, was calling del_gendisk before calling mmc_cleanup-queue. The comment in the mmc_blk_remove_req code indicated that it expected del_gendisk to block all further requests from being queued but it doesn't. The mmc driver uses the presences of the mmc_queue to determine if the request should be queued. The fix was to clean up the mmc_queue before the rest of the the delete partition code is called. This prevents the overwriting of the partition table. However, the umount gets an error trying to write the super block. The umount should be issued before the device is removed but that is not always possible. The umount is still needed to cleanup other data structures. Addresses the problem described in http://crbug.com/240815 Signed-off-by: Paul Taysom <taysom@chromium.org> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/card/block.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index c900d2818aa..59a13fce774 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2185,6 +2185,14 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
struct mmc_card *card;
if (md) {
+ /*
+ * Flush remaining requests and free queues. It
+ * is freeing the queue that stops new requests
+ * from being accepted.
+ */
+ mmc_cleanup_queue(&md->queue);
+ if (md->flags & MMC_BLK_PACKED_CMD)
+ mmc_packed_clean(&md->queue);
card = md->queue.card;
if (md->disk->flags & GENHD_FL_UP) {
device_remove_file(disk_to_dev(md->disk), &md->force_ro);
@@ -2193,14 +2201,8 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
device_remove_file(disk_to_dev(md->disk),
&md->power_ro_lock);
- /* Stop new requests from getting into the queue */
del_gendisk(md->disk);
}
-
- /* Then flush out any already in there */
- mmc_cleanup_queue(&md->queue);
- if (md->flags & MMC_BLK_PACKED_CMD)
- mmc_packed_clean(&md->queue);
mmc_blk_put(md);
}
}