* [PATCH 0/1] nvme-pci: fix hang during error recovery when the PCI device is isolated
@ 2022-07-12 12:44 Niklas Schnelle
2022-07-12 12:44 ` [PATCH 1/1] " Niklas Schnelle
0 siblings, 1 reply; 7+ messages in thread
From: Niklas Schnelle @ 2022-07-12 12:44 UTC (permalink / raw)
To: Christoph Hellwig, Keith Busch
Cc: Stefan Roese, Matthew Rosato, linux-nvme, linux-kernel
Hi Christoph, Hi Keith,
I found a regression when recovering NVMes after a simulated PCI error on
s390, though I believe at least some POWER systems should be affected as
well. I tracked this down to commit b98235d3a471 ("nvme-pci: harden drive
presence detect in nvme_dev_disable()") which causes nvme_start_freeze() to
not be called before nvme_reset_work() does nvme_wait_freeze() thus hanging
forever. The detailed analysis is included in the commit message and not
too complex but I'm not entirely sure my proposed solution is the correct
one.
The patch I'm sending here works for me and should at least only affect
platforms using the explicit driver->err_handler->slot_reset callback. To
my understanding it seems that the nvme_dev_disable() in
nvme_error_detected() still does the necessary quiescing towards upper
layers and I assume that nvme_start_freeze() won't do anything useful if
the controller is inaccessible but I'm not an expert in this. In particular
I'm not sure it makes sense to start freezing the queues right after
a reset.
Also note I will be travelling for about 3 weeks starting July 14th and
won't have access to s390 machines or my work mail address so apologies if
I won't answer. Feel free to do your own fix. Also Matt (on CC) might be
able to test fixes for this.
Best regards,
Niklas
Niklas Schnelle (1):
nvme-pci: fix hang during error recovery when the PCI device is
isolated
drivers/nvme/host/pci.c | 1 +
1 file changed, 1 insertion(+)
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/1] nvme-pci: fix hang during error recovery when the PCI device is isolated
2022-07-12 12:44 [PATCH 0/1] nvme-pci: fix hang during error recovery when the PCI device is isolated Niklas Schnelle
@ 2022-07-12 12:44 ` Niklas Schnelle
2022-07-12 13:49 ` Hannes Reinecke
2022-07-12 14:17 ` Keith Busch
0 siblings, 2 replies; 7+ messages in thread
From: Niklas Schnelle @ 2022-07-12 12:44 UTC (permalink / raw)
To: Christoph Hellwig, Keith Busch
Cc: Stefan Roese, Matthew Rosato, linux-nvme, linux-kernel
On s390 and powerpc PCI devices are isolated when an error is detected
and driver->err_handler->error_detected is called with an inaccessible
PCI device and PCI channel state set to pci_channel_io_frozen
(see Step 1 in Documentation/PCI/pci-error-recovery.rst).
In the case of NVMe devices nvme_error_detected() then calls
nvme_dev_disable(dev, false) and requests a reset. After a successful
reset the device is accessible again and nvme_slot_reset() resets the
controller and queues nvme_reset_work() which then recovers the
controller.
Since commit b98235d3a471 ("nvme-pci: harden drive presence detect in
nvme_dev_disable()") however nvme_dev_disable() no longer freezes the
queues if pci_device_is_present() returns false. This is the case for an
isolated PCI device. In principle this makes sense as there are no
accessible hardware queues to run. The problem though is that for
a previously live reset controller with online queues nvme_reset_work()
calls nvme_wait_freeze() which, without the freeze having been
initiated, then hangs forever. Fix this by starting the freeze in
nvme_slot_reset() which is the earliest point where we know the device
should be accessible again.
Fixes: b98235d3a471 ("nvme-pci: harden drive presence detect in nvme_dev_disable()")
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
---
drivers/nvme/host/pci.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 193b44755662..7c0c61b74c30 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -3399,6 +3399,7 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev)
dev_info(dev->ctrl.device, "restart after slot reset\n");
pci_restore_state(pdev);
nvme_reset_ctrl(&dev->ctrl);
+ nvme_start_freeze(&dev->ctrl);
return PCI_ERS_RESULT_RECOVERED;
}
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/1] nvme-pci: fix hang during error recovery when the PCI device is isolated
2022-07-12 12:44 ` [PATCH 1/1] " Niklas Schnelle
@ 2022-07-12 13:49 ` Hannes Reinecke
2022-07-12 14:05 ` Niklas Schnelle
2022-07-12 14:17 ` Keith Busch
1 sibling, 1 reply; 7+ messages in thread
From: Hannes Reinecke @ 2022-07-12 13:49 UTC (permalink / raw)
To: Niklas Schnelle, Christoph Hellwig, Keith Busch
Cc: Stefan Roese, Matthew Rosato, linux-nvme, linux-kernel
On 7/12/22 14:44, Niklas Schnelle wrote:
> On s390 and powerpc PCI devices are isolated when an error is detected
> and driver->err_handler->error_detected is called with an inaccessible
> PCI device and PCI channel state set to pci_channel_io_frozen
> (see Step 1 in Documentation/PCI/pci-error-recovery.rst).
>
> In the case of NVMe devices nvme_error_detected() then calls
> nvme_dev_disable(dev, false) and requests a reset. After a successful
> reset the device is accessible again and nvme_slot_reset() resets the
> controller and queues nvme_reset_work() which then recovers the
> controller.
>
> Since commit b98235d3a471 ("nvme-pci: harden drive presence detect in
> nvme_dev_disable()") however nvme_dev_disable() no longer freezes the
> queues if pci_device_is_present() returns false. This is the case for an
> isolated PCI device. In principle this makes sense as there are no
> accessible hardware queues to run. The problem though is that for
> a previously live reset controller with online queues nvme_reset_work()
> calls nvme_wait_freeze() which, without the freeze having been
> initiated, then hangs forever. Fix this by starting the freeze in
> nvme_slot_reset() which is the earliest point where we know the device
> should be accessible again.
>
> Fixes: b98235d3a471 ("nvme-pci: harden drive presence detect in nvme_dev_disable()")
> Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
> ---
> drivers/nvme/host/pci.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 193b44755662..7c0c61b74c30 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -3399,6 +3399,7 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev)
> dev_info(dev->ctrl.device, "restart after slot reset\n");
> pci_restore_state(pdev);
> nvme_reset_ctrl(&dev->ctrl);
> + nvme_start_freeze(&dev->ctrl);
> return PCI_ERS_RESULT_RECOVERED;
> }
>
I am not sure if that's the right fix.
From your description the hang occurs as nvme_reset_ctrl() is calling
nvme_wait_freeze() without an corresponding nvme_start_freeze().
So why are you calling it _after_ the call to nvme_reset_ctrl()?
Cheers,
Hannes
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/1] nvme-pci: fix hang during error recovery when the PCI device is isolated
2022-07-12 13:49 ` Hannes Reinecke
@ 2022-07-12 14:05 ` Niklas Schnelle
0 siblings, 0 replies; 7+ messages in thread
From: Niklas Schnelle @ 2022-07-12 14:05 UTC (permalink / raw)
To: Hannes Reinecke, Christoph Hellwig, Keith Busch
Cc: Stefan Roese, Matthew Rosato, linux-nvme, linux-kernel
On Tue, 2022-07-12 at 15:49 +0200, Hannes Reinecke wrote:
> On 7/12/22 14:44, Niklas Schnelle wrote:
> > On s390 and powerpc PCI devices are isolated when an error is detected
> > and driver->err_handler->error_detected is called with an inaccessible
> > PCI device and PCI channel state set to pci_channel_io_frozen
> > (see Step 1 in Documentation/PCI/pci-error-recovery.rst).
> >
> > In the case of NVMe devices nvme_error_detected() then calls
> > nvme_dev_disable(dev, false) and requests a reset. After a successful
> > reset the device is accessible again and nvme_slot_reset() resets the
> > controller and queues nvme_reset_work() which then recovers the
> > controller.
> >
> > Since commit b98235d3a471 ("nvme-pci: harden drive presence detect in
> > nvme_dev_disable()") however nvme_dev_disable() no longer freezes the
> > queues if pci_device_is_present() returns false. This is the case for an
> > isolated PCI device. In principle this makes sense as there are no
> > accessible hardware queues to run. The problem though is that for
> > a previously live reset controller with online queues nvme_reset_work()
> > calls nvme_wait_freeze() which, without the freeze having been
> > initiated, then hangs forever. Fix this by starting the freeze in
> > nvme_slot_reset() which is the earliest point where we know the device
> > should be accessible again.
> >
> > Fixes: b98235d3a471 ("nvme-pci: harden drive presence detect in nvme_dev_disable()")
> > Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
> > ---
> > drivers/nvme/host/pci.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> > index 193b44755662..7c0c61b74c30 100644
> > --- a/drivers/nvme/host/pci.c
> > +++ b/drivers/nvme/host/pci.c
> > @@ -3399,6 +3399,7 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev)
> > dev_info(dev->ctrl.device, "restart after slot reset\n");
> > pci_restore_state(pdev);
> > nvme_reset_ctrl(&dev->ctrl);
> > + nvme_start_freeze(&dev->ctrl);
> > return PCI_ERS_RESULT_RECOVERED;
> > }
> >
> I am not sure if that's the right fix.
> From your description the hang occurs as nvme_reset_ctrl() is calling
> nvme_wait_freeze() without an corresponding nvme_start_freeze().
> So why are you calling it _after_ the call to nvme_reset_ctrl()?
>
> Cheers,
>
> Hannes
Hmm, the call chain that used to have the nvme_start_freeze()
is nvme_error_detected()->nvme_dev_disable()->nvme_start_freeze().
With the referenced commit that nvme_start_freeze() no longer happens
because the nvme_error_detected callback occurs before the reset when
the device is still inaccessible (as mentioned Step 1 in
Documentation/PCI/pci-error-recovery.rst).
There is indeed another nvme_dev_disable() call in nvme_reset_work()
but in the nvme_slot_reset() path this comes before
pci_enable_device_mem() was called so that also doesn't do the
nvme_start_freeze(). I also tried doing the nvme_start_freeze() there
but at least in my test that broke /sys/bus/pci/devices/<dev>/reset,
though not entirely sure why since nvme_start_freeze() looks like a no-
op when done a second time. I'm also not sure though what the right
approach is here though.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/1] nvme-pci: fix hang during error recovery when the PCI device is isolated
2022-07-12 12:44 ` [PATCH 1/1] " Niklas Schnelle
2022-07-12 13:49 ` Hannes Reinecke
@ 2022-07-12 14:17 ` Keith Busch
2022-07-12 14:36 ` Niklas Schnelle
2022-07-18 9:30 ` Stefan Roese
1 sibling, 2 replies; 7+ messages in thread
From: Keith Busch @ 2022-07-12 14:17 UTC (permalink / raw)
To: Niklas Schnelle
Cc: Christoph Hellwig, Stefan Roese, Matthew Rosato, linux-nvme,
linux-kernel
On Tue, Jul 12, 2022 at 02:44:53PM +0200, Niklas Schnelle wrote:
> On s390 and powerpc PCI devices are isolated when an error is detected
> and driver->err_handler->error_detected is called with an inaccessible
> PCI device and PCI channel state set to pci_channel_io_frozen
> (see Step 1 in Documentation/PCI/pci-error-recovery.rst).
>
> In the case of NVMe devices nvme_error_detected() then calls
> nvme_dev_disable(dev, false) and requests a reset. After a successful
> reset the device is accessible again and nvme_slot_reset() resets the
> controller and queues nvme_reset_work() which then recovers the
> controller.
>
> Since commit b98235d3a471 ("nvme-pci: harden drive presence detect in
> nvme_dev_disable()") however nvme_dev_disable() no longer freezes the
> queues if pci_device_is_present() returns false. This is the case for an
> isolated PCI device. In principle this makes sense as there are no
> accessible hardware queues to run. The problem though is that for
> a previously live reset controller with online queues nvme_reset_work()
> calls nvme_wait_freeze() which, without the freeze having been
> initiated, then hangs forever. Fix this by starting the freeze in
> nvme_slot_reset() which is the earliest point where we know the device
> should be accessible again.
>
> Fixes: b98235d3a471 ("nvme-pci: harden drive presence detect in nvme_dev_disable()")
> Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Oh, we've messed up the expected sequence. The mistaken assumption is a device
not present means we're about to unbind from it, but it could appear that way
just for normal error handling and reset, so we need to preserve the previous
handling.
The offending commit really just wants to avoid the register access (which we
shouldn't have to do, but hey, broken hardware...). So let's keep the sequence
the same as before and just skip the register read. Does this work for you?
---
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index fdfee3e590db..c40e82cee735 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
static void nvme_dev_remove_admin(struct nvme_dev *dev)
@@ -2690,9 +2772,11 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
struct pci_dev *pdev = to_pci_dev(dev->dev);
mutex_lock(&dev->shutdown_lock);
- if (pci_device_is_present(pdev) && pci_is_enabled(pdev)) {
- u32 csts = readl(dev->bar + NVME_REG_CSTS);
+ if (pci_is_enabled(pdev)) {
+ u32 csts = ~0;
+ if (pci_device_is_present(pdev))
+ csts = readl(dev->bar + NVME_REG_CSTS);
if (dev->ctrl.state == NVME_CTRL_LIVE ||
dev->ctrl.state == NVME_CTRL_RESETTING) {
freeze = true;
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/1] nvme-pci: fix hang during error recovery when the PCI device is isolated
2022-07-12 14:17 ` Keith Busch
@ 2022-07-12 14:36 ` Niklas Schnelle
2022-07-18 9:30 ` Stefan Roese
1 sibling, 0 replies; 7+ messages in thread
From: Niklas Schnelle @ 2022-07-12 14:36 UTC (permalink / raw)
To: Keith Busch
Cc: Christoph Hellwig, Stefan Roese, Matthew Rosato, linux-nvme,
linux-kernel
On Tue, 2022-07-12 at 08:17 -0600, Keith Busch wrote:
> On Tue, Jul 12, 2022 at 02:44:53PM +0200, Niklas Schnelle wrote:
> > On s390 and powerpc PCI devices are isolated when an error is detected
> > and driver->err_handler->error_detected is called with an inaccessible
> > PCI device and PCI channel state set to pci_channel_io_frozen
> > (see Step 1 in Documentation/PCI/pci-error-recovery.rst).
> >
> > In the case of NVMe devices nvme_error_detected() then calls
> > nvme_dev_disable(dev, false) and requests a reset. After a successful
> > reset the device is accessible again and nvme_slot_reset() resets the
> > controller and queues nvme_reset_work() which then recovers the
> > controller.
> >
> > Since commit b98235d3a471 ("nvme-pci: harden drive presence detect in
> > nvme_dev_disable()") however nvme_dev_disable() no longer freezes the
> > queues if pci_device_is_present() returns false. This is the case for an
> > isolated PCI device. In principle this makes sense as there are no
> > accessible hardware queues to run. The problem though is that for
> > a previously live reset controller with online queues nvme_reset_work()
> > calls nvme_wait_freeze() which, without the freeze having been
> > initiated, then hangs forever. Fix this by starting the freeze in
> > nvme_slot_reset() which is the earliest point where we know the device
> > should be accessible again.
> >
> > Fixes: b98235d3a471 ("nvme-pci: harden drive presence detect in nvme_dev_disable()")
> > Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
>
> Oh, we've messed up the expected sequence. The mistaken assumption is a device
> not present means we're about to unbind from it, but it could appear that way
> just for normal error handling and reset, so we need to preserve the previous
> handling.
>
> The offending commit really just wants to avoid the register access (which we
> shouldn't have to do, but hey, broken hardware...). So let's keep the sequence
> the same as before and just skip the register read. Does this work for you?
Ah thanks for the explanation! I had actually tested a similar patch
but wasn't sure if nvme_start_freeze() also does register access for
starting the HW queues and if it makes sense on a dead/isolated device
at all. On the other hand this code very explicitly handles dead
devices so I guess this was kept in mind.
So yes the below patch works for me.
>
> ---
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index fdfee3e590db..c40e82cee735 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> static void nvme_dev_remove_admin(struct nvme_dev *dev)
> @@ -2690,9 +2772,11 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
> struct pci_dev *pdev = to_pci_dev(dev->dev);
>
> mutex_lock(&dev->shutdown_lock);
> - if (pci_device_is_present(pdev) && pci_is_enabled(pdev)) {
> - u32 csts = readl(dev->bar + NVME_REG_CSTS);
> + if (pci_is_enabled(pdev)) {
> + u32 csts = ~0;
>
> + if (pci_device_is_present(pdev))
> + csts = readl(dev->bar + NVME_REG_CSTS);
> if (dev->ctrl.state == NVME_CTRL_LIVE ||
> dev->ctrl.state == NVME_CTRL_RESETTING) {
> freeze = true;
> --
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/1] nvme-pci: fix hang during error recovery when the PCI device is isolated
2022-07-12 14:17 ` Keith Busch
2022-07-12 14:36 ` Niklas Schnelle
@ 2022-07-18 9:30 ` Stefan Roese
1 sibling, 0 replies; 7+ messages in thread
From: Stefan Roese @ 2022-07-18 9:30 UTC (permalink / raw)
To: Keith Busch, Niklas Schnelle
Cc: Christoph Hellwig, Matthew Rosato, linux-nvme, linux-kernel
On 12.07.22 16:17, Keith Busch wrote:
> On Tue, Jul 12, 2022 at 02:44:53PM +0200, Niklas Schnelle wrote:
>> On s390 and powerpc PCI devices are isolated when an error is detected
>> and driver->err_handler->error_detected is called with an inaccessible
>> PCI device and PCI channel state set to pci_channel_io_frozen
>> (see Step 1 in Documentation/PCI/pci-error-recovery.rst).
>>
>> In the case of NVMe devices nvme_error_detected() then calls
>> nvme_dev_disable(dev, false) and requests a reset. After a successful
>> reset the device is accessible again and nvme_slot_reset() resets the
>> controller and queues nvme_reset_work() which then recovers the
>> controller.
>>
>> Since commit b98235d3a471 ("nvme-pci: harden drive presence detect in
>> nvme_dev_disable()") however nvme_dev_disable() no longer freezes the
>> queues if pci_device_is_present() returns false. This is the case for an
>> isolated PCI device. In principle this makes sense as there are no
>> accessible hardware queues to run. The problem though is that for
>> a previously live reset controller with online queues nvme_reset_work()
>> calls nvme_wait_freeze() which, without the freeze having been
>> initiated, then hangs forever. Fix this by starting the freeze in
>> nvme_slot_reset() which is the earliest point where we know the device
>> should be accessible again.
>>
>> Fixes: b98235d3a471 ("nvme-pci: harden drive presence detect in nvme_dev_disable()")
>> Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
>
> Oh, we've messed up the expected sequence. The mistaken assumption is a device
> not present means we're about to unbind from it, but it could appear that way
> just for normal error handling and reset, so we need to preserve the previous
> handling.
>
> The offending commit really just wants to avoid the register access (which we
> shouldn't have to do, but hey, broken hardware...).
Correct.
> So let's keep the sequence
> the same as before and just skip the register read. Does this work for you?
>
> ---
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index fdfee3e590db..c40e82cee735 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> static void nvme_dev_remove_admin(struct nvme_dev *dev)
> @@ -2690,9 +2772,11 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
> struct pci_dev *pdev = to_pci_dev(dev->dev);
>
> mutex_lock(&dev->shutdown_lock);
> - if (pci_device_is_present(pdev) && pci_is_enabled(pdev)) {
> - u32 csts = readl(dev->bar + NVME_REG_CSTS);
> + if (pci_is_enabled(pdev)) {
> + u32 csts = ~0;
>
> + if (pci_device_is_present(pdev))
> + csts = readl(dev->bar + NVME_REG_CSTS);
> if (dev->ctrl.state == NVME_CTRL_LIVE ||
> dev->ctrl.state == NVME_CTRL_RESETTING) {
> freeze = true;
> --
Thanks. Looks good to me. So if anyone whats to send a proper patch with
this change, feel free to add my:
Reviewed-by: Stefan Roese <sr@denx.de>
Thanks,
Stefan
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2022-07-18 9:31 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-12 12:44 [PATCH 0/1] nvme-pci: fix hang during error recovery when the PCI device is isolated Niklas Schnelle
2022-07-12 12:44 ` [PATCH 1/1] " Niklas Schnelle
2022-07-12 13:49 ` Hannes Reinecke
2022-07-12 14:05 ` Niklas Schnelle
2022-07-12 14:17 ` Keith Busch
2022-07-12 14:36 ` Niklas Schnelle
2022-07-18 9:30 ` Stefan Roese
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®