IB/srpt: Accept GUIDs as port names

Port and ACL information must be configured before an initiator
logs in.  Make it possible to configure this information before
a subnet prefix has been assigned to a port by not only accepting
GIDs as target port and initiator port names but by also accepting
port GUIDs.

Add a 'priv' member to struct se_wwn to allow target drivers to
associate their own data with struct se_wwn.

Reported-by: Doug Ledford <dledford@redhat.com>
References: http://www.spinics.net/lists/linux-rdma/msg39505.html
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
Bart Van Assche 2016-12-09 11:00:33 -08:00 committed by Doug Ledford
parent a3dd3a48a5
commit 2bce1a6d22
4 changed files with 98 additions and 61 deletions

View File

@ -500,6 +500,7 @@ static int srpt_refresh_port(struct srpt_port *sport)
struct ib_mad_reg_req reg_req; struct ib_mad_reg_req reg_req;
struct ib_port_modify port_modify; struct ib_port_modify port_modify;
struct ib_port_attr port_attr; struct ib_port_attr port_attr;
__be16 *guid;
int ret; int ret;
memset(&port_modify, 0, sizeof(port_modify)); memset(&port_modify, 0, sizeof(port_modify));
@ -522,10 +523,17 @@ static int srpt_refresh_port(struct srpt_port *sport)
if (ret) if (ret)
goto err_query_port; goto err_query_port;
sport->port_guid_wwn.priv = sport;
guid = (__be16 *)&sport->gid.global.interface_id;
snprintf(sport->port_guid, sizeof(sport->port_guid), snprintf(sport->port_guid, sizeof(sport->port_guid),
"0x%016llx%016llx", "%04x:%04x:%04x:%04x",
be64_to_cpu(sport->gid.global.subnet_prefix), be16_to_cpu(guid[0]), be16_to_cpu(guid[1]),
be64_to_cpu(sport->gid.global.interface_id)); be16_to_cpu(guid[2]), be16_to_cpu(guid[3]));
sport->port_gid_wwn.priv = sport;
snprintf(sport->port_gid, sizeof(sport->port_gid),
"0x%016llx%016llx",
be64_to_cpu(sport->gid.global.subnet_prefix),
be64_to_cpu(sport->gid.global.interface_id));
if (!sport->mad_agent) { if (!sport->mad_agent) {
memset(&reg_req, 0, sizeof(reg_req)); memset(&reg_req, 0, sizeof(reg_req));
@ -1838,6 +1846,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
struct srp_login_rej *rej; struct srp_login_rej *rej;
struct ib_cm_rep_param *rep_param; struct ib_cm_rep_param *rep_param;
struct srpt_rdma_ch *ch, *tmp_ch; struct srpt_rdma_ch *ch, *tmp_ch;
__be16 *guid;
u32 it_iu_len; u32 it_iu_len;
int i, ret = 0; int i, ret = 0;
@ -1983,26 +1992,30 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
goto destroy_ib; goto destroy_ib;
} }
/* guid = (__be16 *)&param->primary_path->sgid.global.interface_id;
* Use the initator port identifier as the session name, when snprintf(ch->ini_guid, sizeof(ch->ini_guid), "%04x:%04x:%04x:%04x",
* checking against se_node_acl->initiatorname[] this can be be16_to_cpu(guid[0]), be16_to_cpu(guid[1]),
* with or without preceeding '0x'. be16_to_cpu(guid[2]), be16_to_cpu(guid[3]));
*/
snprintf(ch->sess_name, sizeof(ch->sess_name), "0x%016llx%016llx", snprintf(ch->sess_name, sizeof(ch->sess_name), "0x%016llx%016llx",
be64_to_cpu(*(__be64 *)ch->i_port_id), be64_to_cpu(*(__be64 *)ch->i_port_id),
be64_to_cpu(*(__be64 *)(ch->i_port_id + 8))); be64_to_cpu(*(__be64 *)(ch->i_port_id + 8)));
pr_debug("registering session %s\n", ch->sess_name); pr_debug("registering session %s\n", ch->sess_name);
ch->sess = target_alloc_session(&sport->port_tpg_1, 0, 0, if (sport->port_guid_tpg.se_tpg_wwn)
ch->sess = target_alloc_session(&sport->port_guid_tpg, 0, 0,
TARGET_PROT_NORMAL,
ch->ini_guid, ch, NULL);
if (sport->port_gid_tpg.se_tpg_wwn && IS_ERR_OR_NULL(ch->sess))
ch->sess = target_alloc_session(&sport->port_gid_tpg, 0, 0,
TARGET_PROT_NORMAL, ch->sess_name, ch, TARGET_PROT_NORMAL, ch->sess_name, ch,
NULL); NULL);
/* Retry without leading "0x" */ /* Retry without leading "0x" */
if (IS_ERR(ch->sess)) if (sport->port_gid_tpg.se_tpg_wwn && IS_ERR_OR_NULL(ch->sess))
ch->sess = target_alloc_session(&sport->port_tpg_1, 0, 0, ch->sess = target_alloc_session(&sport->port_gid_tpg, 0, 0,
TARGET_PROT_NORMAL, TARGET_PROT_NORMAL,
ch->sess_name + 2, ch, NULL); ch->sess_name + 2, ch, NULL);
if (IS_ERR(ch->sess)) { if (IS_ERR_OR_NULL(ch->sess)) {
pr_info("Rejected login because no ACL has been configured yet for initiator %s.\n", pr_info("Rejected login because no ACL has been configured yet for initiator %s.\n",
ch->sess_name); ch->sess_name);
rej->reason = cpu_to_be32((PTR_ERR(ch->sess) == -ENOMEM) ? rej->reason = cpu_to_be32((PTR_ERR(ch->sess) == -ENOMEM) ?
@ -2420,7 +2433,7 @@ static int srpt_release_sdev(struct srpt_device *sdev)
return 0; return 0;
} }
static struct srpt_port *__srpt_lookup_port(const char *name) static struct se_wwn *__srpt_lookup_wwn(const char *name)
{ {
struct ib_device *dev; struct ib_device *dev;
struct srpt_device *sdev; struct srpt_device *sdev;
@ -2435,23 +2448,25 @@ static struct srpt_port *__srpt_lookup_port(const char *name)
for (i = 0; i < dev->phys_port_cnt; i++) { for (i = 0; i < dev->phys_port_cnt; i++) {
sport = &sdev->port[i]; sport = &sdev->port[i];
if (!strcmp(sport->port_guid, name)) if (strcmp(sport->port_guid, name) == 0)
return sport; return &sport->port_guid_wwn;
if (strcmp(sport->port_gid, name) == 0)
return &sport->port_gid_wwn;
} }
} }
return NULL; return NULL;
} }
static struct srpt_port *srpt_lookup_port(const char *name) static struct se_wwn *srpt_lookup_wwn(const char *name)
{ {
struct srpt_port *sport; struct se_wwn *wwn;
spin_lock(&srpt_dev_lock); spin_lock(&srpt_dev_lock);
sport = __srpt_lookup_port(name); wwn = __srpt_lookup_wwn(name);
spin_unlock(&srpt_dev_lock); spin_unlock(&srpt_dev_lock);
return sport; return wwn;
} }
/** /**
@ -2643,11 +2658,19 @@ static char *srpt_get_fabric_name(void)
return "srpt"; return "srpt";
} }
static struct srpt_port *srpt_tpg_to_sport(struct se_portal_group *tpg)
{
return tpg->se_tpg_wwn->priv;
}
static char *srpt_get_fabric_wwn(struct se_portal_group *tpg) static char *srpt_get_fabric_wwn(struct se_portal_group *tpg)
{ {
struct srpt_port *sport = container_of(tpg, struct srpt_port, port_tpg_1); struct srpt_port *sport = srpt_tpg_to_sport(tpg);
return sport->port_guid; WARN_ON_ONCE(tpg != &sport->port_guid_tpg &&
tpg != &sport->port_gid_tpg);
return tpg == &sport->port_guid_tpg ? sport->port_guid :
sport->port_gid;
} }
static u16 srpt_get_tag(struct se_portal_group *tpg) static u16 srpt_get_tag(struct se_portal_group *tpg)
@ -2737,6 +2760,19 @@ static int srpt_get_tcm_cmd_state(struct se_cmd *se_cmd)
return srpt_get_cmd_state(ioctx); return srpt_get_cmd_state(ioctx);
} }
static int srpt_parse_guid(u64 *guid, const char *name)
{
u16 w[4];
int ret = -EINVAL;
if (sscanf(name, "%hx:%hx:%hx:%hx", &w[0], &w[1], &w[2], &w[3]) != 4)
goto out;
*guid = get_unaligned_be64(w);
ret = 0;
out:
return ret;
}
/** /**
* srpt_parse_i_port_id() - Parse an initiator port ID. * srpt_parse_i_port_id() - Parse an initiator port ID.
* @name: ASCII representation of a 128-bit initiator port ID. * @name: ASCII representation of a 128-bit initiator port ID.
@ -2772,20 +2808,23 @@ out:
*/ */
static int srpt_init_nodeacl(struct se_node_acl *se_nacl, const char *name) static int srpt_init_nodeacl(struct se_node_acl *se_nacl, const char *name)
{ {
u64 guid;
u8 i_port_id[16]; u8 i_port_id[16];
int ret;
if (srpt_parse_i_port_id(i_port_id, name) < 0) { ret = srpt_parse_guid(&guid, name);
if (ret < 0)
ret = srpt_parse_i_port_id(i_port_id, name);
if (ret < 0)
pr_err("invalid initiator port ID %s\n", name); pr_err("invalid initiator port ID %s\n", name);
return -EINVAL; return ret;
}
return 0;
} }
static ssize_t srpt_tpg_attrib_srp_max_rdma_size_show(struct config_item *item, static ssize_t srpt_tpg_attrib_srp_max_rdma_size_show(struct config_item *item,
char *page) char *page)
{ {
struct se_portal_group *se_tpg = attrib_to_tpg(item); struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg);
return sprintf(page, "%u\n", sport->port_attrib.srp_max_rdma_size); return sprintf(page, "%u\n", sport->port_attrib.srp_max_rdma_size);
} }
@ -2794,7 +2833,7 @@ static ssize_t srpt_tpg_attrib_srp_max_rdma_size_store(struct config_item *item,
const char *page, size_t count) const char *page, size_t count)
{ {
struct se_portal_group *se_tpg = attrib_to_tpg(item); struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg);
unsigned long val; unsigned long val;
int ret; int ret;
@ -2822,7 +2861,7 @@ static ssize_t srpt_tpg_attrib_srp_max_rsp_size_show(struct config_item *item,
char *page) char *page)
{ {
struct se_portal_group *se_tpg = attrib_to_tpg(item); struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg);
return sprintf(page, "%u\n", sport->port_attrib.srp_max_rsp_size); return sprintf(page, "%u\n", sport->port_attrib.srp_max_rsp_size);
} }
@ -2831,7 +2870,7 @@ static ssize_t srpt_tpg_attrib_srp_max_rsp_size_store(struct config_item *item,
const char *page, size_t count) const char *page, size_t count)
{ {
struct se_portal_group *se_tpg = attrib_to_tpg(item); struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg);
unsigned long val; unsigned long val;
int ret; int ret;
@ -2859,7 +2898,7 @@ static ssize_t srpt_tpg_attrib_srp_sq_size_show(struct config_item *item,
char *page) char *page)
{ {
struct se_portal_group *se_tpg = attrib_to_tpg(item); struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg);
return sprintf(page, "%u\n", sport->port_attrib.srp_sq_size); return sprintf(page, "%u\n", sport->port_attrib.srp_sq_size);
} }
@ -2868,7 +2907,7 @@ static ssize_t srpt_tpg_attrib_srp_sq_size_store(struct config_item *item,
const char *page, size_t count) const char *page, size_t count)
{ {
struct se_portal_group *se_tpg = attrib_to_tpg(item); struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg);
unsigned long val; unsigned long val;
int ret; int ret;
@ -2906,7 +2945,7 @@ static struct configfs_attribute *srpt_tpg_attrib_attrs[] = {
static ssize_t srpt_tpg_enable_show(struct config_item *item, char *page) static ssize_t srpt_tpg_enable_show(struct config_item *item, char *page)
{ {
struct se_portal_group *se_tpg = to_tpg(item); struct se_portal_group *se_tpg = to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg);
return snprintf(page, PAGE_SIZE, "%d\n", (sport->enabled) ? 1: 0); return snprintf(page, PAGE_SIZE, "%d\n", (sport->enabled) ? 1: 0);
} }
@ -2915,7 +2954,7 @@ static ssize_t srpt_tpg_enable_store(struct config_item *item,
const char *page, size_t count) const char *page, size_t count)
{ {
struct se_portal_group *se_tpg = to_tpg(item); struct se_portal_group *se_tpg = to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg);
struct srpt_device *sdev = sport->sdev; struct srpt_device *sdev = sport->sdev;
struct srpt_rdma_ch *ch; struct srpt_rdma_ch *ch;
unsigned long tmp; unsigned long tmp;
@ -2967,15 +3006,19 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn,
struct config_group *group, struct config_group *group,
const char *name) const char *name)
{ {
struct srpt_port *sport = container_of(wwn, struct srpt_port, port_wwn); struct srpt_port *sport = wwn->priv;
static struct se_portal_group *tpg;
int res; int res;
/* Initialize sport->port_wwn and sport->port_tpg_1 */ WARN_ON_ONCE(wwn != &sport->port_guid_wwn &&
res = core_tpg_register(&sport->port_wwn, &sport->port_tpg_1, SCSI_PROTOCOL_SRP); wwn != &sport->port_gid_wwn);
tpg = wwn == &sport->port_guid_wwn ? &sport->port_guid_tpg :
&sport->port_gid_tpg;
res = core_tpg_register(wwn, tpg, SCSI_PROTOCOL_SRP);
if (res) if (res)
return ERR_PTR(res); return ERR_PTR(res);
return &sport->port_tpg_1; return tpg;
} }
/** /**
@ -2984,11 +3027,10 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn,
*/ */
static void srpt_drop_tpg(struct se_portal_group *tpg) static void srpt_drop_tpg(struct se_portal_group *tpg)
{ {
struct srpt_port *sport = container_of(tpg, struct srpt_port *sport = srpt_tpg_to_sport(tpg);
struct srpt_port, port_tpg_1);
sport->enabled = false; sport->enabled = false;
core_tpg_deregister(&sport->port_tpg_1); core_tpg_deregister(tpg);
} }
/** /**
@ -2999,19 +3041,7 @@ static struct se_wwn *srpt_make_tport(struct target_fabric_configfs *tf,
struct config_group *group, struct config_group *group,
const char *name) const char *name)
{ {
struct srpt_port *sport; return srpt_lookup_wwn(name) ? : ERR_PTR(-EINVAL);
int ret;
sport = srpt_lookup_port(name);
pr_debug("make_tport(%s)\n", name);
ret = -EINVAL;
if (!sport)
goto err;
return &sport->port_wwn;
err:
return ERR_PTR(ret);
} }
/** /**
@ -3020,9 +3050,6 @@ err:
*/ */
static void srpt_drop_tport(struct se_wwn *wwn) static void srpt_drop_tport(struct se_wwn *wwn)
{ {
struct srpt_port *sport = container_of(wwn, struct srpt_port, port_wwn);
pr_debug("drop_tport(%s\n", config_item_name(&sport->port_wwn.wwn_group.cg_item));
} }
static ssize_t srpt_wwn_version_show(struct config_item *item, char *buf) static ssize_t srpt_wwn_version_show(struct config_item *item, char *buf)

