diff mbox

[01/12] target: Convert se_node_acl->device_list[] to RCU hlist

Message ID 1431933444.24645.7.camel@haakon3.risingtidesystems.com (mailing list archive)
State New, archived
Headers show

Commit Message

Nicholas A. Bellinger May 18, 2015, 7:17 a.m. UTC
On Sun, 2015-05-17 at 18:51 +0200, Christoph Hellwig wrote:
> On Wed, May 13, 2015 at 01:46:11AM -0700, Nicholas A. Bellinger wrote:
> > Updated to use a mirror lun->lun_rtpi, with the assignment from sep_rtpi
> > occuring in core_dev_export() code.
> 
> From looking at your current tree I suspect freeing the se_port structure
> using kfree_rcu might be a better idea.  Together with dropping the references
> to the se_device from call_rcu context this basically means all pointers
> in struct se_lun are rcu protected which is much safer if you want
> to access struct se_lun under rcu protection, as this avoids having to
> deal with special cases.  Additionally that basically allows you to
> replace lun_sep_lock with rcu_read_lock for anything remotely like
> a fast path.

Here's a first pass at this along with kref + completion conversion for
the special case PR ALL_TGT_PT=1 pointer dereference.

Thanks HCH.

From 3a6e7fffe13050a0d8cb0c668e122e16e0a8b17d Mon Sep 17 00:00:00 2001
From: Nicholas Bellinger <nab@linux-iscsi.org>
Date: Sun, 17 May 2015 23:00:31 -0700
Subject: [PATCH] target: Convert se_lun->lun_sep updater + readers to RCU

Reported-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
 drivers/target/target_core_device.c    |  51 +++----
 drivers/target/target_core_internal.h  |   1 +
 drivers/target/target_core_pr.c        |   8 +-
 drivers/target/target_core_stat.c      | 268 ++++++++++-----------------------
 drivers/target/target_core_transport.c |  48 +++---
 include/target/target_core_base.h      |   4 +-
 6 files changed, 135 insertions(+), 245 deletions(-)

Comments

Christoph Hellwig May 18, 2015, 7:41 a.m. UTC | #1
On Mon, May 18, 2015 at 12:17:24AM -0700, Nicholas A. Bellinger wrote:
> On Sun, 2015-05-17 at 18:51 +0200, Christoph Hellwig wrote:
> > On Wed, May 13, 2015 at 01:46:11AM -0700, Nicholas A. Bellinger wrote:
> > > Updated to use a mirror lun->lun_rtpi, with the assignment from sep_rtpi
> > > occuring in core_dev_export() code.
> > 
> > From looking at your current tree I suspect freeing the se_port structure
> > using kfree_rcu might be a better idea.  Together with dropping the references
> > to the se_device from call_rcu context this basically means all pointers
> > in struct se_lun are rcu protected which is much safer if you want
> > to access struct se_lun under rcu protection, as this avoids having to
> > deal with special cases.  Additionally that basically allows you to
> > replace lun_sep_lock with rcu_read_lock for anything remotely like
> > a fast path.
> 
> Here's a first pass at this along with kref + completion conversion for
> the special case PR ALL_TGT_PT=1 pointer dereference.

Btw, I started hacking up a patch to merge se_port and t10_alua_tg_pt_gp_member
in se_lun, which seems even better as it closes all kinds of other
races.  Can you keep this one back for now, I'll send out that patch
ASAP after finishing some testing.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 2f4c8fa..88dad15 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -452,6 +452,8 @@  static struct se_port *core_alloc_port(struct se_device *dev)
 	atomic_set(&port->sep_tg_pt_secondary_offline, 0);
 	spin_lock_init(&port->sep_alua_lock);
 	mutex_init(&port->sep_tg_pt_md_mutex);
+	kref_init(&port->sep_tg_pt_ref);
+	init_completion(&port->sep_tg_pt_comp);
 
 	spin_lock(&dev->se_port_lock);
 	if (dev->dev_port_count == 0x0000ffff) {
@@ -502,7 +504,7 @@  static void core_export_port(
 	spin_lock(&lun->lun_sep_lock);
 	port->sep_tpg = tpg;
 	port->sep_lun = lun;
-	lun->lun_sep = port;
+	rcu_assign_pointer(lun->lun_sep, port);
 	spin_unlock(&lun->lun_sep_lock);
 
 	list_add_tail(&port->sep_list, &dev->dev_sep_list);
@@ -529,28 +531,6 @@  static void core_export_port(
 	port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFIER */
 }
 
-/*
- *	Called with struct se_device->se_port_lock spinlock held.
- */
-static void core_release_port(struct se_device *dev, struct se_port *port)
-	__releases(&dev->se_port_lock) __acquires(&dev->se_port_lock)
-{
-	/*
-	 * Wait for any port reference for PR ALL_TG_PT=1 operation
-	 * to complete in __core_scsi3_alloc_registration()
-	 */
-	spin_unlock(&dev->se_port_lock);
-	if (atomic_read(&port->sep_tg_pt_ref_cnt))
-		cpu_relax();
-	spin_lock(&dev->se_port_lock);
-
-	core_alua_free_tg_pt_gp_mem(port);
-
-	list_del(&port->sep_list);
-	dev->dev_port_count--;
-	kfree(port);
-}
-
 int core_dev_export(
 	struct se_device *dev,
 	struct se_portal_group *tpg,
@@ -574,31 +554,46 @@  int core_dev_export(
 	return 0;
 }
 
+void target_port_kref_release(struct kref *kref)
+{
+	struct se_port *port = container_of(kref, struct se_port, sep_tg_pt_ref);
+
+	complete(&port->sep_tg_pt_comp);
+}
+
 void core_dev_unexport(
 	struct se_device *dev,
 	struct se_portal_group *tpg,
 	struct se_lun *lun)
 {
 	struct se_hba *hba = dev->se_hba;
-	struct se_port *port = lun->lun_sep;
+	struct se_port *port;
 
 	spin_lock(&lun->lun_sep_lock);
-	if (lun->lun_se_dev == NULL) {
+	port = lun->lun_sep;
+	if (!port) {
 		spin_unlock(&lun->lun_sep_lock);
 		return;
 	}
+	rcu_assign_pointer(lun->lun_sep, NULL);
+	lun->lun_se_dev = NULL;
 	spin_unlock(&lun->lun_sep_lock);
 
+	kref_put(&port->sep_tg_pt_ref, target_port_kref_release);
+	wait_for_completion(&port->sep_tg_pt_comp);
+
+	core_alua_free_tg_pt_gp_mem(port);
+
 	spin_lock(&dev->se_port_lock);
-	core_release_port(dev, port);
+	list_del(&port->sep_list);
+	dev->dev_port_count--;
 	spin_unlock(&dev->se_port_lock);
 
 	spin_lock(&hba->device_lock);
 	dev->export_count--;
 	spin_unlock(&hba->device_lock);
 
-	lun->lun_sep = NULL;
-	lun->lun_se_dev = NULL;
+	kfree_rcu(port, sep_rcu);
 }
 
 static void se_release_vpd_for_dev(struct se_device *dev)
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index beb1c3e..21e5f9e 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -23,6 +23,7 @@  extern struct list_head g_device_list;
 
 struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
 void	target_pr_kref_release(struct kref *);
+void	target_port_kref_release(struct kref *);
 void	core_free_device_list_for_node(struct se_node_acl *,
 		struct se_portal_group *);
 void	core_update_device_list_access(u32, u32, struct se_node_acl *);
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index cee2b31..c53b66c 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -702,7 +702,7 @@  static struct t10_pr_registration *__core_scsi3_alloc_registration(
 	 */
 	spin_lock(&dev->se_port_lock);
 	list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) {
-		atomic_inc_mb(&port->sep_tg_pt_ref_cnt);
+		kref_get(&port->sep_tg_pt_ref);
 		spin_unlock(&dev->se_port_lock);
 
 		spin_lock_bh(&port->sep_alua_lock);
@@ -748,7 +748,7 @@  static struct t10_pr_registration *__core_scsi3_alloc_registration(
 			if (ret < 0) {
 				pr_err("core_scsi3_lunacl_depend"
 						"_item() failed\n");
-				atomic_dec_mb(&port->sep_tg_pt_ref_cnt);
+				kref_put(&port->sep_tg_pt_ref, target_port_kref_release);
 				kref_put(&deve_tmp->pr_kref, target_pr_kref_release);
 				goto out;
 			}
@@ -764,7 +764,7 @@  static struct t10_pr_registration *__core_scsi3_alloc_registration(
 						deve_tmp, deve_tmp->mapped_lun,
 						NULL, sa_res_key, all_tg_pt, aptpl);
 			if (!pr_reg_atp) {
-				atomic_dec_mb(&port->sep_tg_pt_ref_cnt);
+				kref_put(&port->sep_tg_pt_ref, target_port_kref_release);
 				core_scsi3_lunacl_undepend_item(deve_tmp);
 				goto out;
 			}
@@ -776,7 +776,7 @@  static struct t10_pr_registration *__core_scsi3_alloc_registration(
 		spin_unlock_bh(&port->sep_alua_lock);
 
 		spin_lock(&dev->se_port_lock);
-		atomic_dec_mb(&port->sep_tg_pt_ref_cnt);
+		kref_put(&port->sep_tg_pt_ref, target_port_kref_release);
 	}
 	spin_unlock(&dev->se_port_lock);
 
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index 7b7b524..7af692c 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -542,21 +542,9 @@  static ssize_t target_stat_scsi_port_show_attr_inst(
 	struct se_port_stat_grps *pgrps, char *page)
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
-	struct se_port *sep;
 	struct se_device *dev = lun->lun_se_dev;
-	struct se_hba *hba;
-	ssize_t ret;
 
-	spin_lock(&lun->lun_sep_lock);
-	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
-	hba = dev->se_hba;
-	ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index);
-	spin_unlock(&lun->lun_sep_lock);
-	return ret;
+	return snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index);
 }
 DEV_STAT_SCSI_PORT_ATTR_RO(inst);
 
@@ -564,19 +552,9 @@  static ssize_t target_stat_scsi_port_show_attr_dev(
 	struct se_port_stat_grps *pgrps, char *page)
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
-	struct se_port *sep;
 	struct se_device *dev = lun->lun_se_dev;
-	ssize_t ret;
 
-	spin_lock(&lun->lun_sep_lock);
-	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
-	ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);
-	spin_unlock(&lun->lun_sep_lock);
-	return ret;
+	return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);
 }
 DEV_STAT_SCSI_PORT_ATTR_RO(dev);
 
@@ -587,14 +565,15 @@  static ssize_t target_stat_scsi_port_show_attr_indx(
 	struct se_port *sep;
 	ssize_t ret;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
 	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
+		rcu_read_unlock();
 		return -ENODEV;
 	}
 	ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index);
-	spin_unlock(&lun->lun_sep_lock);
+	rcu_read_unlock();
+
 	return ret;
 }
 DEV_STAT_SCSI_PORT_ATTR_RO(indx);
@@ -604,41 +583,16 @@  static ssize_t target_stat_scsi_port_show_attr_role(
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_device *dev = lun->lun_se_dev;
-	struct se_port *sep;
-	ssize_t ret;
 
-	if (!dev)
-		return -ENODEV;
-
-	spin_lock(&lun->lun_sep_lock);
-	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
-	ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index);
-	spin_unlock(&lun->lun_sep_lock);
-	return ret;
+	return snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index);
 }
 DEV_STAT_SCSI_PORT_ATTR_RO(role);
 
 static ssize_t target_stat_scsi_port_show_attr_busy_count(
 	struct se_port_stat_grps *pgrps, char *page)
 {
-	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
-	struct se_port *sep;
-	ssize_t ret;
-
-	spin_lock(&lun->lun_sep_lock);
-	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
 	/* FIXME: scsiPortBusyStatuses  */
-	ret = snprintf(page, PAGE_SIZE, "%u\n", 0);
-	spin_unlock(&lun->lun_sep_lock);
-	return ret;
+	return snprintf(page, PAGE_SIZE, "%u\n", 0);
 }
 DEV_STAT_SCSI_PORT_ATTR_RO(busy_count);
 
@@ -686,20 +640,8 @@  static ssize_t target_stat_scsi_tgt_port_show_attr_inst(
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_device *dev = lun->lun_se_dev;
-	struct se_port *sep;
-	struct se_hba *hba;
-	ssize_t ret;
 
-	spin_lock(&lun->lun_sep_lock);
-	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
-	hba = dev->se_hba;
-	ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index);
-	spin_unlock(&lun->lun_sep_lock);
-	return ret;
+	return snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index);
 }
 DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst);
 
@@ -708,18 +650,8 @@  static ssize_t target_stat_scsi_tgt_port_show_attr_dev(
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_device *dev = lun->lun_se_dev;
-	struct se_port *sep;
-	ssize_t ret;
 
-	spin_lock(&lun->lun_sep_lock);
-	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
-	ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);
-	spin_unlock(&lun->lun_sep_lock);
-	return ret;
+	return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);
 }
 DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev);
 
@@ -728,16 +660,14 @@  static ssize_t target_stat_scsi_tgt_port_show_attr_indx(
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
-	ssize_t ret;
+	ssize_t ret = 0;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
-	ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index);
-	spin_unlock(&lun->lun_sep_lock);
+	if (sep)
+		ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index);
+	rcu_read_unlock();
+
 	return ret;
 }
 DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx);
@@ -748,19 +678,17 @@  static ssize_t target_stat_scsi_tgt_port_show_attr_name(
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
 	struct se_portal_group *tpg;
-	ssize_t ret;
+	ssize_t ret = 0;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
+	if (sep) {
+		tpg = sep->sep_tpg;
+		ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n",
+			tpg->se_tpg_tfo->get_fabric_name(), sep->sep_index);
 	}
-	tpg = sep->sep_tpg;
+	rcu_read_unlock();
 
-	ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n",
-		tpg->se_tpg_tfo->get_fabric_name(), sep->sep_index);
-	spin_unlock(&lun->lun_sep_lock);
 	return ret;
 }
 DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name);
@@ -771,20 +699,18 @@  static ssize_t target_stat_scsi_tgt_port_show_attr_port_index(
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
 	struct se_portal_group *tpg;
-	ssize_t ret;
+	ssize_t ret = 0;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
+	if (sep) {
+		tpg = sep->sep_tpg;
+		ret = snprintf(page, PAGE_SIZE, "%s%s%d\n",
+			tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+",
+			tpg->se_tpg_tfo->tpg_get_tag(tpg));
 	}
-	tpg = sep->sep_tpg;
+	rcu_read_unlock();
 
-	ret = snprintf(page, PAGE_SIZE, "%s%s%d\n",
-		tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+",
-		tpg->se_tpg_tfo->tpg_get_tag(tpg));
-	spin_unlock(&lun->lun_sep_lock);
 	return ret;
 }
 DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index);
@@ -794,17 +720,14 @@  static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds(
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
-	ssize_t ret;
+	ssize_t ret = 0;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
+	if (sep)
+		ret = snprintf(page, PAGE_SIZE, "%llu\n", sep->sep_stats.cmd_pdus);
+	rcu_read_unlock();
 
-	ret = snprintf(page, PAGE_SIZE, "%llu\n", sep->sep_stats.cmd_pdus);
-	spin_unlock(&lun->lun_sep_lock);
 	return ret;
 }
 DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds);
@@ -814,18 +737,15 @@  static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes(
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
-	ssize_t ret;
+	ssize_t ret = 0;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
+	if (sep)
+		ret = snprintf(page, PAGE_SIZE, "%u\n",
+				(u32)(sep->sep_stats.rx_data_octets >> 20));
+	rcu_read_unlock();
 
-	ret = snprintf(page, PAGE_SIZE, "%u\n",
-			(u32)(sep->sep_stats.rx_data_octets >> 20));
-	spin_unlock(&lun->lun_sep_lock);
 	return ret;
 }
 DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes);
@@ -837,16 +757,13 @@  static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes(
 	struct se_port *sep;
 	ssize_t ret;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
+	if (sep)
+		ret = snprintf(page, PAGE_SIZE, "%u\n",
+				(u32)(sep->sep_stats.tx_data_octets >> 20));
+	rcu_read_unlock();
 
-	ret = snprintf(page, PAGE_SIZE, "%u\n",
-			(u32)(sep->sep_stats.tx_data_octets >> 20));
-	spin_unlock(&lun->lun_sep_lock);
 	return ret;
 }
 DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes);
@@ -854,21 +771,8 @@  DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes);
 static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds(
 	struct se_port_stat_grps *pgrps, char *page)
 {
-	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
-	struct se_port *sep;
-	ssize_t ret;
-
-	spin_lock(&lun->lun_sep_lock);
-	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
-
 	/* FIXME: scsiTgtPortHsInCommands */
-	ret = snprintf(page, PAGE_SIZE, "%u\n", 0);
-	spin_unlock(&lun->lun_sep_lock);
-	return ret;
+	return snprintf(page, PAGE_SIZE, "%u\n", 0);
 }
 DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds);
 
@@ -922,21 +826,8 @@  static ssize_t target_stat_scsi_transport_show_attr_inst(
 {
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_device *dev = lun->lun_se_dev;
-	struct se_port *sep;
-	struct se_hba *hba;
-	ssize_t ret;
-
-	spin_lock(&lun->lun_sep_lock);
-	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
-	}
 
-	hba = dev->se_hba;
-	ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index);
-	spin_unlock(&lun->lun_sep_lock);
-	return ret;
+	return snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index);
 }
 DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst);
 
@@ -946,19 +837,18 @@  static ssize_t target_stat_scsi_transport_show_attr_device(
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
 	struct se_portal_group *tpg;
-	ssize_t ret;
+	ssize_t ret = 0;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
+	if (sep) {
+		tpg = sep->sep_tpg;
+		/* scsiTransportType */
+		ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n",
+				tpg->se_tpg_tfo->get_fabric_name());
 	}
-	tpg = sep->sep_tpg;
-	/* scsiTransportType */
-	ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n",
-			tpg->se_tpg_tfo->get_fabric_name());
-	spin_unlock(&lun->lun_sep_lock);
+	rcu_read_unlock();
+
 	return ret;
 }
 DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device);
@@ -969,18 +859,17 @@  static ssize_t target_stat_scsi_transport_show_attr_indx(
 	struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
 	struct se_port *sep;
 	struct se_portal_group *tpg;
-	ssize_t ret;
+	ssize_t ret = 0;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
+	if (sep) {
+		tpg = sep->sep_tpg;
+		ret = snprintf(page, PAGE_SIZE, "%u\n",
+				tpg->se_tpg_tfo->tpg_get_inst_index(tpg));
 	}
-	tpg = sep->sep_tpg;
-	ret = snprintf(page, PAGE_SIZE, "%u\n",
-			tpg->se_tpg_tfo->tpg_get_inst_index(tpg));
-	spin_unlock(&lun->lun_sep_lock);
+	rcu_read_unlock();
+
 	return ret;
 }
 DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx);
@@ -993,22 +882,21 @@  static ssize_t target_stat_scsi_transport_show_attr_dev_name(
 	struct se_port *sep;
 	struct se_portal_group *tpg;
 	struct t10_wwn *wwn;
-	ssize_t ret;
+	ssize_t ret = 0;
 
-	spin_lock(&lun->lun_sep_lock);
+	rcu_read_lock();
 	sep = lun->lun_sep;
-	if (!sep) {
-		spin_unlock(&lun->lun_sep_lock);
-		return -ENODEV;
+	if (sep) {
+		tpg = sep->sep_tpg;
+		wwn = &dev->t10_wwn;
+		/* scsiTransportDevName */
+		ret = snprintf(page, PAGE_SIZE, "%s+%s\n",
+				tpg->se_tpg_tfo->tpg_get_wwn(tpg),
+				(strlen(wwn->unit_serial)) ? wwn->unit_serial :
+				wwn->vendor);
 	}
-	tpg = sep->sep_tpg;
-	wwn = &dev->t10_wwn;
-	/* scsiTransportDevName */
-	ret = snprintf(page, PAGE_SIZE, "%s+%s\n",
-			tpg->se_tpg_tfo->tpg_get_wwn(tpg),
-			(strlen(wwn->unit_serial)) ? wwn->unit_serial :
-			wwn->vendor);
-	spin_unlock(&lun->lun_sep_lock);
+	rcu_read_unlock();
+
 	return ret;
 }
 DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 2b9f41a..0de29d8 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1213,6 +1213,7 @@  sense_reason_t
 target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
 {
 	struct se_device *dev = cmd->se_dev;
+	struct se_port *sep;
 	sense_reason_t ret;
 
 	/*
@@ -1276,10 +1277,12 @@  target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
 
 	cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
 
-	spin_lock(&cmd->se_lun->lun_sep_lock);
-	if (cmd->se_lun->lun_sep)
-		cmd->se_lun->lun_sep->sep_stats.cmd_pdus++;
-	spin_unlock(&cmd->se_lun->lun_sep_lock);
+	rcu_read_lock();
+	sep = cmd->se_lun->lun_sep;
+	if (sep)
+		sep->sep_stats.cmd_pdus++;
+	rcu_read_unlock();
+
 	return 0;
 }
 EXPORT_SYMBOL(target_setup_cmd_from_cdb);
@@ -2016,6 +2019,7 @@  static bool target_read_prot_action(struct se_cmd *cmd)
 static void target_complete_ok_work(struct work_struct *work)
 {
 	struct se_cmd *cmd = container_of(work, struct se_cmd, work);
+	struct se_port *sep;
 	int ret;
 
 	/*
@@ -2076,12 +2080,12 @@  static void target_complete_ok_work(struct work_struct *work)
 queue_rsp:
 	switch (cmd->data_direction) {
 	case DMA_FROM_DEVICE:
-		spin_lock(&cmd->se_lun->lun_sep_lock);
-		if (cmd->se_lun->lun_sep) {
-			cmd->se_lun->lun_sep->sep_stats.tx_data_octets +=
-					cmd->data_length;
-		}
-		spin_unlock(&cmd->se_lun->lun_sep_lock);
+		rcu_read_lock();
+		sep = cmd->se_lun->lun_sep;
+		if (sep)
+			sep->sep_stats.tx_data_octets += cmd->data_length;
+		rcu_read_unlock();
+
 		/*
 		 * Perform READ_STRIP of PI using software emulation when
 		 * backend had PI enabled, if the transport will not be
@@ -2104,22 +2108,22 @@  queue_rsp:
 			goto queue_full;
 		break;
 	case DMA_TO_DEVICE:
-		spin_lock(&cmd->se_lun->lun_sep_lock);
-		if (cmd->se_lun->lun_sep) {
-			cmd->se_lun->lun_sep->sep_stats.rx_data_octets +=
-				cmd->data_length;
-		}
-		spin_unlock(&cmd->se_lun->lun_sep_lock);
+		rcu_read_lock();
+		sep = cmd->se_lun->lun_sep;
+		if (sep)
+			sep->sep_stats.rx_data_octets += cmd->data_length;
+		rcu_read_unlock();
+
 		/*
 		 * Check if we need to send READ payload for BIDI-COMMAND
 		 */
 		if (cmd->se_cmd_flags & SCF_BIDI) {
-			spin_lock(&cmd->se_lun->lun_sep_lock);
-			if (cmd->se_lun->lun_sep) {
-				cmd->se_lun->lun_sep->sep_stats.tx_data_octets +=
-					cmd->data_length;
-			}
-			spin_unlock(&cmd->se_lun->lun_sep_lock);
+			rcu_read_lock();
+			sep = cmd->se_lun->lun_sep;
+			if (sep)
+				sep->sep_stats.tx_data_octets += cmd->data_length;
+			rcu_read_unlock();
+
 			ret = cmd->se_tfo->queue_data_in(cmd);
 			if (ret == -EAGAIN || ret == -ENOMEM)
 				goto queue_full;
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 86c0c5c..01f2d91 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -845,7 +845,8 @@  struct se_port {
 	/* Used for ALUA Target Port Groups membership */
 	atomic_t	sep_tg_pt_secondary_offline;
 	/* Used for PR ALL_TG_PT=1 */
-	atomic_t	sep_tg_pt_ref_cnt;
+	struct kref	sep_tg_pt_ref;
+	struct completion sep_tg_pt_comp;
 	spinlock_t	sep_alua_lock;
 	struct mutex	sep_tg_pt_md_mutex;
 	struct t10_alua_tg_pt_gp_member *sep_alua_tg_pt_gp_mem;
@@ -853,6 +854,7 @@  struct se_port {
 	struct se_portal_group *sep_tpg;
 	struct list_head sep_alua_list;
 	struct list_head sep_list;
+	struct rcu_head	sep_rcu;
 };
 
 struct se_tpg_np {