Commit ef5ede4b authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Jim Harris
Browse files

lib/ftl: allow parent/child relations between IOs



Extended the IO descriptors with the ability to group them together in a
parent / child(-ren) relationship. It allows to delay parent completion
until all children are done and enables the children to have additional
context in their completion routines (as opposed to having a single IO
describe all requests).

Signed-off-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I6ad111dc231813e397697109a333e2a5d7f5941d
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/449068


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarWojciech Malikowski <wojciech.malikowski@intel.com>
Reviewed-by: default avatarYoung Tack Jin <youngtack.jin@circuitblvd.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
parent 3f442687
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1340,7 +1340,7 @@ _spdk_ftl_write(struct ftl_io *io)

	rc = ftl_io_write(io);
	if (rc == -EAGAIN) {
		spdk_thread_send_msg(spdk_io_channel_get_thread(io->ch),
		spdk_thread_send_msg(spdk_io_channel_get_thread(io->ioch),
				     _ftl_write, io);
		return 0;
	}
+91 −11
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@

#include "spdk/stdinc.h"
#include "spdk/ftl.h"
#include "spdk/likely.h"

#include "ftl_io.h"
#include "ftl_core.h"
@@ -190,7 +191,12 @@ ftl_io_init_internal(const struct ftl_io_init_opts *opts)
	struct spdk_ftl_dev *dev = opts->dev;

	if (!io) {
		if (opts->parent) {
			io = ftl_io_alloc_child(opts->parent);
		} else {
			io = ftl_io_alloc(dev->ioch);
		}

		if (!io) {
			return NULL;
		}
@@ -289,19 +295,87 @@ ftl_io_user_init(struct spdk_ftl_dev *dev, struct ftl_io *io, uint64_t lba, size
	ftl_trace_lba_io_init(io->dev, io);
}

static void
_ftl_io_free(struct ftl_io *io)
{
	struct ftl_io_channel *ioch;

	assert(LIST_EMPTY(&io->children));

	if ((io->flags & FTL_IO_INTERNAL) && io->iov_cnt > 1) {
		free(io->iovs);
	}

	if (pthread_spin_destroy(&io->lock)) {
		SPDK_ERRLOG("pthread_spin_destroy failed\n");
	}

	ioch = spdk_io_channel_get_ctx(io->ioch);
	spdk_mempool_put(ioch->io_pool, io);
}

static bool
ftl_io_remove_child(struct ftl_io *io)
{
	struct ftl_io *parent = io->parent;
	bool parent_done;

	pthread_spin_lock(&parent->lock);
	LIST_REMOVE(io, child_entry);
	parent_done = parent->done && LIST_EMPTY(&parent->children);
	parent->status = parent->status ? : io->status;
	pthread_spin_unlock(&parent->lock);

	return parent_done;
}

void
ftl_io_complete(struct ftl_io *io)
{
	int keep_alive = io->flags & FTL_IO_KEEP_ALIVE;
	struct ftl_io *parent = io->parent;
	bool complete, keep_alive = io->flags & FTL_IO_KEEP_ALIVE;

	io->flags &= ~FTL_IO_INITIALIZED;

	pthread_spin_lock(&io->lock);
	complete = LIST_EMPTY(&io->children);
	io->done = true;
	pthread_spin_unlock(&io->lock);

	if (complete) {
		if (io->cb.fn) {
			io->cb.fn(io->cb.ctx, io->status);
		}

		if (parent && ftl_io_remove_child(io)) {
			ftl_io_complete(parent);
		}

		if (!keep_alive) {
		ftl_io_free(io);
			_ftl_io_free(io);
		}
	}
}

struct ftl_io *
ftl_io_alloc_child(struct ftl_io *parent)
{
	struct ftl_io *io;

	io = ftl_io_alloc(parent->ioch);
	if (spdk_unlikely(!io)) {
		return NULL;
	}

	io->parent = parent;

	pthread_spin_lock(&parent->lock);
	LIST_INSERT_HEAD(&parent->children, io, child_entry);
	pthread_spin_unlock(&parent->lock);

	return io;
}

void
ftl_io_process_error(struct ftl_io *io, const struct spdk_nvme_cpl *status)
{
@@ -336,7 +410,14 @@ ftl_io_alloc(struct spdk_io_channel *ch)
	}

	memset(io, 0, ioch->elem_size);
	io->ch = ch;
	io->ioch = ch;

	if (pthread_spin_init(&io->lock, PTHREAD_PROCESS_PRIVATE)) {
		SPDK_ERRLOG("pthread_spin_init failed\n");
		spdk_mempool_put(ioch->io_pool, io);
		return NULL;
	}

	return io;
}

@@ -362,16 +443,15 @@ ftl_io_clear(struct ftl_io *io)
void
ftl_io_free(struct ftl_io *io)
{
	struct ftl_io_channel *ioch;
	struct ftl_io *parent = io->parent;

	if (!io) {
		return;
	}

	if ((io->flags & FTL_IO_INTERNAL) && io->iov_cnt > 1) {
		free(io->iovs);
	if (parent && ftl_io_remove_child(io)) {
		ftl_io_complete(parent);
	}

	ioch = spdk_io_channel_get_ctx(io->ch);
	spdk_mempool_put(ioch->io_pool, io);
	_ftl_io_free(io);
}
+17 −1
Original line number Diff line number Diff line
@@ -84,6 +84,9 @@ struct ftl_io_init_opts {
	/* IO descriptor */
	struct ftl_io				*io;

	/* Parent request */
	struct ftl_io				*parent;

	/* Size of IO descriptor */
	size_t                                  size;

@@ -137,7 +140,7 @@ struct ftl_io {
	struct spdk_ftl_dev			*dev;

	/* IO channel */
	struct spdk_io_channel			*ch;
	struct spdk_io_channel			*ioch;

	union {
		/* LBA table */
@@ -197,6 +200,18 @@ struct ftl_io {
	/* IO type */
	enum ftl_io_type			type;

	/* Done flag */
	bool					done;

	/* Parent request */
	struct ftl_io				*parent;
	/* Child requests list */
	LIST_HEAD(, ftl_io)			children;
	/* Child list link */
	LIST_ENTRY(ftl_io)			child_entry;
	/* Children lock */
	pthread_spinlock_t			lock;

	/* Trace group id */
	uint64_t				trace;

@@ -240,6 +255,7 @@ ftl_io_done(const struct ftl_io *io)
}

struct ftl_io *ftl_io_alloc(struct spdk_io_channel *ch);
struct ftl_io *ftl_io_alloc_child(struct ftl_io *parent);
void ftl_io_free(struct ftl_io *io);
struct ftl_io *ftl_io_init_internal(const struct ftl_io_init_opts *opts);
void ftl_io_reinit(struct ftl_io *io, spdk_ftl_fn cb,
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk

DIRS-y = ftl_rwb.c ftl_ppa ftl_band.c ftl_reloc.c ftl_wptr ftl_md
DIRS-y = ftl_rwb.c ftl_ppa ftl_band.c ftl_reloc.c ftl_wptr ftl_md ftl_io.c

.PHONY: all clean $(DIRS-y)

+1 −0
Original line number Diff line number Diff line
ftl_io_ut
Loading