mmc: Flush block queue when removing card
authorPierre Ossman <drzeus@drzeus.cx>
Tue, 14 Nov 2006 21:08:16 +0000 (22:08 +0100)
committerPierre Ossman <drzeus@drzeus.cx>
Fri, 1 Dec 2006 18:06:05 +0000 (19:06 +0100)
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>
drivers/mmc/mmc_block.c
drivers/mmc/mmc_queue.c

index f9027c8db79226250a0e0fced80633be29d16cba..5025abebfc82b6347cb195c96ae89913fb99bf8e 100644 (file)
@@ -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);
index 4e6a534e91d065f21dabe3ebc8d5c2de8243ce28..5fa72ccb4feb0d26a39ec48943bd2cd1293d020e 100644 (file)
@@ -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);