Commit 77f5fcfa authored by Mateusz Kozlowski's avatar Mateusz Kozlowski Committed by Tomasz Zawadzki
Browse files

lib/ftl: Add store/load blob layout tracker functions



The functions allow for saving and loading the state of the layout
tracker from a blob.

Change-Id: Iad73fc0c80f53b489fa036d87a95b0d6e1c0e74d
Signed-off-by: default avatarMateusz Kozlowski <mateusz.kozlowski@solidigm.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/20523


Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Reviewed-by: default avatarBen Walker <ben@nvidia.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 8fcffeba
Loading
Loading
Loading
Loading
+215 −15
Original line number Diff line number Diff line
@@ -18,22 +18,32 @@ struct ftl_layout_tracker_bdev {
	uint32_t regs_cnt;
};

struct ftl_layout_tracker_bdev *
ftl_layout_tracker_bdev_init(uint64_t bdev_blks)
{
	struct ftl_layout_tracker_bdev *tracker = calloc(1, sizeof(*tracker));
	struct layout_tracker_entry *entry_free;
struct layout_tracker_blob_entry {
	/* Region type */
	uint32_t type;

	if (!tracker) {
		return NULL;
	}
	/* Region version */
	uint32_t ver;

	/* Region offset in blocks */
	uint64_t blk_offs;

	/* Region size in blocks */
	uint64_t blk_sz;
} __attribute__((packed));

static int
layout_tracker_init_entries(struct ftl_layout_tracker_bdev *tracker, uint64_t bdev_blks)
{
	struct layout_tracker_entry *entry_free = calloc(1, sizeof(*entry_free));

	entry_free = calloc(1, sizeof(*entry_free));
	if (!entry_free) {
		free(tracker);
		return NULL;
		return -ENOMEM;
	}

	assert(tracker);
	assert(tracker->regs_cnt == 0);

	tracker->bdev_blks = bdev_blks;
	tracker->regs_cnt = 1;
	TAILQ_INIT(&tracker->layout_head);
@@ -42,22 +52,43 @@ ftl_layout_tracker_bdev_init(uint64_t bdev_blks)
	entry_free->reg.type = FTL_LAYOUT_REGION_TYPE_FREE;

	TAILQ_INSERT_HEAD(&tracker->layout_head, entry_free, layout_entry);
	return 0;
}

struct ftl_layout_tracker_bdev *
ftl_layout_tracker_bdev_init(uint64_t bdev_blks)
{
	struct ftl_layout_tracker_bdev *tracker = calloc(1, sizeof(*tracker));

	if (!tracker) {
		return NULL;
	}

	if (layout_tracker_init_entries(tracker, bdev_blks)) {
		free(tracker);
		return NULL;
	}

	return tracker;
}

void
ftl_layout_tracker_bdev_fini(struct ftl_layout_tracker_bdev *tracker)
static void
layout_tracker_free_entries(struct ftl_layout_tracker_bdev *tracker)
{
	struct layout_tracker_entry *entry;

	assert(tracker);

	while ((entry = TAILQ_FIRST(&tracker->layout_head))) {
		TAILQ_REMOVE(&tracker->layout_head, entry, layout_entry);
		free(entry);
	}
	tracker->regs_cnt = 0;
}

void
ftl_layout_tracker_bdev_fini(struct ftl_layout_tracker_bdev *tracker)
{
	assert(tracker);
	layout_tracker_free_entries(tracker);
	free(tracker);
}

@@ -213,6 +244,102 @@ ftl_layout_tracker_bdev_add_region(struct ftl_layout_tracker_bdev *tracker,
	return &entry_new->reg;
}

const struct ftl_layout_tracker_bdev_region_props *
ftl_layout_tracker_bdev_insert_region(struct ftl_layout_tracker_bdev *tracker,
				      enum ftl_layout_region_type reg_type, uint32_t reg_ver,
				      uint64_t blk_offs, uint64_t blk_sz)
{
	struct layout_tracker_entry *entry_free;
	struct layout_tracker_entry *entry_new;
	uint64_t entry_free_blks_left;

	assert(tracker);

	if (reg_type >= FTL_LAYOUT_REGION_TYPE_MAX && reg_type != FTL_LAYOUT_REGION_TYPE_INVALID) {
		/* Invalid region type */
		return NULL;
	}

	entry_new = layout_region_find_first(tracker, reg_type, reg_ver);
	if (entry_new) {
		/* Region already exists */
		return NULL;
	}

	/* Look up for the free region corresponding to the blk_offs */
	for (entry_free = layout_region_find_first(tracker, FTL_LAYOUT_REGION_TYPE_FREE, REG_VER_ANY);
	     entry_free;
	     entry_free = layout_region_find_next(tracker, FTL_LAYOUT_REGION_TYPE_FREE, REG_VER_ANY,
			     entry_free)) {
		/* Test if the region being added fits into the free region */
		if (entry_free->reg.blk_offs <= blk_offs
		    && blk_offs + blk_sz <= entry_free->reg.blk_offs + entry_free->reg.blk_sz) {
			break;
		}
	}

	if (!entry_free) {
		/* Did not found the corresponding free region */
		return NULL;
	}

	entry_free_blks_left = blk_offs - entry_free->reg.blk_offs;
	if (entry_free_blks_left) {
		/* Subdivide the free region */
		entry_new = calloc(1, sizeof(*entry_new));
		if (!entry_new) {
			return NULL;
		}

		/* Setup another free region at the beginning of the free region found */
		entry_new->reg.type = FTL_LAYOUT_REGION_TYPE_FREE;
		entry_new->reg.blk_offs = entry_free->reg.blk_offs;
		entry_new->reg.blk_sz = entry_free_blks_left;

		/* Shrink the free region found */
		entry_free->reg.blk_offs += entry_free_blks_left;
		assert(entry_free->reg.blk_sz > entry_free_blks_left);
		entry_free->reg.blk_sz -= entry_free_blks_left;

		/* Add the new free region */
		TAILQ_INSERT_BEFORE(entry_free, entry_new, layout_entry);
		tracker->regs_cnt++;
	}

	assert(entry_free->reg.blk_offs == blk_offs);
	assert(blk_sz <= entry_free->reg.blk_sz);

	entry_free_blks_left = entry_free->reg.blk_sz - blk_sz;
	if (entry_free_blks_left) {
		/* Subdivide the free region */
		entry_new = calloc(1, sizeof(*entry_new));
		if (!entry_new) {
			return NULL;
		}

		/* Setup the new region at the beginning of the free region found */
		entry_new->reg.type = reg_type;
		entry_new->reg.ver = reg_ver;
		entry_new->reg.blk_offs = entry_free->reg.blk_offs;
		entry_new->reg.blk_sz = blk_sz;

		/* Shrink the free region found */
		entry_free->reg.blk_offs += blk_sz;
		entry_free->reg.blk_sz = entry_free_blks_left;

		/* Add the new region */
		TAILQ_INSERT_BEFORE(entry_free, entry_new, layout_entry);
		tracker->regs_cnt++;
	} else {
		/* Setup the new region in place */
		entry_new = entry_free;
		entry_new->reg.type = reg_type;
		entry_new->reg.ver = reg_ver;
	}

	return &entry_new->reg;
}

int
ftl_layout_tracker_bdev_rm_region(struct ftl_layout_tracker_bdev *tracker,
				  enum ftl_layout_region_type reg_type, uint32_t reg_ver)
@@ -286,3 +413,76 @@ ftl_layout_tracker_bdev_find_next_region(struct ftl_layout_tracker_bdev *tracker
	}
	*search_ctx = entry ? &entry->reg : NULL;
}

