Commit 31cf6336 authored by Kozlowski Mateusz's avatar Kozlowski Mateusz Committed by Ben Walker
Browse files

FTL: Add writer logic



Add writer - tracks and manages band state transitions and write pointer as IO
is issued to it.

Signed-off-by: default avatarKozlowski Mateusz <mateusz.kozlowski@intel.com>
Signed-off-by: default avatarArtur Paszkiewicz <artur.paszkiewicz@intel.com>
Change-Id: I5f878dc15bc1c1ac84835f75fe440672fad541d5
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13335


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent 0291b284
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ CFLAGS += -I.
FTL_SUBDIRS := mngt utils

C_SRCS = ftl_core.c ftl_init.c ftl_layout.c ftl_debug.c ftl_io.c ftl_sb.c ftl_l2p.c ftl_l2p_flat.c
C_SRCS += ftl_nv_cache.c ftl_band.c ftl_band_ops.c
C_SRCS += ftl_nv_cache.c ftl_band.c ftl_band_ops.c ftl_writer.c
C_SRCS += mngt/ftl_mngt.c mngt/ftl_mngt_bdev.c mngt/ftl_mngt_shutdown.c mngt/ftl_mngt_startup.c
C_SRCS += mngt/ftl_mngt_md.c mngt/ftl_mngt_misc.c mngt/ftl_mngt_ioch.c mngt/ftl_mngt_l2p.c
C_SRCS += mngt/ftl_mngt_band.c
+12 −0
Original line number Diff line number Diff line
@@ -73,6 +73,16 @@ ftl_shutdown_complete(struct spdk_ftl_dev *dev)
		return false;
	}

	if (!ftl_writer_is_halted(&dev->writer_user)) {
		ftl_writer_halt(&dev->writer_user);
		return false;
	}

	if (!ftl_writer_is_halted(&dev->writer_gc)) {
		ftl_writer_halt(&dev->writer_gc);
		return false;
	}

	if (!ftl_nv_cache_chunks_busy(&dev->nv_cache)) {
		return false;
	}
@@ -481,6 +491,8 @@ ftl_core_poller(void *ctx)
	}

	ftl_process_io_queue(dev);
	ftl_writer_run(&dev->writer_user);
	ftl_writer_run(&dev->writer_gc);
	ftl_nv_cache_process(dev);
	ftl_l2p_process(dev);

+7 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include "ftl_internal.h"
#include "ftl_io.h"
#include "ftl_nv_cache.h"
#include "ftl_writer.h"
#include "ftl_layout.h"
#include "ftl_sb.h"
#include "ftl_l2p.h"
@@ -138,6 +139,12 @@ struct spdk_ftl_dev {

	/* Write submission queue */
	TAILQ_HEAD(, ftl_io)		wr_sq;

	/* Writer for user IOs */
	struct ftl_writer		writer_user;

	/* Writer for GC IOs */
	struct ftl_writer		writer_gc;
};

void ftl_apply_limits(struct spdk_ftl_dev *dev);
+4 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "ftl_band.h"
#include "ftl_debug.h"
#include "ftl_nv_cache.h"
#include "ftl_writer.h"
#include "ftl_utils.h"
#include "mngt/ftl_mngt.h"

@@ -118,6 +119,9 @@ allocate_dev(const struct spdk_ftl_conf *conf, int *error)
	TAILQ_INIT(&dev->wr_sq);
	TAILQ_INIT(&dev->ioch_queue);

	ftl_writer_init(dev, &dev->writer_user, SPDK_FTL_LIMIT_HIGH, FTL_BAND_TYPE_COMPACTION);
	ftl_writer_init(dev, &dev->writer_gc, SPDK_FTL_LIMIT_CRIT, FTL_BAND_TYPE_GC);

	return dev;
error:
	free_dev(dev);

lib/ftl/ftl_writer.c

0 → 100644
+193 −0
Original line number Diff line number Diff line
/*   SPDX-License-Identifier: BSD-3-Clause
 *   Copyright (c) Intel Corporation.
 *   All rights reserved.
 */

#include "spdk/likely.h"

#include "ftl_writer.h"
#include "ftl_band.h"

void
ftl_writer_init(struct spdk_ftl_dev *dev, struct ftl_writer *writer,
		uint64_t limit, enum ftl_band_type type)
{
	memset(writer, 0, sizeof(*writer));
	writer->dev = dev;
	TAILQ_INIT(&writer->rq_queue);
	TAILQ_INIT(&writer->full_bands);
	writer->limit = limit;
	writer->halt = true;
	writer->writer_type = type;
}

