Commit bb91c1a0 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Nicholas Bellinger

target_core_alua: validate ALUA state transition

As we now can modify the list of supported states we need to
validate the requested ALUA state when doing a state transition.
Signed-off-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 340dbf72
...@@ -41,11 +41,14 @@ ...@@ -41,11 +41,14 @@
#include "target_core_alua.h" #include "target_core_alua.h"
#include "target_core_ua.h" #include "target_core_ua.h"
static sense_reason_t core_alua_check_transition(int state, int *primary); static sense_reason_t core_alua_check_transition(int state, int valid,
int *primary);
static int core_alua_set_tg_pt_secondary_state( static int core_alua_set_tg_pt_secondary_state(
struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
struct se_port *port, int explicit, int offline); struct se_port *port, int explicit, int offline);
static char *core_alua_dump_state(int state);
static u16 alua_lu_gps_counter; static u16 alua_lu_gps_counter;
static u32 alua_lu_gps_count; static u32 alua_lu_gps_count;
...@@ -210,7 +213,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) ...@@ -210,7 +213,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
unsigned char *ptr; unsigned char *ptr;
sense_reason_t rc = TCM_NO_SENSE; sense_reason_t rc = TCM_NO_SENSE;
u32 len = 4; /* Skip over RESERVED area in header */ u32 len = 4; /* Skip over RESERVED area in header */
int alua_access_state, primary = 0; int alua_access_state, primary = 0, valid_states;
u16 tg_pt_id, rtpi; u16 tg_pt_id, rtpi;
if (!l_port) if (!l_port)
...@@ -252,6 +255,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) ...@@ -252,6 +255,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
rc = TCM_UNSUPPORTED_SCSI_OPCODE; rc = TCM_UNSUPPORTED_SCSI_OPCODE;
goto out; goto out;
} }
valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
ptr = &buf[4]; /* Skip over RESERVED area in header */ ptr = &buf[4]; /* Skip over RESERVED area in header */
...@@ -263,7 +267,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) ...@@ -263,7 +267,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
* the state is a primary or secondary target port asymmetric * the state is a primary or secondary target port asymmetric
* access state. * access state.
*/ */
rc = core_alua_check_transition(alua_access_state, &primary); rc = core_alua_check_transition(alua_access_state,
valid_states, &primary);
if (rc) { if (rc) {
/* /*
* If the SET TARGET PORT GROUPS attempts to establish * If the SET TARGET PORT GROUPS attempts to establish
...@@ -618,17 +623,31 @@ target_alua_state_check(struct se_cmd *cmd) ...@@ -618,17 +623,31 @@ target_alua_state_check(struct se_cmd *cmd)
* Check implicit and explicit ALUA state change request. * Check implicit and explicit ALUA state change request.
*/ */
static sense_reason_t static sense_reason_t
core_alua_check_transition(int state, int *primary) core_alua_check_transition(int state, int valid, int *primary)
{ {
/*
* OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are
* defined as primary target port asymmetric access states.
*/
switch (state) { switch (state) {
case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED:
if (!(valid & ALUA_AO_SUP))
goto not_supported;
*primary = 1;
break;
case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
if (!(valid & ALUA_AN_SUP))
goto not_supported;
*primary = 1;
break;
case ALUA_ACCESS_STATE_STANDBY: case ALUA_ACCESS_STATE_STANDBY:
if (!(valid & ALUA_S_SUP))
goto not_supported;
*primary = 1;
break;
case ALUA_ACCESS_STATE_UNAVAILABLE: case ALUA_ACCESS_STATE_UNAVAILABLE:
/* if (!(valid & ALUA_U_SUP))
* OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are goto not_supported;
* defined as primary target port asymmetric access states.
*/
*primary = 1; *primary = 1;
break; break;
case ALUA_ACCESS_STATE_OFFLINE: case ALUA_ACCESS_STATE_OFFLINE:
...@@ -636,14 +655,27 @@ core_alua_check_transition(int state, int *primary) ...@@ -636,14 +655,27 @@ core_alua_check_transition(int state, int *primary)
* OFFLINE state is defined as a secondary target port * OFFLINE state is defined as a secondary target port
* asymmetric access state. * asymmetric access state.
*/ */
if (!(valid & ALUA_O_SUP))
goto not_supported;
*primary = 0; *primary = 0;
break; break;
case ALUA_ACCESS_STATE_TRANSITION:
/*
* Transitioning is set internally, and
* cannot be selected manually.
*/
goto not_supported;
default: default:
pr_err("Unknown ALUA access state: 0x%02x\n", state); pr_err("Unknown ALUA access state: 0x%02x\n", state);
return TCM_INVALID_PARAMETER_LIST; return TCM_INVALID_PARAMETER_LIST;
} }
return 0; return 0;
not_supported:
pr_err("ALUA access state %s not supported",
core_alua_dump_state(state));
return TCM_INVALID_PARAMETER_LIST;
} }
static char *core_alua_dump_state(int state) static char *core_alua_dump_state(int state)
...@@ -659,6 +691,8 @@ static char *core_alua_dump_state(int state) ...@@ -659,6 +691,8 @@ static char *core_alua_dump_state(int state)
return "Unavailable"; return "Unavailable";
case ALUA_ACCESS_STATE_OFFLINE: case ALUA_ACCESS_STATE_OFFLINE:
return "Offline"; return "Offline";
case ALUA_ACCESS_STATE_TRANSITION:
return "Transitioning";
default: default:
return "Unknown"; return "Unknown";
} }
...@@ -884,9 +918,10 @@ int core_alua_do_port_transition( ...@@ -884,9 +918,10 @@ int core_alua_do_port_transition(
struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem;
struct t10_alua_tg_pt_gp *tg_pt_gp; struct t10_alua_tg_pt_gp *tg_pt_gp;
unsigned char *md_buf; unsigned char *md_buf;
int primary; int primary, valid_states;
if (core_alua_check_transition(new_state, &primary) != 0) valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
if (core_alua_check_transition(new_state, valid_states, &primary) != 0)
return -EINVAL; return -EINVAL;
md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL); md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment