Commit 3cb9bc25 authored by Jim Harris's avatar Jim Harris Committed by Tomasz Zawadzki
Browse files

nvme: add spdk_nvme_ctrlr_prepare_for_reset()



This new API signals that the ctrlr will soon be
reset. This allows the transport to skip unnecessary
steps in following calls to the driver prior to the
reset - for example, skipping PCIe DELETE_SQ/CQ
commands when freeing an IO qpair.

Note that if we are deleting a qpair after
prepare_for_reset was called, and the qpair is
still waiting for a CREATE_IO_CQ or CREATE_IO_SQ,
we cannot poll for those commands to complete,
but we also cannot free the qpair immediately.
So set a flag for this case to defer the
destruction until the outstanding CREATE_IO_CQ or
CREATE_IO_SQ callback is invoked (typically as an
aborted command when the reset happens).

Signed-off-by: default avatarJim Harris <james.r.harris@intel.com>
Change-Id: I34c6276ae71e7d61ad4a3720f1a985b1ee96bd8b

Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9249


Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
parent 89c4d059
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -1039,6 +1039,17 @@ void spdk_nvme_ctrlr_set_remove_cb(struct spdk_nvme_ctrlr *ctrlr,
 */
int spdk_nvme_ctrlr_reset(struct spdk_nvme_ctrlr *ctrlr);

/**
 * Inform the driver that the application is preparing to reset the specified NVMe controller.
 *
 * This function allows the driver to make decisions knowing that a reset is about to happen.
 * For example, the pcie transport in this case could skip sending DELETE_CQ and DELETE_SQ
 * commands to the controller if an io qpair is freed after this function is called.
 *
 * \param ctrlr Opaque handle to NVMe controller.
 */
void spdk_nvme_ctrlr_prepare_for_reset(struct spdk_nvme_ctrlr *ctrlr);

struct spdk_nvme_ctrlr_reset_ctx;

/**
+9 −0
Original line number Diff line number Diff line
@@ -1440,6 +1440,7 @@ nvme_ctrlr_reset_pre(struct spdk_nvme_ctrlr *ctrlr)
	struct spdk_nvme_qpair	*qpair;

	nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
	ctrlr->prepare_for_reset = false;

	if (ctrlr->is_resetting || ctrlr->is_removed) {
		/*
@@ -1629,6 +1630,14 @@ spdk_nvme_ctrlr_reset(struct spdk_nvme_ctrlr *ctrlr)
	return rc;
}

void
spdk_nvme_ctrlr_prepare_for_reset(struct spdk_nvme_ctrlr *ctrlr)
{
	nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
	ctrlr->prepare_for_reset = true;
	nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock);
}

int
spdk_nvme_ctrlr_reset_subsystem(struct spdk_nvme_ctrlr *ctrlr)
{
+6 −0
Original line number Diff line number Diff line
@@ -801,6 +801,12 @@ struct spdk_nvme_ctrlr {

	bool				timeout_enabled;

	/* The application is preparing to reset the controller.  Transports
	 * can use this to skip unnecessary parts of the qpair deletion process
	 * for example, like the DELETE_SQ/CQ commands.
	 */
	bool				prepare_for_reset;

	uint16_t			max_sges;

	uint16_t			cntlid;
+33 −1
Original line number Diff line number Diff line
@@ -465,6 +465,17 @@ nvme_completion_create_sq_cb(void *arg, const struct spdk_nvme_cpl *cpl)
	struct nvme_pcie_ctrlr	*pctrlr = nvme_pcie_ctrlr(ctrlr);
	int rc;

	if (pqpair->flags.defer_destruction) {
		/* This qpair was deleted by the application while the
		 * connection was still in progress.  We had to wait
		 * to free the qpair resources until this outstanding
		 * command was completed.  Now that we have the completion
		 * free it now.
		 */
		nvme_pcie_qpair_destroy(qpair);
		return;
	}

	if (spdk_nvme_cpl_is_error(cpl)) {
		SPDK_ERRLOG("nvme_create_io_sq failed, deleting cq!\n");
		rc = nvme_pcie_ctrlr_cmd_delete_io_cq(qpair->ctrlr, qpair, nvme_completion_sq_error_delete_cq_cb,
@@ -502,6 +513,17 @@ nvme_completion_create_cq_cb(void *arg, const struct spdk_nvme_cpl *cpl)
	struct nvme_pcie_qpair	*pqpair = nvme_pcie_qpair(qpair);
	int rc;

	if (pqpair->flags.defer_destruction) {
		/* This qpair was deleted by the application while the
		 * connection was still in progress.  We had to wait
		 * to free the qpair resources until this outstanding
		 * command was completed.  Now that we have the completion
		 * free it now.
		 */
		nvme_pcie_qpair_destroy(qpair);
		return;
	}

	if (spdk_nvme_cpl_is_error(cpl)) {
		pqpair->pcie_state = NVME_PCIE_QPAIR_FAILED;
		nvme_qpair_set_state(qpair, NVME_QPAIR_DISCONNECTED);
@@ -1047,6 +1069,13 @@ nvme_pcie_ctrlr_delete_io_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_
		goto free;
	}

	if (ctrlr->prepare_for_reset) {
		if (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING) {
			pqpair->flags.defer_destruction = true;
		}
		goto clear_shadow_doorbells;
	}

	/* If attempting to delete a qpair that's still being connected, we have to wait until it's
	 * finished, so that we don't free it while it's waiting for the create cq/sq callbacks.
	 */
@@ -1098,6 +1127,7 @@ nvme_pcie_ctrlr_delete_io_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_
	}
	free(status);

clear_shadow_doorbells:
	if (pqpair->flags.has_shadow_doorbell) {
		*pqpair->shadow_doorbell.sq_tdbl = 0;
		*pqpair->shadow_doorbell.cq_hdbl = 0;
@@ -1110,7 +1140,9 @@ free:
		nvme_pcie_qpair_abort_trackers(qpair, 1);
	}

	if (!pqpair->flags.defer_destruction) {
		nvme_pcie_qpair_destroy(qpair);
	}
	return 0;
}

+1 −0
Original line number Diff line number Diff line
@@ -186,6 +186,7 @@ struct nvme_pcie_qpair {
		uint8_t delay_cmd_submit	: 1;
		uint8_t has_shadow_doorbell	: 1;
		uint8_t has_pending_vtophys_failures : 1;
		uint8_t defer_destruction	: 1;
	} flags;

	/*
Loading