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:
Jim Harris 2017-06-15 07:17:12 -07:00 committed by Daniel Verkamp
parent dfa0618d29
commit 3e4ac61d92
3 changed files with 76 additions and 18 deletions

View File

@ -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! */

View File

@ -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));

View File

@ -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)