[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: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
parent
fdafd4dfc7
commit
22a39fbbfe
@ -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 @@ release_host:
|
|||||||
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,
|
|||||||
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)
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user