From c01fe4c5306f2de9f43b557293a5bd748eebb678 Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Tue, 26 May 2020 07:13:09 +0900 Subject: [PATCH] bdev/delay: Abort all I/Os delayed to complete at reset I/O Improve reset I/O to abort all I/Os delayed to complete by parsing all channels. The generic bdev layer stops new I/O submission during reset processing. So freezing/unfreezing channels is not necessary. Additionally, clean up the code which run if I/O submission failed. Signed-off-by: Shuhei Matsumoto Change-Id: I63e1ba78971944558d9317b63befecd86a6d6b60 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/1993 Tested-by: SPDK CI Jenkins Community-CI: Mellanox Build Bot Community-CI: Broadcom CI Reviewed-by: Jim Harris Reviewed-by: Aleksey Marchuk --- module/bdev/delay/vbdev_delay.c | 85 +++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/module/bdev/delay/vbdev_delay.c b/module/bdev/delay/vbdev_delay.c index 472e3b204..ee00dce7b 100644 --- a/module/bdev/delay/vbdev_delay.c +++ b/module/bdev/delay/vbdev_delay.c @@ -174,7 +174,7 @@ _process_io_stailq(void *arg, uint64_t ticks) STAILQ_FOREACH_SAFE(io_ctx, head, link, tmp) { if (io_ctx->completion_tick <= ticks) { STAILQ_REMOVE(head, io_ctx, delay_bdev_io, link); - spdk_bdev_io_complete(SPDK_CONTAINEROF(io_ctx, struct spdk_bdev_io, driver_ctx), io_ctx->status); + spdk_bdev_io_complete(spdk_bdev_io_from_ctx(io_ctx), io_ctx->status); } else { /* In the general case, I/O will become ready in an fifo order. When timeouts are dynamically * changed, this is not necessarily the case. However, the normal behavior will be restored @@ -287,17 +287,62 @@ delay_read_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bdev_io->u.bdev.num_blocks, _delay_complete_io, bdev_io); - if (rc != 0) { - if (rc == -ENOMEM) { - SPDK_ERRLOG("No memory, start to queue io for delay.\n"); - vbdev_delay_queue_io(bdev_io); - } else { - SPDK_ERRLOG("ERROR on bdev_io submission!\n"); - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); - } + if (rc == -ENOMEM) { + SPDK_ERRLOG("No memory, start to queue io for delay.\n"); + vbdev_delay_queue_io(bdev_io); + } else if (rc != 0) { + SPDK_ERRLOG("ERROR on bdev_io submission!\n"); + spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); } } +static void +vbdev_delay_reset_dev(struct spdk_io_channel_iter *i, int status) +{ + struct spdk_bdev_io *bdev_io = spdk_io_channel_iter_get_ctx(i); + struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); + struct delay_io_channel *delay_ch = spdk_io_channel_get_ctx(ch); + struct vbdev_delay *delay_node = spdk_io_channel_iter_get_io_device(i); + int rc; + + rc = spdk_bdev_reset(delay_node->base_desc, delay_ch->base_ch, + _delay_complete_io, bdev_io); + + if (rc == -ENOMEM) { + SPDK_ERRLOG("No memory, start to queue io for delay.\n"); + vbdev_delay_queue_io(bdev_io); + } else if (rc != 0) { + SPDK_ERRLOG("ERROR on bdev_io submission!\n"); + spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); + } +} + +static void +_abort_all_delayed_io(void *arg) +{ + STAILQ_HEAD(, delay_bdev_io) *head = arg; + struct delay_bdev_io *io_ctx, *tmp; + + STAILQ_FOREACH_SAFE(io_ctx, head, link, tmp) { + STAILQ_REMOVE(head, io_ctx, delay_bdev_io, link); + spdk_bdev_io_complete(spdk_bdev_io_from_ctx(io_ctx), SPDK_BDEV_IO_STATUS_ABORTED); + } +} + +static void +vbdev_delay_reset_channel(struct spdk_io_channel_iter *i) +{ + struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i); + struct delay_io_channel *delay_ch = spdk_io_channel_get_ctx(ch); + + _abort_all_delayed_io(&delay_ch->avg_read_io); + _abort_all_delayed_io(&delay_ch->avg_write_io); + _abort_all_delayed_io(&delay_ch->p99_read_io); + _abort_all_delayed_io(&delay_ch->p99_write_io); + + spdk_for_each_channel_continue(i, 0); +} + static void vbdev_delay_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) { @@ -344,22 +389,24 @@ vbdev_delay_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev _delay_complete_io, bdev_io); break; case SPDK_BDEV_IO_TYPE_RESET: - rc = spdk_bdev_reset(delay_node->base_desc, delay_ch->base_ch, - _delay_complete_io, bdev_io); + /* During reset, the generic bdev layer aborts all new I/Os and queues all new resets. + * Hence we can simply abort all I/Os delayed to complete. + */ + spdk_for_each_channel(delay_node, vbdev_delay_reset_channel, bdev_io, + vbdev_delay_reset_dev); break; default: SPDK_ERRLOG("delay: unknown I/O type %d\n", bdev_io->type); spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); return; } - if (rc != 0) { - if (rc == -ENOMEM) { - SPDK_ERRLOG("No memory, start to queue io for delay.\n"); - vbdev_delay_queue_io(bdev_io); - } else { - SPDK_ERRLOG("ERROR on bdev_io submission!\n"); - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); - } + + if (rc == -ENOMEM) { + SPDK_ERRLOG("No memory, start to queue io for delay.\n"); + vbdev_delay_queue_io(bdev_io); + } else if (rc != 0) { + SPDK_ERRLOG("ERROR on bdev_io submission!\n"); + spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); } }