Thread (78 messages) 78 messages, 4 authors, 2015-09-23

Re: [PATCH v2 08/30] cxlflash: Fix to avoid CXL services during EEH

From: Matthew R. Ochs <hidden>
Date: 2015-09-18 23:54:56
Also in: linux-scsi

On Sep 18, 2015, at 8:37 AM, Brian King [off-list ref] =
wrote:
On 09/16/2015 04:27 PM, Matthew R. Ochs wrote:
quoted
=20
/**
+ * drain_ioctls() - wait until all currently executing ioctls have =
completed
quoted
+ * @cfg:	Internal structure associated with the host.
+ *
+ * Obtain write access to read/write semaphore that wraps ioctl
+ * handling to 'drain' ioctls currently executing.
+ */
+static void drain_ioctls(struct cxlflash_cfg *cfg)
+{
+	down_write(&cfg->ioctl_rwsem);
+	up_write(&cfg->ioctl_rwsem);
+}
+
+/**
 * cxlflash_pci_error_detected() - called when a PCI error is =
detected
quoted
 * @pdev:	PCI device struct.
 * @state:	PCI channel state.
@@ -2383,16 +2397,14 @@ static pci_ers_result_t =
cxlflash_pci_error_detected(struct pci_dev *pdev,
quoted
	switch (state) {
	case pci_channel_io_frozen:
		cfg->state =3D STATE_LIMBO;
-
-		/* Turn off legacy I/O */
		scsi_block_requests(cfg->host);
+		drain_ioctls(cfg);
=20
So, what kicks any outstanding ioctls back? Let's assume you are in =
the middle of disk_attach
and you've sent the READ_CAP16 to the device. It appears as if what =
would happen here is we'd
sit here in cxlflash_pci_error_detected. Eventually, the READ_CAP16 =
would timeout. This would
wake the SCSI error handler, and end up calling your eh_device_reset =
handler, which would see that
we are in STATE_LIMBO, where it would then do a wait_event, waiting =
for us to get out of STATE_LIMBO,
and we would end up in a deadlock.
=20
Rather than implementing a rw semaphore, would it be better to simply =
make the ioctls check the
state we are in and either wait to get out of EEH state or fail =
themselves?

We do have the ioctls check the state and wait for EEH to complete
or fail completely in the event that the device is terminating (see
ioctl_common()). The drain exists to create a wait point for ioctls that
have already passed the state check and are active. The CXL services
cannot be called during the recovery window (maybe this requirement
will go away in a future release?), thus the reason for this 'drain'.

To handle it I considered 3 options:

 - add state check wraps to all CXL service calls
 - create a "running ioctls" count that could be evaluated
 - wrap the ioctl in read semaphore and obtain write access to 'wait'

I started with the first option and it quickly made the code very nasty. =
I then
began implementing the second option and as I was writing the code to =
wrap
the ioctl with increment/decrement statements, the third option entered =
my
mind and seemed like a much cleaner solution. Therefore I went with that
approach and did not look back.

With regard to your example, you bring up a good point and we'll need to
do something about that. One thought that comes to mind would be for us
to drop the semaphore before making this type of call (I believe there =
are
only 2 places like this), reacquiring it when we return, and then =
checking
the state to make sure we're not in a reset situation.
=20
quoted
		rc =3D cxlflash_mark_contexts_error(cfg);
		if (unlikely(rc))
			dev_err(dev, "%s: Failed to mark user =
contexts!(%d)\n",
quoted
				__func__, rc);
		term_mc(cfg, UNDO_START);
		stop_afu(cfg);
-
		return PCI_ERS_RESULT_NEED_RESET;
	case pci_channel_io_perm_failure:
		cfg->state =3D STATE_FAILTERM;
diff --git a/drivers/scsi/cxlflash/superpipe.c =
b/drivers/scsi/cxlflash/superpipe.c
quoted
index cf2a85d..8a18230 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -1214,6 +1214,48 @@ static const struct file_operations null_fops =
=3D {
quoted
};
=20
/**
+ * check_state() - checks and responds to the current adapter state
+ * @cfg:	Internal structure associated with the host.
+ * @ioctl:	Indicates if on an ioctl thread.
+ *
+ * This routine can block and should only be used on process =
context.
quoted
+ * When blocking on an ioctl thread, the ioctl read semaphore should =
be
quoted
+ * let up to allow for draining actively running ioctls. Also note =
that
quoted
+ * when waking up from waiting in reset, the state is unknown and =
must
quoted
+ * be checked again before proceeding.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int check_state(struct cxlflash_cfg *cfg, bool ioctl)
=20
All your callers appear to set the second parameter to true, so why =
bother having it?

That's a good point. I originally had a case where there was a need for =
this
but have since removed it. I can fix that in v3.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help