bdev: only allow one reset per io_device at a time
This also requires vbdev modules to call spdk_bdev_reset explicitly on the base bdev, rather than just resubmitting the original reset bdev_io. Signed-off-by: Jim Harris <james.r.harris@intel.com> Change-Id: Ie33d506f68506096306c9f0a9ff5e11141578b15 Reviewed-on: https://review.gerrithub.io/365712 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
dfa0618d29
commit
3e4ac61d92
@ -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! */
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user