Commit cbd2283a authored by Mike Christie's avatar Mike Christie Committed by Martin K. Petersen

scsi: iscsi: Fix offload conn cleanup when iscsid restarts

When userspace restarts during boot or upgrades it won't know about the
offload driver's endpoint and connection mappings. iscsid will start by
cleaning up the old session by doing a stop_conn call. Later, if we are
able to create a new connection, we clean up the old endpoint during the
binding stage. The problem is that if we do stop_conn before doing the
ep_disconnect call offload, drivers can still be executing I/O. We then
might free tasks from the under the card/driver.

This moves the ep_disconnect call to before we do the stop_conn call for
this case. It will then work and look like a normal recovery/cleanup
procedure from the driver's point of view.

Link: https://lore.kernel.org/r/20220408001314.5014-3-michael.christie@oracle.comTested-by: default avatarManish Rangankar <mrangankar@marvell.com>
Reviewed-by: default avatarLee Duncan <lduncan@suse.com>
Reviewed-by: default avatarChris Leech <cleech@redhat.com>
Signed-off-by: default avatarMike Christie <michael.christie@oracle.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent c34f95e9
...@@ -2236,6 +2236,23 @@ static void iscsi_ep_disconnect(struct iscsi_cls_conn *conn, bool is_active) ...@@ -2236,6 +2236,23 @@ static void iscsi_ep_disconnect(struct iscsi_cls_conn *conn, bool is_active)
ISCSI_DBG_TRANS_CONN(conn, "disconnect ep done.\n"); ISCSI_DBG_TRANS_CONN(conn, "disconnect ep done.\n");
} }
static void iscsi_if_disconnect_bound_ep(struct iscsi_cls_conn *conn,
struct iscsi_endpoint *ep,
bool is_active)
{
/* Check if this was a conn error and the kernel took ownership */
if (!test_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) {
iscsi_ep_disconnect(conn, is_active);
} else {
ISCSI_DBG_TRANS_CONN(conn, "flush kernel conn cleanup.\n");
mutex_unlock(&conn->ep_mutex);
flush_work(&conn->cleanup_work);
mutex_lock(&conn->ep_mutex);
}
}
static int iscsi_if_stop_conn(struct iscsi_transport *transport, static int iscsi_if_stop_conn(struct iscsi_transport *transport,
struct iscsi_uevent *ev) struct iscsi_uevent *ev)
{ {
...@@ -2256,6 +2273,16 @@ static int iscsi_if_stop_conn(struct iscsi_transport *transport, ...@@ -2256,6 +2273,16 @@ static int iscsi_if_stop_conn(struct iscsi_transport *transport,
cancel_work_sync(&conn->cleanup_work); cancel_work_sync(&conn->cleanup_work);
iscsi_stop_conn(conn, flag); iscsi_stop_conn(conn, flag);
} else { } else {
/*
* For offload, when iscsid is restarted it won't know about
* existing endpoints so it can't do a ep_disconnect. We clean
* it up here for userspace.
*/
mutex_lock(&conn->ep_mutex);
if (conn->ep)
iscsi_if_disconnect_bound_ep(conn, conn->ep, true);
mutex_unlock(&conn->ep_mutex);
/* /*
* Figure out if it was the kernel or userspace initiating this. * Figure out if it was the kernel or userspace initiating this.
*/ */
...@@ -2984,16 +3011,7 @@ static int iscsi_if_ep_disconnect(struct iscsi_transport *transport, ...@@ -2984,16 +3011,7 @@ static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
} }
mutex_lock(&conn->ep_mutex); mutex_lock(&conn->ep_mutex);
/* Check if this was a conn error and the kernel took ownership */ iscsi_if_disconnect_bound_ep(conn, ep, false);
if (test_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) {
ISCSI_DBG_TRANS_CONN(conn, "flush kernel conn cleanup.\n");
mutex_unlock(&conn->ep_mutex);
flush_work(&conn->cleanup_work);
goto put_ep;
}
iscsi_ep_disconnect(conn, false);
mutex_unlock(&conn->ep_mutex); mutex_unlock(&conn->ep_mutex);
put_ep: put_ep:
iscsi_put_endpoint(ep); iscsi_put_endpoint(ep);
...@@ -3704,16 +3722,6 @@ static int iscsi_if_transport_conn(struct iscsi_transport *transport, ...@@ -3704,16 +3722,6 @@ static int iscsi_if_transport_conn(struct iscsi_transport *transport,
switch (nlh->nlmsg_type) { switch (nlh->nlmsg_type) {
case ISCSI_UEVENT_BIND_CONN: case ISCSI_UEVENT_BIND_CONN:
if (conn->ep) {
/*
* For offload boot support where iscsid is restarted
* during the pivot root stage, the ep will be intact
* here when the new iscsid instance starts up and
* reconnects.
*/
iscsi_ep_disconnect(conn, true);
}
session = iscsi_session_lookup(ev->u.b_conn.sid); session = iscsi_session_lookup(ev->u.b_conn.sid);
if (!session) { if (!session) {
err = -EINVAL; err = -EINVAL;
......
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