Commit 22a39fbb authored by Mike Christie's avatar Mike Christie Committed by James Bottomley

[SCSI] iscsi: fix iscsi_endpoint leak

When iscsid restarts it does not know the connection's
endpoint, so it is getting leaked. This fixes the problem
by having the iscsi class force a disconnect before a
new connection is bound.
Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent fdafd4df
...@@ -954,6 +954,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) ...@@ -954,6 +954,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
if (dd_size) if (dd_size)
conn->dd_data = &conn[1]; conn->dd_data = &conn[1];
mutex_init(&conn->ep_mutex);
INIT_LIST_HEAD(&conn->conn_list); INIT_LIST_HEAD(&conn->conn_list);
conn->transport = transport; conn->transport = transport;
conn->cid = cid; conn->cid = cid;
...@@ -1430,6 +1431,29 @@ static int iscsi_if_ep_connect(struct iscsi_transport *transport, ...@@ -1430,6 +1431,29 @@ static int iscsi_if_ep_connect(struct iscsi_transport *transport,
return err; return err;
} }
static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
u64 ep_handle)
{
struct iscsi_cls_conn *conn;
struct iscsi_endpoint *ep;
if (!transport->ep_disconnect)
return -EINVAL;
ep = iscsi_lookup_endpoint(ep_handle);
if (!ep)
return -EINVAL;
conn = ep->conn;
if (conn) {
mutex_lock(&conn->ep_mutex);
conn->ep = NULL;
mutex_unlock(&conn->ep_mutex);
}
transport->ep_disconnect(ep);
return 0;
}
static int static int
iscsi_if_transport_ep(struct iscsi_transport *transport, iscsi_if_transport_ep(struct iscsi_transport *transport,
struct iscsi_uevent *ev, int msg_type) struct iscsi_uevent *ev, int msg_type)
...@@ -1454,14 +1478,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, ...@@ -1454,14 +1478,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
ev->u.ep_poll.timeout_ms); ev->u.ep_poll.timeout_ms);
break; break;
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
if (!transport->ep_disconnect) rc = iscsi_if_ep_disconnect(transport,
return -EINVAL; ev->u.ep_disconnect.ep_handle);
ep = iscsi_lookup_endpoint(ev->u.ep_disconnect.ep_handle);
if (!ep)
return -EINVAL;
transport->ep_disconnect(ep);
break; break;
} }
return rc; return rc;
...@@ -1609,12 +1627,31 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) ...@@ -1609,12 +1627,31 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
session = iscsi_session_lookup(ev->u.b_conn.sid); session = iscsi_session_lookup(ev->u.b_conn.sid);
conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid); conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
if (session && conn) if (conn && conn->ep)
ev->r.retcode = transport->bind_conn(session, conn, iscsi_if_ep_disconnect(transport, conn->ep->id);
ev->u.b_conn.transport_eph,
ev->u.b_conn.is_leading); if (!session || !conn) {
else
err = -EINVAL; err = -EINVAL;
break;
}
ev->r.retcode = transport->bind_conn(session, conn,
ev->u.b_conn.transport_eph,
ev->u.b_conn.is_leading);
if (ev->r.retcode || !transport->ep_connect)
break;
ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph);
if (ep) {
ep->conn = conn;
mutex_lock(&conn->ep_mutex);
conn->ep = ep;
mutex_unlock(&conn->ep_mutex);
} else
iscsi_cls_conn_printk(KERN_ERR, conn,
"Could not set ep conn "
"binding\n");
break; break;
case ISCSI_UEVENT_SET_PARAM: case ISCSI_UEVENT_SET_PARAM:
err = iscsi_set_param(transport, ev); err = iscsi_set_param(transport, ev);
......
...@@ -160,6 +160,8 @@ struct iscsi_cls_conn { ...@@ -160,6 +160,8 @@ struct iscsi_cls_conn {
void *dd_data; /* LLD private data */ void *dd_data; /* LLD private data */
struct iscsi_transport *transport; struct iscsi_transport *transport;
uint32_t cid; /* connection id */ uint32_t cid; /* connection id */
struct mutex ep_mutex;
struct iscsi_endpoint *ep;
int active; /* must be accessed with the connlock */ int active; /* must be accessed with the connlock */
struct device dev; /* sysfs transport/container device */ struct device dev; /* sysfs transport/container device */
...@@ -222,6 +224,7 @@ struct iscsi_endpoint { ...@@ -222,6 +224,7 @@ struct iscsi_endpoint {
void *dd_data; /* LLD private data */ void *dd_data; /* LLD private data */
struct device dev; struct device dev;
uint64_t id; uint64_t id;
struct iscsi_cls_conn *conn;
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment