Commit adf653f9 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Nicholas Bellinger
Browse files

target: Subsume se_port + t10_alua_tg_pt_gp_member into se_lun



This patch eliminates all se_port + t10_alua_tg_pt_gp_member usage,
and converts current users to direct se_lun pointer dereference.

This includes the removal of core_export_port(), core_release_port()
core_dev_export() and core_dev_unexport().  Along with conversion
of special case se_lun pointer dereference within PR ALL_TG_PT=1
and ALUA access state transition UNIT_ATTENTION handling.

Also, update core_enable_device_list_for_node() to reference the
new per se_lun->lun_deve_list when creating a new entry, or
replacing an existing one via RCU.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent b3eeea66
Loading
Loading
Loading
Loading
+148 −246
Original line number Diff line number Diff line
@@ -43,11 +43,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 +147,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 +223,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 +234,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 +259,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;
		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(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
		}
		spin_unlock(&cmd->se_lun->lun_tg_pt_gp_lock);
	}
	transport_kunmap_data_sg(cmd);

@@ -284,10 +280,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 +290,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 +304,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 +383,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 +393,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 +406,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 +684,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 +692,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 +744,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 +886,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,
@@ -971,16 +947,14 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *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,14 +969,13 @@ 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);
		atomic_inc_mb(&lun->lun_active);
		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) {
		spin_lock_bh(&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(&port->sep_alua_lock));
					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
@@ -1014,18 +987,18 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
			     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,
				ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED);
		}
		spin_unlock_bh(&port->sep_alua_lock);
		spin_unlock_bh(&lun->lun_deve_lock);

		spin_lock(&tg_pt_gp->tg_pt_gp_lock);
		atomic_dec_mb(&mem->tg_pt_gp_mem_ref_cnt);
		atomic_dec_mb(&lun->lun_active);
	}
	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
	/*
@@ -1143,7 +1116,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)
@@ -1173,7 +1146,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);
@@ -1212,10 +1185,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);
@@ -1252,22 +1225,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);
@@ -1282,32 +1253,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",
			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;
@@ -1315,14 +1287,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;

@@ -1331,7 +1303,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.
@@ -1342,11 +1314,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;
}
@@ -1700,7 +1669,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);
@@ -1794,32 +1763,11 @@ int core_alua_set_tg_pt_gp_id(
	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
@@ -1850,30 +1798,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);
	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--;
			tg_pt_gp_mem->tg_pt_gp_assoc = 0;
		}

		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);
	}
@@ -1882,35 +1824,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)
{
@@ -1944,50 +1857,58 @@ 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,
static void __target_attach_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);
	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_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,
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:"
@@ -1999,34 +1920,29 @@ 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;
	struct se_device *dev = 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");
@@ -2050,8 +1966,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
@@ -2069,24 +1985,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),
@@ -2269,11 +2180,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(
@@ -2281,11 +2189,12 @@ ssize_t core_alua_store_offline_bit(
	const char *page,
	size_t count)
{
	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
	struct se_device *dev = 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);
@@ -2298,14 +2207,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;

@@ -2316,7 +2219,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(
@@ -2339,7 +2242,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;
}
@@ -2348,8 +2251,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(
@@ -2370,7 +2272,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;
}
+5 −9

File changed.

Preview size limit exceeded, changes collapsed.

+3 −8
Original line number Diff line number Diff line
@@ -2889,21 +2889,16 @@ static ssize_t target_core_alua_tg_pt_gp_show_attr_members(
	struct t10_alua_tg_pt_gp *tg_pt_gp,
	char *page)
{
	struct se_port *port;
	struct se_portal_group *tpg;
	struct se_lun *lun;
	struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
	ssize_t len = 0, cur_len;
	unsigned char buf[TG_PT_GROUP_NAME_BUF];

	memset(buf, 0, TG_PT_GROUP_NAME_BUF);

	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;
		tpg = port->sep_tpg;
		lun = port->sep_lun;
	list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list,
			lun_tg_pt_gp_link) {
		struct se_portal_group *tpg = lun->lun_tpg;

		cur_len = snprintf(buf, TG_PT_GROUP_NAME_BUF, "%s/%s/tpgt_%hu"
			"/%s\n", tpg->se_tpg_tfo->get_fabric_name(),
+29 −150

File changed.

Preview size limit exceeded, changes collapsed.

+15 −17

File changed.

Preview size limit exceeded, changes collapsed.

Loading