Commit ce3e56d6 authored by Jinlong Chen's avatar Jinlong Chen Committed by Jim Harris
Browse files

lib/thread: add spdk_io_channel_ref for taking ref of existing channels



There are cases that we just want to take a reference for an existing io
channel. An existing example is that bdev reset requests take extra
reference to bdev io channels to protect the io channels during reset
operations.

A more universal case is to take reference to an io channel for each
request sent to it to protect the channel during io operations, so that
users do not need to implement their own refcounting mechanisms.

Therefore, a light-weight and lockless alternative to spdk_get_io_channel
could be useful.

Change-Id: I570fe47f0ad7fb4943fc20af6d76aadb37e51d86
Signed-off-by: default avatarJinlong Chen <chenjinlong.cjl@alibaba-inc.com>
Reviewed-on: https://review.spdk.io/c/spdk/spdk/+/26232


Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK Automated Test System <spdkbot@gmail.com>
Reviewed-by: default avatarJim Harris <jim.harris@nvidia.com>
Reviewed-by: default avatarBen Walker <ben@nvidia.com>
parent b8e4cd6a
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -726,6 +726,20 @@ struct spdk_io_channel *spdk_get_io_channel(void *io_device);
 */
void spdk_put_io_channel(struct spdk_io_channel *ch);

/**
 * Take a reference to an existing I/O channel.
 *
 * This can be called on an existing io_channel that was previously returned from
 * spdk_get_io_channel(). This must be called on the same thread that called
 * spdk_get_io_channel() for the specified I/O channel. spdk_put_io_channel() must
 * be called to release the reference when it is no longer needed.
 *
 * \param ch The existing I/O channel to reference.
 *
 * \return The same I/O channel pointer that was passed in.
 */
struct spdk_io_channel *spdk_io_channel_ref(struct spdk_io_channel *ch);

/**
 * Get the context buffer associated with an I/O channel.
 *
+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
	spdk_io_device_unregister;
	spdk_get_io_channel;
	spdk_put_io_channel;
	spdk_io_channel_ref;
	spdk_io_channel_get_ctx;
	spdk_io_channel_from_ctx;
	spdk_io_channel_get_thread;
+15 −0
Original line number Diff line number Diff line
@@ -2565,6 +2565,21 @@ spdk_put_io_channel(struct spdk_io_channel *ch)
	}
}

struct spdk_io_channel *
spdk_io_channel_ref(struct spdk_io_channel *ch)
{
	struct spdk_thread *thread;

	thread = spdk_get_thread();
	if (spdk_unlikely(ch->thread != thread)) {
		wrong_thread(__func__, "ch", ch->thread, thread);
		return NULL;
	}

	ch->ref++;
	return ch;
}

struct spdk_io_channel *
spdk_io_channel_from_ctx(void *ctx)
{
+13 −1
Original line number Diff line number Diff line
@@ -803,7 +803,7 @@ destroy_cb_2(void *io_device, void *ctx_buf)
static void
channel(void)
{
	struct spdk_io_channel *ch1, *ch2;
	struct spdk_io_channel *ch1, *ch2, *ch1_ref;
	void *ctx;

	allocate_threads(1);
@@ -825,6 +825,13 @@ channel(void)
	SPDK_CU_ASSERT_FATAL(ch2 != NULL);
	CU_ASSERT(spdk_io_channel_get_io_device(ch2) == &g_device1);

	g_create_cb_calls = 0;
	ch1_ref = spdk_io_channel_ref(ch1);
	CU_ASSERT(g_create_cb_calls == 0);
	CU_ASSERT(ch1_ref == ch1);
	SPDK_CU_ASSERT_FATAL(ch1_ref != NULL);
	CU_ASSERT(spdk_io_channel_get_io_device(ch1_ref) == &g_device1);

	g_destroy_cb_calls = 0;
	spdk_put_io_channel(ch2);
	poll_threads();
@@ -843,6 +850,11 @@ channel(void)
	g_destroy_cb_calls = 0;
	spdk_put_io_channel(ch1);
	poll_threads();
	CU_ASSERT(g_destroy_cb_calls == 0);

	g_destroy_cb_calls = 0;
	spdk_put_io_channel(ch1_ref);
	poll_threads();
	CU_ASSERT(g_destroy_cb_calls == 1);

	g_destroy_cb_calls = 0;