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);

Reply via email to