lib/ftl: Create l2p on l2p_path file if set in config

New spdk_ftl_conf parameter l2p_path, l2p_path defines
location of existing pmem file or device to use as l2p table.

ftl_dev_l2p_alloc now has two flows:
1. If l2p_path is set perform pmem_map_file (PMDK) of l2p_size on it
2. Else malloc l2p table as usual

l2p_get/set will use atomic_load/store on both of those storage
locations as PMDK pmem_memcpy family of functions is not thread safe.

Signed-off-by: Maciej Szczepaniak <maciej.szczepaniak@intel.com>
Change-Id: I91806feb7aa0ef8057792bc120b09a39c63c8640
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/649
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Wojciech Malikowski <wojciech.malikowski@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Maciej Szczepaniak 2020-02-06 12:58:20 +01:00 committed by Tomasz Zawadzki
parent 15a3067b78
commit 01ea524068
3 changed files with 80 additions and 13 deletions

View File

@ -102,6 +102,9 @@ struct spdk_ftl_conf {
/* Maximum number of blocks per one request */
size_t max_request_size;
} nv_cache;
/* Create l2p table on l2p_path persistent memory file or device instead of in DRAM */
const char *l2p_path;
};
enum spdk_ftl_mode {

View File

@ -175,6 +175,8 @@ struct spdk_ftl_dev {
void *l2p;
/* Size of the l2p table */
uint64_t num_lbas;
/* Size of pages mmapped for l2p, valid only for mapping on persistent memory */
size_t l2p_pmem_len;
/* Address size */
size_t addr_len;

View File

@ -42,6 +42,7 @@
#include "spdk/string.h"
#include "spdk/bdev_zone.h"
#include "spdk/bdev_module.h"
#include "spdk/config.h"
#include "ftl_core.h"
#include "ftl_io.h"
@ -49,6 +50,10 @@
#include "ftl_band.h"
#include "ftl_debug.h"
#ifdef SPDK_CONFIG_PMDK
#include "libpmem.h"
#endif /* SPDK_CONFIG_PMDK */
#define FTL_CORE_RING_SIZE 4096
#define FTL_INIT_TIMEOUT 30
#define FTL_NSID 1
@ -529,31 +534,73 @@ ftl_dev_init_core_thread(struct spdk_ftl_dev *dev, const struct spdk_ftl_dev_ini
return 0;
}
static int
ftl_dev_l2p_alloc_pmem(struct spdk_ftl_dev *dev, size_t l2p_size, const char *l2p_path)
{
#ifdef SPDK_CONFIG_PMDK
int is_pmem;
if ((dev->l2p = pmem_map_file(l2p_path, 0,
0, 0, &dev->l2p_pmem_len, &is_pmem)) == NULL) {
SPDK_ERRLOG("Failed to mmap l2p_path\n");
return -1;
}
if (!is_pmem) {
SPDK_NOTICELOG("l2p_path mapped on non-pmem device\n");
}
if (dev->l2p_pmem_len < l2p_size) {
SPDK_ERRLOG("l2p_path file is too small\n");
return -1;
}
pmem_memset_persist(dev->l2p, FTL_ADDR_INVALID, l2p_size);
return 0;
#else /* SPDK_CONFIG_PMDK */
SPDK_ERRLOG("Libpmem not available, cannot use pmem l2p_path\n");
return -1;
#endif /* SPDK_CONFIG_PMDK */
}
static int
ftl_dev_l2p_alloc_dram(struct spdk_ftl_dev *dev, size_t l2p_size)
{
dev->l2p = malloc(l2p_size);
if (!dev->l2p) {
SPDK_ERRLOG("Failed to allocate l2p table\n");
return -1;
}
memset(dev->l2p, FTL_ADDR_INVALID, l2p_size);
return 0;
}
static int
ftl_dev_l2p_alloc(struct spdk_ftl_dev *dev)
{
size_t addr_size;
size_t addr_size = dev->addr_len >= 32 ? 8 : 4;
size_t l2p_size = dev->num_lbas * addr_size;
const char *l2p_path = dev->conf.l2p_path;
if (dev->num_lbas == 0) {
SPDK_DEBUGLOG(SPDK_LOG_FTL_INIT, "Invalid l2p table size\n");
SPDK_ERRLOG("Invalid l2p table size\n");
return -1;
}
if (dev->l2p) {
SPDK_DEBUGLOG(SPDK_LOG_FTL_INIT, "L2p table already allocated\n");
SPDK_ERRLOG("L2p table already allocated\n");
return -1;
}
addr_size = dev->addr_len >= 32 ? 8 : 4;
dev->l2p = malloc(dev->num_lbas * addr_size);
if (!dev->l2p) {
SPDK_DEBUGLOG(SPDK_LOG_FTL_INIT, "Failed to allocate l2p table\n");
return -1;
dev->l2p_pmem_len = 0;
if (l2p_path) {
return ftl_dev_l2p_alloc_pmem(dev, l2p_size, l2p_path);
} else {
return ftl_dev_l2p_alloc_dram(dev, l2p_size);
}
memset(dev->l2p, FTL_ADDR_INVALID, dev->num_lbas * addr_size);
return 0;
}
static void
@ -1383,7 +1430,14 @@ ftl_dev_free_sync(struct spdk_ftl_dev *dev)
free(dev->iov_buf);
free(dev->name);
free(dev->bands);
free(dev->l2p);
if (dev->l2p_pmem_len != 0) {
#ifdef SPDK_CONFIG_PMDK
pmem_unmap(dev->l2p, dev->l2p_pmem_len);
#endif /* SPDK_CONFIG_PMDK */
} else {
free(dev->l2p);
}
free((char *)dev->conf.l2p_path);
free(dev);
}
@ -1435,6 +1489,14 @@ spdk_ftl_dev_init(const struct spdk_ftl_dev_init_opts *_opts, spdk_ftl_init_fn c
goto fail_sync;
}
if (opts.conf->l2p_path) {
dev->conf.l2p_path = strdup(opts.conf->l2p_path);
if (!dev->conf.l2p_path) {
rc = -ENOMEM;
goto fail_sync;
}
}
/* In case of errors, we free all of the memory in ftl_dev_free_sync(), */
/* so we don't have to clean up in each of the init functions. */
if (ftl_check_conf(dev, opts.conf)) {