nvme-mpath: fix I/O failure with EAGAIN when failing over I/O
authorSagi Grimberg <sagi@grimberg.me>
Tue, 20 Jun 2023 13:07:36 +0000 (16:07 +0300)
committerKeith Busch <kbusch@kernel.org>
Tue, 27 Jun 2023 15:16:26 +0000 (08:16 -0700)
It is possible that the next available path we failover to, happens to
be frozen (for example if it is during connection establishment). If
the original I/O was set with NOWAIT, this cause the I/O to unnecessarily
fail because the request queue cannot be entered, hence the I/O fails with
EAGAIN.

The NOWAIT restriction that was originally set for the I/O is no longer
relevant or needed because this is the nvme requeue context. Hence we
clear the REQ_NOWAIT flag when failing over I/O.

This fix a simple test case of nvme controller reset during I/O when the
multipath device that has only a single path and I/O fails with "Resource
temporarily unavailable" errno. Note that this reproduces with io_uring
which by default sets IOCB_NOWAIT by default.

Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/host/multipath.c

index 91a9a55..3acb477 100644 (file)
@@ -106,6 +106,14 @@ void nvme_failover_req(struct request *req)
                        bio->bi_opf &= ~REQ_POLLED;
                        bio->bi_cookie = BLK_QC_T_NONE;
                }
+               /*
+                * The alternate request queue that we may end up submitting
+                * the bio to may be frozen temporarily, in this case REQ_NOWAIT
+                * will fail the I/O immediately with EAGAIN to the issuer.
+                * We are not in the issuer context which cannot block. Clear
+                * the flag to avoid spurious EAGAIN I/O failures.
+                */
+               bio->bi_opf &= ~REQ_NOWAIT;
        }
        blk_steal_bios(&ns->head->requeue_list, req);
        spin_unlock_irqrestore(&ns->head->requeue_lock, flags);