@@ -3196,6 +3196,8 @@ static int __init target_core_init_configfs(void)
config_group_init(&subsys->su_group);
mutex_init(&subsys->su_mutex);
+ target_init_device_idr();
+
ret = init_se_kmem_caches();
if (ret < 0)
return ret;
@@ -3300,6 +3302,7 @@ static void __exit target_core_exit_configfs(void)
rd_module_exit();
target_xcopy_release_pt();
release_se_kmem_caches();
+ target_destroy_device_idr();
}
MODULE_DESCRIPTION("Target_Core_Mod/ConfigFS");
@@ -51,6 +51,7 @@
DEFINE_MUTEX(g_device_mutex);
LIST_HEAD(g_device_list);
+static struct idr devices_idr;
static struct se_hba *lun0_hba;
/* not static, needed by tpg.c */
@@ -879,10 +880,20 @@ sector_t target_to_linux_sector(struct se_device *dev, sector_t lb)
}
EXPORT_SYMBOL(target_to_linux_sector);
+void target_init_device_idr(void)
+{
+ idr_init(&devices_idr);
+}
+
+void target_destroy_device_idr(void)
+{
+ idr_destroy(&devices_idr);
+}
+
int target_configure_device(struct se_device *dev)
{
struct se_hba *hba = dev->se_hba;
- int ret;
+ int ret, id;
if (dev->dev_flags & DF_CONFIGURED) {
pr_err("se_dev->se_dev_ptr already set for storage"
@@ -890,9 +901,28 @@ int target_configure_device(struct se_device *dev)
return -EEXIST;
}
+ /*
+ * Add early so modules like tcmu can use during its
+ * configuration.
+ */
+ idr_preload(GFP_KERNEL);
+ mutex_lock(&g_device_mutex);
+ /*
+ * Use cyclic to try and avoid collisions with devices
+ * that were recently removed.
+ */
+ id = idr_alloc_cyclic(&devices_idr, dev, 0, INT_MAX, GFP_KERNEL);
+ mutex_unlock(&g_device_mutex);
+ idr_preload_end();
+ if (id < 0) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ dev->dev_index = id;
+
ret = dev->transport->configure_device(dev);
if (ret)
- goto out;
+ goto out_free_index;
/*
* XXX: there is not much point to have two different values here..
*/
@@ -907,12 +937,11 @@ int target_configure_device(struct se_device *dev)
dev->dev_attrib.hw_block_size);
dev->dev_attrib.optimal_sectors = dev->dev_attrib.hw_max_sectors;
- dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX);
dev->creation_time = get_jiffies_64();
ret = core_setup_alua(dev);
if (ret)
- goto out;
+ goto out_free_index;
/*
* Startup the struct se_device processing thread
@@ -960,6 +989,10 @@ int target_configure_device(struct se_device *dev)
out_free_alua:
core_alua_free_lu_gp_mem(dev);
+out_free_index:
+ mutex_lock(&g_device_mutex);
+ idr_remove(&devices_idr, dev->dev_index);
+ mutex_unlock(&g_device_mutex);
out:
se_release_vpd_for_dev(dev);
return ret;
@@ -968,10 +1001,12 @@ int target_configure_device(struct se_device *dev)
void target_free_device(struct se_device *dev)
{
struct se_hba *hba = dev->se_hba;
+ int dev_index = -1;
WARN_ON(!list_empty(&dev->dev_sep_list));
if (dev->dev_flags & DF_CONFIGURED) {
+ dev_index = dev->dev_index;
destroy_workqueue(dev->tmr_wq);
mutex_lock(&g_device_mutex);
@@ -992,6 +1027,16 @@ void target_free_device(struct se_device *dev)
dev->transport->free_prot(dev);
dev->transport->free_device(dev);
+
+ /*
+ * We have to delay removal in case the free_device callout needs
+ * to use it.
+ */
+ if (dev_index >= 0) {
+ mutex_lock(&g_device_mutex);
+ idr_remove(&devices_idr, dev_index);
+ mutex_unlock(&g_device_mutex);
+ }
}
int core_dev_setup_virtual_lun0(void)
@@ -132,6 +132,8 @@ struct se_node_acl *core_tpg_add_initiator_node_acl(struct se_portal_group *tpg,
/* target_core_transport.c */
extern struct kmem_cache *se_tmr_req_cache;
+void target_init_device_idr(void);
+void target_destroy_device_idr(void);
int init_se_kmem_caches(void);
void release_se_kmem_caches(void);
u32 scsi_get_new_index(scsi_index_t);
@@ -219,7 +219,6 @@ enum tcm_tmrsp_table {
*/
typedef enum {
SCSI_INST_INDEX,
- SCSI_DEVICE_INDEX,
SCSI_AUTH_INTR_INDEX,
SCSI_INDEX_TYPE_MAX
} scsi_index_t;
In the next patches we will add tcmu netlink support that allows userspace to send commands to target_core_user. To execute operations on a se_device/tcmu_dev we need to be able to look it by any old id. This patch replaces the se_device->dev_index with a idr created id. In the next patches I will add helpers so tcmu can look up the device by that id, and there is an optional patch at the end to replace the g_device_list with the idr iterator. Signed-off-by: Mike Christie <mchristi@redhat.com> --- drivers/target/target_core_configfs.c | 3 ++ drivers/target/target_core_device.c | 53 ++++++++++++++++++++++++++++++++--- drivers/target/target_core_internal.h | 2 ++ include/target/target_core_base.h | 1 - 4 files changed, 54 insertions(+), 5 deletions(-)