[PATCH 1/2] [Target_Core_Mod/ALUA]: Add t10_alua_lu_gp_member_t usage for Logical Unit Groups

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From 5574e3e0240e1bf5e54529bfeca51aec5025dd13 Mon Sep 17 00:00:00 2001
From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>
Date: Wed, 11 Feb 2009 20:13:07 -0800
Subject: [PATCH 1/2] [Target_Core_Mod/ALUA]: Add t10_alua_lu_gp_member_t usage for Logical Unit Groups

This patch defines t10_alua_lu_gp_member_t and changes se_device_t->dev_alua_lu_gp
to a pointer at se_device_t->dev_alua_lu_gp_mem that is allocated/released by
se_device_t.  This allows the shutdown logic for se_device_t and ALUA Logical Unit
associated for said se_device_t much cleaner and prevents a potential OOPs with the
existing code.

This patch also adds the following logic to ALUA logical unit groups:

*) The deletion of logical unit groups with 'rmdir core/alua/lu_gps/$LU_GROUP' will cause
   any associated se_device_t to be put back into core/alua/lu_gps/default_lu_gp
*) Emulated INQUIRY EVPD Logical Unit Identifier will also return a value if there
   is an association to default_lu_gp or a user defined logical unit group.
   Completely releasing a given associated via echo NULL > core/$HBA/$DEV/alua_lu_gp
   will return no EVPD Logical Unit Identifier.

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
 drivers/lio-core/target_core_alua.c      |  185 ++++++++++++++++++++----------
 drivers/lio-core/target_core_alua.h      |   11 +-
 drivers/lio-core/target_core_base.h      |   27 ++++-
 drivers/lio-core/target_core_configfs.c  |   85 ++++++++++----
 drivers/lio-core/target_core_device.c    |    3 +-
 drivers/lio-core/target_core_transport.c |   41 ++++++--
 6 files changed, 244 insertions(+), 108 deletions(-)

diff --git a/drivers/lio-core/target_core_alua.c b/drivers/lio-core/target_core_alua.c
index 722be1a..86a1546 100644
--- a/drivers/lio-core/target_core_alua.c
+++ b/drivers/lio-core/target_core_alua.c
@@ -46,7 +46,9 @@
 extern se_global_t *se_global;
 
 extern struct kmem_cache *t10_alua_lu_gp_cache;
+extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
 extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
+extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
 
 /*
  * REPORT_TARGET_PORT_GROUPS
@@ -138,8 +140,8 @@ extern t10_alua_lu_gp_t *core_alua_allocate_lu_gp (const char *name)
 		return(NULL);
 	}
 	INIT_LIST_HEAD(&lu_gp->lu_gp_list);
-	INIT_LIST_HEAD(&lu_gp->lu_gp_ref_list);
-	spin_lock_init(&lu_gp->lu_gp_ref_lock);
+	INIT_LIST_HEAD(&lu_gp->lu_gp_mem_list);
+	spin_lock_init(&lu_gp->lu_gp_lock);
 	lu_gp->lu_gp_alua_access_state = ALUA_ACCESS_STATE_ACTIVE_OPTMIZED;
 
 	spin_lock(&se_global->lu_gps_lock);
@@ -163,9 +165,27 @@ again:
 	return(lu_gp);
 }
 
+extern t10_alua_lu_gp_member_t *core_alua_allocate_lu_gp_mem (
+	se_device_t *dev)
+{
+	t10_alua_lu_gp_member_t *lu_gp_mem;
+
+	if (!(lu_gp_mem = kmem_cache_zalloc(t10_alua_lu_gp_mem_cache, GFP_KERNEL))) {
+		printk(KERN_ERR "Unable to allocate t10_alua_lu_gp_member_t\n");
+		return(ERR_PTR(-ENOMEM));
+	}
+	INIT_LIST_HEAD(&lu_gp_mem->lu_gp_mem_list);
+	spin_lock_init(&lu_gp_mem->lu_gp_mem_lock);
+
+	lu_gp_mem->lu_gp_mem_dev = dev;
+	dev->dev_alua_lu_gp_mem = lu_gp_mem;
+
+	return(lu_gp_mem);
+}
+
 extern void core_alua_free_lu_gp (t10_alua_lu_gp_t *lu_gp)
 {
-	se_device_t *dev, *dev_tmp;
+	t10_alua_lu_gp_member_t *lu_gp_mem, *lu_gp_mem_tmp;
 	/*
 	 * Once we have reached this point, config_item_put() has
 	 * already been called from target_core_alua_drop_lu_gp().
@@ -175,28 +195,85 @@ extern void core_alua_free_lu_gp (t10_alua_lu_gp_t *lu_gp)
 	 * t10_alua_lu_gp_t.
 	 */
 	spin_lock(&se_global->lu_gps_lock);
