mmc: fix host release issue after discard operation
authorRay Jui <rjui@broadcom.com>
Sat, 26 Oct 2013 18:03:44 +0000 (11:03 -0700)
committerlintao <lintao@rock-chips.com>
Fri, 7 Mar 2014 12:09:22 +0000 (20:09 +0800)
Under function mmc_blk_issue_rq, after an MMC discard operation,
the MMC request data structure may be freed in memory. Later in
the same function, the check of req->cmd_flags & MMC_REQ_SPECIAL_MASK
is dangerous and invalid. It causes the MMC host not to be released
when it should.

This patch fixes the issue by marking the special request down before
the discard/flush operation.

Reported by: Harold (SoonYeal) Yang <haroldsy@broadcom.com>
Signed-off-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Seungwon Jeon <tgih.jun@samsung.com>
Acked-by: Seungwon Jeon <tgih.jun@samsung.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
drivers/mmc/card/block.c

index 65d6c0d566de507144f6ba76e806be04e3a212c1..78f9cfe8bc53dbb1dbab60e2c2a660ad4ee2b809 100644 (file)
@@ -1960,6 +1960,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
        struct mmc_card *card = md->queue.card;
        struct mmc_host *host = card->host;
        unsigned long flags;
+       unsigned int cmd_flags = req ? req->cmd_flags : 0;
 
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
        if (mmc_bus_needs_resume(card->host))
@@ -1980,7 +1981,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
        }
 
        mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
-       if (req && req->cmd_flags & REQ_DISCARD) {
+       if (cmd_flags & REQ_DISCARD) {
                /* complete ongoing async transfer before issuing discard */
                if (card->host->areq)
                        mmc_blk_issue_rw_rq(mq, NULL);
@@ -1989,7 +1990,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                        ret = mmc_blk_issue_secdiscard_rq(mq, req);
                else
                        ret = mmc_blk_issue_discard_rq(mq, req);
-       } else if (req && req->cmd_flags & REQ_FLUSH) {
+       } else if (cmd_flags & REQ_FLUSH) {
                /* complete ongoing async transfer before issuing flush */
                if (card->host->areq)
                        mmc_blk_issue_rw_rq(mq, NULL);
@@ -2005,7 +2006,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
 out:
        if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
-            (req && (req->cmd_flags & MMC_REQ_SPECIAL_MASK)))
+            (cmd_flags & MMC_REQ_SPECIAL_MASK))
                /*
                 * Release host when there are no more requests
                 * and after special request(discard, flush) is done.