Commit bb91c1a087ed29ceb5b25b9c210c6665e13c36eb
Committed by
Nicholas Bellinger
1 parent
340dbf729c
Exists in
master
and in
16 other branches
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>
Showing 1 changed file with 45 additions and 10 deletions Side-by-side Diff
drivers/target/target_core_alua.c
... | ... | @@ -41,11 +41,14 @@ |
41 | 41 | #include "target_core_alua.h" |
42 | 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 | 46 | static int core_alua_set_tg_pt_secondary_state( |
46 | 47 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, |
47 | 48 | struct se_port *port, int explicit, int offline); |
48 | 49 | |
50 | +static char *core_alua_dump_state(int state); | |
51 | + | |
49 | 52 | static u16 alua_lu_gps_counter; |
50 | 53 | static u32 alua_lu_gps_count; |
51 | 54 | |
... | ... | @@ -210,7 +213,7 @@ |
210 | 213 | unsigned char *ptr; |
211 | 214 | sense_reason_t rc = TCM_NO_SENSE; |
212 | 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 | 217 | u16 tg_pt_id, rtpi; |
215 | 218 | |
216 | 219 | if (!l_port) |
... | ... | @@ -252,6 +255,7 @@ |
252 | 255 | rc = TCM_UNSUPPORTED_SCSI_OPCODE; |
253 | 256 | goto out; |
254 | 257 | } |
258 | + valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; | |
255 | 259 | |
256 | 260 | ptr = &buf[4]; /* Skip over RESERVED area in header */ |
257 | 261 | |
... | ... | @@ -263,7 +267,8 @@ |
263 | 267 | * the state is a primary or secondary target port asymmetric |
264 | 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 | 272 | if (rc) { |
268 | 273 | /* |
269 | 274 | * If the SET TARGET PORT GROUPS attempts to establish |
270 | 275 | |
271 | 276 | |
272 | 277 | |
273 | 278 | |
274 | 279 | |
... | ... | @@ -618,17 +623,31 @@ |
618 | 623 | * Check implicit and explicit ALUA state change request. |
619 | 624 | */ |
620 | 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 | 632 | switch (state) { |
624 | 633 | case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: |
634 | + if (!(valid & ALUA_AO_SUP)) | |
635 | + goto not_supported; | |
636 | + *primary = 1; | |
637 | + break; | |
625 | 638 | case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: |
639 | + if (!(valid & ALUA_AN_SUP)) | |
640 | + goto not_supported; | |
641 | + *primary = 1; | |
642 | + break; | |
626 | 643 | case ALUA_ACCESS_STATE_STANDBY: |
644 | + if (!(valid & ALUA_S_SUP)) | |
645 | + goto not_supported; | |
646 | + *primary = 1; | |
647 | + break; | |
627 | 648 | case ALUA_ACCESS_STATE_UNAVAILABLE: |
628 | - /* | |
629 | - * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are | |
630 | - * defined as primary target port asymmetric access states. | |
631 | - */ | |
649 | + if (!(valid & ALUA_U_SUP)) | |
650 | + goto not_supported; | |
632 | 651 | *primary = 1; |
633 | 652 | break; |
634 | 653 | case ALUA_ACCESS_STATE_OFFLINE: |
635 | 654 | |
636 | 655 | |
... | ... | @@ -636,14 +655,27 @@ |
636 | 655 | * OFFLINE state is defined as a secondary target port |
637 | 656 | * asymmetric access state. |
638 | 657 | */ |
658 | + if (!(valid & ALUA_O_SUP)) | |
659 | + goto not_supported; | |
639 | 660 | *primary = 0; |
640 | 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 | 668 | default: |
642 | 669 | pr_err("Unknown ALUA access state: 0x%02x\n", state); |
643 | 670 | return TCM_INVALID_PARAMETER_LIST; |
644 | 671 | } |
645 | 672 | |
646 | 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 | 681 | static char *core_alua_dump_state(int state) |
... | ... | @@ -659,6 +691,8 @@ |
659 | 691 | return "Unavailable"; |
660 | 692 | case ALUA_ACCESS_STATE_OFFLINE: |
661 | 693 | return "Offline"; |
694 | + case ALUA_ACCESS_STATE_TRANSITION: | |
695 | + return "Transitioning"; | |
662 | 696 | default: |
663 | 697 | return "Unknown"; |
664 | 698 | } |
665 | 699 | |
... | ... | @@ -884,9 +918,10 @@ |
884 | 918 | struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; |
885 | 919 | struct t10_alua_tg_pt_gp *tg_pt_gp; |
886 | 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 | 925 | return -EINVAL; |
891 | 926 | |
892 | 927 | md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL); |