Spdk/lib/ftl/mngt/ftl_mngt_bdev.c
Artur Paszkiewicz 884980d0aa ftl: vss null buffer workaround
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com>
Change-Id: I94ea399ed30fae29f92b4216eaa9209c02b3478b
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13310
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
2022-08-02 19:00:42 +00:00

262 lines
6.9 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation.
* All rights reserved.
*/
#include "spdk/bdev_module.h"
#include "spdk/ftl.h"
#include "ftl_internal.h"
#include "ftl_mngt_steps.h"
#include "ftl_internal.h"
#include "ftl_core.h"
#include "utils/ftl_defs.h"
#define MINIMUM_CACHE_SIZE_GIB 5
#define MINIMUM_BASE_SIZE_GIB 20
/* Dummy bdev module used to to claim bdevs. */
static struct spdk_bdev_module g_ftl_bdev_module = {
.name = "ftl_lib",
};
static inline size_t
ftl_calculate_num_zones_in_band(struct spdk_bdev_desc *desc)
{
if (spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(desc))) {
return spdk_bdev_get_optimal_open_zones(spdk_bdev_desc_get_bdev(desc));
}
return 1;
}
static inline size_t
ftl_calculate_num_blocks_in_zone(struct spdk_bdev_desc *desc)
{
if (spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(desc))) {
return spdk_bdev_get_zone_size(spdk_bdev_desc_get_bdev(desc));
}
/* TODO: this should be passed via input parameter */
#ifdef SPDK_FTL_ZONE_EMU_BLOCKS
return SPDK_FTL_ZONE_EMU_BLOCKS;
#else
return (1ULL << 30) / FTL_BLOCK_SIZE;
#endif
}
static inline uint64_t
ftl_calculate_num_blocks_in_band(struct spdk_bdev_desc *desc)
{
return ftl_calculate_num_zones_in_band(desc) * ftl_calculate_num_blocks_in_zone(desc);
}
static void
base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
{
switch (type) {
case SPDK_BDEV_EVENT_REMOVE:
assert(0);
break;
default:
break;
}
}
void
ftl_mngt_open_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
uint32_t block_size;
uint64_t num_blocks;
const char *bdev_name = dev->conf.base_bdev;
struct spdk_bdev *bdev;
if (spdk_bdev_open_ext(bdev_name, true, base_bdev_event_cb,
dev, &dev->base_bdev_desc)) {
FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
goto error;
}
bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
if (spdk_bdev_module_claim_bdev(bdev, dev->base_bdev_desc, &g_ftl_bdev_module)) {
/* clear the desc so that we don't try to release the claim on cleanup */
spdk_bdev_close(dev->base_bdev_desc);
dev->base_bdev_desc = NULL;
FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
goto error;
}
block_size = spdk_bdev_get_block_size(bdev);
if (block_size != FTL_BLOCK_SIZE) {
FTL_ERRLOG(dev, "Unsupported block size (%"PRIu32")\n", block_size);
goto error;
}
num_blocks = spdk_bdev_get_num_blocks(bdev);
if (num_blocks * block_size < MINIMUM_BASE_SIZE_GIB * GiB) {
FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
spdk_bdev_get_name(bdev), MINIMUM_BASE_SIZE_GIB);
goto error;
}
dev->base_ioch = spdk_bdev_get_io_channel(dev->base_bdev_desc);
if (!dev->base_ioch) {
FTL_ERRLOG(dev, "Failed to create base bdev IO channel\n");
goto error;
}
dev->xfer_size = ftl_get_write_unit_size(bdev);
/* TODO: validate size when base device VSS usage gets added */
dev->md_size = spdk_bdev_get_md_size(bdev);
/* Cache frequently used values */
dev->num_blocks_in_band = ftl_calculate_num_blocks_in_band(dev->base_bdev_desc);
dev->num_zones_in_band = ftl_calculate_num_zones_in_band(dev->base_bdev_desc);
dev->num_blocks_in_zone = ftl_calculate_num_blocks_in_zone(dev->base_bdev_desc);
dev->is_zoned = spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
if (dev->is_zoned) {
/* TODO - current FTL code isn't fully compatible with ZNS drives */
FTL_ERRLOG(dev, "Creating FTL on Zoned devices is not supported\n");
goto error;
}
dev->num_bands = num_blocks / ftl_get_num_blocks_in_band(dev);
/* Save a band worth of space for metadata */
dev->num_bands--;
ftl_mngt_next_step(mngt);
return;
error:
ftl_mngt_fail_step(mngt);
}
void
ftl_mngt_close_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
if (dev->base_ioch) {
spdk_put_io_channel(dev->base_ioch);
dev->base_ioch = NULL;
}
if (dev->base_bdev_desc) {
struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
spdk_bdev_module_release_bdev(bdev);
spdk_bdev_close(dev->base_bdev_desc);
dev->base_bdev_desc = NULL;
}
ftl_mngt_next_step(mngt);
}
static void
nv_cache_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
{
switch (type) {
case SPDK_BDEV_EVENT_REMOVE:
assert(0);
break;
default:
break;
}
}
void
ftl_mngt_open_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
struct spdk_bdev *bdev;
const char *bdev_name = dev->conf.cache_bdev;
if (spdk_bdev_open_ext(bdev_name, true, nv_cache_bdev_event_cb, dev,
&dev->cache_bdev_desc)) {
FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
goto error;
}
bdev = spdk_bdev_desc_get_bdev(dev->cache_bdev_desc);
if (spdk_bdev_module_claim_bdev(bdev, dev->cache_bdev_desc, &g_ftl_bdev_module)) {
/* clear the desc so that we don't try to release the claim on cleanup */
spdk_bdev_close(dev->cache_bdev_desc);
dev->cache_bdev_desc = NULL;
FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
goto error;
}
FTL_NOTICELOG(dev, "Using %s as write buffer cache\n", spdk_bdev_get_name(bdev));
if (spdk_bdev_get_block_size(bdev) != FTL_BLOCK_SIZE) {
FTL_ERRLOG(dev, "Unsupported block size (%d)\n",
spdk_bdev_get_block_size(bdev));
goto error;
}
dev->cache_ioch = spdk_bdev_get_io_channel(dev->cache_bdev_desc);
if (!dev->cache_ioch) {
FTL_ERRLOG(dev, "Failed to create cache IO channel for NV Cache\n");
goto error;
}
if (!spdk_bdev_is_md_separate(bdev)) {
FTL_ERRLOG(dev, "Bdev %s doesn't support separate metadata buffer IO\n",
spdk_bdev_get_name(bdev));
goto error;
}
dev->cache_md_size = spdk_bdev_get_md_size(bdev);
if (dev->cache_md_size != sizeof(union ftl_md_vss)) {
FTL_ERRLOG(dev, "Bdev's %s metadata is invalid size (%"PRIu32")\n",
spdk_bdev_get_name(bdev), spdk_bdev_get_md_size(bdev));
goto error;
}
if (spdk_bdev_get_dif_type(bdev) != SPDK_DIF_DISABLE) {
FTL_ERRLOG(dev, "Unsupported DIF type used by bdev %s\n",
spdk_bdev_get_name(bdev));
goto error;
}
if (bdev->blockcnt * bdev->blocklen < MINIMUM_CACHE_SIZE_GIB * GiB) {
FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
spdk_bdev_get_name(bdev), MINIMUM_CACHE_SIZE_GIB);
goto error;
}
if (ftl_md_xfer_blocks(dev) * dev->cache_md_size > FTL_ZERO_BUFFER_SIZE) {
FTL_ERRLOG(dev, "Zero buffer too small for bdev %s metadata transfer\n",
spdk_bdev_get_name(bdev));
goto error;
}
ftl_mngt_next_step(mngt);
return;
error:
ftl_mngt_fail_step(mngt);
}
void
ftl_mngt_close_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
{
if (dev->cache_ioch) {
spdk_put_io_channel(dev->cache_ioch);
dev->cache_ioch = NULL;
}
if (dev->cache_bdev_desc) {
struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->cache_bdev_desc);
spdk_bdev_module_release_bdev(bdev);
spdk_bdev_close(dev->cache_bdev_desc);
dev->cache_bdev_desc = NULL;
}
ftl_mngt_next_step(mngt);
}