scsi: iscsi: Add helper to remove a session from the kernel

During qedi shutdown we need to stop the iSCSI layer from sending new nops
as pings and from responding to target ones and make sure there is no
running connection cleanups. Commit d1f2ce7763 ("scsi: qedi: Fix host
removal with running sessions") converted the driver to use the libicsi
helper to drive session removal, so the above issues could be handled. The
problem is that during system shutdown iscsid will not be running so when
we try to remove the root session we will hang waiting for userspace to
reply.

Add a helper that will drive the destruction of sessions like these during
system shutdown.

Link: https://lore.kernel.org/r/20220616222738.5722-5-michael.christie@oracle.com
Tested-by: Nilesh Javali <njavali@marvell.com>
Reviewed-by: Nilesh Javali <njavali@marvell.com>
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Mike Christie 2022-06-16 17:27:36 -05:00 committed by Martin K. Petersen
parent da2f132d00
commit bb42856bfd
2 changed files with 50 additions and 0 deletions

View File

@ -2334,6 +2334,55 @@ static void iscsi_cleanup_conn_work_fn(struct work_struct *work)
ISCSI_DBG_TRANS_CONN(conn, "cleanup done.\n");
}
static int iscsi_iter_force_destroy_conn_fn(struct device *dev, void *data)
{
struct iscsi_transport *transport;
struct iscsi_cls_conn *conn;
if (!iscsi_is_conn_dev(dev))
return 0;
conn = iscsi_dev_to_conn(dev);
transport = conn->transport;
if (READ_ONCE(conn->state) != ISCSI_CONN_DOWN)
iscsi_if_stop_conn(conn, STOP_CONN_TERM);
transport->destroy_conn(conn);
return 0;
}
/**
* iscsi_force_destroy_session - destroy a session from the kernel
* @session: session to destroy
*
* Force the destruction of a session from the kernel. This should only be
* used when userspace is no longer running during system shutdown.
*/
void iscsi_force_destroy_session(struct iscsi_cls_session *session)
{
struct iscsi_transport *transport = session->transport;
unsigned long flags;
WARN_ON_ONCE(system_state == SYSTEM_RUNNING);
spin_lock_irqsave(&sesslock, flags);
if (list_empty(&session->sess_list)) {
spin_unlock_irqrestore(&sesslock, flags);
/*
* Conn/ep is already freed. Session is being torn down via
* async path. For shutdown we don't care about it so return.
*/
return;
}
spin_unlock_irqrestore(&sesslock, flags);
device_for_each_child(&session->dev, NULL,
iscsi_iter_force_destroy_conn_fn);
transport->destroy_session(session);
}
EXPORT_SYMBOL_GPL(iscsi_force_destroy_session);
void iscsi_free_session(struct iscsi_cls_session *session)
{
ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n");

View File

@ -442,6 +442,7 @@ extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
struct iscsi_transport *t,
int dd_size,
unsigned int target_id);
extern void iscsi_force_destroy_session(struct iscsi_cls_session *session);
extern void iscsi_remove_session(struct iscsi_cls_session *session);
extern void iscsi_free_session(struct iscsi_cls_session *session);
extern struct iscsi_cls_conn *iscsi_alloc_conn(struct iscsi_cls_session *sess,