Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+45 −10
Original line number Original line Diff line number Diff line
@@ -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);