lib/iscsi: Wait until all PDUs are flushed for LUN hotplug

We ensure current pending tasks are aborted and no new task or PDU
is pending after LUN is unplugged now.  Then we have to ensure all
task completions and aborts are sent to initiator.

However, we had removed pending tasks without any notification to
initiator.  For this implementation, we are not surprised if initiator
waits for in-flight commands for a long time.

Due to recent refinements of LUN hotplug, we can wait safely that
all existing tasks complete or abort.

In _iscsi_conn_hotremove_lun(), after aborting R2Ts, start a poller
to wait until all PDUs for the LUN are flushed.  Then close the LUN.
We can safely free deferred PDUs for the LUN because they are
already flushed.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I869b79a7c93d2e8a4a1577cc20d3b466548dfaaa
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/476033
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-11-28 12:44:53 -05:00 committed by Tomasz Zawadzki
parent 081153a82c
commit 27d79ee367
2 changed files with 54 additions and 3 deletions

View File

@ -447,6 +447,7 @@ iscsi_conn_close_lun(struct spdk_iscsi_conn *conn, int lun_id)
spdk_scsi_lun_free_io_channel(iscsi_lun->desc);
spdk_scsi_lun_close(iscsi_lun->desc);
spdk_poller_unregister(&iscsi_lun->remove_poller);
free(iscsi_lun);
conn->luns[lun_id] = NULL;
@ -462,13 +463,62 @@ iscsi_conn_close_luns(struct spdk_iscsi_conn *conn)
}
}
static bool
iscsi_conn_check_tasks_for_lun(struct spdk_iscsi_conn *conn,
struct spdk_scsi_lun *lun)
{
struct spdk_iscsi_pdu *pdu, *tmp_pdu;
struct spdk_iscsi_task *task;
assert(lun != NULL);
/* We can remove deferred PDUs safely because they are already flushed. */
TAILQ_FOREACH_SAFE(pdu, &conn->snack_pdu_list, tailq, tmp_pdu) {
if (lun == pdu->task->scsi.lun) {
TAILQ_REMOVE(&conn->snack_pdu_list, pdu, tailq);
spdk_iscsi_conn_free_pdu(conn, pdu);
}
}
TAILQ_FOREACH(task, &conn->queued_datain_tasks, link) {
if (lun == task->scsi.lun) {
return false;
}
}
/* This check loop works even when connection exits in the middle of LUN hotplug
* because all PDUs in write_pdu_list are removed in iscsi_conn_free_tasks().
*/
TAILQ_FOREACH(pdu, &conn->write_pdu_list, tailq) {
if (pdu->task && lun == pdu->task->scsi.lun) {
return false;
}
}
return true;
}
static int
iscsi_conn_remove_lun(void *ctx)
{
struct spdk_iscsi_lun *iscsi_lun = ctx;
struct spdk_iscsi_conn *conn = iscsi_lun->conn;
struct spdk_scsi_lun *lun = iscsi_lun->lun;
int lun_id = spdk_scsi_lun_get_id(lun);
if (!iscsi_conn_check_tasks_for_lun(conn, lun)) {
return -1;
}
iscsi_conn_close_lun(conn, lun_id);
return -1;
}
static void
_iscsi_conn_hotremove_lun(void *ctx)
{
struct spdk_iscsi_lun *iscsi_lun = ctx;
struct spdk_iscsi_conn *conn = iscsi_lun->conn;
struct spdk_scsi_lun *lun = iscsi_lun->lun;
int lun_id = spdk_scsi_lun_get_id(lun);
assert(spdk_io_channel_get_thread(spdk_io_channel_from_ctx(conn->pg)) ==
spdk_get_thread());
@ -479,9 +529,9 @@ _iscsi_conn_hotremove_lun(void *ctx)
}
spdk_clear_all_transfer_task(conn, lun, NULL);
_iscsi_conn_free_tasks(conn, lun);
iscsi_conn_close_lun(conn, lun_id);
iscsi_lun->remove_poller = spdk_poller_register(iscsi_conn_remove_lun, iscsi_lun,
1000);
}
static void

View File

@ -88,6 +88,7 @@ struct spdk_iscsi_lun {
struct spdk_iscsi_conn *conn;
struct spdk_scsi_lun *lun;
struct spdk_scsi_lun_desc *desc;
struct spdk_poller *remove_poller;
};
struct spdk_iscsi_conn {