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: Hannes Reinecke <hare@suse.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
Hannes Reinecke 2013-12-17 09:18:43 +01:00 committed by Nicholas Bellinger
parent 340dbf729c
commit bb91c1a087

View File

@ -41,11 +41,14 @@
#include "target_core_alua.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(
struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
struct se_port *port, int explicit, int offline);
static char *core_alua_dump_state(int state);
static u16 alua_lu_gps_counter;
static u32 alua_lu_gps_count;
@ -210,7 +213,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
unsigned char *ptr;
sense_reason_t rc = TCM_NO_SENSE;
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;
if (!l_port)
@ -252,6 +255,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
rc = TCM_UNSUPPORTED_SCSI_OPCODE;
goto out;
}
valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
ptr = &buf[4]; /* Skip over RESERVED area in header */
@ -263,7 +267,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
* the state is a primary or secondary target port asymmetric
* 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 the SET TARGET PORT GROUPS attempts to establish
@ -618,17 +623,31 @@ out:
* Check implicit and explicit ALUA state change request.
*/
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) {
case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED:
if (!(valid & ALUA_AO_SUP))
goto not_supported;
*primary = 1;
break;
case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
if (!(valid & ALUA_AN_SUP))
goto not_supported;
*primary = 1;
break;
case ALUA_ACCESS_STATE_STANDBY:
if (!(valid & ALUA_S_SUP))
goto not_supported;
*primary = 1;
break;
case ALUA_ACCESS_STATE_UNAVAILABLE:
/*
* OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are
* defined as primary target port asymmetric access states.
*/
if (!(valid & ALUA_U_SUP))
goto not_supported;
*primary = 1;
break;
case ALUA_ACCESS_STATE_OFFLINE:
@ -636,14 +655,27 @@ core_alua_check_transition(int state, int *primary)
* OFFLINE state is defined as a secondary target port
* asymmetric access state.
*/
if (!(valid & ALUA_O_SUP))
goto not_supported;
*primary = 0;
break;
case ALUA_ACCESS_STATE_TRANSITION:
/*
* Transitioning is set internally, and
* cannot be selected manually.
*/
goto not_supported;
default:
pr_err("Unknown ALUA access state: 0x%02x\n", state);
return TCM_INVALID_PARAMETER_LIST;
}
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)
@ -659,6 +691,8 @@ static char *core_alua_dump_state(int state)
return "Unavailable";
case ALUA_ACCESS_STATE_OFFLINE:
return "Offline";
case ALUA_ACCESS_STATE_TRANSITION:
return "Transitioning";
default:
return "Unknown";
}
@ -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_tg_pt_gp *tg_pt_gp;
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;
md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL);