Skip to content

Commit

Permalink
target_core_alua: validate ALUA state transition
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hannes Reinecke authored and Nicholas Bellinger committed Dec 17, 2013
1 parent 340dbf7 commit bb91c1a
Showing 1 changed file with 45 additions and 10 deletions.
55 changes: 45 additions & 10 deletions drivers/target/target_core_alua.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 */

Expand All @@ -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
Expand Down Expand Up @@ -618,32 +623,59 @@ target_alua_state_check(struct se_cmd *cmd)
* 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:
/*
* 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)
Expand All @@ -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";
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit bb91c1a

Please sign in to comment.