diff options
author | Hannes Reinecke <hare@suse.de> | 2013-12-17 03:18:43 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-12-17 13:30:26 -0500 |
commit | bb91c1a087ed29ceb5b25b9c210c6665e13c36eb (patch) | |
tree | b4b86f4accb7e5e810a181b4e19cc1b86ba0186f | |
parent | 340dbf729c3395cf1317890d033aa9ac7347766c (diff) |
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>
-rw-r--r-- | drivers/target/target_core_alua.c | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index fdcee326bfbc..292ecce98d1f 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c | |||
@@ -41,11 +41,14 @@ | |||
41 | #include "target_core_alua.h" | 41 | #include "target_core_alua.h" |
42 | #include "target_core_ua.h" | 42 | #include "target_core_ua.h" |
43 | 43 | ||
44 | static sense_reason_t core_alua_check_transition(int state, int *primary); | 44 | static sense_reason_t core_alua_check_transition(int state, int valid, |
45 | int *primary); | ||
45 | static int core_alua_set_tg_pt_secondary_state( | 46 | static int core_alua_set_tg_pt_secondary_state( |
46 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, | 47 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, |
47 | struct se_port *port, int explicit, int offline); | 48 | struct se_port *port, int explicit, int offline); |
48 | 49 | ||
50 | static char *core_alua_dump_state(int state); | ||
51 | |||
49 | static u16 alua_lu_gps_counter; | 52 | static u16 alua_lu_gps_counter; |
50 | static u32 alua_lu_gps_count; | 53 | static u32 alua_lu_gps_count; |
51 | 54 | ||
@@ -210,7 +213,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) | |||
210 | unsigned char *ptr; | 213 | unsigned char *ptr; |
211 | sense_reason_t rc = TCM_NO_SENSE; | 214 | sense_reason_t rc = TCM_NO_SENSE; |
212 | u32 len = 4; /* Skip over RESERVED area in header */ | 215 | u32 len = 4; /* Skip over RESERVED area in header */ |
213 | int alua_access_state, primary = 0; | 216 | int alua_access_state, primary = 0, valid_states; |
214 | u16 tg_pt_id, rtpi; | 217 | u16 tg_pt_id, rtpi; |
215 | 218 | ||
216 | if (!l_port) | 219 | if (!l_port) |
@@ -252,6 +255,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) | |||
252 | rc = TCM_UNSUPPORTED_SCSI_OPCODE; | 255 | rc = TCM_UNSUPPORTED_SCSI_OPCODE; |
253 | goto out; | 256 | goto out; |
254 | } | 257 | } |
258 | valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; | ||
255 | 259 | ||
256 | ptr = &buf[4]; /* Skip over RESERVED area in header */ | 260 | ptr = &buf[4]; /* Skip over RESERVED area in header */ |
257 | 261 | ||
@@ -263,7 +267,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) | |||
263 | * the state is a primary or secondary target port asymmetric | 267 | * the state is a primary or secondary target port asymmetric |
264 | * access state. | 268 | * access state. |
265 | */ | 269 | */ |
266 | rc = core_alua_check_transition(alua_access_state, &primary); | 270 | rc = core_alua_check_transition(alua_access_state, |
271 | valid_states, &primary); | ||
267 | if (rc) { | 272 | if (rc) { |
268 | /* | 273 | /* |
269 | * If the SET TARGET PORT GROUPS attempts to establish | 274 | * If the SET TARGET PORT GROUPS attempts to establish |
@@ -618,17 +623,31 @@ out: | |||
618 | * Check implicit and explicit ALUA state change request. | 623 | * Check implicit and explicit ALUA state change request. |
619 | */ | 624 | */ |
620 | static sense_reason_t | 625 | static sense_reason_t |
621 | core_alua_check_transition(int state, int *primary) | 626 | core_alua_check_transition(int state, int valid, int *primary) |
622 | { | 627 | { |
628 | /* | ||
629 | * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are | ||
630 | * defined as primary target port asymmetric access states. | ||
631 | */ | ||
623 | switch (state) { | 632 | switch (state) { |
624 | case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: | 633 | case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: |
634 | if (!(valid & ALUA_AO_SUP)) | ||
635 | goto not_supported; | ||
636 | *primary = 1; | ||
637 | break; | ||
625 | case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: | 638 | case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: |
639 | if (!(valid & ALUA_AN_SUP)) | ||
640 | goto not_supported; | ||
641 | *primary = 1; | ||
642 | break; | ||
626 | case ALUA_ACCESS_STATE_STANDBY: | 643 | case ALUA_ACCESS_STATE_STANDBY: |
644 | if (!(valid & ALUA_S_SUP)) | ||
645 | goto not_supported; | ||
646 | *primary = 1; | ||
647 | break; | ||
627 | case ALUA_ACCESS_STATE_UNAVAILABLE: | 648 | case ALUA_ACCESS_STATE_UNAVAILABLE: |
628 | /* | 649 | if (!(valid & ALUA_U_SUP)) |
629 | * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are | 650 | goto not_supported; |
630 | * defined as primary target port asymmetric access states. | ||
631 | */ | ||
632 | *primary = 1; | 651 | *primary = 1; |
633 | break; | 652 | break; |
634 | case ALUA_ACCESS_STATE_OFFLINE: | 653 | case ALUA_ACCESS_STATE_OFFLINE: |
@@ -636,14 +655,27 @@ core_alua_check_transition(int state, int *primary) | |||
636 | * OFFLINE state is defined as a secondary target port | 655 | * OFFLINE state is defined as a secondary target port |
637 | * asymmetric access state. | 656 | * asymmetric access state. |
638 | */ | 657 | */ |
658 | if (!(valid & ALUA_O_SUP)) | ||
659 | goto not_supported; | ||
639 | *primary = 0; | 660 | *primary = 0; |
640 | break; | 661 | break; |
662 | case ALUA_ACCESS_STATE_TRANSITION: | ||
663 | /* | ||
664 | * Transitioning is set internally, and | ||
665 | * cannot be selected manually. | ||
666 | */ | ||
667 | goto not_supported; | ||
641 | default: | 668 | default: |
642 | pr_err("Unknown ALUA access state: 0x%02x\n", state); | 669 | pr_err("Unknown ALUA access state: 0x%02x\n", state); |
643 | return TCM_INVALID_PARAMETER_LIST; | 670 | return TCM_INVALID_PARAMETER_LIST; |
644 | } | 671 | } |
645 | 672 | ||
646 | return 0; | 673 | return 0; |
674 | |||
675 | not_supported: | ||
676 | pr_err("ALUA access state %s not supported", | ||
677 | core_alua_dump_state(state)); | ||
678 | return TCM_INVALID_PARAMETER_LIST; | ||
647 | } | 679 | } |
648 | 680 | ||
649 | static char *core_alua_dump_state(int state) | 681 | static char *core_alua_dump_state(int state) |
@@ -659,6 +691,8 @@ static char *core_alua_dump_state(int state) | |||
659 | return "Unavailable"; | 691 | return "Unavailable"; |
660 | case ALUA_ACCESS_STATE_OFFLINE: | 692 | case ALUA_ACCESS_STATE_OFFLINE: |
661 | return "Offline"; | 693 | return "Offline"; |
694 | case ALUA_ACCESS_STATE_TRANSITION: | ||
695 | return "Transitioning"; | ||
662 | default: | 696 | default: |
663 | return "Unknown"; | 697 | return "Unknown"; |
664 | } | 698 | } |
@@ -884,9 +918,10 @@ int core_alua_do_port_transition( | |||
884 | struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; | 918 | struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; |
885 | struct t10_alua_tg_pt_gp *tg_pt_gp; | 919 | struct t10_alua_tg_pt_gp *tg_pt_gp; |
886 | unsigned char *md_buf; | 920 | unsigned char *md_buf; |
887 | int primary; | 921 | int primary, valid_states; |
888 | 922 | ||
889 | if (core_alua_check_transition(new_state, &primary) != 0) | 923 | valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; |
924 | if (core_alua_check_transition(new_state, valid_states, &primary) != 0) | ||
890 | return -EINVAL; | 925 | return -EINVAL; |
891 | 926 | ||
892 | md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL); | 927 | md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL); |