The ability to modify the SCSI device state was introduced by commit
638127e579a4 ("[PATCH] Fix error handler offline behaviour"; v2.6.12). That
same commit introduced the following device states:

       { SDEV_CREATED, "created" },
       { SDEV_RUNNING, "running" },
       { SDEV_CANCEL,  "cancel"  },
       { SDEV_DEL,     "deleted" },
       { SDEV_QUIESCE, "quiesce" },
       { SDEV_OFFLINE, "offline" },

The SDEV_BLOCK state was introduced later to avoid that an FC cable pull
would immediately result in an I/O error (commit 1094e682310e; "[PATCH]
suspending I/Os to a device"; v2.6.12). That same patch introduced the
ability to set the SDEV_BLOCK state from user space. I'm not sure whether
that ability was introduced on purpose or accidentally.

This patch makes sure that SDEV_BLOCK is only used for its original
purpose, namely to allow transport drivers and LLDs to block further
.queuecommand() calls while transport layer or adapter recovery is in
progress.

Notes:
- While SDEV_BLOCK blocks all SCSI commands, in the SDEV_QUIESCE
  state only those block layer requests are blocked for which RQF_PREEMPT
  has not been set. RQF_PREEMPT is not set for I/O requests submitted by
  e.g. a filesystem but is set for all requests pass-through requests.
  See also __scsi_execute().
- By doing a web search for ("blocked" OR "quiesce") AND
  "/sys/class/scsi_device" AND "device/state" I found several storage
  configuration guides. The instructions I found in these guides
  tell users to write the value "running" or "offline" in the SCSI
  device state sysfs attribute and no other values.

Cc: Christoph Hellwig <h...@lst.de>
Cc: Ming Lei <ming....@redhat.com>
Cc: Hannes Reinecke <h...@suse.de>
Cc: Johannes Thumshirn <jthumsh...@suse.de>
Cc: James Smart <james.sm...@broadcom.com>
Signed-off-by: Bart Van Assche <bvanass...@acm.org>
---
 drivers/scsi/scsi_sysfs.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index ff0aea7ac87f..a49ee113b3c4 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -769,6 +769,13 @@ store_state_field(struct device *dev, struct 
device_attribute *attr,
        }
        if (!state)
                return -EINVAL;
+       /*
+        * The state SDEV_BLOCK should not be set from userspace. Translate
+        * SDEV_BLOCK into SDEV_QUIESCE in case the SDEV_BLOCK state transition
+        * is requested from user space.
+        */
+       if (state == SDEV_BLOCK)
+               state = SDEV_QUIESCE;
 
        mutex_lock(&sdev->state_mutex);
        ret = scsi_device_set_state(sdev, state);
-- 
2.22.0.rc3

Reply via email to