View File

@ -258,6 +258,7 @@ enum rdma_ch_state {
* against concurrent modification by the cm_id spinlock. * against concurrent modification by the cm_id spinlock.
* @sess: Session information associated with this SRP channel. * @sess: Session information associated with this SRP channel.
* @sess_name: Session name. * @sess_name: Session name.
* @ini_guid: Initiator port GUID.
* @release_work: Allows scheduling of srpt_release_channel(). * @release_work: Allows scheduling of srpt_release_channel().
* @release_done: Enables waiting for srpt_release_channel() completion. * @release_done: Enables waiting for srpt_release_channel() completion.
*/ */
@ -284,6 +285,7 @@ struct srpt_rdma_ch {
struct list_head cmd_wait_list; struct list_head cmd_wait_list;
struct se_session *sess; struct se_session *sess;
u8 sess_name[36]; u8 sess_name[36];
u8 ini_guid[24];
struct work_struct release_work; struct work_struct release_work;
struct completion *release_done; struct completion *release_done;
}; };
@ -306,28 +308,34 @@ struct srpt_port_attrib {
* @mad_agent: per-port management datagram processing information. * @mad_agent: per-port management datagram processing information.
* @enabled: Whether or not this target port is enabled. * @enabled: Whether or not this target port is enabled.
* @port_guid: ASCII representation of Port GUID * @port_guid: ASCII representation of Port GUID
* @port_gid: ASCII representation of Port GID
* @port: one-based port number. * @port: one-based port number.
* @sm_lid: cached value of the port's sm_lid. * @sm_lid: cached value of the port's sm_lid.
* @lid: cached value of the port's lid. * @lid: cached value of the port's lid.
* @gid: cached value of the port's gid. * @gid: cached value of the port's gid.
* @port_acl_lock spinlock for port_acl_list: * @port_acl_lock spinlock for port_acl_list:
* @work: work structure for refreshing the aforementioned cached values. * @work: work structure for refreshing the aforementioned cached values.
* @port_tpg_1 Target portal group = 1 data. * @port_guid_tpg: TPG associated with target port GUID.
* @port_wwn: Target core WWN data. * @port_guid_wwn: WWN associated with target port GUID.
* @port_gid_tpg: TPG associated with target port GID.
* @port_gid_wwn: WWN associated with target port GID.
* @port_acl_list: Head of the list with all node ACLs for this port. * @port_acl_list: Head of the list with all node ACLs for this port.
*/ */
struct srpt_port { struct srpt_port {
struct srpt_device *sdev; struct srpt_device *sdev;
struct ib_mad_agent *mad_agent; struct ib_mad_agent *mad_agent;
bool enabled; bool enabled;
u8 port_guid[64]; u8 port_guid[24];
u8 port_gid[64];
u8 port; u8 port;
u16 sm_lid; u16 sm_lid;
u16 lid; u16 lid;
union ib_gid gid; union ib_gid gid;
struct work_struct work; struct work_struct work;
struct se_portal_group port_tpg_1; struct se_portal_group port_guid_tpg;
struct se_wwn port_wwn; struct se_wwn port_guid_wwn;
struct se_portal_group port_gid_tpg;
struct se_wwn port_gid_wwn;
struct srpt_port_attrib port_attrib; struct srpt_port_attrib port_attrib;
}; };

View File

@ -448,6 +448,7 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref)
complete(&lun->lun_ref_comp); complete(&lun->lun_ref_comp);
} }
/* Does not change se_wwn->priv. */
int core_tpg_register( int core_tpg_register(
struct se_wwn *se_wwn, struct se_wwn *se_wwn,
struct se_portal_group *se_tpg, struct se_portal_group *se_tpg,

View File

@ -909,6 +909,7 @@ static inline struct se_portal_group *param_to_tpg(struct config_item *item)
struct se_wwn { struct se_wwn {
struct target_fabric_configfs *wwn_tf; struct target_fabric_configfs *wwn_tf;
void *priv;
struct config_group wwn_group; struct config_group wwn_group;
struct config_group fabric_stat_group; struct config_group fabric_stat_group;
}; };