summaryrefslogtreecommitdiff
path: root/drivers/target/target_core_alua.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target/target_core_alua.c')
-rw-r--r--drivers/target/target_core_alua.c236
1 files changed, 106 insertions, 130 deletions
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 6b0d9beacf90..10250aca5a81 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
* Filename: target_core_alua.c
*
@@ -7,20 +8,6 @@
*
* Nicholas A. Bellinger <nab@kernel.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
******************************************************************************/
#include <linux/slab.h>
@@ -32,7 +19,7 @@
#include <linux/file.h>
#include <linux/fs.h>
#include <scsi/scsi_proto.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <target/target_core_base.h>
#include <target/target_core_backend.h>
@@ -136,7 +123,7 @@ target_emulate_report_referrals(struct se_cmd *cmd)
transport_kunmap_data_sg(cmd);
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
@@ -177,6 +164,9 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
spin_lock(&dev->t10_alua.tg_pt_gps_lock);
list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
tg_pt_gp_list) {
+ /* Skip empty port groups */
+ if (!tg_pt_gp->tg_pt_gp_members)
+ continue;
/*
* Check if the Target port group and Target port descriptor list
* based on tg_pt_gp_members count will fit into the response payload.
@@ -235,7 +225,7 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
/*
* Set RELATIVE TARGET PORT IDENTIFIER
*/
- put_unaligned_be16(lun->lun_rtpi, &buf[off]);
+ put_unaligned_be16(lun->lun_tpg->tpg_rtpi, &buf[off]);
off += 2;
rd_len += 4;
}
@@ -260,15 +250,15 @@ 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.
*/
- spin_lock(&cmd->se_lun->lun_tg_pt_gp_lock);
- tg_pt_gp = cmd->se_lun->lun_tg_pt_gp;
+ rcu_read_lock();
+ tg_pt_gp = rcu_dereference(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);
+ rcu_read_unlock();
}
transport_kunmap_data_sg(cmd);
- target_complete_cmd_with_length(cmd, GOOD, rd_len + 4);
+ target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, rd_len + 4);
return 0;
}
@@ -305,24 +295,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.
*/
- spin_lock(&l_lun->lun_tg_pt_gp_lock);
- l_tg_pt_gp = l_lun->lun_tg_pt_gp;
+ rcu_read_lock();
+ l_tg_pt_gp = rcu_dereference(l_lun->lun_tg_pt_gp);
if (!l_tg_pt_gp) {
- spin_unlock(&l_lun->lun_tg_pt_gp_lock);
+ rcu_read_unlock();
pr_err("Unable to access l_lun->tg_pt_gp\n");
rc = TCM_UNSUPPORTED_SCSI_OPCODE;
goto out;
}
if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) {
- spin_unlock(&l_lun->lun_tg_pt_gp_lock);
+ rcu_read_unlock();
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);
+ rcu_read_unlock();
ptr = &buf[4]; /* Skip over RESERVED area in header */
@@ -398,7 +388,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
/*
* Extract the RELATIVE TARGET PORT IDENTIFIER to identify
- * the Target Port in question for the the incoming
+ * the Target Port in question for the incoming
* SET_TARGET_PORT_GROUPS op.
*/
rtpi = get_unaligned_be16(ptr + 2);
@@ -409,7 +399,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
spin_lock(&dev->se_port_lock);
list_for_each_entry(lun, &dev->dev_sep_list,
lun_dev_link) {
- if (lun->lun_rtpi != rtpi)
+ if (lun->lun_tpg->tpg_rtpi != rtpi)
continue;
// XXX: racy unlock
@@ -437,26 +427,10 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
out:
transport_kunmap_data_sg(cmd);
if (!rc)
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return rc;
}
-static inline void set_ascq(struct se_cmd *cmd, u8 alua_ascq)
-{
- /*
- * Set SCSI additional sense code (ASC) to 'LUN Not Accessible';
- * The ALUA additional sense code qualifier (ASCQ) is determined
- * by the ALUA primary or secondary access state..
- */
- pr_debug("[%s]: ALUA TG Port not available, "
- "SenseKey: NOT_READY, ASC/ASCQ: "
- "0x04/0x%02x\n",
- cmd->se_tfo->fabric_name, alua_ascq);
-
- cmd->scsi_asc = 0x04;
- cmd->scsi_ascq = alua_ascq;
-}
-
static inline void core_alua_state_nonoptimized(
struct se_cmd *cmd,
unsigned char *cdb,
@@ -471,9 +445,9 @@ static inline void core_alua_state_nonoptimized(
cmd->alua_nonop_delay = nonop_delay_msecs;
}
-static inline int core_alua_state_lba_dependent(
+static inline sense_reason_t core_alua_state_lba_dependent(
struct se_cmd *cmd,
- struct t10_alua_tg_pt_gp *tg_pt_gp)
+ u16 tg_pt_gp_id)
{
struct se_device *dev = cmd->se_dev;
u64 segment_size, segment_mult, sectors, lba;
@@ -519,23 +493,19 @@ static inline int core_alua_state_lba_dependent(
}
if (!cur_map) {
spin_unlock(&dev->t10_alua.lba_map_lock);
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
- return 1;
+ return TCM_ALUA_TG_PT_UNAVAILABLE;
}
list_for_each_entry(map_mem, &cur_map->lba_map_mem_list,
lba_map_mem_list) {
- if (map_mem->lba_map_mem_alua_pg_id !=
- tg_pt_gp->tg_pt_gp_id)
+ if (map_mem->lba_map_mem_alua_pg_id != tg_pt_gp_id)
continue;
switch(map_mem->lba_map_mem_alua_state) {
case ALUA_ACCESS_STATE_STANDBY:
spin_unlock(&dev->t10_alua.lba_map_lock);
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY);
- return 1;
+ return TCM_ALUA_TG_PT_STANDBY;
case ALUA_ACCESS_STATE_UNAVAILABLE:
spin_unlock(&dev->t10_alua.lba_map_lock);
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
- return 1;
+ return TCM_ALUA_TG_PT_UNAVAILABLE;
default:
break;
}
@@ -545,7 +515,7 @@ static inline int core_alua_state_lba_dependent(
return 0;
}
-static inline int core_alua_state_standby(
+static inline sense_reason_t core_alua_state_standby(
struct se_cmd *cmd,
unsigned char *cdb)
{
@@ -569,24 +539,21 @@ static inline int core_alua_state_standby(
case SAI_READ_CAPACITY_16:
return 0;
default:
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY);
- return 1;
+ return TCM_ALUA_TG_PT_STANDBY;
}
case MAINTENANCE_IN:
switch (cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
return 0;
default:
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY);
- return 1;
+ return TCM_ALUA_TG_PT_STANDBY;
}
case MAINTENANCE_OUT:
switch (cdb[1]) {
case MO_SET_TARGET_PGS:
return 0;
default:
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY);
- return 1;
+ return TCM_ALUA_TG_PT_STANDBY;
}
case REQUEST_SENSE:
case PERSISTENT_RESERVE_IN:
@@ -595,14 +562,13 @@ static inline int core_alua_state_standby(
case WRITE_BUFFER:
return 0;
default:
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_STANDBY);
- return 1;
+ return TCM_ALUA_TG_PT_STANDBY;
}
return 0;
}
-static inline int core_alua_state_unavailable(
+static inline sense_reason_t core_alua_state_unavailable(
struct se_cmd *cmd,
unsigned char *cdb)
{
@@ -619,30 +585,27 @@ static inline int core_alua_state_unavailable(
case MI_REPORT_TARGET_PGS:
return 0;
default:
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
- return 1;
+ return TCM_ALUA_TG_PT_UNAVAILABLE;
}
case MAINTENANCE_OUT:
switch (cdb[1]) {
case MO_SET_TARGET_PGS:
return 0;
default:
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
- return 1;
+ return TCM_ALUA_TG_PT_UNAVAILABLE;
}
case REQUEST_SENSE:
case READ_BUFFER:
case WRITE_BUFFER:
return 0;
default:
- set_ascq(cmd, ASCQ_04H_ALUA_TG_PT_UNAVAILABLE);
- return 1;
+ return TCM_ALUA_TG_PT_UNAVAILABLE;
}
return 0;
}
-static inline int core_alua_state_transition(
+static inline sense_reason_t core_alua_state_transition(
struct se_cmd *cmd,
unsigned char *cdb)
{
@@ -659,16 +622,14 @@ static inline int core_alua_state_transition(
case MI_REPORT_TARGET_PGS:
return 0;
default:
- set_ascq(cmd, ASCQ_04H_ALUA_STATE_TRANSITION);
- return 1;
+ return TCM_ALUA_STATE_TRANSITION;
}
case REQUEST_SENSE:
case READ_BUFFER:
case WRITE_BUFFER:
return 0;
default:
- set_ascq(cmd, ASCQ_04H_ALUA_STATE_TRANSITION);
- return 1;
+ return TCM_ALUA_STATE_TRANSITION;
}
return 0;
@@ -687,10 +648,12 @@ target_alua_state_check(struct se_cmd *cmd)
struct se_lun *lun = cmd->se_lun;
struct t10_alua_tg_pt_gp *tg_pt_gp;
int out_alua_state, nonop_delay_msecs;
+ u16 tg_pt_gp_id;
+ sense_reason_t rc = TCM_NO_SENSE;
if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)
return 0;
- if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA)
+ if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA)
return 0;
/*
@@ -700,20 +663,19 @@ target_alua_state_check(struct se_cmd *cmd)
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;
+ return TCM_ALUA_OFFLINE;
}
-
- if (!lun->lun_tg_pt_gp)
+ rcu_read_lock();
+ tg_pt_gp = rcu_dereference(lun->lun_tg_pt_gp);
+ if (!tg_pt_gp) {
+ rcu_read_unlock();
return 0;
+ }
- spin_lock(&lun->lun_tg_pt_gp_lock);
- tg_pt_gp = lun->lun_tg_pt_gp;
out_alua_state = tg_pt_gp->tg_pt_gp_alua_access_state;
nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs;
-
- // XXX: keeps using tg_pt_gp witout reference after unlock
- spin_unlock(&lun->lun_tg_pt_gp_lock);
+ tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id;
+ rcu_read_unlock();
/*
* Process ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED in a separate conditional
* statement so the compiler knows explicitly to check this case first.
@@ -728,20 +690,16 @@ target_alua_state_check(struct se_cmd *cmd)
core_alua_state_nonoptimized(cmd, cdb, nonop_delay_msecs);
break;
case ALUA_ACCESS_STATE_STANDBY:
- if (core_alua_state_standby(cmd, cdb))
- return TCM_CHECK_CONDITION_NOT_READY;
+ rc = core_alua_state_standby(cmd, cdb);
break;
case ALUA_ACCESS_STATE_UNAVAILABLE:
- if (core_alua_state_unavailable(cmd, cdb))
- return TCM_CHECK_CONDITION_NOT_READY;
+ rc = core_alua_state_unavailable(cmd, cdb);
break;
case ALUA_ACCESS_STATE_TRANSITION:
- if (core_alua_state_transition(cmd, cdb))
- return TCM_CHECK_CONDITION_NOT_READY;
+ rc = core_alua_state_transition(cmd, cdb);
break;
case ALUA_ACCESS_STATE_LBA_DEPENDENT:
- if (core_alua_state_lba_dependent(cmd, tg_pt_gp))
- return TCM_CHECK_CONDITION_NOT_READY;
+ rc = core_alua_state_lba_dependent(cmd, tg_pt_gp_id);
break;
/*
* OFFLINE is a secondary ALUA target port group access state, that is
@@ -751,10 +709,16 @@ target_alua_state_check(struct se_cmd *cmd)
default:
pr_err("Unknown ALUA access state: 0x%02x\n",
out_alua_state);
- return TCM_INVALID_CDB_FIELD;
+ rc = TCM_INVALID_CDB_FIELD;
}
- return 0;
+ if (rc && rc != TCM_INVALID_CDB_FIELD) {
+ pr_debug("[%s]: ALUA TG Port not available, "
+ "SenseKey: NOT_READY, ASC/rc: 0x04/%d\n",
+ cmd->se_tfo->fabric_name, rc);
+ }
+
+ return rc;
}
/*
@@ -873,8 +837,6 @@ int core_alua_check_nonop_delay(
{
if (!(cmd->se_cmd_flags & SCF_ALUA_NON_OPTIMIZED))
return 0;
- if (in_interrupt())
- return 0;
/*
* The ALUA Active/NonOptimized access state delay can be disabled
* in via configfs with a value of zero
@@ -888,7 +850,6 @@ int core_alua_check_nonop_delay(
msleep_interruptible(cmd->alua_nonop_delay);
return 0;
}
-EXPORT_SYMBOL(core_alua_check_nonop_delay);
static int core_alua_write_tpg_metadata(
const char *path,
@@ -910,9 +871,6 @@ static int core_alua_write_tpg_metadata(
return (ret < 0) ? -EIO : 0;
}
-/*
- * Called with tg_pt_gp->tg_pt_gp_transition_mutex held
- */
static int core_alua_update_tpg_primary_metadata(
struct t10_alua_tg_pt_gp *tg_pt_gp)
{
@@ -921,6 +879,8 @@ static int core_alua_update_tpg_primary_metadata(
char *path;
int len, rc;
+ lockdep_assert_held(&tg_pt_gp->tg_pt_gp_transition_mutex);
+
md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL);
if (!md_buf) {
pr_err("Unable to allocate buf for ALUA metadata\n");
@@ -976,8 +936,7 @@ static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp)
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));
+ lacl = se_deve->se_lun_acl;
/*
* spc4r37 p.242:
@@ -1104,7 +1063,7 @@ int core_alua_do_port_transition(
struct t10_alua_tg_pt_gp *tg_pt_gp;
int primary, valid_states, rc = 0;
- if (l_dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA)
+ if (l_dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA)
return -ENODEV;
valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
@@ -1261,10 +1220,10 @@ static int core_alua_set_tg_pt_secondary_state(
struct t10_alua_tg_pt_gp *tg_pt_gp;
int trans_delay_msecs;
- spin_lock(&lun->lun_tg_pt_gp_lock);
- tg_pt_gp = lun->lun_tg_pt_gp;
+ rcu_read_lock();
+ tg_pt_gp = rcu_dereference(lun->lun_tg_pt_gp);
if (!tg_pt_gp) {
- spin_unlock(&lun->lun_tg_pt_gp_lock);
+ rcu_read_unlock();
pr_err("Unable to complete secondary state"
" transition\n");
return -EINVAL;
@@ -1288,7 +1247,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(&lun->lun_tg_pt_gp_lock);
+ rcu_read_unlock();
/*
* Do the optional transition delay after we set the secondary
* ALUA access state.
@@ -1716,7 +1675,6 @@ int core_alua_set_tg_pt_gp_id(
pr_err("Maximum ALUA alua_tg_pt_gps_count:"
" 0x0000ffff reached\n");
spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
- kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
return -ENOSPC;
}
again:
@@ -1761,8 +1719,10 @@ void core_alua_free_tg_pt_gp(
* can be made while we are releasing struct t10_alua_tg_pt_gp.
*/
spin_lock(&dev->t10_alua.tg_pt_gps_lock);
- list_del(&tg_pt_gp->tg_pt_gp_list);
- dev->t10_alua.alua_tg_pt_gps_counter--;
+ if (tg_pt_gp->tg_pt_gp_valid_id) {
+ list_del(&tg_pt_gp->tg_pt_gp_list);
+ dev->t10_alua.alua_tg_pt_gps_count--;
+ }
spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
/*
@@ -1795,13 +1755,14 @@ void core_alua_free_tg_pt_gp(
__target_attach_tg_pt_gp(lun,
dev->t10_alua.default_tg_pt_gp);
} else
- lun->lun_tg_pt_gp = NULL;
+ rcu_assign_pointer(lun->lun_tg_pt_gp, NULL);
spin_unlock(&lun->lun_tg_pt_gp_lock);
spin_lock(&tg_pt_gp->tg_pt_gp_lock);
}
spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ synchronize_rcu();
kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
}
@@ -1846,7 +1807,7 @@ static void __target_attach_tg_pt_gp(struct se_lun *lun,
assert_spin_locked(&lun->lun_tg_pt_gp_lock);
spin_lock(&tg_pt_gp->tg_pt_gp_lock);
- lun->lun_tg_pt_gp = tg_pt_gp;
+ rcu_assign_pointer(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);
@@ -1863,6 +1824,7 @@ void target_attach_tg_pt_gp(struct se_lun *lun,
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);
+ synchronize_rcu();
}
static void __target_detach_tg_pt_gp(struct se_lun *lun,
@@ -1874,8 +1836,6 @@ static void __target_detach_tg_pt_gp(struct se_lun *lun,
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;
}
void target_detach_tg_pt_gp(struct se_lun *lun)
@@ -1883,10 +1843,25 @@ 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)
+ tg_pt_gp = rcu_dereference_check(lun->lun_tg_pt_gp,
+ lockdep_is_held(&lun->lun_tg_pt_gp_lock));
+ if (tg_pt_gp) {
__target_detach_tg_pt_gp(lun, tg_pt_gp);
+ rcu_assign_pointer(lun->lun_tg_pt_gp, NULL);
+ }
spin_unlock(&lun->lun_tg_pt_gp_lock);
+ synchronize_rcu();
+}
+
+static void target_swap_tg_pt_gp(struct se_lun *lun,
+ struct t10_alua_tg_pt_gp *old_tg_pt_gp,
+ struct t10_alua_tg_pt_gp *new_tg_pt_gp)
+{
+ assert_spin_locked(&lun->lun_tg_pt_gp_lock);
+
+ if (old_tg_pt_gp)
+ __target_detach_tg_pt_gp(lun, old_tg_pt_gp);
+ __target_attach_tg_pt_gp(lun, new_tg_pt_gp);
}
ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page)
@@ -1895,8 +1870,8 @@ ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page)
struct t10_alua_tg_pt_gp *tg_pt_gp;
ssize_t len = 0;
- spin_lock(&lun->lun_tg_pt_gp_lock);
- tg_pt_gp = lun->lun_tg_pt_gp;
+ rcu_read_lock();
+ tg_pt_gp = rcu_dereference(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:"
@@ -1912,7 +1887,7 @@ ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page)
"Offline" : "None",
core_alua_dump_status(lun->lun_tg_pt_secondary_stat));
}
- spin_unlock(&lun->lun_tg_pt_gp_lock);
+ rcu_read_unlock();
return len;
}
@@ -1932,7 +1907,7 @@ ssize_t core_alua_store_tg_pt_gp_info(
unsigned char buf[TG_PT_GROUP_NAME_BUF];
int move = 0;
- if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ||
+ if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ||
(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
return -ENODEV;
@@ -1959,7 +1934,8 @@ ssize_t core_alua_store_tg_pt_gp_info(
}
spin_lock(&lun->lun_tg_pt_gp_lock);
- tg_pt_gp = lun->lun_tg_pt_gp;
+ tg_pt_gp = rcu_dereference_check(lun->lun_tg_pt_gp,
+ lockdep_is_held(&lun->lun_tg_pt_gp_lock));
if (tg_pt_gp) {
/*
* Clearing an existing tg_pt_gp association, and replacing
@@ -1977,18 +1953,16 @@ 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);
- __target_detach_tg_pt_gp(lun, tg_pt_gp);
- __target_attach_tg_pt_gp(lun,
+ target_swap_tg_pt_gp(lun, tg_pt_gp,
dev->t10_alua.default_tg_pt_gp);
spin_unlock(&lun->lun_tg_pt_gp_lock);
- return count;
+ goto sync_rcu;
}
- __target_detach_tg_pt_gp(lun, tg_pt_gp);
move = 1;
}
- __target_attach_tg_pt_gp(lun, tg_pt_gp_new);
+ target_swap_tg_pt_gp(lun, tg_pt_gp, 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) ?
@@ -1999,6 +1973,8 @@ ssize_t core_alua_store_tg_pt_gp_info(
tg_pt_gp_new->tg_pt_gp_id);
core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new);
+sync_rcu:
+ synchronize_rcu();
return count;
}
@@ -2189,7 +2165,7 @@ ssize_t core_alua_store_offline_bit(
unsigned long tmp;
int ret;
- if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ||
+ if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ||
(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
return -ENODEV;
@@ -2275,7 +2251,7 @@ ssize_t core_alua_store_secondary_write_metadata(
int core_setup_alua(struct se_device *dev)
{
- if (!(dev->transport->transport_flags &
+ if (!(dev->transport_flags &
TRANSPORT_FLAG_PASSTHROUGH_ALUA) &&
!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) {
struct t10_alua_lu_gp_member *lu_gp_mem;