On 11/07/2010 02:34 AM, Or Gerlitz wrote:
add support for reporting the current portal (address/port) used
by a connection, which is needed when doing iscsi redirection.
Hey,
I was working on this patch. It seems to work for iser and cxgbi in the
normal case. iscsi_tcp is broken with it (there is debugging stuff in
iscsi_tcp.c so do not look at it for review purposes).
There is one problem with in the error path. If we are disconnecting the
interconnect (running ep_disconnect in iser's case), while the address
sysfs file is being read, the ep_disconnect function could free, and the
kernel could realloc to something else, the low level struct's memory
that the ib_conn is accessing at the same time and we could end up with
memory access issues.
I was thinking we could just add a lock around the
ep_connect/ep_disconnect and iscsi_iser_conn_get_param code and add some
state bits and do something similar for other drivers.
--
You received this message because you are subscribed to the Google Groups
"open-iscsi" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/open-iscsi?hl=en.
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c
b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 921c2cb..3ab2bc8 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -532,6 +532,31 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn,
struct iscsi_stats *s
stats->custom[3].value = conn->fmr_unalign_cnt;
}
+static int iscsi_iser_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = iser_conn->ib_conn;
+ int len;
+
+ switch (param) {
+ case ISCSI_PARAM_CONN_PORT:
+ case ISCSI_PARAM_CONN_ADDRESS:
+ if (!ib_conn || !ib_conn->cma_id)
+ return -ENOTCONN;
+
+ return iscsi_conn_get_addr_param((struct sockaddr_storage *)
+ &ib_conn->cma_id->route.addr.dst_addr,
+ param, buf);
+ break;
+ default:
+ return iscsi_conn_get_param(cls_conn, param, buf);
+ }
+
+ return len;
+}
+
static struct iscsi_endpoint *
iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
int non_blocking)
@@ -637,6 +662,8 @@ static struct iscsi_transport iscsi_iser_transport = {
ISCSI_MAX_BURST |
ISCSI_PDU_INORDER_EN |
ISCSI_DATASEQ_INORDER_EN |
+ ISCSI_CONN_PORT |
+ ISCSI_CONN_ADDRESS |
ISCSI_EXP_STATSN |
ISCSI_PERSISTENT_PORT |
ISCSI_PERSISTENT_ADDRESS |
@@ -658,7 +685,7 @@ static struct iscsi_transport iscsi_iser_transport = {
.bind_conn = iscsi_iser_conn_bind,
.destroy_conn = iscsi_iser_conn_destroy,
.set_param = iscsi_iser_set_param,
- .get_conn_param = iscsi_conn_get_param,
+ .get_conn_param = iscsi_iser_conn_get_param,
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_iser_conn_start,
.stop_conn = iscsi_iser_conn_stop,
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 84125e9..eac3b7a 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -543,6 +543,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr
*dst_addr)
csk->dst = dst;
csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr;
csk->daddr.sin_port = daddr->sin_port;
+ csk->daddr.sin_family = daddr->sin_family;
csk->saddr.sin_addr.s_addr = rt->rt_src;
return csk;
@@ -2213,7 +2214,11 @@ EXPORT_SYMBOL_GPL(cxgbi_set_conn_param);
int cxgbi_get_conn_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf)
{
- struct iscsi_conn *iconn = cls_conn->dd_data;
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ struct cxgbi_conn *cconn = tcp_conn->dd_data;
+ struct cxgbi_endpoint *cep;
+ struct cxgbi_sock *csk;
int len;
log_debug(1 << CXGBI_DBG_ISCSI,
@@ -2221,15 +2226,17 @@ int cxgbi_get_conn_param(struct iscsi_cls_conn
*cls_conn,
switch (param) {
case ISCSI_PARAM_CONN_PORT:
- spin_lock_bh(&iconn->session->lock);
- len = sprintf(buf, "%hu\n", iconn->portal_port);
- spin_unlock_bh(&iconn->session->lock);
- break;
case ISCSI_PARAM_CONN_ADDRESS:
- spin_lock_bh(&iconn->session->lock);
- len = sprintf(buf, "%s\n", iconn->portal_address);
- spin_unlock_bh(&iconn->session->lock);
- break;
+ cep = cconn->cep;
+ if (!cep)
+ return -ENOTCONN;
+
+ csk = cep->csk;
+ if (!csk)
+ return -ENOTCONN;
+
+ return iscsi_conn_get_addr_param((struct sockaddr_storage *)
+ &csk->daddr, param, buf);
default:
return iscsi_conn_get_param(cls_conn, param, buf);
}
@@ -2302,11 +2309,6 @@ int cxgbi_bind_conn(struct iscsi_cls_session
*cls_session,
cxgbi_conn_max_xmit_dlength(conn);
cxgbi_conn_max_recv_dlength(conn);
- spin_lock_bh(&conn->session->lock);
- sprintf(conn->portal_address, "%pI4", &csk->daddr.sin_addr.s_addr);
- conn->portal_port = ntohs(csk->daddr.sin_port);
- spin_unlock_bh(&conn->session->lock);
-
log_debug(1 << CXGBI_DBG_ISCSI,
"cls 0x%p,0x%p, ep 0x%p, cconn 0x%p, csk 0x%p.\n",
cls_session, cls_conn, ep, cconn, csk);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 9961c22..c328b91 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -585,9 +585,11 @@ static void iscsi_sw_tcp_conn_destroy(struct
iscsi_cls_conn *cls_conn)
static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
{
struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_session *session = conn->session;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
struct socket *sock = tcp_sw_conn->sock;
+ struct iscsi_sw_tcp_host *tcp_sw_host;
/* userspace may have goofed up and not bound us */
if (!sock)
@@ -605,59 +607,22 @@ static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn
*cls_conn, int flag)
wake_up_interruptible(sk_sleep(sock->sk));
iscsi_conn_stop(cls_conn, flag);
- iscsi_sw_tcp_release_conn(conn);
-}
-static int iscsi_sw_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
- char *buf, int *port,
- int (*getname)(struct socket *,
- struct sockaddr *,
- int *addrlen))
-{
- struct sockaddr_storage *addr;
- struct sockaddr_in6 *sin6;
- struct sockaddr_in *sin;
- int rc = 0, len;
-
- addr = kmalloc(sizeof(*addr), GFP_KERNEL);
- if (!addr)
- return -ENOMEM;
+ tcp_sw_host = iscsi_host_priv(session->host);
+ tcp_sw_host->tcp_sw_conn = NULL;
- if (getname(sock, (struct sockaddr *) addr, &len)) {
- rc = -ENODEV;
- goto free_addr;
- }
-
- switch (addr->ss_family) {
- case AF_INET:
- sin = (struct sockaddr_in *)addr;
- spin_lock_bh(&conn->session->lock);
- sprintf(buf, "%pI4", &sin->sin_addr.s_addr);
- *port = be16_to_cpu(sin->sin_port);
- spin_unlock_bh(&conn->session->lock);
- break;
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *)addr;
- spin_lock_bh(&conn->session->lock);
- sprintf(buf, "%pI6", &sin6->sin6_addr);
- *port = be16_to_cpu(sin6->sin6_port);
- spin_unlock_bh(&conn->session->lock);
- break;
- }
-free_addr:
- kfree(addr);
- return rc;
+ iscsi_sw_tcp_release_conn(conn);
}
static int
iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn, uint64_t transport_eph)
{
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- struct iscsi_host *ihost = shost_priv(shost);
+ struct iscsi_session *session = cls_session->dd_data;
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
+ struct iscsi_sw_tcp_host *tcp_sw_host;
struct sock *sk;
struct socket *sock;
int err;
@@ -669,25 +634,13 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session
*cls_session,
"sockfd_lookup failed %d\n", err);
return -EEXIST;
}
- /*
- * copy these values now because if we drop the session
- * userspace may still want to query the values since we will
- * be using them for the reconnect
- */
- err = iscsi_sw_tcp_get_addr(conn, sock, conn->portal_address,
- &conn->portal_port, kernel_getpeername);
- if (err)
- goto free_socket;
-
- err = iscsi_sw_tcp_get_addr(conn, sock, ihost->local_address,
- &ihost->local_port, kernel_getsockname);
- if (err)
- goto free_socket;
err = iscsi_conn_bind(cls_session, cls_conn, NULL);
if (err)
goto free_socket;
+ tcp_sw_host = iscsi_host_priv(session->host);
+ tcp_sw_host->tcp_sw_conn = tcp_sw_conn;
/* bind iSCSI connection and socket */
tcp_sw_conn->sock = sock;
@@ -751,24 +704,73 @@ static int iscsi_sw_tcp_conn_get_param(struct
iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf)
{
struct iscsi_conn *conn = cls_conn->dd_data;
- int len;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
+ struct sockaddr_in6 addr;
+ int rc, len;
switch(param) {
case ISCSI_PARAM_CONN_PORT:
- spin_lock_bh(&conn->session->lock);
- len = sprintf(buf, "%hu\n", conn->portal_port);
- spin_unlock_bh(&conn->session->lock);
- break;
case ISCSI_PARAM_CONN_ADDRESS:
- spin_lock_bh(&conn->session->lock);
- len = sprintf(buf, "%s\n", conn->portal_address);
- spin_unlock_bh(&conn->session->lock);
- break;
+ if (!tcp_sw_conn->sock)
+ return -ENOTCONN;
+
+ rc = kernel_getpeername(tcp_sw_conn->sock,
+ (struct sockaddr *)&addr, &len);
+ if (rc)
+ return rc;
+
+ return iscsi_conn_get_addr_param((struct sockaddr_storage *)
+ &addr, param, buf);
default:
return iscsi_conn_get_param(cls_conn, param, buf);
}
- return len;
+ return 0;
+}
+
+int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+ char *buf)
+{
+ struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost);
+ struct iscsi_sw_tcp_conn *tcp_sw_conn;// = tcp_sw_host->tcp_sw_conn;
+ struct sockaddr_in6 addr;
+ int rc, len;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_IPADDRESS:
+ if (!tcp_sw_host) {
+ printk(KERN_ERR "no host\n");
+ return -ENOTCONN;
+ }
+
+ tcp_sw_conn = tcp_sw_host->tcp_sw_conn;
+ if (!tcp_sw_conn) {
+ printk(KERN_ERR "no tcp_sw_conn\n");
+ return -ENOTCONN;
+ }
+
+ if (!tcp_sw_conn->sock) {
+ printk(KERN_ERR "no sock\n");
+ return -ENOTCONN;
+ }
+
+ if (!tcp_sw_conn || !tcp_sw_conn->sock)
+ return -ENOTCONN;
+
+ printk(KERN_ERR "sockname\n");
+ rc = kernel_getsockname(tcp_sw_conn->sock,
+ (struct sockaddr *)&addr, &len);
+ if (rc)
+ return rc;
+ printk(KERN_ERR "get addr\n");
+ return iscsi_conn_get_addr_param((struct sockaddr_storage *)
+ &addr, param, buf);
+
+ default:
+ return iscsi_host_get_param(shost, param, buf);
+ }
+ return 0;
}
static void
@@ -803,7 +805,8 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep,
uint16_t cmds_max,
return NULL;
}
- shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, 0, 1);
+ shost = iscsi_host_alloc(&iscsi_sw_tcp_sht,
+ sizeof(struct iscsi_sw_tcp_host), 1);
if (!shost)
return NULL;
shost->transportt = iscsi_sw_tcp_scsi_transport;
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 94644ba..3da1f23 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -55,6 +55,11 @@ struct iscsi_sw_tcp_conn {
ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
};
+struct iscsi_sw_tcp_host {
+ /* currently bound conn */
+ struct iscsi_sw_tcp_conn *tcp_sw_conn;
+};
+
struct iscsi_sw_tcp_hdrbuf {
struct iscsi_hdr hdrbuf;
char hdrextbuf[ISCSI_MAX_AHS_SIZE +
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index d382b84..51b0f6d 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -3355,6 +3355,46 @@ int iscsi_session_get_param(struct iscsi_cls_session
*cls_session,
}
EXPORT_SYMBOL_GPL(iscsi_session_get_param);
+int iscsi_conn_get_addr_param(struct sockaddr_storage *addr,
+ enum iscsi_param param, char *buf)
+{
+ struct sockaddr_in6 *sin6 = NULL;
+ struct sockaddr_in *sin = NULL;
+ int len;
+
+ switch (addr->ss_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)addr;
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)addr;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (param) {
+ case ISCSI_PARAM_CONN_ADDRESS:
+ if (sin)
+ len = sprintf(buf, "%pI4\n", &sin->sin_addr.s_addr);
+ else
+ len = sprintf(buf, "%pI6\n", &sin6->sin6_addr);
+ break;
+ case ISCSI_PARAM_CONN_PORT:
+ if (sin)
+ len = sprintf(buf, "%hu\n", be16_to_cpu(sin->sin_port));
+ else
+ len = sprintf(buf, "%hu\n",
+ be16_to_cpu(sin6->sin6_port));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_get_addr_param);
+
int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf)
{
@@ -3419,9 +3459,6 @@ int iscsi_host_get_param(struct Scsi_Host *shost, enum
iscsi_host_param param,
case ISCSI_HOST_PARAM_INITIATOR_NAME:
len = sprintf(buf, "%s\n", ihost->initiatorname);
break;
- case ISCSI_HOST_PARAM_IPADDRESS:
- len = sprintf(buf, "%s\n", ihost->local_address);
- break;
default:
return -ENOSYS;
}
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 10b537e..5aa4211 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -212,9 +212,6 @@ struct iscsi_conn {
/* values userspace uses to id a conn */
int persistent_port;
char *persistent_address;
- /* remote portal currently connected to */
- int portal_port;
- char portal_address[ISCSI_ADDRESS_BUF_LEN];
/* MIB-statistics */
uint64_t txdata_octets;
@@ -319,9 +316,6 @@ struct iscsi_host {
/* hw address or netdev iscsi connection is bound to */
char *hwaddress;
char *netdev;
- /* local address */
- int local_port;
- char local_address[ISCSI_ADDRESS_BUF_LEN];
wait_queue_head_t session_removal_wq;
/* protects sessions and state */
@@ -394,6 +388,8 @@ extern void iscsi_session_failure(struct iscsi_session
*session,
enum iscsi_err err);
extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf);
+extern int iscsi_conn_get_addr_param(struct sockaddr_storage *addr,
+ enum iscsi_param param, char *buf);
extern void iscsi_suspend_tx(struct iscsi_conn *conn);
extern void iscsi_suspend_queue(struct iscsi_conn *conn);
extern void iscsi_conn_queue_work(struct iscsi_conn *conn);