diff --git a/include/spdk_internal/bdev.h b/include/spdk_internal/bdev.h index 2a59b1ef5..79a7710c3 100644 --- a/include/spdk_internal/bdev.h +++ b/include/spdk_internal/bdev.h @@ -209,6 +209,11 @@ struct spdk_bdev { void *remove_ctx; TAILQ_ENTRY(spdk_bdev) link; + + /** denotes if a reset is currently in progress on this bdev */ + bool reset_in_progress; + + TAILQ_HEAD(, spdk_bdev_io) queued_resets; }; typedef void (*spdk_bdev_io_get_buf_cb)(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io); @@ -336,7 +341,12 @@ struct spdk_bdev_io { /** Member used for linking child I/Os together. */ TAILQ_ENTRY(spdk_bdev_io) link; - /** Per I/O context for use by the blockdev module */ + /** + * Per I/O context for use by the blockdev module. + * + * Note that vbdev modules may not use this field if modifying a bdev_io and resubmitting + * to the next lower bdev. + */ uint8_t driver_ctx[0]; /* No members may be added after driver_ctx! */ diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index 70c29ba93..0e6bf8695 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -944,6 +944,37 @@ _spdk_bdev_reset_abort_channel(void *io_device, struct spdk_io_channel *ch, _spdk_bdev_abort_io(&mgmt_channel->need_buf_large, channel); } +static void +_spdk_bdev_start_reset(void *ctx) +{ + struct spdk_bdev_io *bdev_io = ctx; + + spdk_for_each_channel(bdev_io->bdev, _spdk_bdev_reset_abort_channel, + bdev_io, _spdk_bdev_reset_dev); +} + +static void +_spdk_bdev_start_next_reset(struct spdk_bdev *bdev) +{ + struct spdk_bdev_io *bdev_io; + struct spdk_thread *thread; + + pthread_mutex_lock(&bdev->mutex); + + if (bdev->reset_in_progress || TAILQ_EMPTY(&bdev->queued_resets)) { + pthread_mutex_unlock(&bdev->mutex); + return; + } else { + bdev_io = TAILQ_FIRST(&bdev->queued_resets); + TAILQ_REMOVE(&bdev->queued_resets, bdev_io, link); + bdev->reset_in_progress = true; + thread = spdk_io_channel_get_thread(bdev_io->ch->channel); + spdk_thread_send_msg(thread, _spdk_bdev_start_reset, bdev_io); + } + + pthread_mutex_unlock(&bdev->mutex); +} + int spdk_bdev_reset(struct spdk_bdev *bdev, struct spdk_io_channel *ch, spdk_bdev_io_completion_cb cb, void *cb_arg) @@ -963,11 +994,11 @@ spdk_bdev_reset(struct spdk_bdev *bdev, struct spdk_io_channel *ch, bdev_io->type = SPDK_BDEV_IO_TYPE_RESET; spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); - /* First, abort all I/O queued up waiting for buffers. */ - spdk_for_each_channel(bdev, - _spdk_bdev_reset_abort_channel, - bdev_io, - _spdk_bdev_reset_dev); + pthread_mutex_lock(&bdev->mutex); + TAILQ_INSERT_TAIL(&bdev->queued_resets, bdev_io, link); + pthread_mutex_unlock(&bdev->mutex); + + _spdk_bdev_start_next_reset(bdev); return 0; } @@ -1093,6 +1124,8 @@ spdk_bdev_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status sta /* Increase the blockdev generation */ bdev_io->bdev->gencnt++; } + bdev_io->bdev->reset_in_progress = false; + _spdk_bdev_start_next_reset(bdev_io->bdev); } else { /* * Check the gencnt, to see if this I/O was issued before the most @@ -1242,6 +1275,9 @@ spdk_bdev_register(struct spdk_bdev *bdev) /* initialize the reset generation value to zero */ bdev->gencnt = 0; + bdev->reset_in_progress = false; + TAILQ_INIT(&bdev->queued_resets); + spdk_io_device_register(bdev, spdk_bdev_channel_create, spdk_bdev_channel_destroy, sizeof(struct spdk_bdev_channel)); diff --git a/lib/bdev/split/vbdev_split.c b/lib/bdev/split/vbdev_split.c index 873bd8175..9e91d0077 100644 --- a/lib/bdev/split/vbdev_split.c +++ b/lib/bdev/split/vbdev_split.c @@ -42,6 +42,7 @@ #include "spdk/conf.h" #include "spdk/endian.h" #include "spdk/string.h" +#include "spdk/io_channel.h" #include "spdk_internal/bdev.h" #include "spdk_internal/log.h" @@ -96,22 +97,21 @@ split_flush(struct split_disk *split_disk, struct spdk_bdev_io *bdev_io) } static void -split_reset(struct split_disk *split_disk, struct spdk_bdev_io *bdev_io) +_vbdev_split_complete_reset(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) { - /* - * No offset to modify for reset - pass the I/O through unmodified. - * - * However, we do need to increment the generation count for the split bdev, - * since the spdk_bdev_io_complete() path that normally updates it will not execute - * after we resubmit the I/O to the base_bdev. - */ - split_disk->disk.gencnt++; + struct spdk_bdev_io *split_io = cb_arg; + struct spdk_io_channel *base_ch = *(struct spdk_io_channel **)split_io->driver_ctx; + + spdk_put_io_channel(base_ch); + spdk_bdev_io_complete(split_io, success); + spdk_bdev_free_io(bdev_io); } static void vbdev_split_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) { struct split_disk *split_disk = bdev_io->bdev->ctxt; + struct spdk_io_channel *base_ch; /* Modify the I/O to adjust for the offset within the base bdev. */ switch (bdev_io->type) { @@ -128,8 +128,10 @@ vbdev_split_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev split_flush(split_disk, bdev_io); break; case SPDK_BDEV_IO_TYPE_RESET: - split_reset(split_disk, bdev_io); - break; + base_ch = spdk_get_io_channel(split_disk->base_bdev); + *(struct spdk_io_channel **)bdev_io->driver_ctx = base_ch; + spdk_bdev_reset(split_disk->base_bdev, base_ch, _vbdev_split_complete_reset, bdev_io); + return; default: SPDK_ERRLOG("split: unknown I/O type %d\n", bdev_io->type); spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); @@ -416,5 +418,15 @@ vbdev_split_fini(void) } } -SPDK_VBDEV_MODULE_REGISTER(vbdev_split_init, vbdev_split_fini, NULL, NULL, NULL) +static int +vbdev_split_get_ctx_size(void) +{ + /* + * Note: this context is only used for RESET operations, since it is the only + * I/O type that does not just resubmit to the base bdev. + */ + return sizeof(struct spdk_io_channel *); +} + +SPDK_VBDEV_MODULE_REGISTER(vbdev_split_init, vbdev_split_fini, NULL, vbdev_split_get_ctx_size, NULL) SPDK_LOG_REGISTER_TRACE_FLAG("vbdev_split", SPDK_TRACE_VBDEV_SPLIT)