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:
parent
340dbf729c
commit
bb91c1a087
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
* 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 @@ out:
|
|||||||
* 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)
|
|||||||
* 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)
|
|||||||
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(
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user