From patchwork Thu May 18 09:29:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 100068 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp629089qge; Thu, 18 May 2017 02:30:18 -0700 (PDT) X-Received: by 10.99.218.69 with SMTP id l5mr3556229pgj.88.1495099817929; Thu, 18 May 2017 02:30:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495099817; cv=none; d=google.com; s=arc-20160816; b=y7LFnB1WJyWRQru1/vhlA+RJRd/twg++JhJvFHybqUub4KunmtQtUJn5JqJssQ4rT+ uW30ZHE1xs/jQD+oTRMA1Q326C/eIVrqbgG+b27VJG5GKYSGA+c3MhRgsLOn3LVNcCS9 DkcLgXHcezlZXnVdjsf/Iaam+QQAf+xeG9BFs6ddbN7W7JqIHjpOXs2Ev/LIO3Aggd6L 4ipjMYYiK0WjIydVflQGOcyVFappv9QIs4kP4KdBFF5azUlEsNm2YQAmrIjc16fliKJu plQxglN53LGwADz9cH1QaaoIuVg6H64s4gtIdDv+/wkx2CmvBP9iQmUkWr2AATU9zJXG 1sLw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=5Arw0yfDKRi4ur3ZCkGjhkTrxn3SMx4QNPSM7pbZ6I4=; b=zMni+Oj0+j6R4XRVNB57xjxCnKjLBjGnRYw2I8vut8yATorn1q8rvxPmAOJXcDbpqg M8Og4jSpQ0KCvTefPepu1iKcgH5RRBcA39d0mG2SiSI6DgALgNLutaKxxc+WGMRlQQ/w eklsm5wEdIv+1zGvLNLubzghL3lV8uTMKHp0knRnnl7D6IfG98bt/bSjud40bpWbl6Ko pj8dd08AlRWE0dMqgpva/sKfN/cwxGaGWCz6xUDXPUcV3yO+1Zq0qlQ9/tWH9HAZH9bf idQ5kvZZqS+2iw6oKwAKYTHFqi3N0Yeyei87D1GpVRU8dq9+vG+FStrRPF9BmL63aea6 9r3Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-mmc-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-mmc-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 33si4553082plk.96.2017.05.18.02.30.17; Thu, 18 May 2017 02:30:17 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-mmc-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-mmc-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-mmc-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754909AbdERJaL (ORCPT + 6 others); Thu, 18 May 2017 05:30:11 -0400 Received: from mail-wr0-f172.google.com ([209.85.128.172]:35376 "EHLO mail-wr0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755158AbdERJaH (ORCPT ); Thu, 18 May 2017 05:30:07 -0400 Received: by mail-wr0-f172.google.com with SMTP id z52so29200240wrc.2 for ; Thu, 18 May 2017 02:30:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=G/IwQ9U0Dm3V+tLyi17MZe4FoulPw25GUV9IuuABn5s=; b=iuLw3v1ICojI/ZO30qpBr6bwD2BuVa5zZ2KI1qjpGUqsWpbLVUhNnFvXR2aqJpI3Ot wbK/HB0RxSsFKKDONhUNQx8e4Wr81ARiOpmR0McEcHMN6Xgi+I7as3hpfQQPtU6/fzW8 coqfawW+jeD7bUsWhXTXg7aayOlmHSNT3qmg8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=G/IwQ9U0Dm3V+tLyi17MZe4FoulPw25GUV9IuuABn5s=; b=babvxPQiUPI9qbEQK4Pahmk2dASRKntDqFRU4b2pO0bXdsveEO/gu9RLIck/VK8GD9 cFLywzWn5ye3qr/P6IaTUL+3b+CCoMPHfU2oCJ6FkREzhWh3UBitBEgUGuP0Z4H0gMxo TR/rfDdAbfqluOkIT6OvoqKSNAkLKswUIoY5rdCQsekdeIC+ODi5siGe2L7eauCyT0x6 blglHic/63zSTjtGoqURQvxWfHbVJxoZGmcSwzL7Ga5QrYaBrko9mZ/LbeBGsq6qthne yjgO6a/F1Z9Zqp+ZTt9eCHm6JuHeFrAOGaNUSiV6d2f+7WvN5Qpr4wA3qvmcEOUbPcpC fBdQ== X-Gm-Message-State: AODbwcBBxIew0xHF20UYa97f+iSoS5iUm6aBa2JSEV2HNd8kol4CEu+T I71dL+lB//WwQKRO X-Received: by 10.46.5.147 with SMTP id 141mr953519ljf.108.1495099806166; Thu, 18 May 2017 02:30:06 -0700 (PDT) Received: from genomnajs.ideon.se ([85.235.10.227]) by smtp.gmail.com with ESMTPSA id u24sm829895ljd.34.2017.05.18.02.30.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 18 May 2017 02:30:05 -0700 (PDT) From: Linus Walleij To: linux-mmc@vger.kernel.org, Ulf Hansson , Adrian Hunter Cc: linux-block@vger.kernel.org, Jens Axboe , Christoph Hellwig , Arnd Bergmann , Bartlomiej Zolnierkiewicz , Paolo Valente , Linus Walleij Subject: [PATCH 4/6 v2] mmc: block: move single ioctl() commands to block requests Date: Thu, 18 May 2017 11:29:34 +0200 Message-Id: <20170518092936.9277-4-linus.walleij@linaro.org> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170518092936.9277-1-linus.walleij@linaro.org> References: <20170518092936.9277-1-linus.walleij@linaro.org> Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org This wraps single ioctl() commands into block requests using the custom block layer request types REQ_OP_DRV_IN and REQ_OP_DRV_OUT. By doing this we are loosening the grip on the big host lock, since two calls to mmc_get_card()/mmc_put_card() are removed. We are storing the ioctl() in/out argument as a pointer in the per-request struct mmc_blk_request container. Since we now let the block layer allocate this data, blk_get_request() will allocate it for us and we can immediately dereference it and use it to pass the argument into the block layer. We refactor the if/else/if/else ladder in mmc_blk_issue_rq() as part of the job, keeping some extra attention to the case when a NULL req is passed into this function and making that pipeline flush more explicit. Tested on the ux500 with the userspace: mmc extcsd read /dev/mmcblk3 resulting in a successful EXTCSD info dump back to the console. This commit fixes a starvation issue in the MMC/SD stack that can be easily provoked in the following way by issueing the following commands in sequence: > dd if=/dev/mmcblk3 of=/dev/null bs=1M & > mmc extcs read /dev/mmcblk3 Before this patch, the extcsd read command would hang (starve) while waiting for the dd command to finish since the block layer was holding the card/host lock. After this patch, the extcsd ioctl() command is nicely interpersed with the rest of the block commands and we can issue a bunch of ioctl()s from userspace while there is some busy block IO going on without any problems. Conversely userspace ioctl()s can no longer starve the block layer by holding the card/host lock. Signed-off-by: Linus Walleij --- ChangeLog v1->v2: - Replace the if/else/if/else nest in mmc_blk_issue_rq() with a switch() clause at Ulf's request. - Update to the API change for req_to_mmc_queue_req() --- drivers/mmc/core/block.c | 111 ++++++++++++++++++++++++++++++++++++----------- drivers/mmc/core/queue.h | 3 ++ 2 files changed, 88 insertions(+), 26 deletions(-) -- 2.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index f4dab1dfd2ab..9fb2bd529156 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -564,8 +564,10 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, { struct mmc_blk_ioc_data *idata; struct mmc_blk_data *md; + struct mmc_queue *mq; struct mmc_card *card; int err = 0, ioc_err = 0; + struct request *req; /* * The caller must have CAP_SYS_RAWIO, and must be calling this on the @@ -591,17 +593,18 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, goto cmd_done; } - mmc_get_card(card); - - ioc_err = __mmc_blk_ioctl_cmd(card, md, idata); - - /* Always switch back to main area after RPMB access */ - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) - mmc_blk_part_switch(card, dev_get_drvdata(&card->dev)); - - mmc_put_card(card); - + /* + * Dispatch the ioctl() into the block request queue. + */ + mq = &md->queue; + req = blk_get_request(mq->queue, + idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, + __GFP_RECLAIM); + req_to_mmc_queue_req(req)->idata = idata; + blk_execute_rq(mq->queue, NULL, req, 0); + ioc_err = req_to_mmc_queue_req(req)->ioc_result; err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); + blk_put_request(req); cmd_done: mmc_blk_put(md); @@ -611,6 +614,31 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, return ioc_err ? ioc_err : err; } +/* + * The ioctl commands come back from the block layer after it queued it and + * processed it with all other requests and then they get issued in this + * function. + */ +static void mmc_blk_ioctl_cmd_issue(struct mmc_queue *mq, struct request *req) +{ + struct mmc_queue_req *mq_rq; + struct mmc_blk_ioc_data *idata; + struct mmc_card *card = mq->card; + struct mmc_blk_data *md = mq->blkdata; + int ioc_err; + + mq_rq = req_to_mmc_queue_req(req); + idata = mq_rq->idata; + ioc_err = __mmc_blk_ioctl_cmd(card, md, idata); + mq_rq->ioc_result = ioc_err; + + /* Always switch back to main area after RPMB access */ + if (md->area_type & MMC_BLK_DATA_AREA_RPMB) + mmc_blk_part_switch(card, dev_get_drvdata(&card->dev)); + + blk_end_request_all(req, ioc_err); +} + static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, struct mmc_ioc_multi_cmd __user *user) { @@ -1854,23 +1882,54 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) goto out; } - if (req && req_op(req) == REQ_OP_DISCARD) { - /* complete ongoing async transfer before issuing discard */ - if (mq->qcnt) - mmc_blk_issue_rw_rq(mq, NULL); - mmc_blk_issue_discard_rq(mq, req); - } else if (req && req_op(req) == REQ_OP_SECURE_ERASE) { - /* complete ongoing async transfer before issuing secure erase*/ - if (mq->qcnt) - mmc_blk_issue_rw_rq(mq, NULL); - mmc_blk_issue_secdiscard_rq(mq, req); - } else if (req && req_op(req) == REQ_OP_FLUSH) { - /* complete ongoing async transfer before issuing flush */ - if (mq->qcnt) - mmc_blk_issue_rw_rq(mq, NULL); - mmc_blk_issue_flush(mq, req); + if (req) { + switch (req_op(req)) { + case REQ_OP_DRV_IN: + case REQ_OP_DRV_OUT: + /* + * Complete ongoing async transfer before issuing + * ioctl()s + */ + if (mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL); + mmc_blk_ioctl_cmd_issue(mq, req); + break; + case REQ_OP_DISCARD: + /* + * Complete ongoing async transfer before issuing + * discard. + */ + if (mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL); + mmc_blk_issue_discard_rq(mq, req); + break; + case REQ_OP_SECURE_ERASE: + /* + * Complete ongoing async transfer before issuing + * secure erase. + */ + if (mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL); + mmc_blk_issue_secdiscard_rq(mq, req); + break; + case REQ_OP_FLUSH: + /* + * Complete ongoing async transfer before issuing + * flush. + */ + if (mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL); + mmc_blk_issue_flush(mq, req); + break; + default: + /* Normal request, just issue it */ + mmc_blk_issue_rw_rq(mq, req); + card->host->context_info.is_waiting_last_req = false; + break; + }; } else { - mmc_blk_issue_rw_rq(mq, req); + /* No request, flushing the pipeline with NULL */ + mmc_blk_issue_rw_rq(mq, NULL); card->host->context_info.is_waiting_last_req = false; } diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index dae31bc0c2d3..005ece9ac7cb 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -22,6 +22,7 @@ static inline bool mmc_req_is_special(struct request *req) struct task_struct; struct mmc_blk_data; +struct mmc_blk_ioc_data; struct mmc_blk_request { struct mmc_request mrq; @@ -40,6 +41,8 @@ struct mmc_queue_req { struct scatterlist *bounce_sg; unsigned int bounce_sg_len; struct mmc_async_req areq; + int ioc_result; + struct mmc_blk_ioc_data *idata; }; struct mmc_queue {