* [PATCHv2 00/22] ALUA device handler update, part II
@ 2016-01-12 15:40 Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 01/22] scsi_dh_alua: Pass buffer as function argument Hannes Reinecke
` (22 more replies)
0 siblings, 23 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
(resending as I failed to include linux-scsi :-( )
Hi all,
as promised here is now the second part of my ALUA device handler update.
This contains a major rework of the ALUA device handler as execution is
moved onto a workqueue. This has the advantage that we avoid having to
do multiple calls to the same LUN (as happens frequently when failing
over a LUN with several paths) and finally retries are handled correctly.
As some arrays are only capable of handling one STPG at a time I've added
a second hardware handler parameter which then uses a singlethreaded
workqueue, thereby effectively synchronize STPG handling.
Thanks to Bart for this suggestion.
As usual, comments and reviews are welcome.
Changes to v1:
- Include reviews from hch
- Switch to hardware handler parameter instead of module option
Hannes Reinecke (22):
scsi_dh_alua: Pass buffer as function argument
scsi_dh_alua: separate out alua_stpg()
scsi_dh_alua: Make stpg synchronous
scsi_dh_alua: call alua_rtpg() if stpg fails
scsi_dh_alua: switch to scsi_execute_req_flags()
scsi_dh_alua: allocate RTPG buffer separately
scsi_dh_alua: Use separate alua_port_group structure
scsi_dh_alua: use unique device id
scsi_dh_alua: simplify alua_initialize()
revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach
should succeed while TPG is transitioning")
scsi_dh_alua: move optimize_stpg evaluation
scsi_dh_alua: remove 'rel_port' from alua_dh_data structure
scsi_dh_alua: Use workqueue for RTPG
scsi_dh_alua: Allow workqueue to run synchronously
scsi_dh_alua: Recheck state on unit attention
scsi_dh_alua: update all port states
scsi_dh_alua: Send TEST UNIT READY to poll for transitioning
scsi_dh: add 'rescan' callback
scsi: Add 'access_state' attribute
scsi_dh_alua: use common definitions for ALUA state
scsi_dh_alua: update 'access_state' field
scsi_dh_alua: Update version to 2.0
drivers/scsi/device_handler/scsi_dh_alua.c | 983 ++++++++++++++++++++---------
drivers/scsi/scsi_lib.c | 1 +
drivers/scsi/scsi_scan.c | 9 +-
drivers/scsi/scsi_sysfs.c | 49 ++
include/scsi/scsi_device.h | 1 +
include/scsi/scsi_dh.h | 2 +
include/scsi/scsi_proto.h | 13 +
7 files changed, 747 insertions(+), 311 deletions(-)
--
1.8.5.6
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCHv2 01/22] scsi_dh_alua: Pass buffer as function argument
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 02/22] scsi_dh_alua: separate out alua_stpg() Hannes Reinecke
` (21 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
Pass in the buffer as a function argument for submit_rtpg().
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 5a328bf..df71e85 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -135,12 +135,13 @@ static struct request *get_alua_req(struct scsi_device *sdev,
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
+static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
+ int bufflen, unsigned char *sense, int flags)
{
struct request *rq;
int err = 0;
- rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
+ rq = get_alua_req(sdev, buff, bufflen, READ);
if (!rq) {
err = DRIVER_BUSY << 24;
goto done;
@@ -148,14 +149,14 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_IN;
- if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP))
+ if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
rq->cmd[1] = MI_REPORT_TARGET_PGS;
- put_unaligned_be32(h->bufflen, &rq->cmd[6]);
+ put_unaligned_be32(bufflen, &rq->cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
- rq->sense = h->sense;
+ rq->sense = sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;
@@ -446,7 +447,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
retry:
- retval = submit_rtpg(sdev, h);
+ retval = submit_rtpg(sdev, h->buff, h->bufflen, h->sense, h->flags);
if (retval) {
if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
&sense_hdr)) {
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 02/22] scsi_dh_alua: separate out alua_stpg()
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 01/22] scsi_dh_alua: Pass buffer as function argument Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 03/22] scsi_dh_alua: Make stpg synchronous Hannes Reinecke
` (20 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
Separate out SET TARGET PORT GROUP functionality into a separate
function alua_stpg().
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 95 +++++++++++++++++++-----------
1 file changed, 61 insertions(+), 34 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index df71e85..7c66e4a 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -579,6 +579,65 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
}
/*
+ * alua_stpg - Issue a SET TARGET GROUP STATES command
+ *
+ * Issue a SET TARGET GROUP STATES command and evaluate the
+ * response. Returns SCSI_DH_RETRY if the target port group
+ * state is found to be in 'transitioning'.
+ * If SCSI_DH_OK is returned the passed-in 'fn' function
+ * this function will take care of executing 'fn'.
+ * Otherwise 'fn' should be executed by the caller with the
+ * returned error code.
+ */
+static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h,
+ activate_complete fn, void *data)
+{
+ int err = SCSI_DH_OK;
+ int stpg = 0;
+
+ if (!(h->tpgs & TPGS_MODE_EXPLICIT))
+ /* Only implicit ALUA supported */
+ goto out;
+
+ switch (h->state) {
+ case TPGS_STATE_NONOPTIMIZED:
+ stpg = 1;
+ if ((h->flags & ALUA_OPTIMIZE_STPG) &&
+ !h->pref &&
+ (h->tpgs & TPGS_MODE_IMPLICIT))
+ stpg = 0;
+ break;
+ case TPGS_STATE_STANDBY:
+ case TPGS_STATE_UNAVAILABLE:
+ stpg = 1;
+ break;
+ case TPGS_STATE_OFFLINE:
+ err = SCSI_DH_IO;
+ break;
+ case TPGS_STATE_TRANSITIONING:
+ err = SCSI_DH_RETRY;
+ break;
+ default:
+ break;
+ }
+
+ if (stpg) {
+ h->callback_fn = fn;
+ h->callback_data = data;
+ err = submit_stpg(h);
+ if (err != SCSI_DH_OK)
+ h->callback_fn = h->callback_data = NULL;
+ else
+ fn = NULL;
+ }
+out:
+ if (fn)
+ fn(data, err);
+
+ return err;
+}
+
+/*
* alua_initialize - Initialize ALUA state
* @sdev: the device to be initialized
*
@@ -655,7 +714,6 @@ static int alua_activate(struct scsi_device *sdev,
{
struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
- int stpg = 0;
err = alua_rtpg(sdev, h, 1);
if (err != SCSI_DH_OK)
@@ -664,41 +722,10 @@ static int alua_activate(struct scsi_device *sdev,
if (optimize_stpg)
h->flags |= ALUA_OPTIMIZE_STPG;
- if (h->tpgs & TPGS_MODE_EXPLICIT) {
- switch (h->state) {
- case TPGS_STATE_NONOPTIMIZED:
- stpg = 1;
- if ((h->flags & ALUA_OPTIMIZE_STPG) &&
- (!h->pref) &&
- (h->tpgs & TPGS_MODE_IMPLICIT))
- stpg = 0;
- break;
- case TPGS_STATE_STANDBY:
- case TPGS_STATE_UNAVAILABLE:
- stpg = 1;
- break;
- case TPGS_STATE_OFFLINE:
- err = SCSI_DH_IO;
- break;
- case TPGS_STATE_TRANSITIONING:
- err = SCSI_DH_RETRY;
- break;
- default:
- break;
- }
- }
-
- if (stpg) {
- h->callback_fn = fn;
- h->callback_data = data;
- err = submit_stpg(h);
- if (err == SCSI_DH_OK)
- return 0;
- h->callback_fn = h->callback_data = NULL;
- }
+ err = alua_stpg(sdev, h, fn, data);
out:
- if (fn)
+ if (err != SCSI_DH_OK && fn)
fn(data, err);
return 0;
}
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 03/22] scsi_dh_alua: Make stpg synchronous
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 01/22] scsi_dh_alua: Pass buffer as function argument Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 02/22] scsi_dh_alua: separate out alua_stpg() Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 04/22] scsi_dh_alua: call alua_rtpg() if stpg fails Hannes Reinecke
` (19 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
The 'activate_complete' function needs to be executed after
stpg has finished, so we can as well execute stpg synchronously
and call the function directly.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 156 ++++++++++-------------------
1 file changed, 55 insertions(+), 101 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 7c66e4a..609691f 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -169,81 +169,28 @@ done:
}
/*
- * stpg_endio - Evaluate SET TARGET GROUP STATES
- * @sdev: the device to be evaluated
- * @state: the new target group state
- *
- * Evaluate a SET TARGET GROUP STATES command response.
- */
-static void stpg_endio(struct request *req, int error)
-{
- struct alua_dh_data *h = req->end_io_data;
- struct scsi_sense_hdr sense_hdr;
- unsigned err = SCSI_DH_OK;
-
- if (host_byte(req->errors) != DID_OK ||
- msg_byte(req->errors) != COMMAND_COMPLETE) {
- err = SCSI_DH_IO;
- goto done;
- }
-
- if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr)) {
- if (sense_hdr.sense_key == NOT_READY &&
- sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) {
- /* ALUA state transition already in progress */
- err = SCSI_DH_OK;
- goto done;
- }
- if (sense_hdr.sense_key == UNIT_ATTENTION) {
- err = SCSI_DH_RETRY;
- goto done;
- }
- sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
- ALUA_DH_NAME);
- scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr);
- err = SCSI_DH_IO;
- } else if (error)
- err = SCSI_DH_IO;
-
- if (err == SCSI_DH_OK) {
- h->state = TPGS_STATE_OPTIMIZED;
- sdev_printk(KERN_INFO, h->sdev,
- "%s: port group %02x switched to state %c\n",
- ALUA_DH_NAME, h->group_id,
- print_alua_state(h->state));
- }
-done:
- req->end_io_data = NULL;
- __blk_put_request(req->q, req);
- if (h->callback_fn) {
- h->callback_fn(h->callback_data, err);
- h->callback_fn = h->callback_data = NULL;
- }
- return;
-}
-
-/*
* submit_stpg - Issue a SET TARGET GROUP STATES command
*
* Currently we're only setting the current target port group state
* to 'active/optimized' and let the array firmware figure out
* the states of the remaining groups.
*/
-static unsigned submit_stpg(struct alua_dh_data *h)
+static unsigned submit_stpg(struct scsi_device *sdev, int group_id,
+ unsigned char *sense)
{
struct request *rq;
+ unsigned char stpg_data[8];
int stpg_len = 8;
- struct scsi_device *sdev = h->sdev;
+ int err = 0;
/* Prepare the data buffer */
- memset(h->buff, 0, stpg_len);
- h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
- put_unaligned_be16(h->group_id, &h->buff[6]);
+ memset(stpg_data, 0, stpg_len);
+ stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
+ put_unaligned_be16(group_id, &stpg_data[6]);
- rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
+ rq = get_alua_req(sdev, stpg_data, stpg_len, WRITE);
if (!rq)
- return SCSI_DH_RES_TEMP_UNAVAIL;
+ return DRIVER_BUSY << 24;
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_OUT;
@@ -251,13 +198,17 @@ static unsigned submit_stpg(struct alua_dh_data *h)
put_unaligned_be32(stpg_len, &rq->cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
- rq->sense = h->sense;
+ rq->sense = sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;
- rq->end_io_data = h;
- blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
- return SCSI_DH_OK;
+ blk_execute_rq(rq->q, NULL, rq, 1);
+ if (rq->errors)
+ err = rq->errors;
+
+ blk_put_request(rq);
+
+ return err;
}
/*
@@ -582,59 +533,63 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* alua_stpg - Issue a SET TARGET GROUP STATES command
*
* Issue a SET TARGET GROUP STATES command and evaluate the
- * response. Returns SCSI_DH_RETRY if the target port group
- * state is found to be in 'transitioning'.
- * If SCSI_DH_OK is returned the passed-in 'fn' function
- * this function will take care of executing 'fn'.
- * Otherwise 'fn' should be executed by the caller with the
- * returned error code.
+ * response. Returns SCSI_DH_RETRY per default to trigger
+ * a re-evaluation of the target group state or SCSI_DH_OK
+ * if no further action needs to be taken.
*/
-static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h,
- activate_complete fn, void *data)
+static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int err = SCSI_DH_OK;
- int stpg = 0;
-
- if (!(h->tpgs & TPGS_MODE_EXPLICIT))
- /* Only implicit ALUA supported */
- goto out;
+ int retval;
+ struct scsi_sense_hdr sense_hdr;
+ if (!(h->tpgs & TPGS_MODE_EXPLICIT)) {
+ /* Only implicit ALUA supported, retry */
+ return SCSI_DH_RETRY;
+ }
switch (h->state) {
+ case TPGS_STATE_OPTIMIZED:
+ return SCSI_DH_OK;
case TPGS_STATE_NONOPTIMIZED:
- stpg = 1;
if ((h->flags & ALUA_OPTIMIZE_STPG) &&
!h->pref &&
(h->tpgs & TPGS_MODE_IMPLICIT))
- stpg = 0;
+ return SCSI_DH_OK;
break;
case TPGS_STATE_STANDBY:
case TPGS_STATE_UNAVAILABLE:
- stpg = 1;
break;
case TPGS_STATE_OFFLINE:
- err = SCSI_DH_IO;
+ return SCSI_DH_IO;
break;
case TPGS_STATE_TRANSITIONING:
- err = SCSI_DH_RETRY;
break;
default:
+ sdev_printk(KERN_INFO, sdev,
+ "%s: stpg failed, unhandled TPGS state %d",
+ ALUA_DH_NAME, h->state);
+ return SCSI_DH_NOSYS;
break;
}
+ /* Set state to transitioning */
+ h->state = TPGS_STATE_TRANSITIONING;
+ retval = submit_stpg(sdev, h->group_id, h->sense);
- if (stpg) {
- h->callback_fn = fn;
- h->callback_data = data;
- err = submit_stpg(h);
- if (err != SCSI_DH_OK)
- h->callback_fn = h->callback_data = NULL;
- else
- fn = NULL;
+ if (retval) {
+ if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: stpg failed, result %d",
+ ALUA_DH_NAME, retval);
+ if (driver_byte(retval) == DRIVER_BUSY)
+ return SCSI_DH_DEV_TEMP_BUSY;
+ } else {
+ sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ }
}
-out:
- if (fn)
- fn(data, err);
-
- return err;
+ /* Retry RTPG */
+ return SCSI_DH_RETRY;
}
/*
@@ -722,10 +677,9 @@ static int alua_activate(struct scsi_device *sdev,
if (optimize_stpg)
h->flags |= ALUA_OPTIMIZE_STPG;
- err = alua_stpg(sdev, h, fn, data);
-
+ err = alua_stpg(sdev, h);
out:
- if (err != SCSI_DH_OK && fn)
+ if (fn)
fn(data, err);
return 0;
}
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 04/22] scsi_dh_alua: call alua_rtpg() if stpg fails
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (2 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 03/22] scsi_dh_alua: Make stpg synchronous Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 05/22] scsi_dh_alua: switch to scsi_execute_req_flags() Hannes Reinecke
` (18 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
If the call to SET TARGET PORT GROUPS fails we have no idea what
state the array is left in, so we need to issue a call to
REPORT TARGET PORT GROUPS in these cases.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 609691f..ba3d23e 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -678,6 +678,8 @@ static int alua_activate(struct scsi_device *sdev,
h->flags |= ALUA_OPTIMIZE_STPG;
err = alua_stpg(sdev, h);
+ if (err == SCSI_DH_RETRY)
+ err = alua_rtpg(sdev, h, 1);
out:
if (fn)
fn(data, err);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 05/22] scsi_dh_alua: switch to scsi_execute_req_flags()
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (3 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 04/22] scsi_dh_alua: call alua_rtpg() if stpg fails Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-13 5:48 ` kbuild test robot
2016-01-12 15:40 ` [PATCHv2 06/22] scsi_dh_alua: allocate RTPG buffer separately Hannes Reinecke
` (17 subsequent siblings)
22 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
All commands are issued synchronously, so no need to open-code
scsi_execute_req_flags() anymore. And we can get rid of the
static sense code structure element. scsi_execute_req_flags()
will be setting REQ_QUIET and REQ_PREEMPT, but that is
perfectly fine as we're evaluating and logging any errors
ourselves and we really need to send the command even if
the device is quiesced.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Ewan Milne <emilne@redhat.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 125 +++++++++--------------------
1 file changed, 36 insertions(+), 89 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index ba3d23e..063c03a 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -75,7 +75,6 @@ struct alua_dh_data {
unsigned char *buff;
int bufflen;
unsigned char transition_tmo;
- unsigned char sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_device *sdev;
activate_complete callback_fn;
void *callback_data;
@@ -101,71 +100,30 @@ static int realloc_buffer(struct alua_dh_data *h, unsigned len)
return 0;
}
-static struct request *get_alua_req(struct scsi_device *sdev,
- void *buffer, unsigned buflen, int rw)
-{
- struct request *rq;
- struct request_queue *q = sdev->request_queue;
-
- rq = blk_get_request(q, rw, GFP_NOIO);
-
- if (IS_ERR(rq)) {
- sdev_printk(KERN_INFO, sdev,
- "%s: blk_get_request failed\n", __func__);
- return NULL;
- }
- blk_rq_set_block_pc(rq);
-
- if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
- blk_put_request(rq);
- sdev_printk(KERN_INFO, sdev,
- "%s: blk_rq_map_kern failed\n", __func__);
- return NULL;
- }
-
- rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
- rq->retries = ALUA_FAILOVER_RETRIES;
- rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ;
-
- return rq;
-}
-
/*
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
-static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
- int bufflen, unsigned char *sense, int flags)
+static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
+ int bufflen, struct scsi_sense_hdr *sshdr, int flags)
{
- struct request *rq;
- int err = 0;
-
- rq = get_alua_req(sdev, buff, bufflen, READ);
- if (!rq) {
- err = DRIVER_BUSY << 24;
- goto done;
- }
+ u8 cdb[COMMAND_SIZE(MAINTENANCE_IN)];
+ int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
/* Prepare the command. */
- rq->cmd[0] = MAINTENANCE_IN;
+ memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_IN));
+ cdb[0] = MAINTENANCE_IN;
if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
- rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
+ cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
- rq->cmd[1] = MI_REPORT_TARGET_PGS;
- put_unaligned_be32(bufflen, &rq->cmd[6]);
- rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
-
- rq->sense = sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = 0;
-
- blk_execute_rq(rq->q, NULL, rq, 1);
- if (rq->errors)
- err = rq->errors;
- blk_put_request(rq);
-done:
- return err;
+ cdb[1] = MI_REPORT_TARGET_PGS;
+ put_unaligned_be32(bufflen, &cdb[6]);
+
+ return scsi_execute_req_flags(sdev, cdb, DMA_FROM_DEVICE,
+ buff, bufflen, sshdr,
+ ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, NULL, req_flags);
}
/*
@@ -175,40 +133,30 @@ done:
* to 'active/optimized' and let the array firmware figure out
* the states of the remaining groups.
*/
-static unsigned submit_stpg(struct scsi_device *sdev, int group_id,
- unsigned char *sense)
+static int submit_stpg(struct scsi_device *sdev, int group_id,
+ struct scsi_sense_hdr *sshdr)
{
- struct request *rq;
+ u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)];
unsigned char stpg_data[8];
int stpg_len = 8;
- int err = 0;
+ int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
/* Prepare the data buffer */
memset(stpg_data, 0, stpg_len);
stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
put_unaligned_be16(group_id, &stpg_data[6]);
- rq = get_alua_req(sdev, stpg_data, stpg_len, WRITE);
- if (!rq)
- return DRIVER_BUSY << 24;
-
/* Prepare the command. */
- rq->cmd[0] = MAINTENANCE_OUT;
- rq->cmd[1] = MO_SET_TARGET_PGS;
- put_unaligned_be32(stpg_len, &rq->cmd[6]);
- rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
-
- rq->sense = sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = 0;
-
- blk_execute_rq(rq->q, NULL, rq, 1);
- if (rq->errors)
- err = rq->errors;
-
- blk_put_request(rq);
-
- return err;
+ memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_OUT));
+ cdb[0] = MAINTENANCE_OUT;
+ cdb[1] = MO_SET_TARGET_PGS;
+ put_unaligned_be32(stpg_len, &cdb[6]);
+
+ return scsi_execute_req_flags(sdev, cdb, DMA_TO_DEVICE,
+ stpg_data, stpg_len,
+ sshdr, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, NULL, req_flags);
}
/*
@@ -398,14 +346,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
retry:
- retval = submit_rtpg(sdev, h->buff, h->bufflen, h->sense, h->flags);
+ retval = submit_rtpg(sdev, h->buff, h->bufflen, &sense_hdr, h->flags);
+
if (retval) {
- if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr)) {
+ if (!scsi_sense_valid(&sense_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: rtpg failed, result %d\n",
ALUA_DH_NAME, retval);
- if (driver_byte(retval) == DRIVER_BUSY)
+ if (driver_byte(retval) == DRIVER_ERROR)
return SCSI_DH_DEV_TEMP_BUSY;
return SCSI_DH_IO;
}
@@ -572,15 +520,14 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
}
/* Set state to transitioning */
h->state = TPGS_STATE_TRANSITIONING;
- retval = submit_stpg(sdev, h->group_id, h->sense);
+ retval = submit_stpg(sdev, h->group_id, &sense_hdr);
if (retval) {
- if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr)) {
+ if (!scsi_sense_valid(&sense_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: stpg failed, result %d",
ALUA_DH_NAME, retval);
- if (driver_byte(retval) == DRIVER_BUSY)
+ if (driver_byte(retval) == DRIVER_ERROR)
return SCSI_DH_DEV_TEMP_BUSY;
} else {
sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 06/22] scsi_dh_alua: allocate RTPG buffer separately
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (4 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 05/22] scsi_dh_alua: switch to scsi_execute_req_flags() Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 07/22] scsi_dh_alua: Use separate alua_port_group structure Hannes Reinecke
` (16 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
The RTPG buffer will only evaluated within alua_rtpg(),
so we can allocate it locally there and avoid having to
put it into the global structure.
Reviewed-by: Ewan Milne <emilne@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 57 ++++++++++++------------------
1 file changed, 23 insertions(+), 34 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 063c03a..49dea42 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -56,7 +56,7 @@
#define TPGS_MODE_IMPLICIT 0x1
#define TPGS_MODE_EXPLICIT 0x2
-#define ALUA_INQUIRY_SIZE 36
+#define ALUA_RTPG_SIZE 128
#define ALUA_FAILOVER_TIMEOUT 60
#define ALUA_FAILOVER_RETRIES 5
@@ -71,9 +71,6 @@ struct alua_dh_data {
int state;
int pref;
unsigned flags; /* used for optimizing STPG */
- unsigned char inq[ALUA_INQUIRY_SIZE];
- unsigned char *buff;
- int bufflen;
unsigned char transition_tmo;
struct scsi_device *sdev;
activate_complete callback_fn;
@@ -85,21 +82,6 @@ struct alua_dh_data {
static char print_alua_state(int);
-static int realloc_buffer(struct alua_dh_data *h, unsigned len)
-{
- if (h->buff && h->buff != h->inq)
- kfree(h->buff);
-
- h->buff = kmalloc(len, GFP_NOIO);
- if (!h->buff) {
- h->buff = h->inq;
- h->bufflen = ALUA_INQUIRY_SIZE;
- return 1;
- }
- h->bufflen = len;
- return 0;
-}
-
/*
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
@@ -333,8 +315,8 @@ static int alua_check_sense(struct scsi_device *sdev,
static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition)
{
struct scsi_sense_hdr sense_hdr;
- int len, k, off, valid_states = 0;
- unsigned char *ucp;
+ int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
+ unsigned char *ucp, *buff;
unsigned err, retval;
unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
@@ -345,14 +327,19 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
else
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
+ buff = kzalloc(bufflen, GFP_KERNEL);
+ if (!buff)
+ return SCSI_DH_DEV_TEMP_BUSY;
+
retry:
- retval = submit_rtpg(sdev, h->buff, h->bufflen, &sense_hdr, h->flags);
+ retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, h->flags);
if (retval) {
if (!scsi_sense_valid(&sense_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: rtpg failed, result %d\n",
ALUA_DH_NAME, retval);
+ kfree(buff);
if (driver_byte(retval) == DRIVER_ERROR)
return SCSI_DH_DEV_TEMP_BUSY;
return SCSI_DH_IO;
@@ -390,14 +377,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ kfree(buff);
return SCSI_DH_IO;
}
- len = get_unaligned_be32(&h->buff[0]) + 4;
+ len = get_unaligned_be32(&buff[0]) + 4;
- if (len > h->bufflen) {
+ if (len > bufflen) {
/* Resubmit with the correct length */
- if (realloc_buffer(h, len)) {
+ kfree(buff);
+ bufflen = len;
+ buff = kmalloc(bufflen, GFP_KERNEL);
+ if (!buff) {
sdev_printk(KERN_WARNING, sdev,
"%s: kmalloc buffer failed\n",__func__);
/* Temporary failure, bypass */
@@ -407,24 +398,25 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
}
orig_transition_tmo = h->transition_tmo;
- if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && h->buff[5] != 0)
- h->transition_tmo = h->buff[5];
+ if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && buff[5] != 0)
+ h->transition_tmo = buff[5];
else
h->transition_tmo = ALUA_FAILOVER_TIMEOUT;
- if (wait_for_transition && (orig_transition_tmo != h->transition_tmo)) {
+ if (wait_for_transition &&
+ (orig_transition_tmo != h->transition_tmo)) {
sdev_printk(KERN_INFO, sdev,
"%s: transition timeout set to %d seconds\n",
ALUA_DH_NAME, h->transition_tmo);
expiry = jiffies + h->transition_tmo * HZ;
}
- if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
+ if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
tpg_desc_tbl_off = 8;
else
tpg_desc_tbl_off = 4;
- for (k = tpg_desc_tbl_off, ucp = h->buff + tpg_desc_tbl_off;
+ for (k = tpg_desc_tbl_off, ucp = buff + tpg_desc_tbl_off;
k < len;
k += off, ucp += off) {
@@ -474,6 +466,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
err = SCSI_DH_OK;
break;
}
+ kfree(buff);
return err;
}
@@ -672,8 +665,6 @@ static int alua_bus_attach(struct scsi_device *sdev)
h->state = TPGS_STATE_OPTIMIZED;
h->group_id = -1;
h->rel_port = -1;
- h->buff = h->inq;
- h->bufflen = ALUA_INQUIRY_SIZE;
h->sdev = sdev;
err = alua_initialize(sdev, h);
@@ -695,8 +686,6 @@ static void alua_bus_detach(struct scsi_device *sdev)
{
struct alua_dh_data *h = sdev->handler_data;
- if (h->buff && h->inq != h->buff)
- kfree(h->buff);
sdev->handler_data = NULL;
kfree(h);
}
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 07/22] scsi_dh_alua: Use separate alua_port_group structure
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (5 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 06/22] scsi_dh_alua: allocate RTPG buffer separately Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 08/22] scsi_dh_alua: use unique device id Hannes Reinecke
` (15 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
The port group needs to be a separate structure as several
LUNs might belong to the same group.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Ewan Milne <emilne@redhat.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 183 ++++++++++++++++++++---------
include/scsi/scsi_dh.h | 1 +
2 files changed, 130 insertions(+), 54 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 49dea42..14b4ca6 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -64,14 +64,24 @@
#define ALUA_OPTIMIZE_STPG 1
#define ALUA_RTPG_EXT_HDR_UNSUPP 2
-struct alua_dh_data {
+static LIST_HEAD(port_group_list);
+static DEFINE_SPINLOCK(port_group_lock);
+
+struct alua_port_group {
+ struct kref kref;
+ struct list_head node;
int group_id;
- int rel_port;
int tpgs;
int state;
int pref;
unsigned flags; /* used for optimizing STPG */
unsigned char transition_tmo;
+};
+
+struct alua_dh_data {
+ struct alua_port_group *pg;
+ int group_id;
+ int rel_port;
struct scsi_device *sdev;
activate_complete callback_fn;
void *callback_data;
@@ -82,6 +92,17 @@ struct alua_dh_data {
static char print_alua_state(int);
+static void release_port_group(struct kref *kref)
+{
+ struct alua_port_group *pg;
+
+ pg = container_of(kref, struct alua_port_group, kref);
+ spin_lock(&port_group_lock);
+ list_del(&pg->node);
+ spin_unlock(&port_group_lock);
+ kfree(pg);
+}
+
/*
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
@@ -142,6 +163,35 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
}
/*
+ * alua_alloc_pg - Allocate a new port_group structure
+ * @sdev: scsi device
+ * @h: alua device_handler data
+ * @group_id: port group id
+ *
+ * Allocate a new port_group structure for a given
+ * device.
+ */
+struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
+ int group_id, int tpgs)
+{
+ struct alua_port_group *pg;
+
+ pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
+ if (!pg)
+ return NULL;
+
+ pg->group_id = group_id;
+ pg->tpgs = tpgs;
+ pg->state = TPGS_STATE_OPTIMIZED;
+ kref_init(&pg->kref);
+ spin_lock(&port_group_lock);
+ list_add(&pg->node, &port_group_list);
+ spin_unlock(&port_group_lock);
+
+ return pg;
+}
+
+/*
* alua_check_tpgs - Evaluate TPGS setting
* @sdev: device to be checked
*
@@ -216,7 +266,6 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
ALUA_DH_NAME);
return SCSI_DH_DEV_UNSUPP;
}
- h->state = TPGS_STATE_OPTIMIZED;
h->group_id = group_id;
sdev_printk(KERN_INFO, sdev,
@@ -312,7 +361,7 @@ static int alua_check_sense(struct scsi_device *sdev,
* Returns SCSI_DH_DEV_OFFLINED if the path is
* found to be unusable.
*/
-static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition)
+static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int wait_for_transition)
{
struct scsi_sense_hdr sense_hdr;
int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
@@ -322,17 +371,17 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
- if (!h->transition_tmo)
+ if (!pg->transition_tmo)
expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
else
- expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
+ expiry = round_jiffies_up(jiffies + pg->transition_tmo * HZ);
buff = kzalloc(bufflen, GFP_KERNEL);
if (!buff)
return SCSI_DH_DEV_TEMP_BUSY;
retry:
- retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, h->flags);
+ retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, pg->flags);
if (retval) {
if (!scsi_sense_valid(&sense_hdr)) {
@@ -353,10 +402,10 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* The retry without rtpg_ext_hdr_req set
* handles this.
*/
- if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
+ if (!(pg->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
sense_hdr.sense_key == ILLEGAL_REQUEST &&
sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
- h->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
+ pg->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
goto retry;
}
/*
@@ -397,18 +446,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
goto retry;
}
- orig_transition_tmo = h->transition_tmo;
+ orig_transition_tmo = pg->transition_tmo;
if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && buff[5] != 0)
- h->transition_tmo = buff[5];
+ pg->transition_tmo = buff[5];
else
- h->transition_tmo = ALUA_FAILOVER_TIMEOUT;
+ pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
if (wait_for_transition &&
- (orig_transition_tmo != h->transition_tmo)) {
+ (orig_transition_tmo != pg->transition_tmo)) {
sdev_printk(KERN_INFO, sdev,
"%s: transition timeout set to %d seconds\n",
- ALUA_DH_NAME, h->transition_tmo);
- expiry = jiffies + h->transition_tmo * HZ;
+ ALUA_DH_NAME, pg->transition_tmo);
+ expiry = jiffies + pg->transition_tmo * HZ;
}
if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
@@ -420,9 +469,9 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
k < len;
k += off, ucp += off) {
- if (h->group_id == get_unaligned_be16(&ucp[2])) {
- h->state = ucp[0] & 0x0f;
- h->pref = ucp[0] >> 7;
+ if (pg->group_id == get_unaligned_be16(&ucp[2])) {
+ pg->state = ucp[0] & 0x0f;
+ pg->pref = ucp[0] >> 7;
valid_states = ucp[1];
}
off = 8 + (ucp[7] * 4);
@@ -430,8 +479,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
sdev_printk(KERN_INFO, sdev,
"%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
- ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
- h->pref ? "preferred" : "non-preferred",
+ ALUA_DH_NAME, pg->group_id, print_alua_state(pg->state),
+ pg->pref ? "preferred" : "non-preferred",
valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l',
@@ -440,7 +489,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
- switch (h->state) {
+ switch (pg->state) {
case TPGS_STATE_TRANSITIONING:
if (wait_for_transition) {
if (time_before(jiffies, expiry)) {
@@ -455,7 +504,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
}
/* Transitioning time exceeded, set port to standby */
- h->state = TPGS_STATE_STANDBY;
+ pg->state = TPGS_STATE_STANDBY;
break;
case TPGS_STATE_OFFLINE:
/* Path unusable */
@@ -478,22 +527,22 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* a re-evaluation of the target group state or SCSI_DH_OK
* if no further action needs to be taken.
*/
-static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
+static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
{
int retval;
struct scsi_sense_hdr sense_hdr;
- if (!(h->tpgs & TPGS_MODE_EXPLICIT)) {
+ if (!(pg->tpgs & TPGS_MODE_EXPLICIT)) {
/* Only implicit ALUA supported, retry */
return SCSI_DH_RETRY;
}
- switch (h->state) {
+ switch (pg->state) {
case TPGS_STATE_OPTIMIZED:
return SCSI_DH_OK;
case TPGS_STATE_NONOPTIMIZED:
- if ((h->flags & ALUA_OPTIMIZE_STPG) &&
- !h->pref &&
- (h->tpgs & TPGS_MODE_IMPLICIT))
+ if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
+ !pg->pref &&
+ (pg->tpgs & TPGS_MODE_IMPLICIT))
return SCSI_DH_OK;
break;
case TPGS_STATE_STANDBY:
@@ -507,13 +556,13 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
default:
sdev_printk(KERN_INFO, sdev,
"%s: stpg failed, unhandled TPGS state %d",
- ALUA_DH_NAME, h->state);
+ ALUA_DH_NAME, pg->state);
return SCSI_DH_NOSYS;
break;
}
/* Set state to transitioning */
- h->state = TPGS_STATE_TRANSITIONING;
- retval = submit_stpg(sdev, h->group_id, &sense_hdr);
+ pg->state = TPGS_STATE_TRANSITIONING;
+ retval = submit_stpg(sdev, pg->group_id, &sense_hdr);
if (retval) {
if (!scsi_sense_valid(&sense_hdr)) {
@@ -523,7 +572,7 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
if (driver_byte(retval) == DRIVER_ERROR)
return SCSI_DH_DEV_TEMP_BUSY;
} else {
- sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
+ sdev_printk(KERN_INFO, sdev, "%s: stpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
}
@@ -541,20 +590,24 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
*/
static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int err = SCSI_DH_DEV_UNSUPP;
+ int err = SCSI_DH_DEV_UNSUPP, tpgs;
- h->tpgs = alua_check_tpgs(sdev);
- if (h->tpgs == TPGS_MODE_NONE)
+ tpgs = alua_check_tpgs(sdev);
+ if (tpgs == TPGS_MODE_NONE)
goto out;
err = alua_check_vpd(sdev, h);
if (err != SCSI_DH_OK)
goto out;
- err = alua_rtpg(sdev, h, 0);
- if (err != SCSI_DH_OK)
+ h->pg = alua_alloc_pg(sdev, h->group_id, tpgs);
+ if (!h->pg) {
+ err = SCSI_DH_NOMEM;
goto out;
-
+ }
+ kref_get(&h->pg->kref);
+ err = alua_rtpg(sdev, h->pg, 0);
+ kref_put(&h->pg->kref, release_port_group);
out:
return err;
}
@@ -570,6 +623,7 @@ out:
static int alua_set_params(struct scsi_device *sdev, const char *params)
{
struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group *pg = NULL;
unsigned int optimize = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
@@ -582,10 +636,14 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
return -EINVAL;
+ pg = h->pg;
+ if (!pg)
+ return -ENXIO;
+
if (optimize)
- h->flags |= ALUA_OPTIMIZE_STPG;
+ pg->flags |= ALUA_OPTIMIZE_STPG;
else
- h->flags &= ~ALUA_OPTIMIZE_STPG;
+ pg->flags |= ~ALUA_OPTIMIZE_STPG;
return result;
}
@@ -610,16 +668,23 @@ static int alua_activate(struct scsi_device *sdev,
struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
- err = alua_rtpg(sdev, h, 1);
- if (err != SCSI_DH_OK)
+ if (!h->pg)
goto out;
+ kref_get(&h->pg->kref);
+
if (optimize_stpg)
- h->flags |= ALUA_OPTIMIZE_STPG;
+ h->pg->flags |= ALUA_OPTIMIZE_STPG;
- err = alua_stpg(sdev, h);
+ err = alua_rtpg(sdev, h->pg, 1);
+ if (err != SCSI_DH_OK) {
+ kref_put(&h->pg->kref, release_port_group);
+ goto out;
+ }
+ err = alua_stpg(sdev, h->pg);
if (err == SCSI_DH_RETRY)
- err = alua_rtpg(sdev, h, 1);
+ err = alua_rtpg(sdev, h->pg, 1);
+ kref_put(&h->pg->kref, release_port_group);
out:
if (fn)
fn(data, err);
@@ -635,13 +700,19 @@ out:
static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
{
struct alua_dh_data *h = sdev->handler_data;
+ int state;
int ret = BLKPREP_OK;
- if (h->state == TPGS_STATE_TRANSITIONING)
+ if (!h->pg)
+ return ret;
+ kref_get(&h->pg->kref);
+ state = h->pg->state;
+ kref_put(&h->pg->kref, release_port_group);
+ if (state == TPGS_STATE_TRANSITIONING)
ret = BLKPREP_DEFER;
- else if (h->state != TPGS_STATE_OPTIMIZED &&
- h->state != TPGS_STATE_NONOPTIMIZED &&
- h->state != TPGS_STATE_LBA_DEPENDENT) {
+ else if (state != TPGS_STATE_OPTIMIZED &&
+ state != TPGS_STATE_NONOPTIMIZED &&
+ state != TPGS_STATE_LBA_DEPENDENT) {
ret = BLKPREP_KILL;
req->cmd_flags |= REQ_QUIET;
}
@@ -656,18 +727,18 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
static int alua_bus_attach(struct scsi_device *sdev)
{
struct alua_dh_data *h;
- int err;
+ int err, ret = -EINVAL;
h = kzalloc(sizeof(*h) , GFP_KERNEL);
if (!h)
return -ENOMEM;
- h->tpgs = TPGS_MODE_UNINITIALIZED;
- h->state = TPGS_STATE_OPTIMIZED;
- h->group_id = -1;
+ h->pg = NULL;
h->rel_port = -1;
h->sdev = sdev;
err = alua_initialize(sdev, h);
+ if (err == SCSI_DH_NOMEM)
+ ret = -ENOMEM;
if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
goto failed;
@@ -675,7 +746,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
return 0;
failed:
kfree(h);
- return -EINVAL;
+ return ret;
}
/*
@@ -686,6 +757,10 @@ static void alua_bus_detach(struct scsi_device *sdev)
{
struct alua_dh_data *h = sdev->handler_data;
+ if (h->pg) {
+ kref_put(&h->pg->kref, release_port_group);
+ h->pg = NULL;
+ }
sdev->handler_data = NULL;
kfree(h);
}
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index 85d7317..7e184c6 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -52,6 +52,7 @@ enum {
SCSI_DH_TIMED_OUT,
SCSI_DH_RES_TEMP_UNAVAIL,
SCSI_DH_DEV_OFFLINED,
+ SCSI_DH_NOMEM,
SCSI_DH_NOSYS,
SCSI_DH_DRIVER_MAX,
};
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 08/22] scsi_dh_alua: use unique device id
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (6 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 07/22] scsi_dh_alua: Use separate alua_port_group structure Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 17:10 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 09/22] scsi_dh_alua: simplify alua_initialize() Hannes Reinecke
` (14 subsequent siblings)
22 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
Use scsi_vpd_lun_id() to assign a unique device identification
to the alua port group structure.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 55 +++++++++++++++++++++++++++---
1 file changed, 51 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 14b4ca6..41fd5e8 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -70,6 +70,8 @@ static DEFINE_SPINLOCK(port_group_lock);
struct alua_port_group {
struct kref kref;
struct list_head node;
+ unsigned char device_id_str[256];
+ int device_id_len;
int group_id;
int tpgs;
int state;
@@ -162,6 +164,25 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
ALUA_FAILOVER_RETRIES, NULL, req_flags);
}
+struct alua_port_group *alua_lookup_pg(char *id_str, size_t id_size,
+ int group_id)
+{
+ struct alua_port_group *pg;
+
+ list_for_each_entry(pg, &port_group_list, node) {
+ if (pg->group_id != group_id)
+ continue;
+ if (pg->device_id_len != id_size)
+ continue;
+ if (strncmp(pg->device_id_str, id_str, id_size))
+ continue;
+ kref_get(&pg->kref);
+ return pg;
+ }
+
+ return NULL;
+}
+
/*
* alua_alloc_pg - Allocate a new port_group structure
* @sdev: scsi device
@@ -174,17 +195,38 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
int group_id, int tpgs)
{
- struct alua_port_group *pg;
+ struct alua_port_group *pg, *tmp_pg;
pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
if (!pg)
- return NULL;
+ return ERR_PTR(-ENOMEM);
+ pg->device_id_len = scsi_vpd_lun_id(sdev, pg->device_id_str,
+ sizeof(pg->device_id_str));
+ if (pg->device_id_len <= 0) {
+ /*
+ * Internal error: TPGS supported but no device
+ * identifcation found. Disable ALUA support.
+ */
+ kfree(pg);
+ sdev_printk(KERN_INFO, sdev,
+ "%s: No device descriptors found\n",
+ ALUA_DH_NAME);
+ return ERR_PTR(-ENXIO);
+ }
pg->group_id = group_id;
pg->tpgs = tpgs;
pg->state = TPGS_STATE_OPTIMIZED;
kref_init(&pg->kref);
+
spin_lock(&port_group_lock);
+ tmp_pg = alua_lookup_pg(pg->device_id_str, pg->device_id_len, group_id);
+ if (tmp_pg) {
+ spin_unlock(&port_group_lock);
+ kfree(pg);
+ return tmp_pg;
+ }
+
list_add(&pg->node, &port_group_list);
spin_unlock(&port_group_lock);
@@ -601,10 +643,15 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
goto out;
h->pg = alua_alloc_pg(sdev, h->group_id, tpgs);
- if (!h->pg) {
- err = SCSI_DH_NOMEM;
+ if (PTR_ERR(h->pg)) {
+ if (PTR_ERR(h->pg) == -ENOMEM)
+ err = SCSI_DH_NOMEM;
goto out;
}
+ sdev_printk(KERN_INFO, sdev,
+ "%s: device %s port group %02x rel port %02x\n",
+ ALUA_DH_NAME, h->pg->device_id_str,
+ h->group_id, h->rel_port);
kref_get(&h->pg->kref);
err = alua_rtpg(sdev, h->pg, 0);
kref_put(&h->pg->kref, release_port_group);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 09/22] scsi_dh_alua: simplify alua_initialize()
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (7 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 08/22] scsi_dh_alua: use unique device id Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 10/22] revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should succeed while TPG is transitioning") Hannes Reinecke
` (13 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
Rework alua_check_vpd() to use scsi_vpd_get_tpg()
and move the port group selection into the function, too.
With that we can simplify alua_initialize() to just
call alua_check_tpgs() and alua_check_vpd();
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 42 ++++++++++++------------------
1 file changed, 17 insertions(+), 25 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 41fd5e8..c4ee225 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -92,6 +92,7 @@ struct alua_dh_data {
#define ALUA_POLICY_SWITCH_CURRENT 0
#define ALUA_POLICY_SWITCH_ALL 1
+static int alua_rtpg(struct scsi_device *, struct alua_port_group *, int);
static char print_alua_state(int);
static void release_port_group(struct kref *kref)
@@ -292,7 +293,8 @@ static int alua_check_tpgs(struct scsi_device *sdev)
* Extract the relative target port and the target port group
* descriptor from the list of identificators.
*/
-static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
+ int tpgs)
{
int rel_port = -1, group_id;
@@ -308,13 +310,21 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
ALUA_DH_NAME);
return SCSI_DH_DEV_UNSUPP;
}
- h->group_id = group_id;
+
+ h->pg = alua_alloc_pg(sdev, group_id, tpgs);
+ if (PTR_ERR(h->pg)) {
+ if (PTR_ERR(h->pg) == -ENOMEM)
+ return SCSI_DH_NOMEM;
+ return SCSI_DH_DEV_UNSUPP;
+ }
+ h->rel_port = rel_port;
sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x rel port %02x\n",
- ALUA_DH_NAME, h->group_id, h->rel_port);
+ "%s: device %s port group %02x rel port %02x\n",
+ ALUA_DH_NAME, h->pg->device_id_str,
+ h->group_id, h->rel_port);
- return 0;
+ return alua_rtpg(sdev, h->pg, 0);
}
static char print_alua_state(int state)
@@ -635,27 +645,9 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
int err = SCSI_DH_DEV_UNSUPP, tpgs;
tpgs = alua_check_tpgs(sdev);
- if (tpgs == TPGS_MODE_NONE)
- goto out;
-
- err = alua_check_vpd(sdev, h);
- if (err != SCSI_DH_OK)
- goto out;
+ if (tpgs != TPGS_MODE_NONE)
+ err = alua_check_vpd(sdev, h, tpgs);
- h->pg = alua_alloc_pg(sdev, h->group_id, tpgs);
- if (PTR_ERR(h->pg)) {
- if (PTR_ERR(h->pg) == -ENOMEM)
- err = SCSI_DH_NOMEM;
- goto out;
- }
- sdev_printk(KERN_INFO, sdev,
- "%s: device %s port group %02x rel port %02x\n",
- ALUA_DH_NAME, h->pg->device_id_str,
- h->group_id, h->rel_port);
- kref_get(&h->pg->kref);
- err = alua_rtpg(sdev, h->pg, 0);
- kref_put(&h->pg->kref, release_port_group);
-out:
return err;
}
/*
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 10/22] revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should succeed while TPG is transitioning")
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (8 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 09/22] scsi_dh_alua: simplify alua_initialize() Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 11/22] scsi_dh_alua: move optimize_stpg evaluation Hannes Reinecke
` (12 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
This reverts commit a8e5a2d593cbfccf530c3382c2c328d2edaa7b66
Obsoleted by the next patch.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Ewan Milne <emilne@redhat.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 31 ++++++++++++------------------
1 file changed, 12 insertions(+), 19 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index c4ee225..2762aba 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -92,7 +92,7 @@ struct alua_dh_data {
#define ALUA_POLICY_SWITCH_CURRENT 0
#define ALUA_POLICY_SWITCH_ALL 1
-static int alua_rtpg(struct scsi_device *, struct alua_port_group *, int);
+static int alua_rtpg(struct scsi_device *, struct alua_port_group *);
static char print_alua_state(int);
static void release_port_group(struct kref *kref)
@@ -324,7 +324,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
ALUA_DH_NAME, h->pg->device_id_str,
h->group_id, h->rel_port);
- return alua_rtpg(sdev, h->pg, 0);
+ return alua_rtpg(sdev, h->pg);
}
static char print_alua_state(int state)
@@ -407,13 +407,12 @@ static int alua_check_sense(struct scsi_device *sdev,
/*
* alua_rtpg - Evaluate REPORT TARGET GROUP STATES
* @sdev: the device to be evaluated.
- * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for device to exit transitioning state
*
* Evaluate the Target Port Group State.
* Returns SCSI_DH_DEV_OFFLINED if the path is
* found to be unusable.
*/
-static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int wait_for_transition)
+static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
{
struct scsi_sense_hdr sense_hdr;
int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
@@ -504,8 +503,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
else
pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
- if (wait_for_transition &&
- (orig_transition_tmo != pg->transition_tmo)) {
+ if (orig_transition_tmo != pg->transition_tmo) {
sdev_printk(KERN_INFO, sdev,
"%s: transition timeout set to %d seconds\n",
ALUA_DH_NAME, pg->transition_tmo);
@@ -543,19 +541,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
switch (pg->state) {
case TPGS_STATE_TRANSITIONING:
- if (wait_for_transition) {
- if (time_before(jiffies, expiry)) {
- /* State transition, retry */
- interval += 2000;
- msleep(interval);
- goto retry;
- }
- err = SCSI_DH_RETRY;
- } else {
- err = SCSI_DH_OK;
+ if (time_before(jiffies, expiry)) {
+ /* State transition, retry */
+ interval += 2000;
+ msleep(interval);
+ goto retry;
}
-
/* Transitioning time exceeded, set port to standby */
+ err = SCSI_DH_RETRY;
pg->state = TPGS_STATE_STANDBY;
break;
case TPGS_STATE_OFFLINE:
@@ -715,14 +708,14 @@ static int alua_activate(struct scsi_device *sdev,
if (optimize_stpg)
h->pg->flags |= ALUA_OPTIMIZE_STPG;
- err = alua_rtpg(sdev, h->pg, 1);
+ err = alua_rtpg(sdev, h->pg);
if (err != SCSI_DH_OK) {
kref_put(&h->pg->kref, release_port_group);
goto out;
}
err = alua_stpg(sdev, h->pg);
if (err == SCSI_DH_RETRY)
- err = alua_rtpg(sdev, h->pg, 1);
+ err = alua_rtpg(sdev, h->pg);
kref_put(&h->pg->kref, release_port_group);
out:
if (fn)
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 11/22] scsi_dh_alua: move optimize_stpg evaluation
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (9 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 10/22] revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should succeed while TPG is transitioning") Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 17:11 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 12/22] scsi_dh_alua: remove 'rel_port' from alua_dh_data structure Hannes Reinecke
` (11 subsequent siblings)
22 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke, Hannes Reinecke
When the optimize_stpg module option is set we should just set it
once during port_group allocation. Doing so allows us to override
it later with device specific settings.
Signed-off-by: Hannes Reinecke <hare@suse.com>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 2762aba..7bd5108 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -64,6 +64,10 @@
#define ALUA_OPTIMIZE_STPG 1
#define ALUA_RTPG_EXT_HDR_UNSUPP 2
+static uint optimize_stpg;
+module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
+
static LIST_HEAD(port_group_list);
static DEFINE_SPINLOCK(port_group_lock);
@@ -218,6 +222,8 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
pg->group_id = group_id;
pg->tpgs = tpgs;
pg->state = TPGS_STATE_OPTIMIZED;
+ if (optimize_stpg)
+ pg->flags |= ALUA_OPTIMIZE_STPG;
kref_init(&pg->kref);
spin_lock(&port_group_lock);
@@ -680,10 +686,6 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
return result;
}
-static uint optimize_stpg;
-module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
-
/*
* alua_activate - activate a path
* @sdev: device on the path to be activated
@@ -705,9 +707,6 @@ static int alua_activate(struct scsi_device *sdev,
kref_get(&h->pg->kref);
- if (optimize_stpg)
- h->pg->flags |= ALUA_OPTIMIZE_STPG;
-
err = alua_rtpg(sdev, h->pg);
if (err != SCSI_DH_OK) {
kref_put(&h->pg->kref, release_port_group);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 12/22] scsi_dh_alua: remove 'rel_port' from alua_dh_data structure
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (10 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 11/22] scsi_dh_alua: move optimize_stpg evaluation Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 17:11 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
` (10 subsequent siblings)
22 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke, Hannes Reinecke
The 'relative port' field is not used, and might get stale when
the port group changes. So remove the field altogether.
Signed-off-by: Hannes Reinecke <hare@suse.com>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 7bd5108..c9d028c 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -87,7 +87,6 @@ struct alua_port_group {
struct alua_dh_data {
struct alua_port_group *pg;
int group_id;
- int rel_port;
struct scsi_device *sdev;
activate_complete callback_fn;
void *callback_data;
@@ -323,12 +322,10 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
return SCSI_DH_NOMEM;
return SCSI_DH_DEV_UNSUPP;
}
- h->rel_port = rel_port;
-
sdev_printk(KERN_INFO, sdev,
"%s: device %s port group %02x rel port %02x\n",
ALUA_DH_NAME, h->pg->device_id_str,
- h->group_id, h->rel_port);
+ h->group_id, rel_port);
return alua_rtpg(sdev, h->pg);
}
@@ -764,7 +761,6 @@ static int alua_bus_attach(struct scsi_device *sdev)
if (!h)
return -ENOMEM;
h->pg = NULL;
- h->rel_port = -1;
h->sdev = sdev;
err = alua_initialize(sdev, h);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (11 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 12/22] scsi_dh_alua: remove 'rel_port' from alua_dh_data structure Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 16:43 ` kbuild test robot
` (2 more replies)
2016-01-12 15:40 ` [PATCHv2 14/22] scsi_dh_alua: Allow workqueue to run synchronously Hannes Reinecke
` (9 subsequent siblings)
22 siblings, 3 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
The current ALUA device_handler has two drawbacks:
- We're sending a 'SET TARGET PORT GROUP' command to every LUN,
disregarding the fact that several LUNs might be in a port group
and will be automatically switched whenever _any_ LUN within
that port group receives the command.
- Whenever a LUN is in 'transitioning' mode we cannot block I/O
to that LUN, instead the controller has to abort the command.
This leads to increased traffic across the wire and heavy load
on the controller during switchover.
With this patch the RTPG handling is moved to a per-portgroup
workqueue. This reduces the number of 'REPORT TARGET PORT GROUP'
and 'SET TARGET PORT GROUPS' sent to the controller as we're sending
them now per port group, and not per device as previously.
It also allows us to block I/O to any LUN / port group found to be
in 'transitioning' ALUA mode, as the workqueue item will be requeued
until the controller moves out of transitioning.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 308 ++++++++++++++++++++++++-----
1 file changed, 257 insertions(+), 51 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index c9d028c..9d56d6a 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -59,10 +59,15 @@
#define ALUA_RTPG_SIZE 128
#define ALUA_FAILOVER_TIMEOUT 60
#define ALUA_FAILOVER_RETRIES 5
+#define ALUA_RTPG_DELAY_MSECS 5
/* device handler flags */
-#define ALUA_OPTIMIZE_STPG 1
-#define ALUA_RTPG_EXT_HDR_UNSUPP 2
+#define ALUA_OPTIMIZE_STPG 0x01
+#define ALUA_RTPG_EXT_HDR_UNSUPP 0x02
+/* State machine flags */
+#define ALUA_PG_RUN_RTPG 0x10
+#define ALUA_PG_RUN_STPG 0x20
+#define ALUA_PG_RUNNING 0x40
static uint optimize_stpg;
module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
@@ -70,6 +75,7 @@ MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than
static LIST_HEAD(port_group_list);
static DEFINE_SPINLOCK(port_group_lock);
+static struct workqueue_struct *kaluad_wq;
struct alua_port_group {
struct kref kref;
@@ -82,12 +88,25 @@ struct alua_port_group {
int pref;
unsigned flags; /* used for optimizing STPG */
unsigned char transition_tmo;
+ unsigned long expiry;
+ unsigned long interval;
+ struct delayed_work rtpg_work;
+ spinlock_t lock;
+ struct list_head rtpg_list;
+ struct scsi_device *rtpg_sdev;
};
struct alua_dh_data {
struct alua_port_group *pg;
int group_id;
+ spinlock_t pg_lock;
struct scsi_device *sdev;
+ int init_error;
+ struct mutex init_mutex;
+};
+
+struct alua_queue_data {
+ struct list_head entry;
activate_complete callback_fn;
void *callback_data;
};
@@ -95,8 +114,10 @@ struct alua_dh_data {
#define ALUA_POLICY_SWITCH_CURRENT 0
#define ALUA_POLICY_SWITCH_ALL 1
-static int alua_rtpg(struct scsi_device *, struct alua_port_group *);
-static char print_alua_state(int);
+static void alua_rtpg_work(struct work_struct *work);
+static void alua_rtpg_queue(struct alua_port_group *pg,
+ struct scsi_device *sdev,
+ struct alua_queue_data *qdata);
static void release_port_group(struct kref *kref)
{
@@ -106,6 +127,7 @@ static void release_port_group(struct kref *kref)
spin_lock(&port_group_lock);
list_del(&pg->node);
spin_unlock(&port_group_lock);
+ WARN_ON(pg->rtpg_sdev);
kfree(pg);
}
@@ -180,7 +202,8 @@ struct alua_port_group *alua_lookup_pg(char *id_str, size_t id_size,
continue;
if (strncmp(pg->device_id_str, id_str, id_size))
continue;
- kref_get(&pg->kref);
+ if (!kref_get_unless_zero(&pg->kref))
+ continue;
return pg;
}
@@ -224,6 +247,10 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
if (optimize_stpg)
pg->flags |= ALUA_OPTIMIZE_STPG;
kref_init(&pg->kref);
+ INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work);
+ INIT_LIST_HEAD(&pg->rtpg_list);
+ INIT_LIST_HEAD(&pg->node);
+ spin_lock_init(&pg->lock);
spin_lock(&port_group_lock);
tmp_pg = alua_lookup_pg(pg->device_id_str, pg->device_id_len, group_id);
@@ -302,6 +329,8 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
int tpgs)
{
int rel_port = -1, group_id;
+ struct alua_port_group *pg, *old_pg = NULL;
+ bool pg_updated = false;
group_id = scsi_vpd_tpg_id(sdev, &rel_port);
if (group_id < 0) {
@@ -316,18 +345,42 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
return SCSI_DH_DEV_UNSUPP;
}
- h->pg = alua_alloc_pg(sdev, group_id, tpgs);
- if (PTR_ERR(h->pg)) {
+ pg = alua_alloc_pg(sdev, group_id, tpgs);
+ if (PTR_ERR(pg)) {
if (PTR_ERR(h->pg) == -ENOMEM)
return SCSI_DH_NOMEM;
return SCSI_DH_DEV_UNSUPP;
}
sdev_printk(KERN_INFO, sdev,
"%s: device %s port group %02x rel port %02x\n",
- ALUA_DH_NAME, h->pg->device_id_str,
- h->group_id, rel_port);
+ ALUA_DH_NAME, pg->device_id_str, group_id, rel_port);
- return alua_rtpg(sdev, h->pg);
+ /* Check for existing port_group references */
+ spin_lock(&h->pg_lock);
+ if (h->pg) {
+ old_pg = pg;
+ /* port_group has changed. Update to new port group */
+ if (h->pg != pg) {
+ old_pg = h->pg;
+ rcu_assign_pointer(h->pg, pg);
+ pg_updated = true;
+ }
+ } else {
+ rcu_assign_pointer(h->pg, pg);
+ pg_updated = true;
+ }
+ alua_rtpg_queue(h->pg, sdev, NULL);
+ spin_unlock(&h->pg_lock);
+
+ if (pg_updated)
+ synchronize_rcu();
+ if (old_pg) {
+ if (old_pg->rtpg_sdev)
+ flush_delayed_work(&old_pg->rtpg_work);
+ kref_put(&old_pg->kref, release_port_group);
+ }
+
+ return SCSI_DH_OK;
}
static char print_alua_state(int state)
@@ -421,14 +474,17 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
unsigned char *ucp, *buff;
unsigned err, retval;
- unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
- if (!pg->transition_tmo)
- expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
- else
- expiry = round_jiffies_up(jiffies + pg->transition_tmo * HZ);
+ if (!pg->expiry) {
+ unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ;
+
+ if (pg->transition_tmo)
+ transition_tmo = pg->transition_tmo * HZ;
+
+ pg->expiry = round_jiffies_up(jiffies + transition_tmo);
+ }
buff = kzalloc(bufflen, GFP_KERNEL);
if (!buff)
@@ -471,16 +527,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
err = SCSI_DH_RETRY;
else if (sense_hdr.sense_key == UNIT_ATTENTION)
err = SCSI_DH_RETRY;
- if (err == SCSI_DH_RETRY && time_before(jiffies, expiry)) {
+ if (err == SCSI_DH_RETRY &&
+ pg->expiry != 0 && time_before(jiffies, pg->expiry)) {
sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
- goto retry;
+ return err;
}
sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
kfree(buff);
+ pg->expiry = 0;
return SCSI_DH_IO;
}
@@ -495,6 +553,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
sdev_printk(KERN_WARNING, sdev,
"%s: kmalloc buffer failed\n",__func__);
/* Temporary failure, bypass */
+ pg->expiry = 0;
return SCSI_DH_DEV_TEMP_BUSY;
}
goto retry;
@@ -510,7 +569,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
sdev_printk(KERN_INFO, sdev,
"%s: transition timeout set to %d seconds\n",
ALUA_DH_NAME, pg->transition_tmo);
- expiry = jiffies + pg->transition_tmo * HZ;
+ pg->expiry = jiffies + pg->transition_tmo * HZ;
}
if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
@@ -544,23 +603,26 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
switch (pg->state) {
case TPGS_STATE_TRANSITIONING:
- if (time_before(jiffies, expiry)) {
+ if (time_before(jiffies, pg->expiry)) {
/* State transition, retry */
- interval += 2000;
- msleep(interval);
- goto retry;
+ pg->interval = 2;
+ err = SCSI_DH_RETRY;
+ } else {
+ /* Transitioning time exceeded, set port to standby */
+ err = SCSI_DH_IO;
+ pg->state = TPGS_STATE_STANDBY;
+ pg->expiry = 0;
}
- /* Transitioning time exceeded, set port to standby */
- err = SCSI_DH_RETRY;
- pg->state = TPGS_STATE_STANDBY;
break;
case TPGS_STATE_OFFLINE:
/* Path unusable */
err = SCSI_DH_DEV_OFFLINED;
+ pg->expiry = 0;
break;
default:
/* Useable path if active */
err = SCSI_DH_OK;
+ pg->expiry = 0;
break;
}
kfree(buff);
@@ -629,6 +691,106 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
return SCSI_DH_RETRY;
}
+static void alua_rtpg_work(struct work_struct *work)
+{
+ struct alua_port_group *pg =
+ container_of(work, struct alua_port_group, rtpg_work.work);
+ struct scsi_device *sdev;
+ LIST_HEAD(qdata_list);
+ int err = SCSI_DH_OK;
+ struct alua_queue_data *qdata, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pg->lock, flags);
+ sdev = pg->rtpg_sdev;
+ if (!sdev) {
+ WARN_ON(pg->flags & ALUA_PG_RUN_RTPG ||
+ pg->flags & ALUA_PG_RUN_STPG);
+ spin_unlock_irqrestore(&pg->lock, flags);
+ return;
+ }
+ pg->flags |= ALUA_PG_RUNNING;
+ if (pg->flags & ALUA_PG_RUN_RTPG) {
+ spin_unlock_irqrestore(&pg->lock, flags);
+ err = alua_rtpg(sdev, pg);
+ spin_lock_irqsave(&pg->lock, flags);
+ if (err == SCSI_DH_RETRY) {
+ pg->flags &= ~ALUA_PG_RUNNING;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ queue_delayed_work(kaluad_wq, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ pg->flags &= ~ALUA_PG_RUN_RTPG;
+ if (err != SCSI_DH_OK)
+ pg->flags &= ~ALUA_PG_RUN_STPG;
+ }
+ if (pg->flags & ALUA_PG_RUN_STPG) {
+ spin_unlock_irqrestore(&pg->lock, flags);
+ err = alua_stpg(sdev, pg);
+ spin_lock_irqsave(&pg->lock, flags);
+ pg->flags &= ~ALUA_PG_RUN_STPG;
+ if (err == SCSI_DH_RETRY) {
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ pg->interval = 0;
+ pg->flags &= ~ALUA_PG_RUNNING;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ queue_delayed_work(kaluad_wq, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ }
+
+ list_splice_init(&pg->rtpg_list, &qdata_list);
+ pg->rtpg_sdev = NULL;
+ spin_unlock_irqrestore(&pg->lock, flags);
+
+ list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) {
+ list_del(&qdata->entry);
+ if (qdata->callback_fn)
+ qdata->callback_fn(qdata->callback_data, err);
+ kfree(qdata);
+ }
+ spin_lock_irqsave(&pg->lock, flags);
+ pg->flags &= ~ALUA_PG_RUNNING;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ scsi_device_put(sdev);
+ kref_put(&pg->kref, release_port_group);
+}
+
+static void alua_rtpg_queue(struct alua_port_group *pg,
+ struct scsi_device *sdev,
+ struct alua_queue_data *qdata)
+{
+ int start_queue = 0;
+ unsigned long flags;
+
+ if (!pg)
+ return;
+
+ spin_lock_irqsave(&pg->lock, flags);
+ if (qdata) {
+ list_add_tail(&qdata->entry, &pg->rtpg_list);
+ pg->flags |= ALUA_PG_RUN_STPG;
+ }
+ if (pg->rtpg_sdev == NULL) {
+ pg->interval = 0;
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ kref_get(&pg->kref);
+ pg->rtpg_sdev = sdev;
+ scsi_device_get(sdev);
+ start_queue = 1;
+ }
+ spin_unlock_irqrestore(&pg->lock, flags);
+
+ if (start_queue &&
+ !queue_delayed_work(kaluad_wq, &pg->rtpg_work,
+ msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS))) {
+ scsi_device_put(sdev);
+ kref_put(&pg->kref, release_port_group);
+ }
+}
+
/*
* alua_initialize - Initialize ALUA state
* @sdev: the device to be initialized
@@ -640,10 +802,12 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
{
int err = SCSI_DH_DEV_UNSUPP, tpgs;
+ mutex_lock(&h->init_mutex);
tpgs = alua_check_tpgs(sdev);
if (tpgs != TPGS_MODE_NONE)
err = alua_check_vpd(sdev, h, tpgs);
-
+ h->init_error = err;
+ mutex_unlock(&h->init_mutex);
return err;
}
/*
@@ -662,6 +826,7 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
unsigned int optimize = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
+ unsigned long flags;
if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
return -EINVAL;
@@ -671,14 +836,19 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
return -EINVAL;
- pg = h->pg;
- if (!pg)
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg) {
+ rcu_read_unlock();
return -ENXIO;
-
+ }
+ spin_lock_irqsave(&pg->lock, flags);
if (optimize)
pg->flags |= ALUA_OPTIMIZE_STPG;
else
pg->flags |= ~ALUA_OPTIMIZE_STPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ rcu_read_unlock();
return result;
}
@@ -698,21 +868,33 @@ static int alua_activate(struct scsi_device *sdev,
{
struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
+ struct alua_queue_data *qdata;
+ struct alua_port_group *pg;
- if (!h->pg)
+ qdata = kzalloc(sizeof(*qdata), GFP_KERNEL);
+ if (!qdata) {
+ err = SCSI_DH_RES_TEMP_UNAVAIL;
goto out;
-
- kref_get(&h->pg->kref);
-
- err = alua_rtpg(sdev, h->pg);
- if (err != SCSI_DH_OK) {
- kref_put(&h->pg->kref, release_port_group);
+ }
+ qdata->callback_fn = fn;
+ qdata->callback_data = data;
+
+ mutex_lock(&h->init_mutex);
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg || !kref_get_unless_zero(&pg->kref)) {
+ rcu_read_unlock();
+ kfree(qdata);
+ err = h->init_error;
+ mutex_unlock(&h->init_mutex);
goto out;
}
- err = alua_stpg(sdev, h->pg);
- if (err == SCSI_DH_RETRY)
- err = alua_rtpg(sdev, h->pg);
- kref_put(&h->pg->kref, release_port_group);
+ mutex_unlock(&h->init_mutex);
+ fn = NULL;
+ rcu_read_unlock();
+
+ alua_rtpg_queue(pg, sdev, qdata);
+ kref_put(&pg->kref, release_port_group);
out:
if (fn)
fn(data, err);
@@ -728,14 +910,19 @@ out:
static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
{
struct alua_dh_data *h = sdev->handler_data;
- int state;
+ struct alua_port_group *pg;
+ int state = TPGS_STATE_OPTIMIZED;
int ret = BLKPREP_OK;
- if (!h->pg)
- return ret;
- kref_get(&h->pg->kref);
- state = h->pg->state;
- kref_put(&h->pg->kref, release_port_group);
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (pg) {
+ state = pg->state;
+ /* Defer I/O while rtpg_work is active */
+ if (pg->rtpg_sdev)
+ state = TPGS_STATE_TRANSITIONING;
+ }
+ rcu_read_unlock();
if (state == TPGS_STATE_TRANSITIONING)
ret = BLKPREP_DEFER;
else if (state != TPGS_STATE_OPTIMIZED &&
@@ -760,9 +947,12 @@ static int alua_bus_attach(struct scsi_device *sdev)
h = kzalloc(sizeof(*h) , GFP_KERNEL);
if (!h)
return -ENOMEM;
- h->pg = NULL;
+ spin_lock_init(&h->pg_lock);
+ rcu_assign_pointer(h->pg, NULL);
+ h->init_error = SCSI_DH_OK;
h->sdev = sdev;
+ mutex_init(&h->init_mutex);
err = alua_initialize(sdev, h);
if (err == SCSI_DH_NOMEM)
ret = -ENOMEM;
@@ -783,10 +973,18 @@ failed:
static void alua_bus_detach(struct scsi_device *sdev)
{
struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group *pg;
- if (h->pg) {
- kref_put(&h->pg->kref, release_port_group);
- h->pg = NULL;
+ spin_lock(&h->pg_lock);
+ pg = h->pg;
+ rcu_assign_pointer(h->pg, NULL);
+ h->sdev = NULL;
+ spin_unlock(&h->pg_lock);
+ if (pg) {
+ synchronize_rcu();
+ if (pg->rtpg_sdev)
+ flush_delayed_work(&pg->rtpg_work);
+ kref_put(&pg->kref, release_port_group);
}
sdev->handler_data = NULL;
kfree(h);
@@ -807,16 +1005,24 @@ static int __init alua_init(void)
{
int r;
+ kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, 0);
+ if (!kaluad_wq) {
+ /* Temporary failure, bypass */
+ return SCSI_DH_DEV_TEMP_BUSY;
+ }
r = scsi_register_device_handler(&alua_dh);
- if (r != 0)
+ if (r != 0) {
printk(KERN_ERR "%s: Failed to register scsi device handler",
ALUA_DH_NAME);
+ destroy_workqueue(kaluad_wq);
+ }
return r;
}
static void __exit alua_exit(void)
{
scsi_unregister_device_handler(&alua_dh);
+ destroy_workqueue(kaluad_wq);
}
module_init(alua_init);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 14/22] scsi_dh_alua: Allow workqueue to run synchronously
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (12 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 17:16 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 15/22] scsi_dh_alua: Recheck state on unit attention Hannes Reinecke
` (8 subsequent siblings)
22 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
Some arrays may only capable of handling one STPG at a time,
so this patch adds a singlethreaded workqueue for STPGs to be
submitted synchronously.
Synchronous STPG can be activated by setting the second module
option to '1'. The corresponding entry in multipath.conf would be:
hardware_handler "3 alua 1 1"
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 41 ++++++++++++++++++++++++------
1 file changed, 33 insertions(+), 8 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 9d56d6a..eb12074 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -64,6 +64,7 @@
/* device handler flags */
#define ALUA_OPTIMIZE_STPG 0x01
#define ALUA_RTPG_EXT_HDR_UNSUPP 0x02
+#define ALUA_SYNC_STPG 0x04
/* State machine flags */
#define ALUA_PG_RUN_RTPG 0x10
#define ALUA_PG_RUN_STPG 0x20
@@ -76,6 +77,7 @@ MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than
static LIST_HEAD(port_group_list);
static DEFINE_SPINLOCK(port_group_lock);
static struct workqueue_struct *kaluad_wq;
+static struct workqueue_struct *kaluad_sync_wq;
struct alua_port_group {
struct kref kref;
@@ -700,6 +702,7 @@ static void alua_rtpg_work(struct work_struct *work)
int err = SCSI_DH_OK;
struct alua_queue_data *qdata, *tmp;
unsigned long flags;
+ struct workqueue_struct *alua_wq = kaluad_wq;
spin_lock_irqsave(&pg->lock, flags);
sdev = pg->rtpg_sdev;
@@ -709,6 +712,8 @@ static void alua_rtpg_work(struct work_struct *work)
spin_unlock_irqrestore(&pg->lock, flags);
return;
}
+ if (pg->flags & ALUA_SYNC_STPG)
+ alua_wq = kaluad_sync_wq;
pg->flags |= ALUA_PG_RUNNING;
if (pg->flags & ALUA_PG_RUN_RTPG) {
spin_unlock_irqrestore(&pg->lock, flags);
@@ -717,7 +722,7 @@ static void alua_rtpg_work(struct work_struct *work)
if (err == SCSI_DH_RETRY) {
pg->flags &= ~ALUA_PG_RUNNING;
spin_unlock_irqrestore(&pg->lock, flags);
- queue_delayed_work(kaluad_wq, &pg->rtpg_work,
+ queue_delayed_work(alua_wq, &pg->rtpg_work,
pg->interval * HZ);
return;
}
@@ -735,7 +740,7 @@ static void alua_rtpg_work(struct work_struct *work)
pg->interval = 0;
pg->flags &= ~ALUA_PG_RUNNING;
spin_unlock_irqrestore(&pg->lock, flags);
- queue_delayed_work(kaluad_wq, &pg->rtpg_work,
+ queue_delayed_work(alua_wq, &pg->rtpg_work,
pg->interval * HZ);
return;
}
@@ -764,6 +769,7 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
{
int start_queue = 0;
unsigned long flags;
+ struct workqueue_struct *alua_wq = kaluad_wq;
if (!pg)
return;
@@ -781,10 +787,12 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
scsi_device_get(sdev);
start_queue = 1;
}
+ if (pg->flags & ALUA_SYNC_STPG)
+ alua_wq = kaluad_sync_wq;
spin_unlock_irqrestore(&pg->lock, flags);
if (start_queue &&
- !queue_delayed_work(kaluad_wq, &pg->rtpg_work,
+ !queue_delayed_work(alua_wq, &pg->rtpg_work,
msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS))) {
scsi_device_put(sdev);
kref_put(&pg->kref, release_port_group);
@@ -811,30 +819,36 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
return err;
}
/*
- * alua_set_params - set/unset the optimize flag
+ * alua_set_params - set/unset the optimize and sync flag
* @sdev: device on the path to be activated
* params - parameters in the following format
* "no_of_params\0param1\0param2\0param3\0...\0"
* For example, to set the flag pass the following parameters
* from multipath.conf
- * hardware_handler "2 alua 1"
+ * hardware_handler "3 alua 1 1"
*/
static int alua_set_params(struct scsi_device *sdev, const char *params)
{
struct alua_dh_data *h = sdev->handler_data;
struct alua_port_group *pg = NULL;
- unsigned int optimize = 0, argc;
+ unsigned int optimize = 0, sync = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
unsigned long flags;
- if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
+ if ((sscanf(params, "%u", &argc) != 1) || (argc > 2))
return -EINVAL;
while (*p++)
;
if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
return -EINVAL;
+ if (argc == 2) {
+ while (*p++)
+ ;
+ if ((sscanf(p, "%u", &sync) != 1) || (sync > 1))
+ return -EINVAL;
+ }
rcu_read_lock();
pg = rcu_dereference(h->pg);
@@ -846,7 +860,11 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
if (optimize)
pg->flags |= ALUA_OPTIMIZE_STPG;
else
- pg->flags |= ~ALUA_OPTIMIZE_STPG;
+ pg->flags &= ~ALUA_OPTIMIZE_STPG;
+ if (sync)
+ pg->flags |= ALUA_SYNC_STPG;
+ else
+ pg->flags &= ~ALUA_SYNC_STPG;
spin_unlock_irqrestore(&pg->lock, flags);
rcu_read_unlock();
@@ -1010,10 +1028,16 @@ static int __init alua_init(void)
/* Temporary failure, bypass */
return SCSI_DH_DEV_TEMP_BUSY;
}
+ kaluad_sync_wq = create_workqueue("kaluad_sync");
+ if (!kaluad_sync_wq) {
+ destroy_workqueue(kaluad_wq);
+ return SCSI_DH_DEV_TEMP_BUSY;
+ }
r = scsi_register_device_handler(&alua_dh);
if (r != 0) {
printk(KERN_ERR "%s: Failed to register scsi device handler",
ALUA_DH_NAME);
+ destroy_workqueue(kaluad_sync_wq);
destroy_workqueue(kaluad_wq);
}
return r;
@@ -1022,6 +1046,7 @@ static int __init alua_init(void)
static void __exit alua_exit(void)
{
scsi_unregister_device_handler(&alua_dh);
+ destroy_workqueue(kaluad_sync_wq);
destroy_workqueue(kaluad_wq);
}
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 15/22] scsi_dh_alua: Recheck state on unit attention
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (13 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 14/22] scsi_dh_alua: Allow workqueue to run synchronously Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 17:17 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 16/22] scsi_dh_alua: update all port states Hannes Reinecke
` (7 subsequent siblings)
22 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
When we receive a unit attention code of 'ALUA state changed'
we should recheck the state, as it might be due to an implicit
ALUA state transition. This allows us to return NEEDS_RETRY
instead of ADD_TO_MLQUEUE, allowing to terminate the retries
after a certain time.
At the same time a workqueue item might already be queued, which
should be started immediately to avoid any delays.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 57 ++++++++++++++++++++++++------
1 file changed, 46 insertions(+), 11 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index eb12074..dd7438b 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -119,7 +119,8 @@ struct alua_queue_data {
static void alua_rtpg_work(struct work_struct *work);
static void alua_rtpg_queue(struct alua_port_group *pg,
struct scsi_device *sdev,
- struct alua_queue_data *qdata);
+ struct alua_queue_data *qdata, bool force);
+static void alua_check(struct scsi_device *sdev, bool force);
static void release_port_group(struct kref *kref)
{
@@ -371,7 +372,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
rcu_assign_pointer(h->pg, pg);
pg_updated = true;
}
- alua_rtpg_queue(h->pg, sdev, NULL);
+ alua_rtpg_queue(h->pg, sdev, NULL, true);
spin_unlock(&h->pg_lock);
if (pg_updated)
@@ -412,18 +413,24 @@ static int alua_check_sense(struct scsi_device *sdev,
{
switch (sense_hdr->sense_key) {
case NOT_READY:
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a)
+ if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
/*
* LUN Not Accessible - ALUA state transition
*/
- return ADD_TO_MLQUEUE;
+ alua_check(sdev, false);
+ return NEEDS_RETRY;
+ }
break;
case UNIT_ATTENTION:
- if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
+ if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
/*
- * Power On, Reset, or Bus Device Reset, just retry.
+ * Power On, Reset, or Bus Device Reset.
+ * Might have obscured a state transition,
+ * so schedule a recheck.
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
+ }
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
/*
* Device internal reset
@@ -434,16 +441,20 @@ static int alua_check_sense(struct scsi_device *sdev,
* Mode Parameters Changed
*/
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06)
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
/*
* ALUA state changed
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07)
+ }
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
/*
* Implicit ALUA state transition failed
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
+ }
if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
/*
* Inquiry data has changed
@@ -765,7 +776,7 @@ static void alua_rtpg_work(struct work_struct *work)
static void alua_rtpg_queue(struct alua_port_group *pg,
struct scsi_device *sdev,
- struct alua_queue_data *qdata)
+ struct alua_queue_data *qdata, bool force)
{
int start_queue = 0;
unsigned long flags;
@@ -786,7 +797,9 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
pg->rtpg_sdev = sdev;
scsi_device_get(sdev);
start_queue = 1;
- }
+ } else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force)
+ start_queue = 1;
+
if (pg->flags & ALUA_SYNC_STPG)
alua_wq = kaluad_sync_wq;
spin_unlock_irqrestore(&pg->lock, flags);
@@ -911,7 +924,7 @@ static int alua_activate(struct scsi_device *sdev,
fn = NULL;
rcu_read_unlock();
- alua_rtpg_queue(pg, sdev, qdata);
+ alua_rtpg_queue(pg, sdev, qdata, true);
kref_put(&pg->kref, release_port_group);
out:
if (fn)
@@ -920,6 +933,28 @@ out:
}
/*
+ * alua_check - check path status
+ * @sdev: device on the path to be checked
+ *
+ * Check the device status
+ */
+static void alua_check(struct scsi_device *sdev, bool force)
+{
+ struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group *pg;
+
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg || !kref_get_unless_zero(&pg->kref)) {
+ rcu_read_unlock();
+ return;
+ }
+ rcu_read_unlock();
+ alua_rtpg_queue(pg, sdev, NULL, force);
+ kref_put(&pg->kref, release_port_group);
+}
+
+/*
* alua_prep_fn - request callback
*
* Fail I/O to all paths not in state
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 16/22] scsi_dh_alua: update all port states
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (14 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 15/22] scsi_dh_alua: Recheck state on unit attention Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 17/22] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning Hannes Reinecke
` (6 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
When we read in the target port group state we should be
updating all affected port groups, otherwise we risk
running out of sync.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 31 +++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index dd7438b..6fefe9f 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -484,11 +484,13 @@ static int alua_check_sense(struct scsi_device *sdev,
static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
{
struct scsi_sense_hdr sense_hdr;
+ struct alua_port_group *tmp_pg;
int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
- unsigned char *ucp, *buff;
+ unsigned char *desc, *buff;
unsigned err, retval;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
+ unsigned long flags;
if (!pg->expiry) {
unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ;
@@ -590,16 +592,27 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
else
tpg_desc_tbl_off = 4;
- for (k = tpg_desc_tbl_off, ucp = buff + tpg_desc_tbl_off;
+ for (k = tpg_desc_tbl_off, desc = buff + tpg_desc_tbl_off;
k < len;
- k += off, ucp += off) {
-
- if (pg->group_id == get_unaligned_be16(&ucp[2])) {
- pg->state = ucp[0] & 0x0f;
- pg->pref = ucp[0] >> 7;
- valid_states = ucp[1];
+ k += off, desc += off) {
+ u16 group_id = get_unaligned_be16(&desc[2]);
+
+ spin_lock_irqsave(&port_group_lock, flags);
+ list_for_each_entry(tmp_pg, &port_group_list, node) {
+ if (tmp_pg->group_id != group_id)
+ continue;
+ if (tmp_pg->device_id_len != pg->device_id_len)
+ continue;
+ if (strncmp(tmp_pg->device_id_str, pg->device_id_str,
+ tmp_pg->device_id_len))
+ continue;
+ tmp_pg->state = desc[0] & 0x0f;
+ tmp_pg->pref = desc[0] >> 7;
+ if (tmp_pg == pg)
+ valid_states = desc[1];
}
- off = 8 + (ucp[7] * 4);
+ spin_unlock_irqrestore(&port_group_lock, flags);
+ off = 8 + (desc[7] * 4);
}
sdev_printk(KERN_INFO, sdev,
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 17/22] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (15 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 16/22] scsi_dh_alua: update all port states Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 18/22] scsi_dh: add 'rescan' callback Hannes Reinecke
` (5 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
Sending a 'REPORT TARGET PORT GROUP' command is a costly operation,
as the array has to gather information about all ports.
So instead of using RTPG to poll for a status update when a port
is in transitioning we should be sending a TEST UNIT READY, and
wait for the sense code to report success.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Ewan Milne <emilne@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 37 ++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6fefe9f..9df2203 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -474,6 +474,30 @@ static int alua_check_sense(struct scsi_device *sdev,
}
/*
+ * alua_tur - Send a TEST UNIT READY
+ * @sdev: device to which the TEST UNIT READY command should be send
+ *
+ * Send a TEST UNIT READY to @sdev to figure out the device state
+ * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING,
+ * SCSI_DH_OK if no error occurred, and SCSI_DH_IO otherwise.
+ */
+static int alua_tur(struct scsi_device *sdev)
+{
+ struct scsi_sense_hdr sense_hdr;
+ int retval;
+
+ retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, &sense_hdr);
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+ return SCSI_DH_RETRY;
+ else if (retval)
+ return SCSI_DH_IO;
+ else
+ return SCSI_DH_OK;
+}
+
+/*
* alua_rtpg - Evaluate REPORT TARGET GROUP STATES
* @sdev: the device to be evaluated.
*
@@ -740,7 +764,20 @@ static void alua_rtpg_work(struct work_struct *work)
alua_wq = kaluad_sync_wq;
pg->flags |= ALUA_PG_RUNNING;
if (pg->flags & ALUA_PG_RUN_RTPG) {
+ int state = pg->state;
+
spin_unlock_irqrestore(&pg->lock, flags);
+ if (state == TPGS_STATE_TRANSITIONING) {
+ if (alua_tur(sdev) == SCSI_DH_RETRY) {
+ spin_lock_irqsave(&pg->lock, flags);
+ pg->flags &= ~ALUA_PG_RUNNING;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ queue_delayed_work(alua_wq, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ /* Send RTPG on failure or if TUR indicates SUCCESS */
+ }
err = alua_rtpg(sdev, pg);
spin_lock_irqsave(&pg->lock, flags);
if (err == SCSI_DH_RETRY) {
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 18/22] scsi_dh: add 'rescan' callback
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (16 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 17/22] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 19/22] scsi: Add 'access_state' attribute Hannes Reinecke
` (4 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
If a device needs to be rescanned the device_handler might need
to be rechecked, too.
So add a 'rescan' callback to the device handler and call it
upon scsi_rescan_device().
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 8 ++++++++
drivers/scsi/scsi_lib.c | 1 +
drivers/scsi/scsi_scan.c | 8 +++++++-
include/scsi/scsi_dh.h | 1 +
4 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 9df2203..ffc419e 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -1038,6 +1038,13 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
}
+static void alua_rescan(struct scsi_device *sdev)
+{
+ struct alua_dh_data *h = sdev->handler_data;
+
+ alua_initialize(sdev, h);
+}
+
/*
* alua_bus_attach - Attach device handler
* @sdev: device to be attached to
@@ -1101,6 +1108,7 @@ static struct scsi_device_handler alua_dh = {
.prep_fn = alua_prep_fn,
.check_sense = alua_check_sense,
.activate = alua_activate,
+ .rescan = alua_rescan,
.set_params = alua_set_params,
};
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index fa6b2c4..d46193a 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2699,6 +2699,7 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
envp[idx++] = "SDEV_MEDIA_CHANGE=1";
break;
case SDEV_EVT_INQUIRY_CHANGE_REPORTED:
+ scsi_rescan_device(&sdev->sdev_gendev);
envp[idx++] = "SDEV_UA=INQUIRY_DATA_HAS_CHANGED";
break;
case SDEV_EVT_CAPACITY_CHANGE_REPORTED:
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index a1c195d..05dc1aa 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -43,6 +43,7 @@
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
+#include <scsi/scsi_dh.h>
#include <scsi/scsi_eh.h>
#include "scsi_priv.h"
@@ -1516,9 +1517,14 @@ EXPORT_SYMBOL(scsi_add_device);
void scsi_rescan_device(struct device *dev)
{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
device_lock(dev);
- scsi_attach_vpd(to_scsi_device(dev));
+ scsi_attach_vpd(sdev);
+
+ if (sdev->handler && sdev->handler->rescan)
+ sdev->handler->rescan(sdev);
if (dev->driver && try_module_get(dev->driver->owner)) {
struct scsi_driver *drv = to_scsi_driver(dev->driver);
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index 7e184c6..c7bba2b 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -71,6 +71,7 @@ struct scsi_device_handler {
int (*activate)(struct scsi_device *, activate_complete, void *);
int (*prep_fn)(struct scsi_device *, struct request *);
int (*set_params)(struct scsi_device *, const char *);
+ void (*rescan)(struct scsi_device *);
};
#ifdef CONFIG_SCSI_DH
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 19/22] scsi: Add 'access_state' attribute
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (17 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 18/22] scsi_dh: add 'rescan' callback Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 20/22] scsi_dh_alua: use common definitions for ALUA state Hannes Reinecke
` (3 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
Add an 'access_state' attribute to struct scsi_device to
display the asymmetric LUN access state.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/scsi_scan.c | 1 +
drivers/scsi/scsi_sysfs.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++
include/scsi/scsi_device.h | 1 +
include/scsi/scsi_proto.h | 13 ++++++++++++
4 files changed, 64 insertions(+)
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 05dc1aa..9fc1531 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -231,6 +231,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
sdev->lun = lun;
sdev->channel = starget->channel;
sdev->sdev_state = SDEV_CREATED;
+ sdev->access_state = SCSI_ACCESS_STATE_UNKNOWN;
INIT_LIST_HEAD(&sdev->siblings);
INIT_LIST_HEAD(&sdev->same_target_siblings);
INIT_LIST_HEAD(&sdev->cmd_list);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index ef36053..80b4c67 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -81,6 +81,34 @@ const char *scsi_host_state_name(enum scsi_host_state state)
return name;
}
+static const struct {
+ enum scsi_access_state value;
+ char *name;
+} sdev_access_states[] = {
+ { SCSI_ACCESS_STATE_OPTIMAL, "active/optimized" },
+ { SCSI_ACCESS_STATE_ACTIVE, "active/non-optimized" },
+ { SCSI_ACCESS_STATE_STANDBY, "standby" },
+ { SCSI_ACCESS_STATE_UNAVAILABLE, "unavailable" },
+ { SCSI_ACCESS_STATE_LBA, "lba-dependent" },
+ { SCSI_ACCESS_STATE_OFFLINE, "offline" },
+ { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" },
+ { SCSI_ACCESS_STATE_UNKNOWN, "unknown" },
+};
+
+const char *scsi_access_state_name(enum scsi_access_state state)
+{
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(sdev_access_states); i++) {
+ if (sdev_access_states[i].value == state) {
+ name = sdev_access_states[i].name;
+ break;
+ }
+ }
+ return name;
+}
+
static int check_set(unsigned long long *val, char *src)
{
char *last;
@@ -973,6 +1001,26 @@ sdev_store_dh_state(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state,
sdev_store_dh_state);
+
+static ssize_t
+sdev_show_access_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ enum scsi_access_state access_state;
+ bool pref = false;
+
+ if (sdev->access_state & SCSI_ACCESS_STATE_PREFERRED)
+ pref = true;
+
+ access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK);
+
+ return snprintf(buf, 32, "%s%s\n",
+ scsi_access_state_name(access_state),
+ pref ? " preferred" : "");
+}
+static DEVICE_ATTR(access_state, S_IRUGO, sdev_show_access_state, NULL);
#endif
static ssize_t
@@ -1047,6 +1095,7 @@ static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_wwid.attr,
#ifdef CONFIG_SCSI_DH
&dev_attr_dh_state.attr,
+ &dev_attr_access_state.attr,
#endif
&dev_attr_queue_ramp_up_period.attr,
REF_EVT(media_change),
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index f63a167..5dd00e9f 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -200,6 +200,7 @@ struct scsi_device {
struct scsi_device_handler *handler;
void *handler_data;
+ enum scsi_access_state access_state;
enum scsi_device_state sdev_state;
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h
index a9fbf1b..80e85e7 100644
--- a/include/scsi/scsi_proto.h
+++ b/include/scsi/scsi_proto.h
@@ -277,5 +277,18 @@ struct scsi_lun {
__u8 scsi_lun[8];
};
+/* SPC asymmetric access states */
+enum scsi_access_state {
+ SCSI_ACCESS_STATE_OPTIMAL = 0,
+ SCSI_ACCESS_STATE_ACTIVE,
+ SCSI_ACCESS_STATE_STANDBY,
+ SCSI_ACCESS_STATE_UNAVAILABLE,
+ SCSI_ACCESS_STATE_LBA,
+ SCSI_ACCESS_STATE_OFFLINE = 0xe,
+ SCSI_ACCESS_STATE_TRANSITIONING = 0xf,
+ SCSI_ACCESS_STATE_UNKNOWN = 0x70,
+};
+#define SCSI_ACCESS_STATE_MASK 0x0f
+#define SCSI_ACCESS_STATE_PREFERRED 0x80
#endif /* _SCSI_PROTO_H_ */
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 20/22] scsi_dh_alua: use common definitions for ALUA state
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (18 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 19/22] scsi: Add 'access_state' attribute Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 21/22] scsi_dh_alua: update 'access_state' field Hannes Reinecke
` (2 subsequent siblings)
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
scsi_proto.h now contains definitions for the ALUA state,
so we don't have to carry them in the device handler.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 62 +++++++++++++-----------------
1 file changed, 27 insertions(+), 35 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index ffc419e..e283c43 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -31,14 +31,6 @@
#define ALUA_DH_NAME "alua"
#define ALUA_DH_VER "1.3"
-#define TPGS_STATE_OPTIMIZED 0x0
-#define TPGS_STATE_NONOPTIMIZED 0x1
-#define TPGS_STATE_STANDBY 0x2
-#define TPGS_STATE_UNAVAILABLE 0x3
-#define TPGS_STATE_LBA_DEPENDENT 0x4
-#define TPGS_STATE_OFFLINE 0xe
-#define TPGS_STATE_TRANSITIONING 0xf
-
#define TPGS_SUPPORT_NONE 0x00
#define TPGS_SUPPORT_OPTIMIZED 0x01
#define TPGS_SUPPORT_NONOPTIMIZED 0x02
@@ -178,7 +170,7 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
/* Prepare the data buffer */
memset(stpg_data, 0, stpg_len);
- stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
+ stpg_data[4] = SCSI_ACCESS_STATE_OPTIMAL & 0x0f;
put_unaligned_be16(group_id, &stpg_data[6]);
/* Prepare the command. */
@@ -246,7 +238,7 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
}
pg->group_id = group_id;
pg->tpgs = tpgs;
- pg->state = TPGS_STATE_OPTIMIZED;
+ pg->state = SCSI_ACCESS_STATE_OPTIMAL;
if (optimize_stpg)
pg->flags |= ALUA_OPTIMIZE_STPG;
kref_init(&pg->kref);
@@ -386,22 +378,22 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
return SCSI_DH_OK;
}
-static char print_alua_state(int state)
+static char print_alua_state(enum scsi_access_state state)
{
switch (state) {
- case TPGS_STATE_OPTIMIZED:
+ case SCSI_ACCESS_STATE_OPTIMAL:
return 'A';
- case TPGS_STATE_NONOPTIMIZED:
+ case SCSI_ACCESS_STATE_ACTIVE:
return 'N';
- case TPGS_STATE_STANDBY:
+ case SCSI_ACCESS_STATE_STANDBY:
return 'S';
- case TPGS_STATE_UNAVAILABLE:
+ case SCSI_ACCESS_STATE_UNAVAILABLE:
return 'U';
- case TPGS_STATE_LBA_DEPENDENT:
+ case SCSI_ACCESS_STATE_LBA:
return 'L';
- case TPGS_STATE_OFFLINE:
+ case SCSI_ACCESS_STATE_OFFLINE:
return 'O';
- case TPGS_STATE_TRANSITIONING:
+ case SCSI_ACCESS_STATE_TRANSITIONING:
return 'T';
default:
return 'X';
@@ -652,7 +644,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
switch (pg->state) {
- case TPGS_STATE_TRANSITIONING:
+ case SCSI_ACCESS_STATE_TRANSITIONING:
if (time_before(jiffies, pg->expiry)) {
/* State transition, retry */
pg->interval = 2;
@@ -660,11 +652,11 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
} else {
/* Transitioning time exceeded, set port to standby */
err = SCSI_DH_IO;
- pg->state = TPGS_STATE_STANDBY;
+ pg->state = SCSI_ACCESS_STATE_STANDBY;
pg->expiry = 0;
}
break;
- case TPGS_STATE_OFFLINE:
+ case SCSI_ACCESS_STATE_OFFLINE:
/* Path unusable */
err = SCSI_DH_DEV_OFFLINED;
pg->expiry = 0;
@@ -697,21 +689,21 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
return SCSI_DH_RETRY;
}
switch (pg->state) {
- case TPGS_STATE_OPTIMIZED:
+ case SCSI_ACCESS_STATE_OPTIMAL:
return SCSI_DH_OK;
- case TPGS_STATE_NONOPTIMIZED:
+ case SCSI_ACCESS_STATE_ACTIVE:
if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
!pg->pref &&
(pg->tpgs & TPGS_MODE_IMPLICIT))
return SCSI_DH_OK;
break;
- case TPGS_STATE_STANDBY:
- case TPGS_STATE_UNAVAILABLE:
+ case SCSI_ACCESS_STATE_STANDBY:
+ case SCSI_ACCESS_STATE_UNAVAILABLE:
break;
- case TPGS_STATE_OFFLINE:
+ case SCSI_ACCESS_STATE_OFFLINE:
return SCSI_DH_IO;
break;
- case TPGS_STATE_TRANSITIONING:
+ case SCSI_ACCESS_STATE_TRANSITIONING:
break;
default:
sdev_printk(KERN_INFO, sdev,
@@ -721,7 +713,7 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
break;
}
/* Set state to transitioning */
- pg->state = TPGS_STATE_TRANSITIONING;
+ pg->state = SCSI_ACCESS_STATE_TRANSITIONING;
retval = submit_stpg(sdev, pg->group_id, &sense_hdr);
if (retval) {
@@ -767,7 +759,7 @@ static void alua_rtpg_work(struct work_struct *work)
int state = pg->state;
spin_unlock_irqrestore(&pg->lock, flags);
- if (state == TPGS_STATE_TRANSITIONING) {
+ if (state == SCSI_ACCESS_STATE_TRANSITIONING) {
if (alua_tur(sdev) == SCSI_DH_RETRY) {
spin_lock_irqsave(&pg->lock, flags);
pg->flags &= ~ALUA_PG_RUNNING;
@@ -1014,7 +1006,7 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
{
struct alua_dh_data *h = sdev->handler_data;
struct alua_port_group *pg;
- int state = TPGS_STATE_OPTIMIZED;
+ enum scsi_access_state state = SCSI_ACCESS_STATE_OPTIMAL;
int ret = BLKPREP_OK;
rcu_read_lock();
@@ -1023,14 +1015,14 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
state = pg->state;
/* Defer I/O while rtpg_work is active */
if (pg->rtpg_sdev)
- state = TPGS_STATE_TRANSITIONING;
+ state = SCSI_ACCESS_STATE_TRANSITIONING;
}
rcu_read_unlock();
- if (state == TPGS_STATE_TRANSITIONING)
+ if (state == SCSI_ACCESS_STATE_TRANSITIONING)
ret = BLKPREP_DEFER;
- else if (state != TPGS_STATE_OPTIMIZED &&
- state != TPGS_STATE_NONOPTIMIZED &&
- state != TPGS_STATE_LBA_DEPENDENT) {
+ else if (state != SCSI_ACCESS_STATE_OPTIMAL &&
+ state != SCSI_ACCESS_STATE_ACTIVE &&
+ state != SCSI_ACCESS_STATE_LBA) {
ret = BLKPREP_KILL;
req->cmd_flags |= REQ_QUIET;
}
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 21/22] scsi_dh_alua: update 'access_state' field
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (19 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 20/22] scsi_dh_alua: use common definitions for ALUA state Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 22/22] scsi_dh_alua: Update version to 2.0 Hannes Reinecke
2016-01-12 17:09 ` [PATCHv2 00/22] ALUA device handler update, part II Christoph Hellwig
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
Track attached SCSI devices and update the 'access_state' field
whenever an ALUA state change has been detected.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index e283c43..93dc425 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_proto.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h>
@@ -74,6 +75,7 @@ static struct workqueue_struct *kaluad_sync_wq;
struct alua_port_group {
struct kref kref;
struct list_head node;
+ struct list_head dh_list;
unsigned char device_id_str[256];
int device_id_len;
int group_id;
@@ -91,6 +93,7 @@ struct alua_port_group {
};
struct alua_dh_data {
+ struct list_head node;
struct alua_port_group *pg;
int group_id;
spinlock_t pg_lock;
@@ -245,6 +248,7 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work);
INIT_LIST_HEAD(&pg->rtpg_list);
INIT_LIST_HEAD(&pg->node);
+ INIT_LIST_HEAD(&pg->dh_list);
spin_lock_init(&pg->lock);
spin_lock(&port_group_lock);
@@ -326,6 +330,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
int rel_port = -1, group_id;
struct alua_port_group *pg, *old_pg = NULL;
bool pg_updated = false;
+ unsigned long flags;
group_id = scsi_vpd_tpg_id(sdev, &rel_port);
if (group_id < 0) {
@@ -357,6 +362,9 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
/* port_group has changed. Update to new port group */
if (h->pg != pg) {
old_pg = h->pg;
+ spin_lock_irqsave(&old_pg->lock, flags);
+ list_del_rcu(&h->node);
+ spin_unlock_irqrestore(&old_pg->lock, flags);
rcu_assign_pointer(h->pg, pg);
pg_updated = true;
}
@@ -367,8 +375,12 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
alua_rtpg_queue(h->pg, sdev, NULL, true);
spin_unlock(&h->pg_lock);
- if (pg_updated)
+ if (pg_updated) {
+ spin_lock_irqsave(&pg->lock, flags);
+ list_add_rcu(&h->node, &pg->dh_list);
+ spin_unlock_irqrestore(&pg->lock, flags);
synchronize_rcu();
+ }
if (old_pg) {
if (old_pg->rtpg_sdev)
flush_delayed_work(&old_pg->rtpg_work);
@@ -615,6 +627,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
spin_lock_irqsave(&port_group_lock, flags);
list_for_each_entry(tmp_pg, &port_group_list, node) {
+ struct alua_dh_data *h;
+
if (tmp_pg->group_id != group_id)
continue;
if (tmp_pg->device_id_len != pg->device_id_len)
@@ -624,6 +638,13 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
continue;
tmp_pg->state = desc[0] & 0x0f;
tmp_pg->pref = desc[0] >> 7;
+ rcu_read_lock();
+ list_for_each_entry_rcu(h, &tmp_pg->dh_list, node) {
+ /* h->sdev should always be valid */
+ BUG_ON(!h->sdev);
+ h->sdev->access_state = desc[0];
+ }
+ rcu_read_unlock();
if (tmp_pg == pg)
valid_states = desc[1];
}
@@ -1053,6 +1074,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
rcu_assign_pointer(h->pg, NULL);
h->init_error = SCSI_DH_OK;
h->sdev = sdev;
+ INIT_LIST_HEAD(&h->node);
mutex_init(&h->init_mutex);
err = alua_initialize(sdev, h);
@@ -1080,14 +1102,17 @@ static void alua_bus_detach(struct scsi_device *sdev)
spin_lock(&h->pg_lock);
pg = h->pg;
rcu_assign_pointer(h->pg, NULL);
- h->sdev = NULL;
spin_unlock(&h->pg_lock);
if (pg) {
+ spin_lock(&pg->lock);
+ list_del_rcu(&h->node);
+ spin_unlock(&pg->lock);
synchronize_rcu();
if (pg->rtpg_sdev)
flush_delayed_work(&pg->rtpg_work);
kref_put(&pg->kref, release_port_group);
}
+ h->sdev = NULL;
sdev->handler_data = NULL;
kfree(h);
}
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCHv2 22/22] scsi_dh_alua: Update version to 2.0
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (20 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 21/22] scsi_dh_alua: update 'access_state' field Hannes Reinecke
@ 2016-01-12 15:40 ` Hannes Reinecke
2016-01-12 17:09 ` [PATCHv2 00/22] ALUA device handler update, part II Christoph Hellwig
22 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-12 15:40 UTC (permalink / raw)
To: Martin K. Petersen
Cc: James Bottomley, Christoph Hellwig, Bart von Assche, Ewan Milne,
linux-scsi, Hannes Reinecke
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 93dc425..47ca96c 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -30,7 +30,7 @@
#include <scsi/scsi_dh.h>
#define ALUA_DH_NAME "alua"
-#define ALUA_DH_VER "1.3"
+#define ALUA_DH_VER "2.0"
#define TPGS_SUPPORT_NONE 0x00
#define TPGS_SUPPORT_OPTIMIZED 0x01
--
1.8.5.6
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG
2016-01-12 15:40 ` [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
@ 2016-01-12 16:43 ` kbuild test robot
2016-01-12 17:14 ` Christoph Hellwig
2016-01-13 6:10 ` kbuild test robot
2 siblings, 0 replies; 38+ messages in thread
From: kbuild test robot @ 2016-01-12 16:43 UTC (permalink / raw)
Cc: kbuild-all, Martin K. Petersen, James Bottomley,
Christoph Hellwig, Bart von Assche, Ewan Milne, linux-scsi,
Hannes Reinecke
Hi Hannes,
[auto build test WARNING on scsi/for-next]
[also build test WARNING on next-20160112]
[cannot apply to v4.4]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Hannes-Reinecke/ALUA-device-handler-update-part-II/20160112-234244
base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
reproduce:
# apt-get install sparse
make ARCH=x86_64 allmodconfig
make C=1 CF=-D__CHECK_ENDIAN__
sparse warnings: (new ones prefixed by >>)
include/linux/compiler.h:228:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/scsi/device_handler/scsi_dh_alua.c:840:14: sparse: incompatible types in comparison expression (different address spaces)
drivers/scsi/device_handler/scsi_dh_alua.c:884:14: sparse: incompatible types in comparison expression (different address spaces)
drivers/scsi/device_handler/scsi_dh_alua.c:918:14: sparse: incompatible types in comparison expression (different address spaces)
vim +840 drivers/scsi/device_handler/scsi_dh_alua.c
824 struct alua_dh_data *h = sdev->handler_data;
825 struct alua_port_group *pg = NULL;
826 unsigned int optimize = 0, argc;
827 const char *p = params;
828 int result = SCSI_DH_OK;
829 unsigned long flags;
830
831 if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
832 return -EINVAL;
833
834 while (*p++)
835 ;
836 if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
837 return -EINVAL;
838
839 rcu_read_lock();
> 840 pg = rcu_dereference(h->pg);
841 if (!pg) {
842 rcu_read_unlock();
843 return -ENXIO;
844 }
845 spin_lock_irqsave(&pg->lock, flags);
846 if (optimize)
847 pg->flags |= ALUA_OPTIMIZE_STPG;
848 else
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 00/22] ALUA device handler update, part II
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
` (21 preceding siblings ...)
2016-01-12 15:40 ` [PATCHv2 22/22] scsi_dh_alua: Update version to 2.0 Hannes Reinecke
@ 2016-01-12 17:09 ` Christoph Hellwig
22 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-01-12 17:09 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Martin K. Petersen, James Bottomley, Christoph Hellwig,
Bart von Assche, Ewan Milne, linux-scsi
Can you push out a git tree for this one as well?
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 08/22] scsi_dh_alua: use unique device id
2016-01-12 15:40 ` [PATCHv2 08/22] scsi_dh_alua: use unique device id Hannes Reinecke
@ 2016-01-12 17:10 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-01-12 17:10 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Martin K. Petersen, James Bottomley, Christoph Hellwig,
Bart von Assche, Ewan Milne, linux-scsi
> +struct alua_port_group *alua_lookup_pg(char *id_str, size_t id_size,
> + int group_id)
Not too important, but I would have preferred alua_find_get_pg here.
> +{
> + struct alua_port_group *pg;
> +
> + list_for_each_entry(pg, &port_group_list, node) {
> + if (pg->group_id != group_id)
> + continue;
> + if (pg->device_id_len != id_size)
> + continue;
> + if (strncmp(pg->device_id_str, id_str, id_size))
> + continue;
> + kref_get(&pg->kref);
This needs to be a kref_get_unless_zero
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 11/22] scsi_dh_alua: move optimize_stpg evaluation
2016-01-12 15:40 ` [PATCHv2 11/22] scsi_dh_alua: move optimize_stpg evaluation Hannes Reinecke
@ 2016-01-12 17:11 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-01-12 17:11 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Martin K. Petersen, James Bottomley, Christoph Hellwig,
Bart von Assche, Ewan Milne, linux-scsi, Hannes Reinecke
On Tue, Jan 12, 2016 at 04:40:47PM +0100, Hannes Reinecke wrote:
> When the optimize_stpg module option is set we should just set it
> once during port_group allocation. Doing so allows us to override
> it later with device specific settings.
Looks fine,
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 12/22] scsi_dh_alua: remove 'rel_port' from alua_dh_data structure
2016-01-12 15:40 ` [PATCHv2 12/22] scsi_dh_alua: remove 'rel_port' from alua_dh_data structure Hannes Reinecke
@ 2016-01-12 17:11 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-01-12 17:11 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Martin K. Petersen, James Bottomley, Christoph Hellwig,
Bart von Assche, Ewan Milne, linux-scsi, Hannes Reinecke
Looks good,
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG
2016-01-12 15:40 ` [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
2016-01-12 16:43 ` kbuild test robot
@ 2016-01-12 17:14 ` Christoph Hellwig
2016-01-13 7:02 ` Hannes Reinecke
2016-01-13 6:10 ` kbuild test robot
2 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2016-01-12 17:14 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Martin K. Petersen, James Bottomley, Christoph Hellwig,
Bart von Assche, Ewan Milne, linux-scsi
> - kref_get(&pg->kref);
> + if (!kref_get_unless_zero(&pg->kref))
> + continue;
As pointed out earlier this should be done from the start.
> + /* Check for existing port_group references */
> + spin_lock(&h->pg_lock);
> + if (h->pg) {
> + old_pg = pg;
> + /* port_group has changed. Update to new port group */
> + if (h->pg != pg) {
> + old_pg = h->pg;
> + rcu_assign_pointer(h->pg, pg);
> + pg_updated = true;
> + }
> + } else {
> + rcu_assign_pointer(h->pg, pg);
> + pg_updated = true;
> + }
> + alua_rtpg_queue(h->pg, sdev, NULL);
> + spin_unlock(&h->pg_lock);
> +
> + if (pg_updated)
> + synchronize_rcu();
> + if (old_pg) {
> + if (old_pg->rtpg_sdev)
> + flush_delayed_work(&old_pg->rtpg_work);
> + kref_put(&old_pg->kref, release_port_group);
> + }
The synchronize_rcu() needs to be done in release_port_group, or even
better be replaced by doing a kfree_rcu there instead of a kfree.
And unless I'm mistaken the flush_delayed_work should probably be
done in release_port_group as well.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 14/22] scsi_dh_alua: Allow workqueue to run synchronously
2016-01-12 15:40 ` [PATCHv2 14/22] scsi_dh_alua: Allow workqueue to run synchronously Hannes Reinecke
@ 2016-01-12 17:16 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-01-12 17:16 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Martin K. Petersen, James Bottomley, Christoph Hellwig,
Bart von Assche, Ewan Milne, linux-scsi
On Tue, Jan 12, 2016 at 04:40:50PM +0100, Hannes Reinecke wrote:
> Some arrays may only capable of handling one STPG at a time,
> so this patch adds a singlethreaded workqueue for STPGs to be
> submitted synchronously.
> Synchronous STPG can be activated by setting the second module
> option to '1'. The corresponding entry in multipath.conf would be:
> hardware_handler "3 alua 1 1"
No new hardware_handle options please. The SCSI way to handle hardware
tweaks is by a devlist entry. The devlist entries ensure setups
work out of the box, but if needed still can be updated dynamically.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 15/22] scsi_dh_alua: Recheck state on unit attention
2016-01-12 15:40 ` [PATCHv2 15/22] scsi_dh_alua: Recheck state on unit attention Hannes Reinecke
@ 2016-01-12 17:17 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-01-12 17:17 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Martin K. Petersen, James Bottomley, Christoph Hellwig,
Bart von Assche, Ewan Milne, linux-scsi
Looks fine,
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 05/22] scsi_dh_alua: switch to scsi_execute_req_flags()
2016-01-12 15:40 ` [PATCHv2 05/22] scsi_dh_alua: switch to scsi_execute_req_flags() Hannes Reinecke
@ 2016-01-13 5:48 ` kbuild test robot
0 siblings, 0 replies; 38+ messages in thread
From: kbuild test robot @ 2016-01-13 5:48 UTC (permalink / raw)
Cc: kbuild-all, Martin K. Petersen, James Bottomley,
Christoph Hellwig, Bart von Assche, Ewan Milne, linux-scsi,
Hannes Reinecke
[-- Attachment #1: Type: text/plain, Size: 3265 bytes --]
Hi Hannes,
[auto build test WARNING on scsi/for-next]
[also build test WARNING on next-20160112]
[cannot apply to v4.4]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Hannes-Reinecke/ALUA-device-handler-update-part-II/20160112-234244
base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
config: s390-allyesconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=s390
All warnings (new ones prefixed by >>):
drivers/scsi/device_handler/scsi_dh_alua.c: In function 'alua_rtpg':
>> drivers/scsi/device_handler/scsi_dh_alua.c:478:1: warning: 'alua_rtpg' uses dynamic stack allocation
}
^
drivers/scsi/device_handler/scsi_dh_alua.c: In function 'alua_activate':
drivers/scsi/device_handler/scsi_dh_alua.c:634:1: warning: 'alua_activate' uses dynamic stack allocation
}
^
vim +/alua_rtpg +478 drivers/scsi/device_handler/scsi_dh_alua.c
a8e5a2d5 Stewart, Sean 2013-10-15 462 err = SCSI_DH_OK;
a8e5a2d5 Stewart, Sean 2013-10-15 463 }
a8e5a2d5 Stewart, Sean 2013-10-15 464
a8e5a2d5 Stewart, Sean 2013-10-15 465 /* Transitioning time exceeded, set port to standby */
69723d17 Hannes Reinecke 2010-09-24 466 h->state = TPGS_STATE_STANDBY;
057ea7c9 Hannes Reinecke 2008-07-17 467 break;
057ea7c9 Hannes Reinecke 2008-07-17 468 case TPGS_STATE_OFFLINE:
e47f8976 Bart Van Assche 2012-08-24 469 /* Path unusable */
057ea7c9 Hannes Reinecke 2008-07-17 470 err = SCSI_DH_DEV_OFFLINED;
057ea7c9 Hannes Reinecke 2008-07-17 471 break;
057ea7c9 Hannes Reinecke 2008-07-17 472 default:
057ea7c9 Hannes Reinecke 2008-07-17 473 /* Useable path if active */
057ea7c9 Hannes Reinecke 2008-07-17 474 err = SCSI_DH_OK;
69723d17 Hannes Reinecke 2010-09-24 475 break;
057ea7c9 Hannes Reinecke 2008-07-17 476 }
057ea7c9 Hannes Reinecke 2008-07-17 477 return err;
057ea7c9 Hannes Reinecke 2008-07-17 @478 }
057ea7c9 Hannes Reinecke 2008-07-17 479
057ea7c9 Hannes Reinecke 2008-07-17 480 /*
d8af10dc Hannes Reinecke 2016-01-12 481 * alua_stpg - Issue a SET TARGET GROUP STATES command
d8af10dc Hannes Reinecke 2016-01-12 482 *
d8af10dc Hannes Reinecke 2016-01-12 483 * Issue a SET TARGET GROUP STATES command and evaluate the
0d223456 Hannes Reinecke 2016-01-12 484 * response. Returns SCSI_DH_RETRY per default to trigger
0d223456 Hannes Reinecke 2016-01-12 485 * a re-evaluation of the target group state or SCSI_DH_OK
0d223456 Hannes Reinecke 2016-01-12 486 * if no further action needs to be taken.
:::::: The code at line 478 was first introduced by commit
:::::: 057ea7c9683c3d684128cced796f03c179ecf1c2 [SCSI] scsi_dh: add generic SPC-3 alua handler
:::::: TO: Hannes Reinecke <hare@suse.de>
:::::: CC: James Bottomley <James.Bottomley@HansenPartnership.com>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 39409 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG
2016-01-12 15:40 ` [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
2016-01-12 16:43 ` kbuild test robot
2016-01-12 17:14 ` Christoph Hellwig
@ 2016-01-13 6:10 ` kbuild test robot
2 siblings, 0 replies; 38+ messages in thread
From: kbuild test robot @ 2016-01-13 6:10 UTC (permalink / raw)
Cc: kbuild-all, Martin K. Petersen, James Bottomley,
Christoph Hellwig, Bart von Assche, Ewan Milne, linux-scsi,
Hannes Reinecke
[-- Attachment #1: Type: text/plain, Size: 6047 bytes --]
Hi Hannes,
[auto build test WARNING on scsi/for-next]
[also build test WARNING on next-20160112]
[cannot apply to v4.4]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Hannes-Reinecke/ALUA-device-handler-update-part-II/20160112-234244
base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
config: s390-allyesconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=s390
All warnings (new ones prefixed by >>):
drivers/scsi/device_handler/scsi_dh_alua.c: In function 'alua_rtpg':
drivers/scsi/device_handler/scsi_dh_alua.c:630:1: warning: 'alua_rtpg' uses dynamic stack allocation
}
^
drivers/scsi/device_handler/scsi_dh_alua.c: In function 'alua_rtpg_work':
>> drivers/scsi/device_handler/scsi_dh_alua.c:759:1: warning: 'alua_rtpg_work' uses dynamic stack allocation
}
^
vim +/alua_rtpg_work +759 drivers/scsi/device_handler/scsi_dh_alua.c
624 err = SCSI_DH_OK;
625 pg->expiry = 0;
626 break;
627 }
628 kfree(buff);
629 return err;
> 630 }
631
632 /*
633 * alua_stpg - Issue a SET TARGET GROUP STATES command
634 *
635 * Issue a SET TARGET GROUP STATES command and evaluate the
636 * response. Returns SCSI_DH_RETRY per default to trigger
637 * a re-evaluation of the target group state or SCSI_DH_OK
638 * if no further action needs to be taken.
639 */
640 static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
641 {
642 int retval;
643 struct scsi_sense_hdr sense_hdr;
644
645 if (!(pg->tpgs & TPGS_MODE_EXPLICIT)) {
646 /* Only implicit ALUA supported, retry */
647 return SCSI_DH_RETRY;
648 }
649 switch (pg->state) {
650 case TPGS_STATE_OPTIMIZED:
651 return SCSI_DH_OK;
652 case TPGS_STATE_NONOPTIMIZED:
653 if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
654 !pg->pref &&
655 (pg->tpgs & TPGS_MODE_IMPLICIT))
656 return SCSI_DH_OK;
657 break;
658 case TPGS_STATE_STANDBY:
659 case TPGS_STATE_UNAVAILABLE:
660 break;
661 case TPGS_STATE_OFFLINE:
662 return SCSI_DH_IO;
663 break;
664 case TPGS_STATE_TRANSITIONING:
665 break;
666 default:
667 sdev_printk(KERN_INFO, sdev,
668 "%s: stpg failed, unhandled TPGS state %d",
669 ALUA_DH_NAME, pg->state);
670 return SCSI_DH_NOSYS;
671 break;
672 }
673 /* Set state to transitioning */
674 pg->state = TPGS_STATE_TRANSITIONING;
675 retval = submit_stpg(sdev, pg->group_id, &sense_hdr);
676
677 if (retval) {
678 if (!scsi_sense_valid(&sense_hdr)) {
679 sdev_printk(KERN_INFO, sdev,
680 "%s: stpg failed, result %d",
681 ALUA_DH_NAME, retval);
682 if (driver_byte(retval) == DRIVER_ERROR)
683 return SCSI_DH_DEV_TEMP_BUSY;
684 } else {
685 sdev_printk(KERN_INFO, sdev, "%s: stpg failed\n",
686 ALUA_DH_NAME);
687 scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
688 }
689 }
690 /* Retry RTPG */
691 return SCSI_DH_RETRY;
692 }
693
694 static void alua_rtpg_work(struct work_struct *work)
695 {
696 struct alua_port_group *pg =
697 container_of(work, struct alua_port_group, rtpg_work.work);
698 struct scsi_device *sdev;
699 LIST_HEAD(qdata_list);
700 int err = SCSI_DH_OK;
701 struct alua_queue_data *qdata, *tmp;
702 unsigned long flags;
703
704 spin_lock_irqsave(&pg->lock, flags);
705 sdev = pg->rtpg_sdev;
706 if (!sdev) {
707 WARN_ON(pg->flags & ALUA_PG_RUN_RTPG ||
708 pg->flags & ALUA_PG_RUN_STPG);
709 spin_unlock_irqrestore(&pg->lock, flags);
710 return;
711 }
712 pg->flags |= ALUA_PG_RUNNING;
713 if (pg->flags & ALUA_PG_RUN_RTPG) {
714 spin_unlock_irqrestore(&pg->lock, flags);
715 err = alua_rtpg(sdev, pg);
716 spin_lock_irqsave(&pg->lock, flags);
717 if (err == SCSI_DH_RETRY) {
718 pg->flags &= ~ALUA_PG_RUNNING;
719 spin_unlock_irqrestore(&pg->lock, flags);
720 queue_delayed_work(kaluad_wq, &pg->rtpg_work,
721 pg->interval * HZ);
722 return;
723 }
724 pg->flags &= ~ALUA_PG_RUN_RTPG;
725 if (err != SCSI_DH_OK)
726 pg->flags &= ~ALUA_PG_RUN_STPG;
727 }
728 if (pg->flags & ALUA_PG_RUN_STPG) {
729 spin_unlock_irqrestore(&pg->lock, flags);
730 err = alua_stpg(sdev, pg);
731 spin_lock_irqsave(&pg->lock, flags);
732 pg->flags &= ~ALUA_PG_RUN_STPG;
733 if (err == SCSI_DH_RETRY) {
734 pg->flags |= ALUA_PG_RUN_RTPG;
735 pg->interval = 0;
736 pg->flags &= ~ALUA_PG_RUNNING;
737 spin_unlock_irqrestore(&pg->lock, flags);
738 queue_delayed_work(kaluad_wq, &pg->rtpg_work,
739 pg->interval * HZ);
740 return;
741 }
742 }
743
744 list_splice_init(&pg->rtpg_list, &qdata_list);
745 pg->rtpg_sdev = NULL;
746 spin_unlock_irqrestore(&pg->lock, flags);
747
748 list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) {
749 list_del(&qdata->entry);
750 if (qdata->callback_fn)
751 qdata->callback_fn(qdata->callback_data, err);
752 kfree(qdata);
753 }
754 spin_lock_irqsave(&pg->lock, flags);
755 pg->flags &= ~ALUA_PG_RUNNING;
756 spin_unlock_irqrestore(&pg->lock, flags);
757 scsi_device_put(sdev);
758 kref_put(&pg->kref, release_port_group);
> 759 }
760
761 static void alua_rtpg_queue(struct alua_port_group *pg,
762 struct scsi_device *sdev,
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 39409 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG
2016-01-12 17:14 ` Christoph Hellwig
@ 2016-01-13 7:02 ` Hannes Reinecke
2016-01-13 7:13 ` Hannes Reinecke
2016-01-13 10:04 ` Christoph Hellwig
0 siblings, 2 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-13 7:02 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Martin K. Petersen, James Bottomley, Bart von Assche, Ewan Milne,
linux-scsi
On 01/12/2016 06:14 PM, Christoph Hellwig wrote:
>> - kref_get(&pg->kref);
>> + if (!kref_get_unless_zero(&pg->kref))
>> + continue;
>
> As pointed out earlier this should be done from the start.
>
Yep.
>> + /* Check for existing port_group references */
>> + spin_lock(&h->pg_lock);
>> + if (h->pg) {
>> + old_pg = pg;
>> + /* port_group has changed. Update to new port group */
>> + if (h->pg != pg) {
>> + old_pg = h->pg;
>> + rcu_assign_pointer(h->pg, pg);
>> + pg_updated = true;
>> + }
>> + } else {
>> + rcu_assign_pointer(h->pg, pg);
>> + pg_updated = true;
>> + }
>> + alua_rtpg_queue(h->pg, sdev, NULL);
>> + spin_unlock(&h->pg_lock);
>> +
>> + if (pg_updated)
>> + synchronize_rcu();
>> + if (old_pg) {
>> + if (old_pg->rtpg_sdev)
>> + flush_delayed_work(&old_pg->rtpg_work);
>> + kref_put(&old_pg->kref, release_port_group);
>> + }
>
> The synchronize_rcu() needs to be done in release_port_group, or even
> better be replaced by doing a kfree_rcu there instead of a kfree.
>
Point is that we don't necessarily have an old_pg to call
release_port_group() on, but we still need to call synchronize_rcu()
to inform everyong that h->pg now has a new value.
So while I could do that it would end with a mess of if-clauses here.
> And unless I'm mistaken the flush_delayed_work should probably be
> done in release_port_group as well.
>
_Actually_ we only need to call flush_delayed_work if sdev ==
rtgp_sdev. Otherwise the workqueue item is running off a different
device and won't be affected.
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
hare@suse.de +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG
2016-01-13 7:02 ` Hannes Reinecke
@ 2016-01-13 7:13 ` Hannes Reinecke
2016-01-13 10:05 ` Christoph Hellwig
2016-01-13 10:04 ` Christoph Hellwig
1 sibling, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-13 7:13 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Martin K. Petersen, James Bottomley, Bart von Assche, Ewan Milne,
linux-scsi
On 01/13/2016 08:02 AM, Hannes Reinecke wrote:
> On 01/12/2016 06:14 PM, Christoph Hellwig wrote:
>>> - kref_get(&pg->kref);
>>> + if (!kref_get_unless_zero(&pg->kref))
>>> + continue;
>>
>> As pointed out earlier this should be done from the start.
>>
> Yep.
>
>>> + /* Check for existing port_group references */
>>> + spin_lock(&h->pg_lock);
>>> + if (h->pg) {
>>> + old_pg = pg;
>>> + /* port_group has changed. Update to new port group */
>>> + if (h->pg != pg) {
>>> + old_pg = h->pg;
>>> + rcu_assign_pointer(h->pg, pg);
>>> + pg_updated = true;
>>> + }
>>> + } else {
>>> + rcu_assign_pointer(h->pg, pg);
>>> + pg_updated = true;
>>> + }
>>> + alua_rtpg_queue(h->pg, sdev, NULL);
>>> + spin_unlock(&h->pg_lock);
>>> +
>>> + if (pg_updated)
>>> + synchronize_rcu();
>>> + if (old_pg) {
>>> + if (old_pg->rtpg_sdev)
>>> + flush_delayed_work(&old_pg->rtpg_work);
>>> + kref_put(&old_pg->kref, release_port_group);
>>> + }
>>
>> The synchronize_rcu() needs to be done in release_port_group, or even
>> better be replaced by doing a kfree_rcu there instead of a kfree.
>>
> Point is that we don't necessarily have an old_pg to call
> release_port_group() on, but we still need to call synchronize_rcu()
> to inform everyong that h->pg now has a new value.
> So while I could do that it would end with a mess of if-clauses here.
>
>> And unless I'm mistaken the flush_delayed_work should probably be
>> done in release_port_group as well.
>>
> _Actually_ we only need to call flush_delayed_work if sdev ==
> rtgp_sdev. Otherwise the workqueue item is running off a different
> device and won't be affected.
>
Hmm. Well, not quite. We run into flush_delayed_work() only if the
port group changes or upon bus detach.
For all other callers rtpg_sdev() should already be NULL.
But looking at the call sites we can indeed move the
flush_delayed_work() into the release function.
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
hare@suse.de +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG
2016-01-13 7:02 ` Hannes Reinecke
2016-01-13 7:13 ` Hannes Reinecke
@ 2016-01-13 10:04 ` Christoph Hellwig
2016-01-13 10:27 ` Hannes Reinecke
1 sibling, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2016-01-13 10:04 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Christoph Hellwig, Martin K. Petersen, James Bottomley,
Bart von Assche, Ewan Milne, linux-scsi
On Wed, Jan 13, 2016 at 08:02:02AM +0100, Hannes Reinecke wrote:
>>> + /* Check for existing port_group references */
>>> + spin_lock(&h->pg_lock);
>>> + if (h->pg) {
>>> + old_pg = pg;
>>> + /* port_group has changed. Update to new port group */
>>> + if (h->pg != pg) {
>>> + old_pg = h->pg;
>>> + rcu_assign_pointer(h->pg, pg);
>>> + pg_updated = true;
>>> + }
>>> + } else {
>>> + rcu_assign_pointer(h->pg, pg);
>>> + pg_updated = true;
>>> + }
>>> + alua_rtpg_queue(h->pg, sdev, NULL);
>>> + spin_unlock(&h->pg_lock);
>>> +
>>> + if (pg_updated)
>>> + synchronize_rcu();
>>> + if (old_pg) {
>>> + if (old_pg->rtpg_sdev)
>>> + flush_delayed_work(&old_pg->rtpg_work);
>>> + kref_put(&old_pg->kref, release_port_group);
>>> + }
>>
>> The synchronize_rcu() needs to be done in release_port_group, or even
>> better be replaced by doing a kfree_rcu there instead of a kfree.
>>
> Point is that we don't necessarily have an old_pg to call
> release_port_group() on, but we still need to call synchronize_rcu()
> to inform everyong that h->pg now has a new value.
No, you don't. synchronize_rcu() just waits for all previously
started RCU grace periods to finish. If old_pg doesn't get freed
you don't need to wait for the grace period. synchronize_rcu does
not notify anyone about anything, it just waits.
>> And unless I'm mistaken the flush_delayed_work should probably be
>> done in release_port_group as well.
>>
> _Actually_ we only need to call flush_delayed_work if sdev == rtgp_sdev.
> Otherwise the workqueue item is running off a different device and won't be
> affected.
I'm actually pretty sure I suggested that in an earlier iteratation,
but you said that's not the case. So please only run it if
sdev == rtgp_sdev only then.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG
2016-01-13 7:13 ` Hannes Reinecke
@ 2016-01-13 10:05 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-01-13 10:05 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Christoph Hellwig, Martin K. Petersen, James Bottomley,
Bart von Assche, Ewan Milne, linux-scsi
On Wed, Jan 13, 2016 at 08:13:54AM +0100, Hannes Reinecke wrote:
>> _Actually_ we only need to call flush_delayed_work if sdev ==
>> rtgp_sdev. Otherwise the workqueue item is running off a different
>> device and won't be affected.
>>
> Hmm. Well, not quite. We run into flush_delayed_work() only if the port
> group changes or upon bus detach.
> For all other callers rtpg_sdev() should already be NULL.
> But looking at the call sites we can indeed move the flush_delayed_work()
> into the release function.
Looks like the earlier you made sense after all :)
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG
2016-01-13 10:04 ` Christoph Hellwig
@ 2016-01-13 10:27 ` Hannes Reinecke
0 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2016-01-13 10:27 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Martin K. Petersen, James Bottomley, Bart von Assche, Ewan Milne,
linux-scsi
On 01/13/2016 11:04 AM, Christoph Hellwig wrote:
> On Wed, Jan 13, 2016 at 08:02:02AM +0100, Hannes Reinecke wrote:
>>>> + /* Check for existing port_group references */
>>>> + spin_lock(&h->pg_lock);
>>>> + if (h->pg) {
>>>> + old_pg = pg;
>>>> + /* port_group has changed. Update to new port group */
>>>> + if (h->pg != pg) {
>>>> + old_pg = h->pg;
>>>> + rcu_assign_pointer(h->pg, pg);
>>>> + pg_updated = true;
>>>> + }
>>>> + } else {
>>>> + rcu_assign_pointer(h->pg, pg);
>>>> + pg_updated = true;
>>>> + }
>>>> + alua_rtpg_queue(h->pg, sdev, NULL);
>>>> + spin_unlock(&h->pg_lock);
>>>> +
>>>> + if (pg_updated)
>>>> + synchronize_rcu();
>>>> + if (old_pg) {
>>>> + if (old_pg->rtpg_sdev)
>>>> + flush_delayed_work(&old_pg->rtpg_work);
>>>> + kref_put(&old_pg->kref, release_port_group);
>>>> + }
>>>
>>> The synchronize_rcu() needs to be done in release_port_group, or even
>>> better be replaced by doing a kfree_rcu there instead of a kfree.
>>>
>> Point is that we don't necessarily have an old_pg to call
>> release_port_group() on, but we still need to call synchronize_rcu()
>> to inform everyong that h->pg now has a new value.
>
> No, you don't. synchronize_rcu() just waits for all previously
> started RCU grace periods to finish. If old_pg doesn't get freed
> you don't need to wait for the grace period. synchronize_rcu does
> not notify anyone about anything, it just waits.
>
Ah. Right. Good point. Of course we don't need to call it if there's
nothing to be freed.
Will be folding it into the next round of patches, or just resending
this one if the remaining patches meets with approval.
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
hare@suse.de +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2016-01-13 10:27 UTC | newest]
Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-12 15:40 [PATCHv2 00/22] ALUA device handler update, part II Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 01/22] scsi_dh_alua: Pass buffer as function argument Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 02/22] scsi_dh_alua: separate out alua_stpg() Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 03/22] scsi_dh_alua: Make stpg synchronous Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 04/22] scsi_dh_alua: call alua_rtpg() if stpg fails Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 05/22] scsi_dh_alua: switch to scsi_execute_req_flags() Hannes Reinecke
2016-01-13 5:48 ` kbuild test robot
2016-01-12 15:40 ` [PATCHv2 06/22] scsi_dh_alua: allocate RTPG buffer separately Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 07/22] scsi_dh_alua: Use separate alua_port_group structure Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 08/22] scsi_dh_alua: use unique device id Hannes Reinecke
2016-01-12 17:10 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 09/22] scsi_dh_alua: simplify alua_initialize() Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 10/22] revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should succeed while TPG is transitioning") Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 11/22] scsi_dh_alua: move optimize_stpg evaluation Hannes Reinecke
2016-01-12 17:11 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 12/22] scsi_dh_alua: remove 'rel_port' from alua_dh_data structure Hannes Reinecke
2016-01-12 17:11 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 13/22] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
2016-01-12 16:43 ` kbuild test robot
2016-01-12 17:14 ` Christoph Hellwig
2016-01-13 7:02 ` Hannes Reinecke
2016-01-13 7:13 ` Hannes Reinecke
2016-01-13 10:05 ` Christoph Hellwig
2016-01-13 10:04 ` Christoph Hellwig
2016-01-13 10:27 ` Hannes Reinecke
2016-01-13 6:10 ` kbuild test robot
2016-01-12 15:40 ` [PATCHv2 14/22] scsi_dh_alua: Allow workqueue to run synchronously Hannes Reinecke
2016-01-12 17:16 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 15/22] scsi_dh_alua: Recheck state on unit attention Hannes Reinecke
2016-01-12 17:17 ` Christoph Hellwig
2016-01-12 15:40 ` [PATCHv2 16/22] scsi_dh_alua: update all port states Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 17/22] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 18/22] scsi_dh: add 'rescan' callback Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 19/22] scsi: Add 'access_state' attribute Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 20/22] scsi_dh_alua: use common definitions for ALUA state Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 21/22] scsi_dh_alua: update 'access_state' field Hannes Reinecke
2016-01-12 15:40 ` [PATCHv2 22/22] scsi_dh_alua: Update version to 2.0 Hannes Reinecke
2016-01-12 17:09 ` [PATCHv2 00/22] ALUA device handler update, part II Christoph Hellwig
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.