From patchwork Fri Sep 8 23:52:25 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bart Van Assche X-Patchwork-Id: 9945151 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 88FCB602D7 for ; Fri, 8 Sep 2017 23:54:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7CDEB2898E for ; Fri, 8 Sep 2017 23:54:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 718F3289D3; Fri, 8 Sep 2017 23:54:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D17522898E for ; Fri, 8 Sep 2017 23:54:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757279AbdIHXy3 (ORCPT ); Fri, 8 Sep 2017 19:54:29 -0400 Received: from esa2.hgst.iphmx.com ([68.232.143.124]:12724 "EHLO esa2.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757247AbdIHXy2 (ORCPT ); Fri, 8 Sep 2017 19:54:28 -0400 X-IronPort-AV: E=Sophos;i="5.42,363,1500912000"; d="scan'208";a="145723576" Received: from sjappemgw11.hgst.com (HELO sjappemgw12.hgst.com) ([199.255.44.62]) by ob1.hgst.iphmx.com with ESMTP; 09 Sep 2017 08:12:40 +0800 Received: from thinkpad-bart.sdcorp.global.sandisk.com (HELO thinkpad-bart.int.fusionio.com) ([10.11.172.152]) by sjappemgw12.hgst.com with ESMTP; 08 Sep 2017 16:52:28 -0700 From: Bart Van Assche To: Jens Axboe Cc: linux-block@vger.kernel.org, Christoph Hellwig , Bart Van Assche , Hannes Reinecke , Johannes Thumshirn , "Rafael J . Wysocki" , Ming Lei Subject: [PATCH 4/5] block: Make SCSI device suspend work reliably Date: Fri, 8 Sep 2017 16:52:25 -0700 Message-Id: <20170908235226.26622-5-bart.vanassche@wdc.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170908235226.26622-1-bart.vanassche@wdc.com> References: <20170908235226.26622-1-bart.vanassche@wdc.com> Sender: linux-block-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Instead of allowing request allocation to succeed for suspended request queues and only to process power management requests, make blk_get_request() wait until the request queue is resumed for requests that are not power management requests. This patch avoids that resume does not occur if the maximum queue depth is reached when a power management request is submitted. Note: this patch affects the behavior of scsi_device_quiesce() only if that function is called from inside a power management callback. This patch does not affect the behavior of scsi_device_quiesce() when a call of that function is triggered by writing "quiesce" into /sys/class/scsi_device/*/device/state. Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Johannes Thumshirn Cc: Rafael J. Wysocki Cc: Ming Lei --- block/blk-core.c | 60 +++++++++++++++++++++++++++----------------------- block/blk.h | 12 ++++++++++ include/linux/blkdev.h | 1 + 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index bb53c6b58e8c..cd2700c763ed 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1325,6 +1325,24 @@ static struct request *__get_request(struct request_list *rl, unsigned int op, return ERR_PTR(-ENOMEM); } +#ifdef CONFIG_PM +static bool blk_wait_until_active(struct request_queue *q, bool wait) + __releases(q->queue_lock) + __acquires(q->queue_lock) +{ + if (wait) + wait_event_lock_irq(q->rpm_active_wq, + q->rpm_status == RPM_ACTIVE, + *q->queue_lock); + return q->rpm_status == RPM_ACTIVE; +} +#else +static bool blk_wait_until_active(struct request_queue *q, bool wait) +{ + return true; +} +#endif + /** * get_request - get a free request * @q: request_queue to allocate request from @@ -1350,6 +1368,16 @@ static struct request *get_request(struct request_queue *q, unsigned int op, lockdep_assert_held(q->queue_lock); WARN_ON_ONCE(q->mq_ops); + WARN_ON_ONCE((op & REQ_PM) && blk_pm_suspended(q)); + + /* + * Wait if the request queue is suspended or in the process of + * suspending/resuming and the request being allocated will not be + * used for power management purposes. + */ + if (!(op & REQ_PM) && !blk_wait_until_active(q, !(op & REQ_NOWAIT))) + return ERR_PTR(-EAGAIN); + rl = blk_get_rl(q, bio); /* transferred to @rq on success */ retry: rq = __get_request(rl, op, bio, gfp_mask); @@ -2458,28 +2486,6 @@ void blk_account_io_done(struct request *req) } } -#ifdef CONFIG_PM -/* - * Don't process normal requests when queue is suspended - * or in the process of suspending/resuming - */ -static struct request *blk_pm_peek_request(struct request_queue *q, - struct request *rq) -{ - if (q->dev && (q->rpm_status == RPM_SUSPENDED || - (q->rpm_status != RPM_ACTIVE && !(rq->cmd_flags & REQ_PM)))) - return NULL; - else - return rq; -} -#else -static inline struct request *blk_pm_peek_request(struct request_queue *q, - struct request *rq) -{ - return rq; -} -#endif - void blk_account_io_start(struct request *rq, bool new_io) { struct hd_struct *part; @@ -2538,11 +2544,6 @@ struct request *blk_peek_request(struct request_queue *q) WARN_ON_ONCE(q->mq_ops); while ((rq = __elv_next_request(q)) != NULL) { - - rq = blk_pm_peek_request(q, rq); - if (!rq) - break; - if (!(rq->rq_flags & RQF_STARTED)) { /* * This is the first time the device driver @@ -3443,6 +3444,7 @@ void blk_pm_runtime_init(struct request_queue *q, struct device *dev) q->dev = dev; q->rpm_status = RPM_ACTIVE; + init_waitqueue_head(&q->rpm_active_wq); pm_runtime_set_autosuspend_delay(q->dev, -1); pm_runtime_use_autosuspend(q->dev); } @@ -3512,6 +3514,7 @@ void blk_post_runtime_suspend(struct request_queue *q, int err) } else { q->rpm_status = RPM_ACTIVE; pm_runtime_mark_last_busy(q->dev); + wake_up_all(&q->rpm_active_wq); } spin_unlock_irq(q->queue_lock); } @@ -3561,8 +3564,8 @@ void blk_post_runtime_resume(struct request_queue *q, int err) spin_lock_irq(q->queue_lock); if (!err) { q->rpm_status = RPM_ACTIVE; - __blk_run_queue(q); pm_runtime_mark_last_busy(q->dev); + wake_up_all(&q->rpm_active_wq); pm_request_autosuspend(q->dev); } else { q->rpm_status = RPM_SUSPENDED; @@ -3590,6 +3593,7 @@ void blk_set_runtime_active(struct request_queue *q) spin_lock_irq(q->queue_lock); q->rpm_status = RPM_ACTIVE; pm_runtime_mark_last_busy(q->dev); + wake_up_all(&q->rpm_active_wq); pm_request_autosuspend(q->dev); spin_unlock_irq(q->queue_lock); } diff --git a/block/blk.h b/block/blk.h index fcb9775b997d..f535ece723ab 100644 --- a/block/blk.h +++ b/block/blk.h @@ -361,4 +361,16 @@ static inline void blk_queue_bounce(struct request_queue *q, struct bio **bio) } #endif /* CONFIG_BOUNCE */ +#ifdef CONFIG_PM +static inline bool blk_pm_suspended(struct request_queue *q) +{ + return q->rpm_status == RPM_SUSPENDED; +} +#else +static inline bool blk_pm_suspended(struct request_queue *q) +{ + return false; +} +#endif + #endif /* BLK_INTERNAL_H */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 7f9a0743fc09..08a709c0971b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -493,6 +493,7 @@ struct request_queue { #ifdef CONFIG_PM struct device *dev; int rpm_status; + struct wait_queue_head rpm_active_wq; unsigned int nr_pending; #endif