summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2006-11-14 22:08:16 +0100
committerPierre Ossman <drzeus@drzeus.cx>2006-12-01 19:06:05 +0100
commit89b4e133afea9fce333054b94d89953583a55c19 (patch)
tree23502a0f8b2bd2ebe0b821a152711746b3457560
parent077df884835ebf2b5db16aacd9a24691d89902a0 (diff)
downloadlinux-3.10-89b4e133afea9fce333054b94d89953583a55c19.tar.gz
linux-3.10-89b4e133afea9fce333054b94d89953583a55c19.tar.bz2
linux-3.10-89b4e133afea9fce333054b94d89953583a55c19.zip
mmc: Flush block queue when removing card
After mmc_block's remove function has exited, we must not touch the card structure in any way. This means we not only must remove the gendisk, we must also flush out any remaning requests already queued up. We previously removed the disk, but didn't flush it, causing oops:es when removing a card in the middle of a transfer. Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
-rw-r--r--drivers/mmc/mmc_block.c8
-rw-r--r--drivers/mmc/mmc_queue.c22
2 files changed, 25 insertions, 5 deletions
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index f9027c8db79..5025abebfc8 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -83,7 +83,6 @@ static void mmc_blk_put(struct mmc_blk_data *md)
md->usage--;
if (md->usage == 0) {
put_disk(md->disk);
- mmc_cleanup_queue(&md->queue);
kfree(md);
}
mutex_unlock(&open_lock);
@@ -553,12 +552,11 @@ static void mmc_blk_remove(struct mmc_card *card)
if (md) {
int devidx;
+ /* Stop new requests from getting into the queue */
del_gendisk(md->disk);
- /*
- * I think this is needed.
- */
- md->disk->queue = NULL;
+ /* Then flush out any already in there */
+ mmc_cleanup_queue(&md->queue);
devidx = md->disk->first_minor >> MMC_SHIFT;
__clear_bit(devidx, dev_use);
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
index 4e6a534e91d..5fa72ccb4fe 100644
--- a/drivers/mmc/mmc_queue.c
+++ b/drivers/mmc/mmc_queue.c
@@ -103,6 +103,19 @@ static int mmc_queue_thread(void *d)
static void mmc_request(request_queue_t *q)
{
struct mmc_queue *mq = q->queuedata;
+ struct request *req;
+ int ret;
+
+ if (!mq) {
+ printk(KERN_ERR "MMC: killing requests for dead queue\n");
+ while ((req = elv_next_request(q)) != NULL) {
+ do {
+ ret = end_that_request_chunk(req, 0,
+ req->current_nr_sectors << 9);
+ } while (ret);
+ }
+ return;
+ }
if (!mq->req)
wake_up_process(mq->thread);
@@ -168,6 +181,15 @@ EXPORT_SYMBOL(mmc_init_queue);
void mmc_cleanup_queue(struct mmc_queue *mq)
{
+ request_queue_t *q = mq->queue;
+ unsigned long flags;
+
+ /* Mark that we should start throwing out stragglers */
+ spin_lock_irqsave(q->queue_lock, flags);
+ q->queuedata = NULL;
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ /* Then terminate our worker thread */
kthread_stop(mq->thread);
kfree(mq->sg);