+	atomic_set(&lu_gp->lu_gp_shutdown, 1);
 	list_del(&lu_gp->lu_gp_list);
 	se_global->alua_lu_gps_count--;
 	spin_unlock(&se_global->lu_gps_lock);
+	/*
+	 * Allow a t10_alua_lu_gp_t * referenced by core_alua_get_lu_gp_by_name()
+	 * in target_core_configfs.c:target_core_store_alua_lu_gp() to be released
+	 * with core_alua_put_lu_gp_from_name()
+	 */
+	while(atomic_read(&lu_gp->lu_gp_ref_cnt))
+		msleep(10);
+	/*
+	 * Release reference to t10_alua_lu_gp_t * from all associated
+	 * se_device_t.
+	 */
+	spin_lock(&lu_gp->lu_gp_lock);
+	list_for_each_entry_safe(lu_gp_mem, lu_gp_mem_tmp,
+				&lu_gp->lu_gp_mem_list, lu_gp_mem_list) {
+		if (lu_gp_mem->lu_gp_assoc) {
+			list_del(&lu_gp_mem->lu_gp_mem_list);
+			lu_gp->lu_gp_members--;
+			lu_gp_mem->lu_gp_assoc = 0;
+		}
+		spin_unlock(&lu_gp->lu_gp_lock);
+		/*
+		 *
+		 * lu_gp_mem is assoicated with a single se_device_t->dev_alua_lu_gp_mem,
+		 * and is released when se_device_t is released via
+		 * core_alua_free_lu_gp_mem().
+		 *
+		 * If the passed lu_gp does NOT match the default_lu_gp, assume we
+		 * want to re-assocate a given lu_gp_mem with default_lu_gp.
+		 */
+		spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+		if (lu_gp != se_global->default_lu_gp)
+			__core_alua_attach_lu_gp_mem(lu_gp_mem, se_global->default_lu_gp);
+		else
+			lu_gp_mem->lu_gp = NULL;
+		spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+		spin_lock(&lu_gp->lu_gp_lock);
+	}
+	spin_unlock(&lu_gp->lu_gp_lock);
 
-	spin_lock(&lu_gp->lu_gp_ref_lock);
-	list_for_each_entry_safe(dev, dev_tmp, &lu_gp->lu_gp_ref_list, dev_lu_gp_list) {
-		list_del(&dev->dev_lu_gp_list);	
-		spin_unlock(&lu_gp->lu_gp_ref_lock);
+	kmem_cache_free(t10_alua_lu_gp_cache, lu_gp);
+	return;
+}
 
-		spin_lock(&dev->dev_alua_lock);
-		dev->dev_alua_lu_gp = NULL;
-		spin_unlock(&dev->dev_alua_lock);
-		
-		spin_lock(&lu_gp->lu_gp_ref_lock);
+extern void core_alua_free_lu_gp_mem (se_device_t *dev)
+{
+	se_subsystem_dev_t *su_dev = dev->se_sub_dev;
+	t10_alua_t *alua = T10_ALUA(su_dev);
+	t10_alua_lu_gp_t *lu_gp;
+	t10_alua_lu_gp_member_t *lu_gp_mem;
+
+	if (alua->alua_type != SPC3_ALUA_EMULATED)
+		return;
+
+	if (!(lu_gp_mem = dev->dev_alua_lu_gp_mem))
+		return;
+
+	spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+	if ((lu_gp = lu_gp_mem->lu_gp)) {
+		spin_lock(&lu_gp->lu_gp_lock);
+		if (lu_gp_mem->lu_gp_assoc) {
+			list_del(&lu_gp_mem->lu_gp_mem_list);
+			lu_gp->lu_gp_members--;
+			lu_gp_mem->lu_gp_assoc = 0;
+		}
+		spin_unlock(&lu_gp->lu_gp_lock);
+		lu_gp_mem->lu_gp = NULL;
 	}
-	spin_unlock(&lu_gp->lu_gp_ref_lock);
+	spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
 
-	kmem_cache_free(t10_alua_lu_gp_cache, lu_gp);
+	kmem_cache_free(t10_alua_lu_gp_mem_cache, lu_gp_mem);
 	return;
 }
 
