diff options
Diffstat (limited to 'drivers/target/target_core_alua.c')
-rw-r--r-- | drivers/target/target_core_alua.c | 463 |
1 files changed, 200 insertions, 263 deletions
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 8ca373774276..49aba4a31747 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -34,7 +34,6 @@ #include <target/target_core_base.h> #include <target/target_core_backend.h> #include <target/target_core_fabric.h> -#include <target/target_core_configfs.h> #include "target_core_internal.h" #include "target_core_alua.h" @@ -43,11 +42,13 @@ static sense_reason_t core_alua_check_transition(int state, int valid, int *primary); static int core_alua_set_tg_pt_secondary_state( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port, int explicit, int offline); + struct se_lun *lun, int explicit, int offline); static char *core_alua_dump_state(int state); +static void __target_attach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp); + static u16 alua_lu_gps_counter; static u32 alua_lu_gps_count; @@ -145,9 +146,8 @@ sense_reason_t target_emulate_report_target_port_groups(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_port *port; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + struct se_lun *lun; unsigned char *buf; u32 rd_len = 0, off; int ext_hdr = (cmd->t_task_cdb[1] & 0x20); @@ -222,9 +222,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) rd_len += 8; spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list, - tg_pt_gp_mem_list) { - port = tg_pt_gp_mem->tg_pt; + list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, + lun_tg_pt_gp_link) { /* * Start Target Port descriptor format * @@ -234,8 +233,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) /* * Set RELATIVE TARGET PORT IDENTIFIER */ - buf[off++] = ((port->sep_rtpi >> 8) & 0xff); - buf[off++] = (port->sep_rtpi & 0xff); + buf[off++] = ((lun->lun_rtpi >> 8) & 0xff); + buf[off++] = (lun->lun_rtpi & 0xff); rd_len += 4; } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); @@ -259,15 +258,11 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) * this CDB was received upon to determine this value individually * for ALUA target port group. */ - port = cmd->se_lun->lun_sep; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (tg_pt_gp_mem) { - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; - if (tg_pt_gp) - buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - } + spin_lock(&cmd->se_lun->lun_tg_pt_gp_lock); + tg_pt_gp = cmd->se_lun->lun_tg_pt_gp; + if (tg_pt_gp) + buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs; + spin_unlock(&cmd->se_lun->lun_tg_pt_gp_lock); } transport_kunmap_data_sg(cmd); @@ -284,10 +279,9 @@ sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_port *port, *l_port = cmd->se_lun->lun_sep; + struct se_lun *l_lun = cmd->se_lun; struct se_node_acl *nacl = cmd->se_sess->se_node_acl; struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem; unsigned char *buf; unsigned char *ptr; sense_reason_t rc = TCM_NO_SENSE; @@ -295,9 +289,6 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) int alua_access_state, primary = 0, valid_states; u16 tg_pt_id, rtpi; - if (!l_port) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - if (cmd->data_length < 4) { pr_warn("SET TARGET PORT GROUPS parameter list length %u too" " small\n", cmd->data_length); @@ -312,29 +303,24 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) * Determine if explicit ALUA via SET_TARGET_PORT_GROUPS is allowed * for the local tg_pt_gp. */ - l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem; - if (!l_tg_pt_gp_mem) { - pr_err("Unable to access l_port->sep_alua_tg_pt_gp_mem\n"); - rc = TCM_UNSUPPORTED_SCSI_OPCODE; - goto out; - } - spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); - l_tg_pt_gp = l_tg_pt_gp_mem->tg_pt_gp; + spin_lock(&l_lun->lun_tg_pt_gp_lock); + l_tg_pt_gp = l_lun->lun_tg_pt_gp; if (!l_tg_pt_gp) { - spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); - pr_err("Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n"); + spin_unlock(&l_lun->lun_tg_pt_gp_lock); + pr_err("Unable to access l_lun->tg_pt_gp\n"); rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } - spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) { + spin_unlock(&l_lun->lun_tg_pt_gp_lock); pr_debug("Unable to process SET_TARGET_PORT_GROUPS" " while TPGS_EXPLICIT_ALUA is disabled\n"); rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; + spin_unlock(&l_lun->lun_tg_pt_gp_lock); ptr = &buf[4]; /* Skip over RESERVED area in header */ @@ -396,7 +382,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) spin_unlock(&dev->t10_alua.tg_pt_gps_lock); if (!core_alua_do_port_transition(tg_pt_gp, - dev, l_port, nacl, + dev, l_lun, nacl, alua_access_state, 1)) found = true; @@ -406,6 +392,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) } spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } else { + struct se_lun *lun; + /* * Extract the RELATIVE TARGET PORT IDENTIFIER to identify * the Target Port in question for the the incoming @@ -417,17 +405,16 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) * for the struct se_device storage object. */ spin_lock(&dev->se_port_lock); - list_for_each_entry(port, &dev->dev_sep_list, - sep_list) { - if (port->sep_rtpi != rtpi) + list_for_each_entry(lun, &dev->dev_sep_list, + lun_dev_link) { + if (lun->lun_rtpi != rtpi) continue; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - + // XXX: racy unlock spin_unlock(&dev->se_port_lock); if (!core_alua_set_tg_pt_secondary_state( - tg_pt_gp_mem, port, 1, 1)) + lun, 1, 1)) found = true; spin_lock(&dev->se_port_lock); @@ -696,9 +683,7 @@ target_alua_state_check(struct se_cmd *cmd) struct se_device *dev = cmd->se_dev; unsigned char *cdb = cmd->t_task_cdb; struct se_lun *lun = cmd->se_lun; - struct se_port *port = lun->lun_sep; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; int out_alua_state, nonop_delay_msecs; if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) @@ -706,33 +691,27 @@ target_alua_state_check(struct se_cmd *cmd) if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; - if (!port) - return 0; /* * First, check for a struct se_port specific secondary ALUA target port * access state: OFFLINE */ - if (atomic_read(&port->sep_tg_pt_secondary_offline)) { + if (atomic_read(&lun->lun_tg_pt_secondary_offline)) { pr_debug("ALUA: Got secondary offline status for local" " target port\n"); set_ascq(cmd, ASCQ_04H_ALUA_OFFLINE); return TCM_CHECK_CONDITION_NOT_READY; } - /* - * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the - * ALUA target port group, to obtain current ALUA access state. - * Otherwise look for the underlying struct se_device association with - * a ALUA logical unit group. - */ - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) + + if (!lun->lun_tg_pt_gp) return 0; - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + // XXX: keeps using tg_pt_gp witout reference after unlock + spin_unlock(&lun->lun_tg_pt_gp_lock); /* * Process ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED in a separate conditional * statement so the compiler knows explicitly to check this case first. @@ -764,7 +743,7 @@ target_alua_state_check(struct se_cmd *cmd) break; /* * OFFLINE is a secondary ALUA target port group access state, that is - * handled above with struct se_port->sep_tg_pt_secondary_offline=1 + * handled above with struct se_lun->lun_tg_pt_secondary_offline=1 */ case ALUA_ACCESS_STATE_OFFLINE: default: @@ -906,10 +885,6 @@ int core_alua_check_nonop_delay( } EXPORT_SYMBOL(core_alua_check_nonop_delay); -/* - * Called with tg_pt_gp->tg_pt_gp_md_mutex or tg_pt_gp_mem->sep_tg_pt_md_mutex - * - */ static int core_alua_write_tpg_metadata( const char *path, unsigned char *md_buf, @@ -965,22 +940,15 @@ static int core_alua_update_tpg_primary_metadata( return rc; } -static void core_alua_do_transition_tg_pt_work(struct work_struct *work) +static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp) { - struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(work, - struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work); - struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; struct se_dev_entry *se_deve; + struct se_lun *lun; struct se_lun_acl *lacl; - struct se_port *port; - struct t10_alua_tg_pt_gp_member *mem; - bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status == - ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry(mem, &tg_pt_gp->tg_pt_gp_mem_list, - tg_pt_gp_mem_list) { - port = mem->tg_pt; + list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, + lun_tg_pt_gp_link) { /* * After an implicit target port asymmetric access state * change, a device server shall establish a unit attention @@ -995,38 +963,58 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) * every I_T nexus other than the I_T nexus on which the SET * TARGET PORT GROUPS command */ - atomic_inc_mb(&mem->tg_pt_gp_mem_ref_cnt); + if (!percpu_ref_tryget_live(&lun->lun_ref)) + continue; spin_unlock(&tg_pt_gp->tg_pt_gp_lock); - spin_lock_bh(&port->sep_alua_lock); - list_for_each_entry(se_deve, &port->sep_alua_list, - alua_port_list) { - lacl = se_deve->se_lun_acl; + spin_lock(&lun->lun_deve_lock); + list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) { + lacl = rcu_dereference_check(se_deve->se_lun_acl, + lockdep_is_held(&lun->lun_deve_lock)); + /* - * se_deve->se_lun_acl pointer may be NULL for a - * entry created without explicit Node+MappedLUN ACLs + * spc4r37 p.242: + * After an explicit target port asymmetric access + * state change, a device server shall establish a + * unit attention condition with the additional sense + * code set to ASYMMETRIC ACCESS STATE CHANGED for + * the initiator port associated with every I_T nexus + * other than the I_T nexus on which the SET TARGET + * PORT GROUPS command was received. */ - if (!lacl) - continue; - if ((tg_pt_gp->tg_pt_gp_alua_access_status == ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) && - (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) && - (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl) && - (tg_pt_gp->tg_pt_gp_alua_port != NULL) && - (tg_pt_gp->tg_pt_gp_alua_port == port)) + (tg_pt_gp->tg_pt_gp_alua_lun != NULL) && + (tg_pt_gp->tg_pt_gp_alua_lun == lun)) continue; - core_scsi3_ua_allocate(lacl->se_lun_nacl, - se_deve->mapped_lun, 0x2A, + /* + * se_deve->se_lun_acl pointer may be NULL for a + * entry created without explicit Node+MappedLUN ACLs + */ + if (lacl && (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) && + (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl)) + continue; + + core_scsi3_ua_allocate(se_deve, 0x2A, ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED); } - spin_unlock_bh(&port->sep_alua_lock); + spin_unlock(&lun->lun_deve_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - atomic_dec_mb(&mem->tg_pt_gp_mem_ref_cnt); + percpu_ref_put(&lun->lun_ref); } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); +} + +static void core_alua_do_transition_tg_pt_work(struct work_struct *work) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(work, + struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work); + struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; + bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status == + ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG); + /* * Update the ALUA metadata buf that has been allocated in * core_alua_do_port_transition(), this metadata will be written @@ -1056,6 +1044,9 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) tg_pt_gp->tg_pt_gp_id, core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_previous_state), core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_pending_state)); + + core_alua_queue_state_change_ua(tg_pt_gp); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); spin_unlock(&dev->t10_alua.tg_pt_gps_lock); @@ -1108,6 +1099,8 @@ static int core_alua_do_transition_tg_pt( ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; + core_alua_queue_state_change_ua(tg_pt_gp); + /* * Check for the optional ALUA primary state transition delay */ @@ -1142,7 +1135,7 @@ static int core_alua_do_transition_tg_pt( int core_alua_do_port_transition( struct t10_alua_tg_pt_gp *l_tg_pt_gp, struct se_device *l_dev, - struct se_port *l_port, + struct se_lun *l_lun, struct se_node_acl *l_nacl, int new_state, int explicit) @@ -1172,7 +1165,7 @@ int core_alua_do_port_transition( * core_alua_do_transition_tg_pt() will always return * success. */ - l_tg_pt_gp->tg_pt_gp_alua_port = l_port; + l_tg_pt_gp->tg_pt_gp_alua_lun = l_lun; l_tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl; rc = core_alua_do_transition_tg_pt(l_tg_pt_gp, new_state, explicit); @@ -1211,10 +1204,10 @@ int core_alua_do_port_transition( continue; if (l_tg_pt_gp == tg_pt_gp) { - tg_pt_gp->tg_pt_gp_alua_port = l_port; + tg_pt_gp->tg_pt_gp_alua_lun = l_lun; tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl; } else { - tg_pt_gp->tg_pt_gp_alua_port = NULL; + tg_pt_gp->tg_pt_gp_alua_lun = NULL; tg_pt_gp->tg_pt_gp_alua_nacl = NULL; } atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt); @@ -1251,22 +1244,20 @@ int core_alua_do_port_transition( return rc; } -/* - * Called with tg_pt_gp_mem->sep_tg_pt_md_mutex held - */ -static int core_alua_update_tpg_secondary_metadata( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port) +static int core_alua_update_tpg_secondary_metadata(struct se_lun *lun) { + struct se_portal_group *se_tpg = lun->lun_tpg; unsigned char *md_buf; - struct se_portal_group *se_tpg = port->sep_tpg; char path[ALUA_METADATA_PATH_LEN], wwn[ALUA_SECONDARY_METADATA_WWN_LEN]; int len, rc; + mutex_lock(&lun->lun_tg_pt_md_mutex); + md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL); if (!md_buf) { pr_err("Unable to allocate buf for ALUA metadata\n"); - return -ENOMEM; + rc = -ENOMEM; + goto out_unlock; } memset(path, 0, ALUA_METADATA_PATH_LEN); @@ -1281,32 +1272,33 @@ static int core_alua_update_tpg_secondary_metadata( len = snprintf(md_buf, ALUA_MD_BUF_LEN, "alua_tg_pt_offline=%d\n" "alua_tg_pt_status=0x%02x\n", - atomic_read(&port->sep_tg_pt_secondary_offline), - port->sep_tg_pt_secondary_stat); + atomic_read(&lun->lun_tg_pt_secondary_offline), + lun->lun_tg_pt_secondary_stat); - snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%u", + snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%llu", se_tpg->se_tpg_tfo->get_fabric_name(), wwn, - port->sep_lun->unpacked_lun); + lun->unpacked_lun); rc = core_alua_write_tpg_metadata(path, md_buf, len); kfree(md_buf); +out_unlock: + mutex_unlock(&lun->lun_tg_pt_md_mutex); return rc; } static int core_alua_set_tg_pt_secondary_state( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port, + struct se_lun *lun, int explicit, int offline) { struct t10_alua_tg_pt_gp *tg_pt_gp; int trans_delay_msecs; - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (!tg_pt_gp) { - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); pr_err("Unable to complete secondary state" " transition\n"); return -EINVAL; @@ -1314,14 +1306,14 @@ static int core_alua_set_tg_pt_secondary_state( trans_delay_msecs = tg_pt_gp->tg_pt_gp_trans_delay_msecs; /* * Set the secondary ALUA target port access state to OFFLINE - * or release the previously secondary state for struct se_port + * or release the previously secondary state for struct se_lun */ if (offline) - atomic_set(&port->sep_tg_pt_secondary_offline, 1); + atomic_set(&lun->lun_tg_pt_secondary_offline, 1); else - atomic_set(&port->sep_tg_pt_secondary_offline, 0); + atomic_set(&lun->lun_tg_pt_secondary_offline, 0); - port->sep_tg_pt_secondary_stat = (explicit) ? + lun->lun_tg_pt_secondary_stat = (explicit) ? ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; @@ -1330,7 +1322,7 @@ static int core_alua_set_tg_pt_secondary_state( "implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item), tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE"); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); /* * Do the optional transition delay after we set the secondary * ALUA access state. @@ -1341,11 +1333,8 @@ static int core_alua_set_tg_pt_secondary_state( * See if we need to update the ALUA fabric port metadata for * secondary state and status */ - if (port->sep_tg_pt_secondary_write_md) { - mutex_lock(&port->sep_tg_pt_md_mutex); - core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port); - mutex_unlock(&port->sep_tg_pt_md_mutex); - } + if (lun->lun_tg_pt_secondary_write_md) + core_alua_update_tpg_secondary_metadata(lun); return 0; } @@ -1699,7 +1688,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev, return NULL; } INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list); - INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_mem_list); + INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_lun_list); mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex); spin_lock_init(&tg_pt_gp->tg_pt_gp_lock); atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0); @@ -1793,32 +1782,11 @@ again: return 0; } -struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( - struct se_port *port) -{ - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; - - tg_pt_gp_mem = kmem_cache_zalloc(t10_alua_tg_pt_gp_mem_cache, - GFP_KERNEL); - if (!tg_pt_gp_mem) { - pr_err("Unable to allocate struct t10_alua_tg_pt_gp_member\n"); - return ERR_PTR(-ENOMEM); - } - INIT_LIST_HEAD(&tg_pt_gp_mem->tg_pt_gp_mem_list); - spin_lock_init(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - atomic_set(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt, 0); - - tg_pt_gp_mem->tg_pt = port; - port->sep_alua_tg_pt_gp_mem = tg_pt_gp_mem; - - return tg_pt_gp_mem; -} - void core_alua_free_tg_pt_gp( struct t10_alua_tg_pt_gp *tg_pt_gp) { struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *tg_pt_gp_mem_tmp; + struct se_lun *lun, *next; /* * Once we have reached this point, config_item_put() has already @@ -1849,30 +1817,24 @@ void core_alua_free_tg_pt_gp( * struct se_port. */ spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry_safe(tg_pt_gp_mem, tg_pt_gp_mem_tmp, - &tg_pt_gp->tg_pt_gp_mem_list, tg_pt_gp_mem_list) { - if (tg_pt_gp_mem->tg_pt_gp_assoc) { - list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); - tg_pt_gp->tg_pt_gp_members--; - tg_pt_gp_mem->tg_pt_gp_assoc = 0; - } + list_for_each_entry_safe(lun, next, + &tg_pt_gp->tg_pt_gp_lun_list, lun_tg_pt_gp_link) { + list_del_init(&lun->lun_tg_pt_gp_link); + tg_pt_gp->tg_pt_gp_members--; + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); /* - * tg_pt_gp_mem is associated with a single - * se_port->sep_alua_tg_pt_gp_mem, and is released via - * core_alua_free_tg_pt_gp_mem(). - * * If the passed tg_pt_gp does NOT match the default_tg_pt_gp, * assume we want to re-associate a given tg_pt_gp_mem with * default_tg_pt_gp. */ - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_lock(&lun->lun_tg_pt_gp_lock); if (tg_pt_gp != dev->t10_alua.default_tg_pt_gp) { - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, + __target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp); } else - tg_pt_gp_mem->tg_pt_gp = NULL; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + lun->lun_tg_pt_gp = NULL; + spin_unlock(&lun->lun_tg_pt_gp_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); } @@ -1881,35 +1843,6 @@ void core_alua_free_tg_pt_gp( kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp); } -void core_alua_free_tg_pt_gp_mem(struct se_port *port) -{ - struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; - - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return; - - while (atomic_read(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt)) - cpu_relax(); - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; - if (tg_pt_gp) { - spin_lock(&tg_pt_gp->tg_pt_gp_lock); - if (tg_pt_gp_mem->tg_pt_gp_assoc) { - list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); - tg_pt_gp->tg_pt_gp_members--; - tg_pt_gp_mem->tg_pt_gp_assoc = 0; - } - spin_unlock(&tg_pt_gp->tg_pt_gp_lock); - tg_pt_gp_mem->tg_pt_gp = NULL; - } - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - - kmem_cache_free(t10_alua_tg_pt_gp_mem_cache, tg_pt_gp_mem); -} - static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name( struct se_device *dev, const char *name) { @@ -1943,50 +1876,65 @@ static void core_alua_put_tg_pt_gp_from_name( spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } -/* - * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held - */ -void __core_alua_attach_tg_pt_gp_mem( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct t10_alua_tg_pt_gp *tg_pt_gp) +static void __target_attach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp) { + struct se_dev_entry *se_deve; + + assert_spin_locked(&lun->lun_tg_pt_gp_lock); + spin_lock(&tg_pt_gp->tg_pt_gp_lock); - tg_pt_gp_mem->tg_pt_gp = tg_pt_gp; - tg_pt_gp_mem->tg_pt_gp_assoc = 1; - list_add_tail(&tg_pt_gp_mem->tg_pt_gp_mem_list, - &tg_pt_gp->tg_pt_gp_mem_list); + lun->lun_tg_pt_gp = tg_pt_gp; + list_add_tail(&lun->lun_tg_pt_gp_link, &tg_pt_gp->tg_pt_gp_lun_list); tg_pt_gp->tg_pt_gp_members++; + spin_lock(&lun->lun_deve_lock); + list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) + core_scsi3_ua_allocate(se_deve, 0x3f, + ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED); + spin_unlock(&lun->lun_deve_lock); spin_unlock(&tg_pt_gp->tg_pt_gp_lock); } -/* - * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held - */ -static void __core_alua_drop_tg_pt_gp_mem( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct t10_alua_tg_pt_gp *tg_pt_gp) +void target_attach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp) { + spin_lock(&lun->lun_tg_pt_gp_lock); + __target_attach_tg_pt_gp(lun, tg_pt_gp); + spin_unlock(&lun->lun_tg_pt_gp_lock); +} + +static void __target_detach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp) +{ + assert_spin_locked(&lun->lun_tg_pt_gp_lock); + spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); - tg_pt_gp_mem->tg_pt_gp = NULL; - tg_pt_gp_mem->tg_pt_gp_assoc = 0; + list_del_init(&lun->lun_tg_pt_gp_link); tg_pt_gp->tg_pt_gp_members--; spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + + lun->lun_tg_pt_gp = NULL; } -ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page) +void target_detach_tg_pt_gp(struct se_lun *lun) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp; + + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; + if (tg_pt_gp) + __target_detach_tg_pt_gp(lun, tg_pt_gp); + spin_unlock(&lun->lun_tg_pt_gp_lock); +} + +ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page) { struct config_item *tg_pt_ci; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; ssize_t len = 0; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return len; - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (tg_pt_gp) { tg_pt_ci = &tg_pt_gp->tg_pt_gp_group.cg_item; len += sprintf(page, "TG Port Alias: %s\nTG Port Group ID:" @@ -1998,34 +1946,33 @@ ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page) &tg_pt_gp->tg_pt_gp_alua_access_state)), core_alua_dump_status( tg_pt_gp->tg_pt_gp_alua_access_status), - (atomic_read(&port->sep_tg_pt_secondary_offline)) ? + atomic_read(&lun->lun_tg_pt_secondary_offline) ? "Offline" : "None", - core_alua_dump_status(port->sep_tg_pt_secondary_stat)); + core_alua_dump_status(lun->lun_tg_pt_secondary_stat)); } - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); return len; } ssize_t core_alua_store_tg_pt_gp_info( - struct se_port *port, + struct se_lun *lun, const char *page, size_t count) { - struct se_portal_group *tpg; - struct se_lun *lun; - struct se_device *dev = port->sep_lun->lun_se_dev; + struct se_portal_group *tpg = lun->lun_tpg; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; unsigned char buf[TG_PT_GROUP_NAME_BUF]; int move = 0; - tpg = port->sep_tpg; - lun = port->sep_lun; - - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return 0; + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH || + (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + return -ENODEV; if (count > TG_PT_GROUP_NAME_BUF) { pr_err("ALUA Target Port Group alias too large!\n"); @@ -2049,8 +1996,8 @@ ssize_t core_alua_store_tg_pt_gp_info( return -ENODEV; } - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (tg_pt_gp) { /* * Clearing an existing tg_pt_gp association, and replacing @@ -2068,24 +2015,19 @@ ssize_t core_alua_store_tg_pt_gp_info( &tg_pt_gp->tg_pt_gp_group.cg_item), tg_pt_gp->tg_pt_gp_id); - __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp); - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, + __target_detach_tg_pt_gp(lun, tg_pt_gp); + __target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); return count; } - /* - * Removing existing association of tg_pt_gp_mem with tg_pt_gp - */ - __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp); + __target_detach_tg_pt_gp(lun, tg_pt_gp); move = 1; } - /* - * Associate tg_pt_gp_mem with tg_pt_gp_new. - */ - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp_new); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + __target_attach_tg_pt_gp(lun, tg_pt_gp_new); + spin_unlock(&lun->lun_tg_pt_gp_lock); pr_debug("Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA" " Target Port Group: alua/%s, ID: %hu\n", (move) ? "Moving" : "Adding", tpg->se_tpg_tfo->tpg_get_wwn(tpg), @@ -2268,11 +2210,8 @@ ssize_t core_alua_store_preferred_bit( ssize_t core_alua_show_offline_bit(struct se_lun *lun, char *page) { - if (!lun->lun_sep) - return -ENODEV; - return sprintf(page, "%d\n", - atomic_read(&lun->lun_sep->sep_tg_pt_secondary_offline)); + atomic_read(&lun->lun_tg_pt_secondary_offline)); } ssize_t core_alua_store_offline_bit( @@ -2280,11 +2219,16 @@ ssize_t core_alua_store_offline_bit( const char *page, size_t count) { - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); unsigned long tmp; int ret; - if (!lun->lun_sep) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH || + (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) return -ENODEV; ret = kstrtoul(page, 0, &tmp); @@ -2297,14 +2241,8 @@ ssize_t core_alua_store_offline_bit( tmp); return -EINVAL; } - tg_pt_gp_mem = lun->lun_sep->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) { - pr_err("Unable to locate *tg_pt_gp_mem\n"); - return -EINVAL; - } - ret = core_alua_set_tg_pt_secondary_state(tg_pt_gp_mem, - lun->lun_sep, 0, (int)tmp); + ret = core_alua_set_tg_pt_secondary_state(lun, 0, (int)tmp); if (ret < 0) return -EINVAL; @@ -2315,7 +2253,7 @@ ssize_t core_alua_show_secondary_status( struct se_lun *lun, char *page) { - return sprintf(page, "%d\n", lun->lun_sep->sep_tg_pt_secondary_stat); + return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_stat); } ssize_t core_alua_store_secondary_status( @@ -2338,7 +2276,7 @@ ssize_t core_alua_store_secondary_status( tmp); return -EINVAL; } - lun->lun_sep->sep_tg_pt_secondary_stat = (int)tmp; + lun->lun_tg_pt_secondary_stat = (int)tmp; return count; } @@ -2347,8 +2285,7 @@ ssize_t core_alua_show_secondary_write_metadata( struct se_lun *lun, char *page) { - return sprintf(page, "%d\n", - lun->lun_sep->sep_tg_pt_secondary_write_md); + return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_write_md); } ssize_t core_alua_store_secondary_write_metadata( @@ -2369,7 +2306,7 @@ ssize_t core_alua_store_secondary_write_metadata( " %lu\n", tmp); return -EINVAL; } - lun->lun_sep->sep_tg_pt_secondary_write_md = (int)tmp; + lun->lun_tg_pt_secondary_write_md = (int)tmp; return count; } |