size_t
ftl_layout_tracker_bdev_blob_store(struct ftl_layout_tracker_bdev *tracker, void *blob_buf,
				   size_t blob_buf_sz)
{
	struct layout_tracker_blob_entry *blob_entry = blob_buf;
	struct layout_tracker_entry *entry;
	size_t blob_sz = 0;

	assert(tracker);

	TAILQ_FOREACH(entry, &tracker->layout_head, layout_entry) {
		if (blob_sz + sizeof(*blob_entry) > blob_buf_sz) {
			/* Ran out of buf space */
			assert(false);
			return 0;
		}

		/* Skip the free space entries */
		if (entry->reg.type == FTL_LAYOUT_REGION_TYPE_FREE) {
			continue;
		}

		/* Store the entry */
		blob_entry->type = entry->reg.type;
		blob_entry->ver = entry->reg.ver;
		blob_entry->blk_offs = entry->reg.blk_offs;
		blob_entry->blk_sz = entry->reg.blk_sz;

		/* Move to the next entry */
		blob_entry++;
		blob_sz += sizeof(*blob_entry);
	}

	return blob_sz;
}

int
ftl_layout_tracker_bdev_blob_load(struct ftl_layout_tracker_bdev *tracker, void *blob_buf,
				  size_t blob_sz)
{
	struct layout_tracker_blob_entry *blob_entry = blob_buf;
	size_t blob_entry_num = blob_sz / sizeof(*blob_entry);
	struct layout_tracker_blob_entry *blob_entry_end = blob_entry + blob_entry_num;

	if (blob_sz % sizeof(*blob_entry) != 0) {
		/* Invalid blob size */
		return -1;
	}

	/* Free the current MD layout tracking info */
	layout_tracker_free_entries(tracker);

	/* Reinit MD layout tracking info */
	if (layout_tracker_init_entries(tracker, tracker->bdev_blks)) {
		return -1;
	}

	for (; blob_entry < blob_entry_end; blob_entry++) {
		/* Verify the type */
		if (blob_entry->type == FTL_LAYOUT_REGION_TYPE_FREE) {
			return -1;
		}

		/* Load the entry */
		if (!ftl_layout_tracker_bdev_insert_region(tracker, blob_entry->type, blob_entry->ver,
				blob_entry->blk_offs, blob_entry->blk_sz)) {
			return -1;
		}
	}

	return 0;
}
+39 −0
Original line number Diff line number Diff line
@@ -85,4 +85,43 @@ void ftl_layout_tracker_bdev_find_next_region(struct ftl_layout_tracker_bdev *tr
		enum ftl_layout_region_type reg_type,
		const struct ftl_layout_tracker_bdev_region_props **search_ctx);

/**
 * @brief Store the layout tracker state into a blob
 *
 * @param tracker pointer to the tracker instance
 * @param blob_buf pointer to the blob buffer
 * @param blob_buf_sz blob buffer size in bytes
 *
 * @return bytes stored, 0 when stored amount would exceed the capacity
 */
size_t ftl_layout_tracker_bdev_blob_store(struct ftl_layout_tracker_bdev *tracker, void *blob_buf,
		size_t blob_buf_sz);

/**
 * @brief Load the layout tracker state from a blob
 *
 * @param tracker pointer to the tracker instance
 * @param blob_buf pointer to the blob buffer
 * @param blob_sz blob size in bytes
 *
 * @return 0 on success : -1 on fault
 */
int ftl_layout_tracker_bdev_blob_load(struct ftl_layout_tracker_bdev *tracker, void *blob_buf,
				      size_t blob_sz);

/**
 * @brief Insert a new FTL layout region into a specific location
 *
 * @param tracker pointer to the tracker instance
 * @param reg_type FTL layout region type
 * @param reg_ver FTL layout region version
 * @param blk_offs offset in blocks of the FTL layout region
 * @param blk_sz size in blocks of the FTL layout region
 *
 * @return pointer to the ftl_layout_tracker_bdev_region_props, describing the region added or NULL upon fault
 */
const struct ftl_layout_tracker_bdev_region_props *ftl_layout_tracker_bdev_insert_region(
	struct ftl_layout_tracker_bdev *tracker, enum ftl_layout_region_type reg_type, uint32_t reg_ver,
	uint64_t blk_offs, uint64_t blk_sz);

#endif /* FTL_LAYOUT_TRACKER_BDEV_H */