static bool
can_write(struct ftl_writer *writer)
{
	if (spdk_unlikely(writer->halt)) {
		return false;
	}

	return writer->band->md->state == FTL_BAND_STATE_OPEN;
}

void
ftl_writer_band_state_change(struct ftl_band *band)
{
	struct ftl_writer *writer = band->owner.priv;

	switch (band->md->state) {
	case FTL_BAND_STATE_FULL:
		assert(writer->band == band);
		TAILQ_INSERT_TAIL(&writer->full_bands, band, queue_entry);
		writer->band = NULL;
		break;

	case FTL_BAND_STATE_CLOSED:
		assert(writer->num_bands > 0);
		writer->num_bands--;
		ftl_band_clear_owner(band, ftl_writer_band_state_change, writer);
		break;

	default:
		break;
	}
}

static void
close_full_bands(struct ftl_writer *writer)
{
	struct ftl_band *band, *next;

	TAILQ_FOREACH_SAFE(band, &writer->full_bands, queue_entry, next) {
		if (band->queue_depth) {
			continue;
		}

		TAILQ_REMOVE(&writer->full_bands, band, queue_entry);
		ftl_band_close(band);
	}
}

static bool
is_active(struct ftl_writer *writer)
{
	if (writer->dev->limit < writer->limit) {
		return false;
	}

	return true;
}

static struct ftl_band *
get_band(struct ftl_writer *writer)
{
	if (spdk_unlikely(!writer->band)) {
		if (!is_active(writer)) {
			return NULL;
		}

		if (spdk_unlikely(NULL != writer->next_band)) {
			if (FTL_BAND_STATE_OPEN == writer->next_band->md->state) {
				writer->band = writer->next_band;
				writer->next_band = NULL;

				return writer->band;
			} else {
				assert(FTL_BAND_STATE_OPEN == writer->next_band->md->state);
				ftl_abort();
			}
		}

		writer->band = ftl_band_get_next_free(writer->dev);
		if (writer->band) {
			writer->num_bands++;
			ftl_band_set_owner(writer->band,
					   ftl_writer_band_state_change, writer);

			if (ftl_band_write_prep(writer->band)) {
				/*
				 * This error might happen due to allocation failure. However number
				 * of open bands is controlled and it should have enough resources
				 * to do it. So here is better to perform a crash and recover from
				 * shared memory to bring back stable state.
				 *  */
				ftl_abort();
			}
		} else {
			return NULL;
		}
	}

	if (spdk_likely(writer->band->md->state == FTL_BAND_STATE_OPEN)) {
		return writer->band;
	} else {
		if (spdk_unlikely(writer->band->md->state == FTL_BAND_STATE_PREP)) {
			ftl_band_open(writer->band, writer->writer_type);
		}
		return NULL;
	}
}

void
ftl_writer_run(struct ftl_writer *writer)
{
	struct ftl_band *band;
	struct ftl_rq *rq;

	close_full_bands(writer);

	if (!TAILQ_EMPTY(&writer->rq_queue)) {
		band = get_band(writer);
		if (spdk_unlikely(!band)) {
			return;
		}

		if (!can_write(writer)) {
			return;
		}

		/* Finally we can write to band */
		rq = TAILQ_FIRST(&writer->rq_queue);
		TAILQ_REMOVE(&writer->rq_queue, rq, qentry);
		ftl_band_rq_write(writer->band, rq);
	}
}

bool
ftl_writer_is_halted(struct ftl_writer *writer)
{
	if (spdk_unlikely(!TAILQ_EMPTY(&writer->full_bands))) {
		return false;
	}

	if (writer->band) {
		if (writer->band->md->state != FTL_BAND_STATE_OPEN) {
			return false;
		}

		if (writer->band->queue_depth) {
			return false;
		}
	}

	return writer->halt;
}

uint64_t
ftl_writer_get_free_blocks(struct ftl_writer *writer)
{
	uint64_t free_blocks = 0;

	if (writer->band) {
		free_blocks += ftl_band_user_blocks_left(writer->band,
				writer->band->md->iter.offset);
	}

	if (writer->next_band) {
		free_blocks += ftl_band_user_blocks_left(writer->next_band,
				writer->next_band->md->iter.offset);
	}

	return free_blocks;
}
Loading