From: Hannes Reinecke <hare@suse.de>
To: sagi@grimberg.me, linux-nvme@lists.infradead.org,
Christoph Hellwig <hch@lst.de>, Keith Busch <kbusch@kernel.org>,
Chaitanya Kulkarni <kch@nvidia.com>
Cc: Daniel Wagner <dwagner@suse.de>,
Shinichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Subject: Re: [PATCH 4/6] nvme-mpath: support controller crd when failing over request
Date: Mon, 24 Aug 2026 15:45:26 +0200 [thread overview]
Message-ID: <c3ca9481-8eaa-496b-bdde-38cd911d8f96@suse.de> (raw)
In-Reply-To: <20260823084903.193188-5-sagi@grimberg.me>
On 8/23/26 10:49 AM, Sagi Grimberg wrote:
> When failing over a request (due to a path based status) we should
> repect controller crd returned in the nvme completion as much as
> possible. Hence we want to delay the failover command execution by
> the controller crdt.
>
> We allocate a new nvme_mpath_failover_timer referencing the request
> stolen bios in a staging list, and when the command retry delay expires,
> and only then the bios are moved to the mpath head requeue list which is
> immediately kicked to re-submit these bios. If we failed to allocate
> a fot, we fallback to the existing behavior.
>
> Given that we now have a new staging list for mpath devices, we drain
> them when removing the device.
>
> Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
> ---
> drivers/nvme/host/multipath.c | 96 +++++++++++++++++++++++++++++++++--
> drivers/nvme/host/nvme.h | 1 +
> 2 files changed, 93 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index b5501217303c..959dd1e05a2d 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -9,6 +9,13 @@
> #include <trace/events/block.h>
> #include "nvme.h"
>
> +struct nvme_mpath_failover_timer {
> + struct list_head entry;
> + struct nvme_ns_head *head;
> + struct bio_list bios;
> + struct timer_list timer;
> +};
> +
> bool multipath = true;
> static bool multipath_always_on;
>
> @@ -144,10 +151,48 @@ void nvme_mpath_start_freeze(struct nvme_subsystem *subsys)
> blk_freeze_queue_start(h->disk->queue);
> }
>
> +static void nvme_mpath_failover_timer_fn(struct timer_list *t)
> +{
> + struct nvme_mpath_failover_timer *fot = timer_container_of(fot, t, timer);
> + struct nvme_ns_head *head = fot->head;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&head->requeue_lock, flags);
> + if (list_empty(&fot->entry)) {
> + spin_unlock_irqrestore(&head->requeue_lock, flags);
> + return;
> + }
> +
> + list_del_init(&fot->entry);
> + if (fot->bios.head)
> + bio_list_merge(&head->requeue_list, &fot->bios);
> + spin_unlock_irqrestore(&head->requeue_lock, flags);
> + kblockd_schedule_work(&head->requeue_work);
> + kfree(fot);
> +}
> +
> +static struct nvme_mpath_failover_timer *
> +nvme_mpath_alloc_failover_timer(struct nvme_ns_head *head)
> +{
> + struct nvme_mpath_failover_timer *fot;
> +
> + fot = kzalloc(sizeof(*fot), GFP_ATOMIC);
> + if (!fot)
> + goto out;
> + fot->head = head;
> + bio_list_init(&fot->bios);
> + INIT_LIST_HEAD(&fot->entry);
> + timer_setup(&fot->timer, nvme_mpath_failover_timer_fn, 0);
> +out:
> + return fot;
> +}
> +
> void nvme_failover_req(struct request *req)
> {
> struct nvme_ns *ns = req->q->queuedata;
> u16 status = nvme_req(req)->status & NVME_SCT_SC_MASK;
> + struct nvme_mpath_failover_timer *fot = NULL;
> + unsigned int delay;
> unsigned long flags;
> struct bio *bio;
>
> @@ -167,13 +212,27 @@ void nvme_failover_req(struct request *req)
> for (bio = req->bio; bio; bio = bio->bi_next)
> bio_set_dev(bio, ns->head->disk->part0);
>
> - spin_lock_irqsave(&ns->head->requeue_lock, flags);
> - blk_steal_bios(&ns->head->requeue_list, req);
> - spin_unlock_irqrestore(&ns->head->requeue_lock, flags);
> + delay = nvme_crd_msecs(nvme_req(req));
> + if (delay) {
> + fot = nvme_mpath_alloc_failover_timer(ns->head);
> + if (fot) {
> + blk_steal_bios(&fot->bios, req);
> + spin_lock_irqsave(&ns->head->requeue_lock, flags);
> + list_add_tail(&fot->entry, &ns->head->fots);
> + spin_unlock_irqrestore(&ns->head->requeue_lock, flags);
> + mod_timer(&fot->timer, jiffies + msecs_to_jiffies(delay));
> + }
> + }
> + /* no CRD or timer allocation failed, fallback to immediate failover */
> + if (!fot) {
> + spin_lock_irqsave(&ns->head->requeue_lock, flags);
> + blk_steal_bios(&ns->head->requeue_list, req);
> + spin_unlock_irqrestore(&ns->head->requeue_lock, flags);
> + kblockd_schedule_work(&ns->head->requeue_work);
> + }
Yikes. Allocation during failover is not going to make you friends.
And this whole mechanism looks pretty similar what we did over at
implementing CCR. Can you use the mechanism from there?
Cheers,
Hannes
--
Dr. Hannes Reinecke Kernel Storage Architect
hare@suse.de +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich
next prev parent reply other threads:[~2026-08-24 13:45 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-23 8:48 [PATCH 0/6] Support per command retry timer Sagi Grimberg
2026-08-23 8:48 ` [PATCH 1/6] nvme-mpath: No need to protect req->bio with requeue_lock Sagi Grimberg
2026-08-24 11:31 ` Hannes Reinecke
2026-08-24 15:53 ` John Garry
2026-09-02 13:39 ` Christoph Hellwig
2026-08-23 8:48 ` [PATCH 2/6] nvme: add nvme_crd_msecs helper Sagi Grimberg
2026-08-24 11:32 ` Hannes Reinecke
2026-09-02 13:40 ` Christoph Hellwig
2026-09-06 0:07 ` Sagi Grimberg
2026-08-23 8:48 ` [PATCH 3/6] nvme: add per request retry timer Sagi Grimberg
2026-08-24 13:25 ` Hannes Reinecke
2026-09-02 13:41 ` Christoph Hellwig
2026-09-06 0:09 ` Sagi Grimberg
2026-09-11 22:53 ` Sagi Grimberg
2026-08-23 8:49 ` [PATCH 4/6] nvme-mpath: support controller crd when failing over request Sagi Grimberg
2026-08-24 13:45 ` Hannes Reinecke [this message]
2026-08-24 14:23 ` Sagi Grimberg
2026-09-02 13:43 ` Christoph Hellwig
2026-09-06 0:15 ` Sagi Grimberg
2026-08-23 8:49 ` [PATCH 5/6] nvmet: Add support for configurable crdt (command retry delay) attributes Sagi Grimberg
2026-09-02 13:44 ` Christoph Hellwig
2026-09-06 0:20 ` Sagi Grimberg
2026-08-23 8:49 ` [PATCH 6/6] nvme/fault-injection: Support for error injection with custom crd Sagi Grimberg
2026-08-23 8:49 ` [PATCH 7/6 RFC] nvme: test per-command retry delay Sagi Grimberg
2026-08-30 8:23 ` Shin'ichiro Kawasaki
2026-08-30 20:55 ` Sagi Grimberg
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=c3ca9481-8eaa-496b-bdde-38cd911d8f96@suse.de \
--to=hare@suse.de \
--cc=dwagner@suse.de \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=kch@nvidia.com \
--cc=linux-nvme@lists.infradead.org \
--cc=sagi@grimberg.me \
--cc=shinichiro.kawasaki@wdc.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox