target: Drop lun_sep_lock for se_lun->lun_se_dev RCU usage

With se_port and t10_alua_tg_pt_gp_member being absored into se_lun,
there is no need for an extra lock to protect se_lun->lun_se_dev
assignment.

This patch also converts backend drivers to use call_rcu() release
to allow any se_device readers to complete.  The call_rcu() instead
of kfree_rcu() is required here because se_device is embedded into
the backend driver specific structure.

Also, convert se_lun->lun_stats to use atomic_long_t within the
target_complete_ok_work() completion callback, and add FIXME for
transport_lookup_tmr_lun() with se_lun->lun_ref.

Finally, update sbp_update_unit_directory() special case usage with
proper rcu_dereference_raw() and configfs symlink comment.

Reported-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Chris Boot <bootc@bootc.net>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
Nicholas Bellinger 2015-05-19 00:03:07 -07:00
parent adf653f92f
commit 4cc987eaff
13 changed files with 175 additions and 115 deletions

View File

@ -1905,8 +1905,11 @@ static int sbp_update_unit_directory(struct sbp_tport *tport)
hlist_for_each_entry_rcu(lun, &tport->tpg->se_tpg.tpg_lun_hlist, link) { hlist_for_each_entry_rcu(lun, &tport->tpg->se_tpg.tpg_lun_hlist, link) {
struct se_device *dev; struct se_device *dev;
int type; int type;
/*
dev = lun->lun_se_dev; * rcu_dereference_raw protected by se_lun->lun_group symlink
* reference to se_device->dev_group.
*/
dev = rcu_dereference_raw(lun->lun_se_dev);
type = dev->transport->get_device_type(dev); type = dev->transport->get_device_type(dev);
/* logical_unit_number */ /* logical_unit_number */

View File

@ -1935,7 +1935,11 @@ ssize_t core_alua_store_tg_pt_gp_info(
size_t count) size_t count)
{ {
struct se_portal_group *tpg = lun->lun_tpg; struct se_portal_group *tpg = lun->lun_tpg;
struct se_device *dev = lun->lun_se_dev; /*
* 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 *tg_pt_gp = NULL, *tg_pt_gp_new = NULL;
unsigned char buf[TG_PT_GROUP_NAME_BUF]; unsigned char buf[TG_PT_GROUP_NAME_BUF];
int move = 0; int move = 0;
@ -2189,7 +2193,11 @@ ssize_t core_alua_store_offline_bit(
const char *page, const char *page,
size_t count) size_t count)
{ {
struct se_device *dev = lun->lun_se_dev; /*
* 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; unsigned long tmp;
int ret; int ret;

View File

@ -61,7 +61,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun)
struct se_lun *se_lun = NULL; struct se_lun *se_lun = NULL;
struct se_session *se_sess = se_cmd->se_sess; struct se_session *se_sess = se_cmd->se_sess;
struct se_node_acl *nacl = se_sess->se_node_acl; struct se_node_acl *nacl = se_sess->se_node_acl;
struct se_device *dev;
struct se_dev_entry *deve; struct se_dev_entry *deve;
if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG)
@ -128,16 +127,21 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun)
percpu_ref_get(&se_lun->lun_ref); percpu_ref_get(&se_lun->lun_ref);
se_cmd->lun_ref_active = true; se_cmd->lun_ref_active = true;
} }
/*
* RCU reference protected by percpu se_lun->lun_ref taken above that
* must drop to zero (including initial reference) before this se_lun
* pointer can be kfree_rcu() by the final se_lun->lun_group put via
* target_core_fabric_configfs.c:target_fabric_port_release
*/
se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev);
atomic_long_inc(&se_cmd->se_dev->num_cmds);
/* Directly associate cmd with se_dev */
se_cmd->se_dev = se_lun->lun_se_dev;
dev = se_lun->lun_se_dev;
atomic_long_inc(&dev->num_cmds);
if (se_cmd->data_direction == DMA_TO_DEVICE) if (se_cmd->data_direction == DMA_TO_DEVICE)
atomic_long_add(se_cmd->data_length, &dev->write_bytes); atomic_long_add(se_cmd->data_length,
&se_cmd->se_dev->write_bytes);
else if (se_cmd->data_direction == DMA_FROM_DEVICE) else if (se_cmd->data_direction == DMA_FROM_DEVICE)
atomic_long_add(se_cmd->data_length, &dev->read_bytes); atomic_long_add(se_cmd->data_length,
&se_cmd->se_dev->read_bytes);
return 0; return 0;
} }
@ -173,10 +177,11 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun)
unpacked_lun); unpacked_lun);
return -ENODEV; return -ENODEV;
} }
/*
/* Directly associate cmd with se_dev */ * XXX: Add percpu se_lun->lun_ref reference count for TMR
se_cmd->se_dev = se_lun->lun_se_dev; */
se_tmr->tmr_dev = se_lun->lun_se_dev; se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev);
se_tmr->tmr_dev = rcu_dereference_raw(se_lun->lun_se_dev);
spin_lock_irqsave(&se_tmr->tmr_dev->se_tmr_lock, flags); spin_lock_irqsave(&se_tmr->tmr_dev->se_tmr_lock, flags);
list_add_tail(&se_tmr->tmr_list, &se_tmr->tmr_dev->dev_tmr_list); list_add_tail(&se_tmr->tmr_list, &se_tmr->tmr_dev->dev_tmr_list);
@ -389,6 +394,11 @@ void core_disable_device_list_for_node(
struct se_node_acl *nacl, struct se_node_acl *nacl,
struct se_portal_group *tpg) struct se_portal_group *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);
/* /*
* If the MappedLUN entry is being disabled, the entry in * If the MappedLUN entry is being disabled, the entry in
* lun->lun_deve_list must be removed now before clearing the * lun->lun_deve_list must be removed now before clearing the
@ -426,7 +436,7 @@ void core_disable_device_list_for_node(
kfree_rcu(orig, rcu_head); kfree_rcu(orig, rcu_head);
core_scsi3_free_pr_reg_from_nacl(lun->lun_se_dev, nacl); core_scsi3_free_pr_reg_from_nacl(dev, nacl);
} }
/* core_clear_lun_from_tpg(): /* core_clear_lun_from_tpg():
@ -629,6 +639,11 @@ int core_dev_add_initiator_node_lun_acl(
u32 lun_access) u32 lun_access)
{ {
struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_node_acl *nacl = lacl->se_lun_nacl;
/*
* 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);
if (!nacl) if (!nacl)
return -EINVAL; return -EINVAL;
@ -652,7 +667,7 @@ int core_dev_add_initiator_node_lun_acl(
* Check to see if there are any existing persistent reservation APTPL * Check to see if there are any existing persistent reservation APTPL
* pre-registrations that need to be enabled for this LUN ACL.. * pre-registrations that need to be enabled for this LUN ACL..
*/ */
core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, nacl, core_scsi3_check_aptpl_registration(dev, tpg, lun, nacl,
lacl->mapped_lun); lacl->mapped_lun);
return 0; return 0;
} }
@ -746,6 +761,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
dev->se_hba = hba; dev->se_hba = hba;
dev->transport = hba->backend->ops; dev->transport = hba->backend->ops;
dev->prot_length = sizeof(struct se_dif_v1_tuple); dev->prot_length = sizeof(struct se_dif_v1_tuple);
dev->hba_index = hba->hba_index;
INIT_LIST_HEAD(&dev->dev_list); INIT_LIST_HEAD(&dev->dev_list);
INIT_LIST_HEAD(&dev->dev_sep_list); INIT_LIST_HEAD(&dev->dev_sep_list);
@ -802,8 +818,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN; dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN;
xcopy_lun = &dev->xcopy_lun; xcopy_lun = &dev->xcopy_lun;
xcopy_lun->lun_se_dev = dev; rcu_assign_pointer(xcopy_lun->lun_se_dev, dev);
spin_lock_init(&xcopy_lun->lun_sep_lock);
init_completion(&xcopy_lun->lun_ref_comp); init_completion(&xcopy_lun->lun_ref_comp);
INIT_LIST_HEAD(&xcopy_lun->lun_deve_list); INIT_LIST_HEAD(&xcopy_lun->lun_deve_list);
INIT_LIST_HEAD(&xcopy_lun->lun_dev_link); INIT_LIST_HEAD(&xcopy_lun->lun_dev_link);

View File

@ -241,6 +241,14 @@ fail:
return ret; return ret;
} }
static void fd_dev_call_rcu(struct rcu_head *p)
{
struct se_device *dev = container_of(p, struct se_device, rcu_head);
struct fd_dev *fd_dev = FD_DEV(dev);
kfree(fd_dev);
}
static void fd_free_device(struct se_device *dev) static void fd_free_device(struct se_device *dev)
{ {
struct fd_dev *fd_dev = FD_DEV(dev); struct fd_dev *fd_dev = FD_DEV(dev);
@ -249,8 +257,7 @@ static void fd_free_device(struct se_device *dev)
filp_close(fd_dev->fd_file, NULL); filp_close(fd_dev->fd_file, NULL);
fd_dev->fd_file = NULL; fd_dev->fd_file = NULL;
} }
call_rcu(&dev->rcu_head, fd_dev_call_rcu);
kfree(fd_dev);
} }
static int fd_do_rw(struct se_cmd *cmd, struct file *fd, static int fd_do_rw(struct se_cmd *cmd, struct file *fd,

View File

@ -191,6 +191,14 @@ out:
return ret; return ret;
} }
static void iblock_dev_call_rcu(struct rcu_head *p)
{
struct se_device *dev = container_of(p, struct se_device, rcu_head);
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
kfree(ib_dev);
}
static void iblock_free_device(struct se_device *dev) static void iblock_free_device(struct se_device *dev)
{ {
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
@ -200,7 +208,7 @@ static void iblock_free_device(struct se_device *dev)
if (ib_dev->ibd_bio_set != NULL) if (ib_dev->ibd_bio_set != NULL)
bioset_free(ib_dev->ibd_bio_set); bioset_free(ib_dev->ibd_bio_set);
kfree(ib_dev); call_rcu(&dev->rcu_head, iblock_dev_call_rcu);
} }
static unsigned long long iblock_emulate_read_cap_with_block_size( static unsigned long long iblock_emulate_read_cap_with_block_size(

View File

@ -579,6 +579,14 @@ static int pscsi_configure_device(struct se_device *dev)
return -ENODEV; return -ENODEV;
} }
static void pscsi_dev_call_rcu(struct rcu_head *p)
{
struct se_device *dev = container_of(p, struct se_device, rcu_head);
struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
kfree(pdv);
}
static void pscsi_free_device(struct se_device *dev) static void pscsi_free_device(struct se_device *dev)
{ {
struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
@ -610,8 +618,7 @@ static void pscsi_free_device(struct se_device *dev)
pdv->pdv_sd = NULL; pdv->pdv_sd = NULL;
} }
call_rcu(&dev->rcu_head, pscsi_dev_call_rcu);
kfree(pdv);
} }
static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,

View File

@ -350,12 +350,20 @@ fail:
return ret; return ret;
} }
static void rd_dev_call_rcu(struct rcu_head *p)
{
struct se_device *dev = container_of(p, struct se_device, rcu_head);
struct rd_dev *rd_dev = RD_DEV(dev);
kfree(rd_dev);
}
static void rd_free_device(struct se_device *dev) static void rd_free_device(struct se_device *dev)
{ {
struct rd_dev *rd_dev = RD_DEV(dev); struct rd_dev *rd_dev = RD_DEV(dev);
rd_release_device_space(rd_dev); rd_release_device_space(rd_dev);
kfree(rd_dev); call_rcu(&dev->rcu_head, rd_dev_call_rcu);
} }
static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)

View File

@ -692,7 +692,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
} }
if (dev == tpg->tpg_virt_lun0->lun_se_dev) if (dev == rcu_access_pointer(tpg->tpg_virt_lun0->lun_se_dev))
buf[0] = 0x3f; /* Not connected */ buf[0] = 0x3f; /* Not connected */
else else
buf[0] = dev->transport->get_device_type(dev); buf[0] = dev->transport->get_device_type(dev);

View File

@ -545,11 +545,11 @@ static ssize_t target_stat_scsi_port_show_attr_inst(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); ret = snprintf(page, PAGE_SIZE, "%u\n", dev->hba_index);
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_PORT_ATTR_RO(inst); DEV_STAT_SCSI_PORT_ATTR_RO(inst);
@ -561,11 +561,11 @@ static ssize_t target_stat_scsi_port_show_attr_dev(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_PORT_ATTR_RO(dev); DEV_STAT_SCSI_PORT_ATTR_RO(dev);
@ -577,11 +577,11 @@ static ssize_t target_stat_scsi_port_show_attr_indx(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi);
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_PORT_ATTR_RO(indx); DEV_STAT_SCSI_PORT_ATTR_RO(indx);
@ -593,11 +593,11 @@ static ssize_t target_stat_scsi_port_show_attr_role(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index);
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_PORT_ATTR_RO(role); DEV_STAT_SCSI_PORT_ATTR_RO(role);
@ -609,13 +609,13 @@ static ssize_t target_stat_scsi_port_show_attr_busy_count(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) { if (dev) {
/* FIXME: scsiPortBusyStatuses */ /* FIXME: scsiPortBusyStatuses */
ret = snprintf(page, PAGE_SIZE, "%u\n", 0); ret = snprintf(page, PAGE_SIZE, "%u\n", 0);
} }
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_PORT_ATTR_RO(busy_count); DEV_STAT_SCSI_PORT_ATTR_RO(busy_count);
@ -666,11 +666,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_inst(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); ret = snprintf(page, PAGE_SIZE, "%u\n", dev->hba_index);
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst); DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst);
@ -682,11 +682,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_dev(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev); DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev);
@ -698,11 +698,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_indx(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi);
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx); DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx);
@ -715,13 +715,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_name(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n",
tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->get_fabric_name(),
lun->lun_rtpi); lun->lun_rtpi);
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name); DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name);
@ -734,13 +734,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_port_index(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", ret = snprintf(page, PAGE_SIZE, "%s%s%d\n",
tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+", tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+",
tpg->se_tpg_tfo->tpg_get_tag(tpg)); tpg->se_tpg_tfo->tpg_get_tag(tpg));
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index); DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index);
@ -752,11 +752,12 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_stats.cmd_pdus); ret = snprintf(page, PAGE_SIZE, "%lu\n",
spin_unlock(&lun->lun_sep_lock); atomic_long_read(&lun->lun_stats.cmd_pdus));
rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds); DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds);
@ -768,12 +769,12 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", ret = snprintf(page, PAGE_SIZE, "%u\n",
(u32)(lun->lun_stats.rx_data_octets >> 20)); (u32)(atomic_long_read(&lun->lun_stats.rx_data_octets) >> 20));
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes); DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes);
@ -785,12 +786,12 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", ret = snprintf(page, PAGE_SIZE, "%u\n",
(u32)(lun->lun_stats.tx_data_octets >> 20)); (u32)(atomic_long_read(&lun->lun_stats.tx_data_octets) >> 20));
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes); DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes);
@ -802,13 +803,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) { if (dev) {
/* FIXME: scsiTgtPortHsInCommands */ /* FIXME: scsiTgtPortHsInCommands */
ret = snprintf(page, PAGE_SIZE, "%u\n", 0); ret = snprintf(page, PAGE_SIZE, "%u\n", 0);
} }
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds); DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds);
@ -865,11 +866,11 @@ static ssize_t target_stat_scsi_transport_show_attr_inst(
struct se_device *dev; struct se_device *dev;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); ret = snprintf(page, PAGE_SIZE, "%u\n", dev->hba_index);
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst); DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst);
@ -882,14 +883,14 @@ static ssize_t target_stat_scsi_transport_show_attr_device(
struct se_portal_group *tpg = lun->lun_tpg; struct se_portal_group *tpg = lun->lun_tpg;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) { if (dev) {
/* scsiTransportType */ /* scsiTransportType */
ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n",
tpg->se_tpg_tfo->get_fabric_name()); tpg->se_tpg_tfo->get_fabric_name());
} }
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device); DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device);
@ -902,12 +903,12 @@ static ssize_t target_stat_scsi_transport_show_attr_indx(
struct se_portal_group *tpg = lun->lun_tpg; struct se_portal_group *tpg = lun->lun_tpg;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) if (dev)
ret = snprintf(page, PAGE_SIZE, "%u\n", ret = snprintf(page, PAGE_SIZE, "%u\n",
tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); tpg->se_tpg_tfo->tpg_get_inst_index(tpg));
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx); DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx);
@ -916,13 +917,13 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name(
struct se_port_stat_grps *pgrps, char *page) struct se_port_stat_grps *pgrps, char *page)
{ {
struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
struct se_device *dev = lun->lun_se_dev; struct se_device *dev;
struct se_portal_group *tpg = lun->lun_tpg; struct se_portal_group *tpg = lun->lun_tpg;
struct t10_wwn *wwn; struct t10_wwn *wwn;
ssize_t ret = -ENODEV; ssize_t ret = -ENODEV;
spin_lock(&lun->lun_sep_lock); rcu_read_lock();
dev = lun->lun_se_dev; dev = rcu_dereference(lun->lun_se_dev);
if (dev) { if (dev) {
wwn = &dev->t10_wwn; wwn = &dev->t10_wwn;
/* scsiTransportDevName */ /* scsiTransportDevName */
@ -931,7 +932,7 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name(
(strlen(wwn->unit_serial)) ? wwn->unit_serial : (strlen(wwn->unit_serial)) ? wwn->unit_serial :
wwn->vendor); wwn->vendor);
} }
spin_unlock(&lun->lun_sep_lock); rcu_read_unlock();
return ret; return ret;
} }
DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name); DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name);

View File

@ -102,7 +102,8 @@ void core_tpg_add_node_to_devs(
if (lun_orig && lun != lun_orig) if (lun_orig && lun != lun_orig)
continue; continue;
dev = lun->lun_se_dev; dev = rcu_dereference_check(lun->lun_se_dev,
lockdep_is_held(&tpg->tpg_lun_mutex));
/* /*
* By default in LIO-Target $FABRIC_MOD, * By default in LIO-Target $FABRIC_MOD,
* demo_mode_write_protect is ON, or READ_ONLY; * demo_mode_write_protect is ON, or READ_ONLY;
@ -598,7 +599,6 @@ struct se_lun *core_tpg_alloc_lun(
lun->unpacked_lun = unpacked_lun; lun->unpacked_lun = unpacked_lun;
lun->lun_link_magic = SE_LUN_LINK_MAGIC; lun->lun_link_magic = SE_LUN_LINK_MAGIC;
atomic_set(&lun->lun_acl_count, 0); atomic_set(&lun->lun_acl_count, 0);
spin_lock_init(&lun->lun_sep_lock);
init_completion(&lun->lun_ref_comp); init_completion(&lun->lun_ref_comp);
INIT_LIST_HEAD(&lun->lun_deve_list); INIT_LIST_HEAD(&lun->lun_deve_list);
INIT_LIST_HEAD(&lun->lun_dev_link); INIT_LIST_HEAD(&lun->lun_dev_link);
@ -636,12 +636,8 @@ int core_tpg_add_lun(
mutex_lock(&tpg->tpg_lun_mutex); mutex_lock(&tpg->tpg_lun_mutex);
spin_lock(&lun->lun_sep_lock);
lun->lun_index = dev->dev_index;
lun->lun_se_dev = dev;
spin_unlock(&lun->lun_sep_lock);
spin_lock(&dev->se_port_lock); spin_lock(&dev->se_port_lock);
lun->lun_index = dev->dev_index;
rcu_assign_pointer(lun->lun_se_dev, dev); rcu_assign_pointer(lun->lun_se_dev, dev);
dev->export_count++; dev->export_count++;
list_add_tail(&lun->lun_dev_link, &dev->dev_sep_list); list_add_tail(&lun->lun_dev_link, &dev->dev_sep_list);
@ -664,7 +660,11 @@ void core_tpg_remove_lun(
struct se_portal_group *tpg, struct se_portal_group *tpg,
struct se_lun *lun) struct se_lun *lun)
{ {
struct se_device *dev = lun->lun_se_dev; /*
* 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);
core_clear_lun_from_tpg(lun, tpg); core_clear_lun_from_tpg(lun, tpg);
transport_clear_lun_ref(lun); transport_clear_lun_ref(lun);

View File

@ -1261,10 +1261,7 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
return ret; return ret;
cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
atomic_long_inc(&cmd->se_lun->lun_stats.cmd_pdus);
spin_lock(&cmd->se_lun->lun_sep_lock);
cmd->se_lun->lun_stats.cmd_pdus++;
spin_unlock(&cmd->se_lun->lun_sep_lock);
return 0; return 0;
} }
EXPORT_SYMBOL(target_setup_cmd_from_cdb); EXPORT_SYMBOL(target_setup_cmd_from_cdb);
@ -2060,9 +2057,8 @@ static void target_complete_ok_work(struct work_struct *work)
queue_rsp: queue_rsp:
switch (cmd->data_direction) { switch (cmd->data_direction) {
case DMA_FROM_DEVICE: case DMA_FROM_DEVICE:
spin_lock(&cmd->se_lun->lun_sep_lock); atomic_long_add(cmd->data_length,
cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; &cmd->se_lun->lun_stats.tx_data_octets);
spin_unlock(&cmd->se_lun->lun_sep_lock);
/* /*
* Perform READ_STRIP of PI using software emulation when * Perform READ_STRIP of PI using software emulation when
* backend had PI enabled, if the transport will not be * backend had PI enabled, if the transport will not be
@ -2085,16 +2081,14 @@ queue_rsp:
goto queue_full; goto queue_full;
break; break;
case DMA_TO_DEVICE: case DMA_TO_DEVICE:
spin_lock(&cmd->se_lun->lun_sep_lock); atomic_long_add(cmd->data_length,
cmd->se_lun->lun_stats.rx_data_octets += cmd->data_length; &cmd->se_lun->lun_stats.rx_data_octets);
spin_unlock(&cmd->se_lun->lun_sep_lock);
/* /*
* Check if we need to send READ payload for BIDI-COMMAND * Check if we need to send READ payload for BIDI-COMMAND
*/ */
if (cmd->se_cmd_flags & SCF_BIDI) { if (cmd->se_cmd_flags & SCF_BIDI) {
spin_lock(&cmd->se_lun->lun_sep_lock); atomic_long_add(cmd->data_length,
cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; &cmd->se_lun->lun_stats.tx_data_octets);
spin_unlock(&cmd->se_lun->lun_sep_lock);
ret = cmd->se_tfo->queue_data_in(cmd); ret = cmd->se_tfo->queue_data_in(cmd);
if (ret == -EAGAIN || ret == -ENOMEM) if (ret == -EAGAIN || ret == -ENOMEM)
goto queue_full; goto queue_full;

View File

@ -950,6 +950,14 @@ static int tcmu_check_pending_cmd(int id, void *p, void *data)
return -EINVAL; return -EINVAL;
} }
static void tcmu_dev_call_rcu(struct rcu_head *p)
{
struct se_device *dev = container_of(p, struct se_device, rcu_head);
struct tcmu_dev *udev = TCMU_DEV(dev);
kfree(udev);
}
static void tcmu_free_device(struct se_device *dev) static void tcmu_free_device(struct se_device *dev)
{ {
struct tcmu_dev *udev = TCMU_DEV(dev); struct tcmu_dev *udev = TCMU_DEV(dev);
@ -975,8 +983,7 @@ static void tcmu_free_device(struct se_device *dev)
kfree(udev->uio_info.name); kfree(udev->uio_info.name);
kfree(udev->name); kfree(udev->name);
} }
call_rcu(&dev->rcu_head, tcmu_dev_call_rcu);
kfree(udev);
} }
enum { enum {

View File

@ -690,9 +690,9 @@ struct se_port_stat_grps {
}; };
struct scsi_port_stats { struct scsi_port_stats {
u32 cmd_pdus; atomic_long_t cmd_pdus;
u64 tx_data_octets; atomic_long_t tx_data_octets;
u64 rx_data_octets; atomic_long_t rx_data_octets;
}; };
struct se_lun { struct se_lun {
@ -705,7 +705,6 @@ struct se_lun {
u32 unpacked_lun; u32 unpacked_lun;
u32 lun_index; u32 lun_index;
atomic_t lun_acl_count; atomic_t lun_acl_count;
spinlock_t lun_sep_lock;
struct se_device __rcu *lun_se_dev; struct se_device __rcu *lun_se_dev;
struct list_head lun_deve_list; struct list_head lun_deve_list;
@ -818,6 +817,9 @@ struct se_device {
struct se_lun xcopy_lun; struct se_lun xcopy_lun;
/* Protection Information */ /* Protection Information */
int prot_length; int prot_length;
/* For se_lun->lun_se_dev RCU read-side critical access */
u32 hba_index;
struct rcu_head rcu_head;
}; };
struct se_hba { struct se_hba {