bdev/nvme: Reset I/O cancels reconnect timer and starts reconnection
Previously, if a reconnect timer was registered when a reset request came, the reset request failed with -EBUSY. However, this means the reset request was queued for a long time until the reconnect timer was expired. When a reconnect timer is registered, reset is not actually in progress. Hence, a new reset request can cancel the reconnect timer and can start reconnection safely. Add a unit test case to verify this change. Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com> Change-Id: Ied8dd0ad822d2fd6829d88cd56cb36bd4fad13f9 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16823 Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
This commit is contained in:
parent
ec2abc81a2
commit
7ea8a5aae5
@ -1863,7 +1863,11 @@ bdev_nvme_reconnect_delay_timer_expired(void *ctx)
|
|||||||
|
|
||||||
spdk_poller_unregister(&nvme_ctrlr->reconnect_delay_timer);
|
spdk_poller_unregister(&nvme_ctrlr->reconnect_delay_timer);
|
||||||
|
|
||||||
assert(nvme_ctrlr->reconnect_is_delayed == true);
|
if (!nvme_ctrlr->reconnect_is_delayed) {
|
||||||
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
||||||
|
return SPDK_POLLER_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
nvme_ctrlr->reconnect_is_delayed = false;
|
nvme_ctrlr->reconnect_is_delayed = false;
|
||||||
|
|
||||||
if (nvme_ctrlr->destruct) {
|
if (nvme_ctrlr->destruct) {
|
||||||
@ -2081,6 +2085,21 @@ bdev_nvme_reset_destroy_qpairs(struct nvme_ctrlr *nvme_ctrlr)
|
|||||||
bdev_nvme_reset_ctrlr);
|
bdev_nvme_reset_ctrlr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_bdev_nvme_reconnect(void *ctx)
|
||||||
|
{
|
||||||
|
struct nvme_ctrlr *nvme_ctrlr = ctx;
|
||||||
|
|
||||||
|
assert(nvme_ctrlr->resetting == true);
|
||||||
|
assert(nvme_ctrlr->thread == spdk_get_thread());
|
||||||
|
|
||||||
|
spdk_poller_unregister(&nvme_ctrlr->reconnect_delay_timer);
|
||||||
|
|
||||||
|
spdk_poller_resume(nvme_ctrlr->adminq_timer_poller);
|
||||||
|
|
||||||
|
bdev_nvme_reconnect_ctrlr(nvme_ctrlr);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_bdev_nvme_reset(void *ctx)
|
_bdev_nvme_reset(void *ctx)
|
||||||
{
|
{
|
||||||
@ -2099,6 +2118,8 @@ _bdev_nvme_reset(void *ctx)
|
|||||||
static int
|
static int
|
||||||
bdev_nvme_reset(struct nvme_ctrlr *nvme_ctrlr)
|
bdev_nvme_reset(struct nvme_ctrlr *nvme_ctrlr)
|
||||||
{
|
{
|
||||||
|
spdk_msg_fn msg_fn;
|
||||||
|
|
||||||
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
||||||
if (nvme_ctrlr->destruct) {
|
if (nvme_ctrlr->destruct) {
|
||||||
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
||||||
@ -2111,20 +2132,22 @@ bdev_nvme_reset(struct nvme_ctrlr *nvme_ctrlr)
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nvme_ctrlr->reconnect_is_delayed) {
|
|
||||||
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
||||||
SPDK_NOTICELOG("Reconnect is already scheduled.\n");
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvme_ctrlr->resetting = true;
|
nvme_ctrlr->resetting = true;
|
||||||
|
|
||||||
assert(nvme_ctrlr->reset_start_tsc == 0);
|
if (nvme_ctrlr->reconnect_is_delayed) {
|
||||||
|
SPDK_DEBUGLOG(bdev_nvme, "Reconnect is already scheduled.\n");
|
||||||
|
msg_fn = _bdev_nvme_reconnect;
|
||||||
|
nvme_ctrlr->reconnect_is_delayed = false;
|
||||||
|
} else {
|
||||||
|
msg_fn = _bdev_nvme_reset;
|
||||||
|
assert(nvme_ctrlr->reset_start_tsc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
nvme_ctrlr->reset_start_tsc = spdk_get_ticks();
|
nvme_ctrlr->reset_start_tsc = spdk_get_ticks();
|
||||||
|
|
||||||
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
||||||
|
|
||||||
spdk_thread_send_msg(nvme_ctrlr->thread, _bdev_nvme_reset, nvme_ctrlr);
|
spdk_thread_send_msg(nvme_ctrlr->thread, msg_fn, nvme_ctrlr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5251,6 +5251,30 @@ test_reconnect_ctrlr(void)
|
|||||||
CU_ASSERT(nvme_ctrlr->reconnect_delay_timer != NULL);
|
CU_ASSERT(nvme_ctrlr->reconnect_delay_timer != NULL);
|
||||||
CU_ASSERT(nvme_ctrlr->reconnect_is_delayed == true);
|
CU_ASSERT(nvme_ctrlr->reconnect_is_delayed == true);
|
||||||
|
|
||||||
|
/* A new reset starts from thread 0. */
|
||||||
|
set_thread(1);
|
||||||
|
|
||||||
|
/* The reset should cancel the reconnect timer and should start from reconnection.
|
||||||
|
* Then, the reset should fail and a reconnect timer should be registered again.
|
||||||
|
*/
|
||||||
|
ctrlr.fail_reset = true;
|
||||||
|
ctrlr.is_failed = true;
|
||||||
|
|
||||||
|
rc = bdev_nvme_reset(nvme_ctrlr);
|
||||||
|
CU_ASSERT(rc == 0);
|
||||||
|
CU_ASSERT(nvme_ctrlr->resetting == true);
|
||||||
|
CU_ASSERT(nvme_ctrlr->reconnect_is_delayed == false);
|
||||||
|
CU_ASSERT(ctrlr.is_failed == true);
|
||||||
|
|
||||||
|
poll_threads();
|
||||||
|
|
||||||
|
CU_ASSERT(nvme_ctrlr->resetting == false);
|
||||||
|
CU_ASSERT(ctrlr.is_failed == false);
|
||||||
|
CU_ASSERT(ctrlr_ch1->qpair->qpair == NULL);
|
||||||
|
CU_ASSERT(ctrlr_ch2->qpair->qpair == NULL);
|
||||||
|
CU_ASSERT(nvme_ctrlr->reconnect_delay_timer != NULL);
|
||||||
|
CU_ASSERT(nvme_ctrlr->reconnect_is_delayed == true);
|
||||||
|
|
||||||
/* Then a reconnect retry should suceeed. */
|
/* Then a reconnect retry should suceeed. */
|
||||||
ctrlr.fail_reset = false;
|
ctrlr.fail_reset = false;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user