util: fail io_device unregister if foreach operations outstanding
Signed-off-by: Jim Harris <james.r.harris@intel.com> Change-Id: Ic102dd4a352d3f796a4a46e4703bedefe014101f Reviewed-on: https://review.gerrithub.io/378228 Reviewed-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
parent
93cfe874b2
commit
f7eb7d6434
@ -52,6 +52,7 @@ struct io_device {
|
|||||||
spdk_io_channel_destroy_cb destroy_cb;
|
spdk_io_channel_destroy_cb destroy_cb;
|
||||||
spdk_io_device_unregister_cb unregister_cb;
|
spdk_io_device_unregister_cb unregister_cb;
|
||||||
uint32_t ctx_size;
|
uint32_t ctx_size;
|
||||||
|
uint32_t for_each_count;
|
||||||
TAILQ_ENTRY(io_device) tailq;
|
TAILQ_ENTRY(io_device) tailq;
|
||||||
|
|
||||||
bool unregistered;
|
bool unregistered;
|
||||||
@ -218,6 +219,7 @@ spdk_io_device_register(void *io_device, spdk_io_channel_create_cb create_cb,
|
|||||||
dev->destroy_cb = destroy_cb;
|
dev->destroy_cb = destroy_cb;
|
||||||
dev->unregister_cb = NULL;
|
dev->unregister_cb = NULL;
|
||||||
dev->ctx_size = ctx_size;
|
dev->ctx_size = ctx_size;
|
||||||
|
dev->for_each_count = 0;
|
||||||
dev->unregistered = false;
|
dev->unregistered = false;
|
||||||
|
|
||||||
pthread_mutex_lock(&g_devlist_mutex);
|
pthread_mutex_lock(&g_devlist_mutex);
|
||||||
@ -276,6 +278,12 @@ spdk_io_device_unregister(void *io_device, spdk_io_device_unregister_cb unregist
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->for_each_count > 0) {
|
||||||
|
SPDK_ERRLOG("io_device %p has %u for_each calls outstanding\n", io_device, dev->for_each_count);
|
||||||
|
pthread_mutex_unlock(&g_devlist_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dev->unregister_cb = unregister_cb;
|
dev->unregister_cb = unregister_cb;
|
||||||
dev->unregistered = true;
|
dev->unregistered = true;
|
||||||
TAILQ_REMOVE(&g_io_devices, dev, tailq);
|
TAILQ_REMOVE(&g_io_devices, dev, tailq);
|
||||||
@ -400,6 +408,7 @@ spdk_io_channel_get_thread(struct spdk_io_channel *ch)
|
|||||||
|
|
||||||
struct call_channel {
|
struct call_channel {
|
||||||
void *io_device;
|
void *io_device;
|
||||||
|
struct io_device *dev;
|
||||||
spdk_channel_msg fn;
|
spdk_channel_msg fn;
|
||||||
void *ctx;
|
void *ctx;
|
||||||
|
|
||||||
@ -459,6 +468,7 @@ _call_channel(void *ctx)
|
|||||||
thread = TAILQ_NEXT(thread, tailq);
|
thread = TAILQ_NEXT(thread, tailq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ch_ctx->dev->for_each_count--;
|
||||||
pthread_mutex_unlock(&g_devlist_mutex);
|
pthread_mutex_unlock(&g_devlist_mutex);
|
||||||
|
|
||||||
spdk_thread_send_msg(ch_ctx->orig_thread, _call_completion, ch_ctx);
|
spdk_thread_send_msg(ch_ctx->orig_thread, _call_completion, ch_ctx);
|
||||||
@ -489,6 +499,8 @@ spdk_for_each_channel(void *io_device, spdk_channel_msg fn, void *ctx,
|
|||||||
TAILQ_FOREACH(thread, &g_threads, tailq) {
|
TAILQ_FOREACH(thread, &g_threads, tailq) {
|
||||||
TAILQ_FOREACH(ch, &thread->io_channels, tailq) {
|
TAILQ_FOREACH(ch, &thread->io_channels, tailq) {
|
||||||
if (ch->dev->io_device == io_device) {
|
if (ch->dev->io_device == io_device) {
|
||||||
|
ch->dev->for_each_count++;
|
||||||
|
ch_ctx->dev = ch->dev;
|
||||||
ch_ctx->cur_thread = thread;
|
ch_ctx->cur_thread = thread;
|
||||||
pthread_mutex_unlock(&g_devlist_mutex);
|
pthread_mutex_unlock(&g_devlist_mutex);
|
||||||
spdk_thread_send_msg(thread, _call_channel, ch_ctx);
|
spdk_thread_send_msg(thread, _call_channel, ch_ctx);
|
||||||
|
@ -170,6 +170,78 @@ for_each_channel_remove(void)
|
|||||||
free_threads();
|
free_threads();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct unreg_ctx {
|
||||||
|
bool ch_done;
|
||||||
|
bool foreach_done;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
unreg_ch_done(void *io_device, struct spdk_io_channel *_ch, void *_ctx)
|
||||||
|
{
|
||||||
|
struct unreg_ctx *ctx = _ctx;
|
||||||
|
|
||||||
|
ctx->ch_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unreg_foreach_done(void *io_device, void *_ctx)
|
||||||
|
{
|
||||||
|
struct unreg_ctx *ctx = _ctx;
|
||||||
|
|
||||||
|
ctx->foreach_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
for_each_channel_unreg(void)
|
||||||
|
{
|
||||||
|
struct spdk_io_channel *ch0;
|
||||||
|
struct io_device *dev;
|
||||||
|
struct unreg_ctx ctx = {};
|
||||||
|
int io_target;
|
||||||
|
|
||||||
|
allocate_threads(1);
|
||||||
|
CU_ASSERT(TAILQ_EMPTY(&g_io_devices));
|
||||||
|
spdk_io_device_register(&io_target, channel_create, channel_destroy, sizeof(int));
|
||||||
|
CU_ASSERT(!TAILQ_EMPTY(&g_io_devices));
|
||||||
|
dev = TAILQ_FIRST(&g_io_devices);
|
||||||
|
SPDK_CU_ASSERT_FATAL(dev != NULL);
|
||||||
|
CU_ASSERT(TAILQ_NEXT(dev, tailq) == NULL);
|
||||||
|
set_thread(0);
|
||||||
|
ch0 = spdk_get_io_channel(&io_target);
|
||||||
|
spdk_for_each_channel(&io_target, unreg_ch_done, &ctx, unreg_foreach_done);
|
||||||
|
|
||||||
|
spdk_io_device_unregister(&io_target, NULL);
|
||||||
|
/*
|
||||||
|
* There is an outstanding foreach call on the io_device, so the unregister should not
|
||||||
|
* have removed the device.
|
||||||
|
*/
|
||||||
|
CU_ASSERT(dev == TAILQ_FIRST(&g_io_devices));
|
||||||
|
spdk_io_device_register(&io_target, channel_create, channel_destroy, sizeof(int));
|
||||||
|
/*
|
||||||
|
* There is already a device registered at &io_target, so a new io_device should not
|
||||||
|
* have been added to g_io_devices.
|
||||||
|
*/
|
||||||
|
CU_ASSERT(dev == TAILQ_FIRST(&g_io_devices));
|
||||||
|
CU_ASSERT(TAILQ_NEXT(dev, tailq) == NULL);
|
||||||
|
|
||||||
|
poll_thread(0);
|
||||||
|
CU_ASSERT(ctx.ch_done == true);
|
||||||
|
CU_ASSERT(ctx.foreach_done == true);
|
||||||
|
/*
|
||||||
|
* There are no more foreach operations outstanding, so we can unregister the device,
|
||||||
|
* even though a channel still exists for the device.
|
||||||
|
*/
|
||||||
|
spdk_io_device_unregister(&io_target, NULL);
|
||||||
|
CU_ASSERT(TAILQ_EMPTY(&g_io_devices));
|
||||||
|
|
||||||
|
set_thread(0);
|
||||||
|
spdk_put_io_channel(ch0);
|
||||||
|
|
||||||
|
poll_threads();
|
||||||
|
|
||||||
|
free_threads();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
thread_name(void)
|
thread_name(void)
|
||||||
{
|
{
|
||||||
@ -318,6 +390,7 @@ main(int argc, char **argv)
|
|||||||
CU_add_test(suite, "thread_alloc", thread_alloc) == NULL ||
|
CU_add_test(suite, "thread_alloc", thread_alloc) == NULL ||
|
||||||
CU_add_test(suite, "thread_send_msg", thread_send_msg) == NULL ||
|
CU_add_test(suite, "thread_send_msg", thread_send_msg) == NULL ||
|
||||||
CU_add_test(suite, "for_each_channel_remove", for_each_channel_remove) == NULL ||
|
CU_add_test(suite, "for_each_channel_remove", for_each_channel_remove) == NULL ||
|
||||||
|
CU_add_test(suite, "for_each_channel_unreg", for_each_channel_unreg) == NULL ||
|
||||||
CU_add_test(suite, "thread_name", thread_name) == NULL ||
|
CU_add_test(suite, "thread_name", thread_name) == NULL ||
|
||||||
CU_add_test(suite, "channel", channel) == NULL
|
CU_add_test(suite, "channel", channel) == NULL
|
||||||
) {
|
) {
|
||||||
|
Loading…
Reference in New Issue
Block a user