From: Ming Lei <ming.lei@redhat.com>
To: Bart Van Assche <bart.vanassche@wdc.com>
Cc: Jens Axboe <axboe@kernel.dk>,
linux-block@vger.kernel.org, Christoph Hellwig <hch@lst.de>,
Hannes Reinecke <hare@suse.com>,
Johannes Thumshirn <jthumshirn@suse.de>,
"Rafael J . Wysocki" <rafael.j.wysocki@intel.com>
Subject: Re: [PATCH 5/5] blk-mq: Implement power management support
Date: Tue, 12 Sep 2017 17:14:59 +0800 [thread overview]
Message-ID: <20170912091456.GA15792@ming.t460p> (raw)
In-Reply-To: <20170908235226.26622-6-bart.vanassche@wdc.com>
On Fri, Sep 08, 2017 at 04:52:26PM -0700, Bart Van Assche wrote:
> Implement the following approach for blk-mq:
> - Either make blk_get_request() wait or make it fail when a
> request queue is not in status RPM_ACTIVE.
> - While suspending, suspended or resuming, only process power
> management requests (REQ_PM).
>
> Reported-by: Oleksandr Natalenko <oleksandr@natalenko.name>
> References: "I/O hangs after resuming from suspend-to-ram" (https://marc.info/?l=linux-block&m=150340235201348).
This patch is nothing to do with Oleksandr's report, please
remove the above two lines. For example, runttime PM can
be bypassed via sysfs, and suspend/resume still can work
well.
> Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Hannes Reinecke <hare@suse.com>
> Cc: Johannes Thumshirn <jthumshirn@suse.de>
> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Cc: Ming Lei <ming.lei@redhat.com>
> ---
> block/blk-core.c | 20 ++++++++++++++++----
> block/blk-mq.c | 34 ++++++++++++++++++++++++++++++++++
> 2 files changed, 50 insertions(+), 4 deletions(-)
>
> diff --git a/block/blk-core.c b/block/blk-core.c
> index cd2700c763ed..49a4cd5b255e 100644
> --- a/block/blk-core.c
> +++ b/block/blk-core.c
> @@ -3438,10 +3438,6 @@ EXPORT_SYMBOL(blk_finish_plug);
> */
> void blk_pm_runtime_init(struct request_queue *q, struct device *dev)
> {
> - /* not support for RQF_PM and ->rpm_status in blk-mq yet */
> - if (q->mq_ops)
> - return;
> -
> q->dev = dev;
> q->rpm_status = RPM_ACTIVE;
> init_waitqueue_head(&q->rpm_active_wq);
> @@ -3478,6 +3474,19 @@ int blk_pre_runtime_suspend(struct request_queue *q)
> if (!q->dev)
> return ret;
>
> + if (q->mq_ops) {
> + percpu_ref_switch_to_atomic_nowait(&q->q_usage_counter);
> + if (!percpu_ref_is_zero(&q->q_usage_counter)) {
> + ret = -EBUSY;
> + pm_runtime_mark_last_busy(q->dev);
> + } else {
> + spin_lock_irq(q->queue_lock);
> + q->rpm_status = RPM_SUSPENDING;
> + spin_unlock_irq(q->queue_lock);
> + }
> + return ret;
> + }
> +
> spin_lock_irq(q->queue_lock);
> if (q->nr_pending) {
> ret = -EBUSY;
> @@ -3561,6 +3570,9 @@ void blk_post_runtime_resume(struct request_queue *q, int err)
> if (!q->dev)
> return;
>
> + if (q->mq_ops)
> + percpu_ref_switch_to_percpu(&q->q_usage_counter);
> +
> spin_lock_irq(q->queue_lock);
> if (!err) {
> q->rpm_status = RPM_ACTIVE;
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index 3f18cff80050..cbd680dc194a 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -383,6 +383,29 @@ static struct request *blk_mq_get_request(struct request_queue *q,
> return rq;
> }
>
> +#ifdef CONFIG_PM
> +static bool blk_mq_wait_until_active(struct request_queue *q, bool wait)
> +{
> + if (!wait)
> + return false;
> + /*
> + * Note: the q->rpm_status check below races against the changes of
> + * that variable by the blk_{pre,post}_runtime_{suspend,resume}()
> + * functions. The worst possible consequence of these races is that a
> + * small number of requests gets passed to the block driver associated
> + * with the request queue after rpm_status has been changed into
> + * RPM_SUSPENDING and before it is changed into RPM_SUSPENDED.
> + */
> + wait_event(q->rpm_active_wq, q->rpm_status == RPM_ACTIVE);
> + return true;
> +}
> +#else
> +static bool blk_mq_wait_until_active(struct request_queue *q, bool nowait)
> +{
> + return true;
> +}
> +#endif
> +
> struct request *blk_mq_alloc_request(struct request_queue *q, unsigned int op,
> unsigned int flags)
> {
> @@ -390,6 +413,17 @@ struct request *blk_mq_alloc_request(struct request_queue *q, unsigned int op,
> struct request *rq;
> int ret;
>
> + 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_mq_wait_until_active(q, !(op & REQ_NOWAIT)))
> + return ERR_PTR(-EAGAIN);
> +
> ret = blk_queue_enter(q, flags & BLK_MQ_REQ_NOWAIT);
> if (ret)
> return ERR_PTR(ret);
> --
> 2.14.1
>
One issue is that pm_runtime_mark_last_busy() isn't set
accurately because it can't check if the freeing req is
the last active one, and set it if yes.
--
Ming
next prev parent reply other threads:[~2017-09-12 9:14 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-09-08 23:52 [PATCH 0/5] Make SCSI device suspend work reliably Bart Van Assche
2017-09-08 23:52 ` [PATCH 1/5] percpu-refcount: Introduce percpu_ref_switch_to_atomic_nowait() Bart Van Assche
2017-09-11 8:42 ` Johannes Thumshirn
2017-09-11 16:10 ` Bart Van Assche
2017-09-11 13:13 ` Tejun Heo
2017-09-11 16:09 ` Bart Van Assche
2017-09-11 16:37 ` tj
2017-09-11 16:55 ` Bart Van Assche
2017-09-11 17:20 ` Tejun Heo
2017-09-11 17:29 ` Bart Van Assche
2017-09-08 23:52 ` [PATCH 2/5] scsi: Change the type of the second last argument of scsi_execute() Bart Van Assche
2017-09-08 23:52 ` [PATCH 3/5] block: Introduce REQ_PM and remove RQF_PM Bart Van Assche
2017-09-08 23:52 ` [PATCH 4/5] block: Make SCSI device suspend work reliably Bart Van Assche
2017-09-12 2:29 ` Ming Lei
2017-09-12 15:45 ` Bart Van Assche
2017-09-12 16:10 ` Ming Lei
2017-09-12 16:25 ` Ming Lei
2017-09-08 23:52 ` [PATCH 5/5] blk-mq: Implement power management support Bart Van Assche
2017-09-12 9:14 ` Ming Lei [this message]
2017-09-09 10:39 ` [PATCH 0/5] Make SCSI device suspend work reliably Ming Lei
2017-09-11 16:25 ` Bart Van Assche
2017-09-12 2:17 ` Ming Lei
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170912091456.GA15792@ming.t460p \
--to=ming.lei@redhat.com \
--cc=axboe@kernel.dk \
--cc=bart.vanassche@wdc.com \
--cc=hare@suse.com \
--cc=hch@lst.de \
--cc=jthumshirn@suse.de \
--cc=linux-block@vger.kernel.org \
--cc=rafael.j.wysocki@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.