[PATCH 2/4] [Target_Core_Mod/ALUA]: Add support for savingsecondary fabric port metadata across target power loss

From: Nicholas A. Bellinger
Date: Mon Aug 31 2009 - 04:29:46 EST


Hello,

This patch adds core_alua_update_tpg_secondary_metadata() for saving ALUA target target group
secondary access state and status in core_alua_set_tg_pt_secondary_state() on a per TCM
fabric Port/LUN basis in /var/target/alua/$FABRIC/$FABRIC_ENDPOINT/. The
writing to each struct file is protected by se_port_t->sep_tg_pt_md_mutex.

This patch updates core_alua_set_tg_pt_secondary_state() to allocate a local
scope buffer of t10_alua_tg_pt_gp_t->tg_pt_gp_md_buf_len (1024 hardcoded
default), and that is then passed into core_alua_update_tpg_secondary_metadata()
for the acual ALUA secondary state transition, and freed upon
core_alua_set_tg_pt_secondary_state() return.

This patch adds the fabric configfs wrappers for handling ALUA secondary access
metadata that are defined as EXPORT_SYMBOL() and called by TCM fabric module code

*) core_alua_show_secondary_status()
*) core_alua_store_secondary_status(),
*) core_alua_show_secondary_write_metadata()
*) core_alua_store_secondary_write_metadata()

This patch also moves the vfs_writev() to struct file for ALUA metadata code
to a generic function in core_alua_write_tpg_metadata() and adds
core_alua_update_tpg_primary_metadata() to use this code for ALUA primary
access state/status metadata writeout as well.

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
drivers/target/target_core_alua.c | 193 ++++++++++++++++++++++++++++++++-----
include/target/target_core_alua.h | 15 +++-
include/target/target_core_base.h | 2 +
3 files changed, 181 insertions(+), 29 deletions(-)

diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 4b92663..8d1f9fc 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -614,44 +614,30 @@ int core_alua_check_nonop_delay(
EXPORT_SYMBOL(core_alua_check_nonop_delay);

/*
- * Called with tg_pt_gp->tg_pt_gp_md_mutex held
+ * Called with tg_pt_gp->tg_pt_gp_md_mutex or tg_pt_gp_mem->sep_tg_pt_md_mutex
+ *
*/
-int core_alua_update_tpg_primary_metadata(
- t10_alua_tg_pt_gp_t *tg_pt_gp,
- int primary_state,
- unsigned char *md_buf)
+int core_alua_write_tpg_metadata(
+ const char *path,
+ unsigned char *md_buf,
+ u32 md_buf_len)
{
- se_subsystem_dev_t *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
- t10_wwn_t *wwn = &su_dev->t10_wwn;
+ mm_segment_t old_fs;
struct file *file;
struct iovec iov[1];
- mm_segment_t old_fs;
- char path[512];
- int flags = O_RDWR | O_CREAT | O_TRUNC;
- int len, ret;
+ int flags = O_RDWR | O_CREAT | O_TRUNC, ret;

memset(iov, 0, sizeof(struct iovec));
- memset(path, 0, 512);
-
- len = snprintf(md_buf, tg_pt_gp->tg_pt_gp_md_buf_len,
- "tg_pt_gp_id=%hu\n"
- "alua_access_state=0x%02x\n"
- "alua_access_status=0x%02x\n",
- tg_pt_gp->tg_pt_gp_id, primary_state,
- tg_pt_gp->tg_pt_gp_alua_access_status);

- snprintf(path, 512, "/var/target/alua/tpgs_%s/%s",
- &wwn->unit_serial[0],
- config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item));
file = filp_open(path, flags, 0600);
if (IS_ERR(file) || !file || !file->f_dentry) {
printk(KERN_ERR "filp_open(%s) for ALUA metadata failed\n",
path);
return -1;
}
-
+
iov[0].iov_base = &md_buf[0];
- iov[0].iov_len = len;
+ iov[0].iov_len = md_buf_len;

old_fs = get_fs();
set_fs(get_ds());
@@ -659,7 +645,7 @@ int core_alua_update_tpg_primary_metadata(
set_fs(old_fs);

if (ret < 0) {
- printk("Error writing ALUA metadata file: %s\n", path);
+ printk("Error writing ALUA metadata file: %s\n", path);
filp_close(file, NULL);
return -1;
}
@@ -668,6 +654,35 @@ int core_alua_update_tpg_primary_metadata(
return 0;
}

+/*
+ * Called with tg_pt_gp->tg_pt_gp_md_mutex held
+ */
+int core_alua_update_tpg_primary_metadata(
+ t10_alua_tg_pt_gp_t *tg_pt_gp,
+ int primary_state,
+ unsigned char *md_buf)
+{
+ se_subsystem_dev_t *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+ t10_wwn_t *wwn = &su_dev->t10_wwn;
+ char path[512];
+ int len;
+
+ memset(path, 0, 512);
+
+ len = snprintf(md_buf, tg_pt_gp->tg_pt_gp_md_buf_len,
+ "tg_pt_gp_id=%hu\n"
+ "alua_access_state=0x%02x\n"
+ "alua_access_status=0x%02x\n",
+ tg_pt_gp->tg_pt_gp_id, primary_state,
+ tg_pt_gp->tg_pt_gp_alua_access_status);
+
+ snprintf(path, 512, "/var/target/alua/tpgs_%s/%s",
+ &wwn->unit_serial[0],
+ config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item));
+
+ return core_alua_write_tpg_metadata(path, md_buf, len);
+}
+
int core_alua_do_transition_tg_pt(
t10_alua_tg_pt_gp_t *tg_pt_gp,
se_port_t *l_port,
@@ -895,6 +910,41 @@ int core_alua_do_port_transition(
return 0;
}

+/*
+ * Called with tg_pt_gp_mem->sep_tg_pt_md_mutex held
+ */
+int core_alua_update_tpg_secondary_metadata(
+ struct t10_alua_tg_pt_gp_member_s *tg_pt_gp_mem,
+ se_port_t *port,
+ unsigned char *md_buf,
+ u32 md_buf_len)
+{
+ se_portal_group_t *se_tpg = port->sep_tpg;
+ char path[512], wwn[1024];
+ int len;
+
+ memset(path, 0, 512);
+ memset(wwn, 0, 1024);
+
+ len = snprintf(wwn, 512, "%s",
+ TPG_TFO(se_tpg)->tpg_get_wwn(se_tpg));
+
+ if (TPG_TFO(se_tpg)->tpg_get_tag != NULL)
+ snprintf(wwn+len, 1024-len, "+%hu",
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg));
+
+ len = snprintf(md_buf, md_buf_len, "alua_tg_pt_offline=%d\n"
+ "alua_tg_pt_status=0x%02x\n",
+ atomic_read(&port->sep_tg_pt_secondary_offline),
+ port->sep_tg_pt_secondary_stat);
+
+ snprintf(path, 512, "/var/target/alua/%s/%s/lun_%u",
+ TPG_TFO(se_tpg)->get_fabric_name(), wwn,
+ port->sep_lun->unpacked_lun);
+
+ return core_alua_write_tpg_metadata(path, md_buf, len);
+}
+
int core_alua_set_tg_pt_secondary_state(
struct t10_alua_tg_pt_gp_member_s *tg_pt_gp_mem,
se_port_t *port,
@@ -902,6 +952,8 @@ int core_alua_set_tg_pt_secondary_state(
int offline)
{
struct t10_alua_tg_pt_gp_s *tg_pt_gp;
+ unsigned char *md_buf;
+ u32 md_buf_len;
int trans_delay_msecs;

spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
@@ -922,6 +974,7 @@ int core_alua_set_tg_pt_secondary_state(
else
atomic_set(&port->sep_tg_pt_secondary_offline, 0);

+ md_buf_len = tg_pt_gp->tg_pt_gp_md_buf_len;
port->sep_tg_pt_secondary_stat = (explict) ?
ALUA_STATUS_ALTERED_BY_EXPLICT_STPG :
ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA;
@@ -932,9 +985,30 @@ int core_alua_set_tg_pt_secondary_state(
tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE");

spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-
+ /*
+ * Do the optional transition delay after we set the secondary
+ * ALUA access state.
+ */
if (trans_delay_msecs != 0)
msleep_interruptible(trans_delay_msecs);
+ /*
+ * See if we need to update the ALUA fabric port metadata for
+ * secondary state and status
+ */
+ if (port->sep_tg_pt_secondary_write_md) {
+ md_buf = kzalloc(md_buf_len, GFP_KERNEL);
+ if (!(md_buf)) {
+ printk(KERN_ERR "Unable to allocate md_buf for"
+ " secondary ALUA access metadata\n");
+ return -1;
+ }
+ mutex_lock(&port->sep_tg_pt_md_mutex);
+ core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port,
+ md_buf, md_buf_len);
+ mutex_unlock(&port->sep_tg_pt_md_mutex);
+
+ kfree(md_buf);
+ }

return 0;
}
@@ -1781,6 +1855,73 @@ ssize_t core_alua_store_offline_bit(se_lun_t *lun, const char *page, size_t coun
}
EXPORT_SYMBOL(core_alua_store_offline_bit);

+ssize_t core_alua_show_secondary_status(
+ se_lun_t *lun,
+ char *page)
+{
+ return sprintf(page, "%d\n", lun->lun_sep->sep_tg_pt_secondary_stat);
+}
+EXPORT_SYMBOL(core_alua_show_secondary_status);
+
+ssize_t core_alua_store_secondary_status(
+ se_lun_t *lun,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_tg_pt_status\n");
+ return -EINVAL;
+ }
+ if ((tmp != ALUA_STATUS_NONE) &&
+ (tmp != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) &&
+ (tmp != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) {
+ printk(KERN_ERR "Illegal value for alua_tg_pt_status: %lu\n",
+ tmp);
+ return -EINVAL;
+ }
+ lun->lun_sep->sep_tg_pt_secondary_stat = (int)tmp;
+
+ return count;
+}
+EXPORT_SYMBOL(core_alua_store_secondary_status);
+
+ssize_t core_alua_show_secondary_write_metadata(
+ se_lun_t *lun,
+ char *page)
+{
+ return sprintf(page, "%d\n",
+ lun->lun_sep->sep_tg_pt_secondary_write_md);
+}
+EXPORT_SYMBOL(core_alua_show_secondary_write_metadata);
+
+ssize_t core_alua_store_secondary_write_metadata(
+ se_lun_t *lun,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_tg_pt_write_md\n");
+ return -EINVAL;
+ }
+ if ((tmp != 0) && (tmp != 1)) {
+ printk(KERN_ERR "Illegal value for alua_tg_pt_write_md:"
+ " %lu\n", tmp);
+ return -EINVAL;
+ }
+ lun->lun_sep->sep_tg_pt_secondary_write_md = (int)tmp;
+
+ return count;
+}
+EXPORT_SYMBOL(core_alua_store_secondary_write_metadata);
+
int core_setup_alua(se_device_t *dev)
{
se_subsystem_dev_t *su_dev = dev->se_sub_dev;
diff --git a/include/target/target_core_alua.h b/include/target/target_core_alua.h
index 7aa3b5d..4e5a107 100644
--- a/include/target/target_core_alua.h
+++ b/include/target/target_core_alua.h
@@ -115,11 +115,20 @@ extern ssize_t core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp_s *,
char *);
extern ssize_t core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp_s *,
const char *, size_t);
-extern ssize_t core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp_s *, char *);
+extern ssize_t core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp_s *,
+ char *);
extern ssize_t core_alua_store_preferred_bit(struct t10_alua_tg_pt_gp_s *,
- const char *, size_t);
+ const char *, size_t);
extern ssize_t core_alua_show_offline_bit(struct se_lun_s *, char *);
-extern ssize_t core_alua_store_offline_bit(struct se_lun_s *, const char *, size_t);
+extern ssize_t core_alua_store_offline_bit(struct se_lun_s *, const char *,
+ size_t);
+extern ssize_t core_alua_show_secondary_status(struct se_lun_s *, char *);
+extern ssize_t core_alua_store_secondary_status(struct se_lun_s *,
+ const char *, size_t);
+extern ssize_t core_alua_show_secondary_write_metadata(struct se_lun_s *,
+ char *);
+extern ssize_t core_alua_store_secondary_write_metadata(struct se_lun_s *,
+ const char *, size_t);
extern int core_setup_alua(struct se_device_s *);

#endif /* TARGET_CORE_ALUA_H */
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index d166606..7ae0758 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -882,6 +882,7 @@ typedef struct se_port_s {
/* RELATIVE TARGET PORT IDENTIFER */
u16 sep_rtpi;
int sep_tg_pt_secondary_stat;
+ int sep_tg_pt_secondary_write_md;
#ifdef SNMP_SUPPORT
u32 sep_index;
scsi_port_stats_t sep_stats;
@@ -890,6 +891,7 @@ typedef struct se_port_s {
atomic_t sep_tg_pt_gp_active;
atomic_t sep_tg_pt_secondary_offline;
spinlock_t sep_alua_lock;
+ struct mutex sep_tg_pt_md_mutex;
struct t10_alua_tg_pt_gp_member_s *sep_alua_tg_pt_gp_mem;
struct se_lun_s *sep_lun;
struct se_portal_group_s *sep_tpg;
--
1.5.4.1



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