-extern t10_alua_lu_gp_t *core_alua_get_lu_gp_by_name (se_device_t *dev, const char *name)
+extern t10_alua_lu_gp_t *core_alua_get_lu_gp_by_name (const char *name)
 {
 	t10_alua_lu_gp_t *lu_gp;
 	struct config_item *ci;
@@ -215,66 +292,41 @@ extern t10_alua_lu_gp_t *core_alua_get_lu_gp_by_name (se_device_t *dev, const ch
 	return(NULL);
 }
 
-extern void core_alua_attach_lu_gp (se_device_t *dev, t10_alua_lu_gp_t *lu_gp)
+extern void core_alua_put_lu_gp_from_name (t10_alua_lu_gp_t *lu_gp)
 {
-	spin_lock(&lu_gp->lu_gp_ref_lock);
-	list_add_tail(&dev->dev_lu_gp_list, &lu_gp->lu_gp_ref_list);
-	lu_gp->lu_gp_members++;
-	spin_lock(&dev->dev_alua_lock);
-	dev->dev_alua_lu_gp = lu_gp;
-	spin_unlock(&dev->dev_alua_lock);
-	spin_unlock(&lu_gp->lu_gp_ref_lock);
+	spin_lock(&se_global->lu_gps_lock);
+	atomic_dec(&lu_gp->lu_gp_ref_cnt);
+	spin_unlock(&se_global->lu_gps_lock);
 
 	return;
 }
 
 /*
- * Called with se_device_t->dev_alua_lock held.
+ * Called with t10_alua_lu_gp_member_t->lu_gp_mem_lock
  */
-extern void __core_alua_put_lu_gp (se_device_t *dev, int clear)
+extern void __core_alua_attach_lu_gp_mem (t10_alua_lu_gp_member_t *lu_gp_mem, t10_alua_lu_gp_t *lu_gp)
 {
-	t10_alua_lu_gp_t *lu_gp;
-
-	if (!(lu_gp = dev->dev_alua_lu_gp)) 
-		return;
-
-	spin_lock(&lu_gp->lu_gp_ref_lock);
-	list_del(&dev->dev_lu_gp_list);
-	atomic_dec(&lu_gp->lu_gp_ref_cnt);
-	lu_gp->lu_gp_members--;
-	
-	if (!(clear)) {
-		spin_unlock(&lu_gp->lu_gp_ref_lock);
-		return;
-	}
-	dev->dev_alua_lu_gp = NULL;
-	spin_unlock(&lu_gp->lu_gp_ref_lock);
+	spin_lock(&lu_gp->lu_gp_lock);
+	lu_gp_mem->lu_gp = lu_gp;
+	lu_gp_mem->lu_gp_assoc = 1;
+	list_add_tail(&lu_gp_mem->lu_gp_mem_list, &lu_gp->lu_gp_mem_list);
+	lu_gp->lu_gp_members++;
+	spin_unlock(&lu_gp->lu_gp_lock);
 
 	return;
 }
 
-extern void core_alua_put_lu_gp (se_device_t *dev, int clear)
+/*
+ * Called with t10_alua_lu_gp_member_t->lu_gp_mem_lock
+ */
+extern void __core_alua_drop_lu_gp_mem (t10_alua_lu_gp_member_t *lu_gp_mem, t10_alua_lu_gp_t *lu_gp)
 {
-	t10_alua_lu_gp_t *lu_gp;
-
-	spin_lock(&dev->dev_alua_lock);
-	if (!(lu_gp = dev->dev_alua_lu_gp)) {
-		spin_unlock(&dev->dev_alua_lock);
-		return;
-	}
-	spin_lock(&lu_gp->lu_gp_ref_lock);
-	list_del(&dev->dev_lu_gp_list);
-	atomic_dec(&lu_gp->lu_gp_ref_cnt);
+	spin_lock(&lu_gp->lu_gp_lock);
+	list_del(&lu_gp_mem->lu_gp_mem_list);
+	lu_gp_mem->lu_gp = NULL;
+	lu_gp_mem->lu_gp_assoc = 0;
 	lu_gp->lu_gp_members--;
-
-	if (!(clear)) {
-		spin_unlock(&lu_gp->lu_gp_ref_lock);
-		spin_unlock(&dev->dev_alua_lock);
-		return;
-	}
-	dev->dev_alua_lu_gp = NULL;
-	spin_unlock(&lu_gp->lu_gp_ref_lock);
-	spin_unlock(&dev->dev_alua_lock);
+	spin_unlock(&lu_gp->lu_gp_lock);
 
 	return;
 }
@@ -513,6 +565,7 @@ extern int core_setup_alua (se_device_t *dev)
 {
 	se_subsystem_dev_t *su_dev = dev->se_sub_dev;
 	t10_alua_t *alua = T10_ALUA(su_dev);
+	t10_alua_lu_gp_member_t *lu_gp_mem;
 	/*
 	 * If this device is from Target_Core_Mod/pSCSI, use the ALUA logic
 	 * of the Underlying SCSI hardware.  In Linux/SCSI terms, this can
@@ -531,14 +584,20 @@ extern int core_setup_alua (se_device_t *dev)
 	 * use emulated ALUA.
 	 */
 	if (TRANSPORT(dev)->get_device_rev(dev) >= SCSI_3) {
-		alua->alua_type = SPC3_ALUA_EMULATED;
 		printk("%s: Enabling ALUA Emulation for SPC-3 device\n",
 				TRANSPORT(dev)->name);
 		/*
 		 * Assoicate this se_device_t with the default ALUA
 		 * LUN Group.
 		 */
-		core_alua_attach_lu_gp(dev, se_global->default_lu_gp);	
+		if (!(lu_gp_mem = core_alua_allocate_lu_gp_mem(dev)))
+			return(-1);
+		
+		alua->alua_type = SPC3_ALUA_EMULATED;
+		spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+		__core_alua_attach_lu_gp_mem(lu_gp_mem, se_global->default_lu_gp);	
+		spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
 		printk("%s: Adding to default ALUA LU Group: core/alua"
 			"/lu_gps/default_lu_gp\n", TRANSPORT(dev)->name);
 	} else {
diff --git a/drivers/lio-core/target_core_alua.h b/drivers/lio-core/target_core_alua.h
index 335847a..714692d 100644
--- a/drivers/lio-core/target_core_alua.h
+++ b/drivers/lio-core/target_core_alua.h
@@ -34,11 +34,14 @@
 
 extern int core_scsi3_emulate_report_target_port_groups (struct se_cmd_s *);
 extern struct t10_alua_lu_gp_s *core_alua_allocate_lu_gp (const char *);
+extern struct t10_alua_lu_gp_member_s *core_alua_allocate_lu_gp_mem (struct se_device_s *);
 extern void core_alua_free_lu_gp (struct t10_alua_lu_gp_s *);
-extern struct t10_alua_lu_gp_s *core_alua_get_lu_gp_by_name (struct se_device_s *, const char *);
-extern void core_alua_attach_lu_gp (struct se_device_s *, struct t10_alua_lu_gp_s *);
-extern void __core_alua_put_lu_gp (struct se_device_s *, int);
-extern void core_alua_put_lu_gp (struct se_device_s *, int);
+extern void core_alua_free_lu_gp_mem (struct se_device_s *);
+extern struct t10_alua_lu_gp_s *core_alua_get_lu_gp_by_name (const char *);
+extern void core_alua_put_lu_gp_from_name (struct t10_alua_lu_gp_s *);
+extern void __core_alua_attach_lu_gp_mem (struct t10_alua_lu_gp_member_s *, struct t10_alua_lu_gp_s *);
+extern void __core_alua_drop_lu_gp_mem (struct t10_alua_lu_gp_member_s *, struct t10_alua_lu_gp_s *);
+extern void core_alua_drop_lu_gp_dev (struct se_device_s *);
 extern struct t10_alua_tg_pt_gp_s *core_alua_allocate_tg_pt_gp (const char *);
 extern void core_alua_free_tg_pt_gp (struct t10_alua_tg_pt_gp_s *);
 extern struct t10_alua_tg_pt_gp_s *core_alua_get_tg_pt_gp_by_name (struct se_port_s *, const char *);
diff --git a/drivers/lio-core/target_core_base.h b/drivers/lio-core/target_core_base.h
index 08859a3..fc5dc29 100644
--- a/drivers/lio-core/target_core_base.h
+++ b/drivers/lio-core/target_core_base.h
@@ -50,7 +50,7 @@
 #define TRANSPORT_SENSE_SEGMENT_TOTAL       68 /* TRANSPORT_SENSE_SEGMENT_LENGTH + Padding */
 
 #define TRANSPORT_IQN_LEN			224 /* Currently same as ISCSI_IQN_LEN */
-
+#define LU_GROUP_NAME_BUF			256
 #define EVPD_TMP_BUF_SIZE			128 /* Used to parse EVPD into t10_evpd_t */
 
 /* used by PSCSI and iBlock Transport drivers */
@@ -193,13 +193,22 @@ typedef struct t10_alua_lu_gp_s {
 	u16	lu_gp_id;
 	int	lu_gp_alua_access_state;
 	u32	lu_gp_members;
+	atomic_t lu_gp_shutdown;
 	atomic_t lu_gp_ref_cnt;
-	spinlock_t lu_gp_ref_lock;
+	spinlock_t lu_gp_lock;
 	struct config_group lu_gp_group;
 	struct list_head lu_gp_list;
-	struct list_head lu_gp_ref_list;
+	struct list_head lu_gp_mem_list;
 } ____cacheline_aligned t10_alua_lu_gp_t;
 
+typedef struct t10_alua_lu_gp_member_s {
+	int lu_gp_assoc;
+	spinlock_t lu_gp_mem_lock;
+	t10_alua_lu_gp_t *lu_gp;
+	struct se_device_s *lu_gp_mem_dev;
+	struct list_head lu_gp_mem_list;
+} ____cacheline_aligned t10_alua_lu_gp_member_t;
+
 typedef struct t10_alua_tg_pt_gp_s {
 	u16	tg_pt_gp_id;
 	int	tg_pt_gp_alua_access_state;
@@ -211,6 +220,14 @@ typedef struct t10_alua_tg_pt_gp_s {
 	struct list_head tg_pt_gp_ref_list;
 } ____cacheline_aligned t10_alua_tg_pt_gp_t;
 
+typedef struct t10_alua_tg_pt_gp_member_s {
+	int tg_pt_gp_assoc;
+	spinlock_t tg_pt_gp_mem_lock;
+	t10_alua_tg_pt_gp_t *tg_pt_gp;
+	struct se_port_s *tg_pt;
+	struct list_head tg_pt_gp_mem_list;
+} ____cacheline_aligned t10_alua_tg_pt_gp_member_t;
+
 typedef struct t10_evpd_s {
 	unsigned char device_identifier[INQUIRY_EVPD_DEVICE_IDENTIFIER_LEN];
 	int protocol_identifier_set;
@@ -602,15 +619,13 @@ typedef struct se_device_s {
 	spinlock_t		execute_task_lock;
 	spinlock_t		state_task_lock;
 	spinlock_t		dev_reservation_lock;
-	spinlock_t		dev_alua_lock;
 	spinlock_t		dev_state_lock;
 	spinlock_t		dev_status_lock;
 	spinlock_t		dev_status_thr_lock;
 	spinlock_t		se_port_lock;
 	struct se_node_acl_s	*dev_reserved_node_acl; /* Used for legacy SPC-2 reservationsa */
-	struct t10_alua_lu_gp_s *dev_alua_lu_gp;	/* Used for ALUA Logical Unit Groups */
+	struct t10_alua_lu_gp_member_s *dev_alua_lu_gp_mem; /* Used for ALUA Logical Unit Group membership */
 	struct t10_pr_registration_s *dev_pr_res_holder; /* Used for SPC-3 Persistent Reservations */
-	struct list_head	dev_lu_gp_list;
 	struct list_head	dev_sep_list;
 	struct timer_list		dev_status_timer;
 	struct task_struct		*process_thread; /* Pointer to descriptor for processing thread */
diff --git a/drivers/lio-core/target_core_configfs.c b/drivers/lio-core/target_core_configfs.c
index 888522b..5b5f7a6 100644
--- a/drivers/lio-core/target_core_configfs.c
+++ b/drivers/lio-core/target_core_configfs.c
@@ -651,7 +651,7 @@ static ssize_t target_core_dev_wwn_store_attr_evpd_protocol_identifier (
 SE_DEV_WWN_ATTR(evpd_protocol_identifier, S_IRUGO | S_IWUSR);
 
 /*
- * Generic wrapper for dumping EVPD identifiers by assoication.
+ * Generic wrapper for dumping EVPD identifiers by association.
  */
 #define DEF_DEV_WWN_ASSOC_SHOW(_name, _assoc)					\
 static ssize_t target_core_dev_wwn_show_attr_##_name (				\
@@ -1252,18 +1252,27 @@ static ssize_t target_core_show_alua_lu_gp (void *p, char *page)
 	se_subsystem_dev_t *su_dev = (se_subsystem_dev_t *)p;
 	struct config_item *lu_ci;
 	t10_alua_lu_gp_t *lu_gp;
+	t10_alua_lu_gp_member_t *lu_gp_mem;
 	ssize_t len = 0;
 
 	if (!(dev = su_dev->se_dev_ptr)) 
 		return(-ENODEV);
 
-	spin_lock(&dev->dev_alua_lock);
-	if ((lu_gp = dev->dev_alua_lu_gp)) {
+	if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED)
+		return(len);
+
+	if (!(lu_gp_mem = dev->dev_alua_lu_gp_mem)) {
+		printk(KERN_ERR "NULL se_device_t->dev_alua_lu_gp_mem pointer\n");
+		return(-EINVAL);
+	}
+
+	spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+	if ((lu_gp = lu_gp_mem->lu_gp)) {
 		lu_ci = &lu_gp->lu_gp_group.cg_item;
 		len += sprintf(page, "LU Group Alias: %s\nLU Group ID: %hu\n",
 			config_item_name(lu_ci), lu_gp->lu_gp_id);
 	}
-	spin_unlock(&dev->dev_alua_lock);	
+	spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
 
 	return(len);
 }
@@ -1273,8 +1282,9 @@ static ssize_t target_core_store_alua_lu_gp (void *p, const char *page, size_t c
 	se_device_t *dev;
 	se_subsystem_dev_t *su_dev = (se_subsystem_dev_t *)p;
 	se_hba_t *hba = su_dev->se_dev_hba;
-	t10_alua_lu_gp_t *lu_gp = NULL, *lu_gp_new;
-	unsigned char buf[256];
+	t10_alua_lu_gp_t *lu_gp = NULL, *lu_gp_new = NULL;
+	t10_alua_lu_gp_member_t *lu_gp_mem;
+	unsigned char buf[LU_GROUP_NAME_BUF];
 	int move = 0;
 
 	if (!(dev = su_dev->se_dev_ptr)) 
@@ -1286,16 +1296,38 @@ static ssize_t target_core_store_alua_lu_gp (void *p, const char *page, size_t c
 			config_item_name(&su_dev->se_dev_group.cg_item));
 		return(-EINVAL);
 	}
-	if (count > 256) {
+	if (count > LU_GROUP_NAME_BUF) {
 		printk(KERN_ERR "ALUA LU Group Alias too large!\n");
 		return(-EINVAL);
 	}
-	memset(buf, 0, 256);
+	memset(buf, 0, LU_GROUP_NAME_BUF);
 	memcpy(buf, page, count);
+	/*
+	 * Any ALUA logical unit alias besides "NULL" means we will be
+	 * making a new group association.
+	 */
+	if (strcmp(strstrip(buf), "NULL")) {
+		/*
+		 * core_alua_get_lu_gp_by_name() will increment reference to
+		 * t10_alua_lu_gp_t.  This reference is released with
+		 * core_alua_get_lu_gp_by_name below().
+		 */
+		if (!(lu_gp_new = core_alua_get_lu_gp_by_name(strstrip(buf))))
+			return(-ENODEV);
+	}
+	if (!(lu_gp_mem = dev->dev_alua_lu_gp_mem)) {
+		if (lu_gp_new)
+			core_alua_put_lu_gp_from_name(lu_gp_new);
+		printk(KERN_ERR "NULL se_device_t->dev_alua_lu_gp_mem pointer\n");
+		return(-EINVAL);
+	}
 
-	spin_lock(&dev->dev_alua_lock);
-	if ((lu_gp = dev->dev_alua_lu_gp)) {
-		if (!(strcmp(strstrip(buf), "NULL"))) {
+	spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+	if ((lu_gp = lu_gp_mem->lu_gp)) {
+		/*
+		 * Clearing an existing lu_gp association, and replacing with NULL
+		 */
+		if (!(lu_gp_new)) {
 			printk("Target_Core_ConfigFS: Releasing %s/%s from ALUA"
 				" LU Group: core/alua/lu_gps/%s, ID: %hu\n",  
 				config_item_name(&hba->hba_group.cg_item),
@@ -1303,22 +1335,22 @@ static ssize_t target_core_store_alua_lu_gp (void *p, const char *page, size_t c
 				config_item_name(&lu_gp->lu_gp_group.cg_item),
 				lu_gp->lu_gp_id);
 
-			__core_alua_put_lu_gp(dev, 1);
-			spin_unlock(&dev->dev_alua_lock);
+			__core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp);
+			spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
 
 			return(count);
 		}
-	}
-	spin_unlock(&dev->dev_alua_lock);
-
-	if (!(lu_gp_new = core_alua_get_lu_gp_by_name(dev, strstrip(buf))))
-		return(-ENODEV);
-
-	if (lu_gp) {
-		core_alua_put_lu_gp(dev, 0);
+		/*
+		 * Removing existing association of lu_gp_mem with lu_gp
+		 */
+		__core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp);
 		move = 1;
 	}
-	core_alua_attach_lu_gp(dev, lu_gp_new);
+	/*
+	 * Associate lu_gp_mem with lu_gp_new.
+	 */
+	__core_alua_attach_lu_gp_mem(lu_gp_mem, lu_gp_new);
+	spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
 
 	printk("Target_Core_ConfigFS: %s %s/%s to ALUA LU Group:"
 		" core/alua/lu_gps/%s, ID: %hu\n",
@@ -1328,6 +1360,7 @@ static ssize_t target_core_store_alua_lu_gp (void *p, const char *page, size_t c
 		config_item_name(&lu_gp_new->lu_gp_group.cg_item),
 		lu_gp_new->lu_gp_id);
 
+	core_alua_put_lu_gp_from_name(lu_gp_new);
 	return(count);
 }
 
@@ -1434,13 +1467,15 @@ static ssize_t target_core_alua_lu_gp_show_attr_members (
 	se_device_t *dev;
 	se_hba_t *hba;
 	se_subsystem_dev_t *su_dev;
+	t10_alua_lu_gp_member_t *lu_gp_mem;
 	ssize_t len = 0, cur_len;
 	unsigned char buf[256];
 
 	memset(buf, 0, 256);
 
-	spin_lock(&lu_gp->lu_gp_ref_lock);
-	list_for_each_entry(dev, &lu_gp->lu_gp_ref_list, dev_lu_gp_list) {
+	spin_lock(&lu_gp->lu_gp_lock);
+	list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, lu_gp_mem_list) {
+		dev = lu_gp_mem->lu_gp_mem_dev;
 		su_dev = dev->se_sub_dev;
 		hba = su_dev->se_dev_hba;
 
@@ -1457,7 +1492,7 @@ static ssize_t target_core_alua_lu_gp_show_attr_members (
 		memcpy(page+len, buf, cur_len);
 		len += cur_len;
 	}
-	spin_unlock(&lu_gp->lu_gp_ref_lock);
+	spin_unlock(&lu_gp->lu_gp_lock);
 
 	return(len);
 }
diff --git a/drivers/lio-core/target_core_device.c b/drivers/lio-core/target_core_device.c
index f7ad451..2c9566e 100644
--- a/drivers/lio-core/target_core_device.c
+++ b/drivers/lio-core/target_core_device.c
@@ -764,8 +764,7 @@ extern int se_free_virtual_device (se_device_t *dev, se_hba_t *hba)
 	se_clear_dev_ports(dev);
 	spin_unlock(&hba->device_lock);
 
-	core_alua_put_lu_gp(dev, 1);	
-	
+	core_alua_free_lu_gp_mem(dev);	
 	se_release_device_for_hba(dev);
 	
 	return(0);
diff --git a/drivers/lio-core/target_core_transport.c b/drivers/lio-core/target_core_transport.c
index 82ccd3c..18c3693 100644
--- a/drivers/lio-core/target_core_transport.c
+++ b/drivers/lio-core/target_core_transport.c
@@ -210,7 +210,9 @@ struct kmem_cache *se_task_cache = NULL;
 struct kmem_cache *se_sess_cache = NULL;
 struct kmem_cache *t10_pr_reg_cache = NULL;
 struct kmem_cache *t10_alua_lu_gp_cache = NULL;
+struct kmem_cache *t10_alua_lu_gp_mem_cache = NULL;
 struct kmem_cache *t10_alua_tg_pt_gp_cache = NULL;
+struct kmem_cache *t10_alua_tg_pt_gp_mem_cache = NULL;
 
 EXPORT_SYMBOL(se_global);
 static int transport_generic_write_pending (se_cmd_t *);
@@ -292,12 +294,24 @@ extern int init_se_global (void)
 		printk(KERN_ERR "kmem_cache_create() for t10_alua_lu_gp_cache failed\n");
 		goto out;
 	}
+	if (!(t10_alua_lu_gp_mem_cache = kmem_cache_create("t10_alua_lu_gp_mem_cache",
+			sizeof(t10_alua_lu_gp_member_t), __alignof__(t10_alua_lu_gp_member_t),
+			0, NULL))) {
+		printk(KERN_ERR "kmem_cache_create() for t10_alua_lu_gp_mem_cache failed\n");
+		goto out;
+	}
 	if (!(t10_alua_tg_pt_gp_cache = kmem_cache_create("t10_alua_tg_pt_gp_cache",
 			sizeof(t10_alua_tg_pt_gp_t), __alignof__(t10_alua_tg_pt_gp_t),
 			0, NULL))) {
 		printk(KERN_ERR "kmem_cache_create() for t10_alua_tg_pt_gp_cache failed\n");
 		goto out;
 	}
+	if (!(t10_alua_tg_pt_gp_mem_cache = kmem_cache_create("t10_alua_tg_pt_gp_mem_cache",
+			sizeof(t10_alua_tg_pt_gp_member_t), __alignof__(t10_alua_tg_pt_gp_member_t),
+			0, NULL))) {
+		printk(KERN_ERR "kmem_cache_create() for t10_alua_tg_pt_gp_mem_t failed\n");
+		goto out;
+	}
 
         if (!(global->hba_list = kzalloc((sizeof(se_hba_t) *
 				TRANSPORT_MAX_GLOBAL_HBAS), GFP_KERNEL))) {
@@ -340,8 +354,12 @@ out:
 		kmem_cache_destroy(t10_pr_reg_cache);
 	if (t10_alua_lu_gp_cache)
 		kmem_cache_destroy(t10_alua_lu_gp_cache);
+	if (t10_alua_lu_gp_mem_cache)
+		kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
 	if (t10_alua_tg_pt_gp_cache)
 		kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+	if (t10_alua_tg_pt_gp_mem_cache)
+		kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
 	kfree(global);
         return(-1);
 }
@@ -360,7 +378,9 @@ extern void release_se_global (void)
 	kmem_cache_destroy(se_sess_cache);
 	kmem_cache_destroy(t10_pr_reg_cache);
 	kmem_cache_destroy(t10_alua_lu_gp_cache);
+	kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
 	kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+	kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
 	kfree(global);
 
 	se_global = NULL;
@@ -2084,13 +2104,11 @@ extern se_device_t *transport_add_device_to_core_hba (
 	dev->transport		= transport;
 	atomic_set(&dev->active_cmds, 0);
 	INIT_LIST_HEAD(&dev->dev_sep_list);
-	INIT_LIST_HEAD(&dev->dev_lu_gp_list);
 	init_MUTEX_LOCKED(&dev->dev_queue_obj->thread_create_sem);
 	init_MUTEX_LOCKED(&dev->dev_queue_obj->thread_done_sem);
 	init_MUTEX_LOCKED(&dev->dev_queue_obj->thread_sem);
 	spin_lock_init(&dev->execute_task_lock);
 	spin_lock_init(&dev->state_task_lock);
-	spin_lock_init(&dev->dev_alua_lock);
 	spin_lock_init(&dev->dev_reservation_lock);
 	spin_lock_init(&dev->dev_status_lock);
 	spin_lock_init(&dev->dev_status_thr_lock);
@@ -2129,7 +2147,8 @@ extern se_device_t *transport_add_device_to_core_hba (
 	/*
 	 * Setup the Asymmetric Logical Unit Assignment for se_device_t
 	 */
-	core_setup_alua(dev);
+	if (core_setup_alua(dev) < 0)
+		goto out;
 	/*
 	 * Startup the se_device_t processing thread
 	 */	
@@ -4192,7 +4211,7 @@ extern int transport_generic_emulate_inquiry (
 		 */
 check_port:
 		if ((port = lun->lun_sep)) {	
-			t10_alua_lu_gp_t *lu_gp_p;
+			t10_alua_lu_gp_t *lu_gp;
 			t10_alua_tg_pt_gp_t *tg_pt_gp_p;
 			u32 padding, scsi_name_len;
 			u16 lu_gp_id = 0;
@@ -4259,10 +4278,16 @@ check_lu_gp:
 				len += 8;
 				goto check_scsi_name;
 			}
-			spin_lock(&dev->dev_alua_lock);
-			if ((lu_gp_p = dev->dev_alua_lu_gp))
-				lu_gp_id = lu_gp_p->lu_gp_id;
-			spin_unlock(&dev->dev_alua_lock);
+			if (!(dev->dev_alua_lu_gp_mem))
+				goto check_scsi_name;
+
+			spin_lock(&dev->dev_alua_lu_gp_mem->lu_gp_mem_lock);
+			if (!(lu_gp = dev->dev_alua_lu_gp_mem->lu_gp)) {
+				spin_unlock(&dev->dev_alua_lu_gp_mem->lu_gp_mem_lock);
+				goto check_scsi_name;
+			}
+			lu_gp_id = lu_gp->lu_gp_id;
+			spin_unlock(&dev->dev_alua_lu_gp_mem->lu_gp_mem_lock);
 
 			buf[off++] |= 0x1; // CODE SET == Binary
 			buf[off++] |= 0x6; // DESIGNATOR TYPE == Logical Unit Group identifier
-- 
1.5.4.1



--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux