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); |
