lib/ftl: ANM logic removal
ANM logic should be moved to ocssd bdev. This patch temporarily disables ANM handling by FTL library. New ANM handling mechanism will be introduced in future patches. Change-Id: I7d0261ee4e42496f60b82fbf6b39d9f84690024f Signed-off-by: Wojciech Malikowski <wojciech.malikowski@intel.com> Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/468784 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Broadcom SPDK FC-NVMe CI <spdk-ci.pdl@broadcom.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Mateusz Kozlowski <mateusz.kozlowski@intel.com> Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
This commit is contained in:
parent
1735a0acd3
commit
988759501d
@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
|
|||||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||||
|
|
||||||
C_SRCS = ftl_band.c ftl_core.c ftl_debug.c ftl_io.c ftl_rwb.c ftl_reloc.c \
|
C_SRCS = ftl_band.c ftl_core.c ftl_debug.c ftl_io.c ftl_rwb.c ftl_reloc.c \
|
||||||
ftl_anm.c ftl_restore.c ftl_init.c ftl_trace.c
|
ftl_restore.c ftl_init.c ftl_trace.c
|
||||||
|
|
||||||
LIBNAME = ftl
|
LIBNAME = ftl
|
||||||
|
|
||||||
|
@ -1,567 +0,0 @@
|
|||||||
/*-
|
|
||||||
* BSD LICENSE
|
|
||||||
*
|
|
||||||
* Copyright (c) Intel Corporation.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in
|
|
||||||
* the documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
* * Neither the name of Intel Corporation nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived
|
|
||||||
* from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "spdk/stdinc.h"
|
|
||||||
#include "spdk/nvme_spec.h"
|
|
||||||
#include "spdk/nvme_ocssd_spec.h"
|
|
||||||
#include "spdk/thread.h"
|
|
||||||
#include "spdk/ftl.h"
|
|
||||||
#include "ftl_anm.h"
|
|
||||||
#include "ftl_core.h"
|
|
||||||
#include "ftl_band.h"
|
|
||||||
#include "ftl_debug.h"
|
|
||||||
|
|
||||||
/* Number of log pages read in single get_log_page call */
|
|
||||||
#define FTL_ANM_LOG_ENTRIES 16
|
|
||||||
|
|
||||||
/* Structure aggregating ANM callback registered by ftl device */
|
|
||||||
struct ftl_anm_poller {
|
|
||||||
struct spdk_ftl_dev *dev;
|
|
||||||
|
|
||||||
ftl_anm_fn fn;
|
|
||||||
|
|
||||||
LIST_ENTRY(ftl_anm_poller) list_entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ftl_anm_ctrlr {
|
|
||||||
/* NVMe controller */
|
|
||||||
struct spdk_nvme_ctrlr *ctrlr;
|
|
||||||
|
|
||||||
/* NVMe namespace */
|
|
||||||
struct spdk_nvme_ns *ns;
|
|
||||||
|
|
||||||
/* Outstanding ANM event counter */
|
|
||||||
int anm_outstanding;
|
|
||||||
|
|
||||||
/* Indicates if get log page command has been submitted to controller */
|
|
||||||
int processing;
|
|
||||||
|
|
||||||
/* Notification counter */
|
|
||||||
uint64_t nc;
|
|
||||||
|
|
||||||
/* DMA allocated buffer for log pages */
|
|
||||||
struct spdk_ocssd_chunk_notification_entry *log;
|
|
||||||
|
|
||||||
/* Protects ctrlr against process_admin_completions from multiple threads */
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
|
|
||||||
/* List link */
|
|
||||||
LIST_ENTRY(ftl_anm_ctrlr) list_entry;
|
|
||||||
|
|
||||||
/* List of registered pollers */
|
|
||||||
LIST_HEAD(, ftl_anm_poller) pollers;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ftl_anm {
|
|
||||||
struct spdk_thread *thread;
|
|
||||||
struct spdk_poller *poller;
|
|
||||||
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
/* List of registered controllers */
|
|
||||||
LIST_HEAD(, ftl_anm_ctrlr) ctrlrs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ftl_anm_init_ctx {
|
|
||||||
spdk_ftl_fn cb;
|
|
||||||
void *cb_arg;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct ftl_anm g_anm = { .lock = PTHREAD_MUTEX_INITIALIZER };
|
|
||||||
|
|
||||||
static int
|
|
||||||
ftl_anm_log_range(struct spdk_ocssd_chunk_notification_entry *log)
|
|
||||||
{
|
|
||||||
if (log->mask.lblk) {
|
|
||||||
return FTL_ANM_RANGE_LBK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log->mask.chunk) {
|
|
||||||
return FTL_ANM_RANGE_CHK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log->mask.pu) {
|
|
||||||
return FTL_ANM_RANGE_PU;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(0);
|
|
||||||
return FTL_ANM_RANGE_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct ftl_anm_event *
|
|
||||||
ftl_anm_event_alloc(struct spdk_ftl_dev *dev, struct ftl_addr addr,
|
|
||||||
enum ftl_anm_range range, size_t num_lbks)
|
|
||||||
{
|
|
||||||
struct ftl_anm_event *event;
|
|
||||||
|
|
||||||
event = calloc(1, sizeof(*event));
|
|
||||||
if (!event) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
event->dev = dev;
|
|
||||||
event->addr = addr;
|
|
||||||
|
|
||||||
switch (range) {
|
|
||||||
case FTL_ANM_RANGE_LBK:
|
|
||||||
event->num_lbks = num_lbks;
|
|
||||||
break;
|
|
||||||
case FTL_ANM_RANGE_CHK:
|
|
||||||
case FTL_ANM_RANGE_PU:
|
|
||||||
event->num_lbks = ftl_dev_lbks_in_zone(dev);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ftl_anm_process_log(struct ftl_anm_poller *poller,
|
|
||||||
struct spdk_ocssd_chunk_notification_entry *log)
|
|
||||||
{
|
|
||||||
struct ftl_anm_event *event;
|
|
||||||
struct ftl_addr addr = ftl_addr_addr_unpack(poller->dev, log->lba);
|
|
||||||
struct spdk_ftl_dev *dev = poller->dev;
|
|
||||||
enum ftl_anm_range range = ftl_anm_log_range(log);
|
|
||||||
int i, num_bands = 1;
|
|
||||||
|
|
||||||
num_bands = range != FTL_ANM_RANGE_PU ? 1 : ftl_dev_num_bands(dev);
|
|
||||||
|
|
||||||
for (i = 0; i < num_bands; ++i) {
|
|
||||||
struct ftl_zone *zone = ftl_band_zone_from_addr(&dev->bands[i], addr);
|
|
||||||
|
|
||||||
if (zone->state == SPDK_BDEV_ZONE_STATE_OFFLINE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
event = ftl_anm_event_alloc(dev, addr, range, log->nlb);
|
|
||||||
if (!event) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
poller->fn(event);
|
|
||||||
addr.zone_id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ftl_anm_in_poller_range(struct ftl_anm_poller *poller,
|
|
||||||
struct spdk_ocssd_chunk_notification_entry *log)
|
|
||||||
{
|
|
||||||
struct spdk_ftl_dev *dev = poller->dev;
|
|
||||||
struct ftl_addr addr = ftl_addr_addr_unpack(dev, log->lba);
|
|
||||||
char buf[128];
|
|
||||||
|
|
||||||
if (addr.zone_id >= ftl_dev_num_bands(dev)) {
|
|
||||||
SPDK_ERRLOG("ANM log contains invalid @addr: %s\n",
|
|
||||||
ftl_addr2str(addr, buf, sizeof(buf)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ftl_anm_log_valid(struct ftl_anm_ctrlr *ctrlr,
|
|
||||||
struct spdk_ocssd_chunk_notification_entry *log)
|
|
||||||
{
|
|
||||||
/* Initialize ctrlr->nc during the first log page read */
|
|
||||||
if (!ctrlr->nc && log->nc) {
|
|
||||||
ctrlr->nc = log->nc - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log->nc > ctrlr->nc) {
|
|
||||||
ctrlr->nc = log->nc;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ftl_anm_log_page_cb(void *ctx, const struct spdk_nvme_cpl *cpl)
|
|
||||||
{
|
|
||||||
struct ftl_anm_ctrlr *ctrlr = ctx;
|
|
||||||
struct ftl_anm_poller *poller;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&ctrlr->lock);
|
|
||||||
|
|
||||||
if (spdk_nvme_cpl_is_error(cpl)) {
|
|
||||||
SPDK_ERRLOG("Unexpected status code: [%d], status code type: [%d]\n",
|
|
||||||
cpl->status.sc, cpl->status.sct);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < FTL_ANM_LOG_ENTRIES; ++i) {
|
|
||||||
if (!ftl_anm_log_valid(ctrlr, &ctrlr->log[i])) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
LIST_FOREACH(poller, &ctrlr->pollers, list_entry) {
|
|
||||||
struct spdk_ocssd_chunk_notification_entry *log = &ctrlr->log[i];
|
|
||||||
|
|
||||||
if (!ftl_anm_in_poller_range(poller, log)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ftl_anm_process_log(poller, log)) {
|
|
||||||
SPDK_ERRLOG("Failed to process ANM log by dev: %p\n", poller->dev);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We increment anm_outstanding counter in case there are more logs in controller */
|
|
||||||
/* than we get in single log page call */
|
|
||||||
ctrlr->anm_outstanding++;
|
|
||||||
out:
|
|
||||||
ctrlr->processing = 0;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&ctrlr->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ftl_anm_aer_cb(void *ctx, const struct spdk_nvme_cpl *cpl)
|
|
||||||
{
|
|
||||||
union spdk_nvme_async_event_completion event = { .raw = cpl->cdw0 };
|
|
||||||
struct ftl_anm_ctrlr *ctrlr = ctx;
|
|
||||||
|
|
||||||
if (spdk_nvme_cpl_is_error(cpl)) {
|
|
||||||
SPDK_ERRLOG("Unexpected status code: [%d], status code type: [%d]\n",
|
|
||||||
cpl->status.sc, cpl->status.sct);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&ctrlr->lock);
|
|
||||||
|
|
||||||
if (event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_VENDOR &&
|
|
||||||
event.bits.log_page_identifier == SPDK_OCSSD_LOG_CHUNK_NOTIFICATION) {
|
|
||||||
ctrlr->anm_outstanding++;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&ctrlr->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ftl_anm_get_log_page(struct ftl_anm_ctrlr *ctrlr)
|
|
||||||
{
|
|
||||||
uint32_t nsid = spdk_nvme_ns_get_id(ctrlr->ns);
|
|
||||||
|
|
||||||
ctrlr->anm_outstanding = 0;
|
|
||||||
|
|
||||||
if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr->ctrlr, SPDK_OCSSD_LOG_CHUNK_NOTIFICATION, nsid,
|
|
||||||
ctrlr->log, sizeof(*ctrlr->log) * FTL_ANM_LOG_ENTRIES, 0,
|
|
||||||
ftl_anm_log_page_cb, (void *)ctrlr)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrlr->processing = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
ftl_anm_poller_cb(void *ctx)
|
|
||||||
{
|
|
||||||
struct ftl_anm *anm = ctx;
|
|
||||||
struct ftl_anm_ctrlr *ctrlr;
|
|
||||||
int rc = 0, num_processed = 0;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&anm->lock);
|
|
||||||
LIST_FOREACH(ctrlr, &anm->ctrlrs, list_entry) {
|
|
||||||
rc = spdk_nvme_ctrlr_process_admin_completions(ctrlr->ctrlr);
|
|
||||||
if (rc < 0) {
|
|
||||||
SPDK_ERRLOG("Processing admin completions failed\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
num_processed += rc;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&ctrlr->lock);
|
|
||||||
if (ctrlr->anm_outstanding && !ctrlr->processing) {
|
|
||||||
if (ftl_anm_get_log_page(ctrlr)) {
|
|
||||||
SPDK_ERRLOG("Failed to get log page from controller %p",
|
|
||||||
ctrlr->ctrlr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&ctrlr->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&anm->lock);
|
|
||||||
return num_processed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct ftl_anm_poller *
|
|
||||||
ftl_anm_alloc_poller(struct spdk_ftl_dev *dev, ftl_anm_fn fn)
|
|
||||||
{
|
|
||||||
struct ftl_anm_poller *poller;
|
|
||||||
|
|
||||||
poller = calloc(1, sizeof(*poller));
|
|
||||||
if (!poller) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
poller->fn = fn;
|
|
||||||
poller->dev = dev;
|
|
||||||
|
|
||||||
return poller;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ftl_anm_ctrlr_free(struct ftl_anm_ctrlr *ctrlr)
|
|
||||||
{
|
|
||||||
if (!ctrlr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unregister ctrlr from aer events */
|
|
||||||
spdk_nvme_ctrlr_register_aer_callback(ctrlr->ctrlr, NULL, NULL);
|
|
||||||
|
|
||||||
pthread_mutex_destroy(&ctrlr->lock);
|
|
||||||
spdk_dma_free(ctrlr->log);
|
|
||||||
free(ctrlr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct ftl_anm_ctrlr *
|
|
||||||
ftl_anm_ctrlr_alloc(struct spdk_ftl_dev *dev)
|
|
||||||
{
|
|
||||||
struct ftl_anm_ctrlr *ctrlr;
|
|
||||||
|
|
||||||
ctrlr = calloc(1, sizeof(*ctrlr));
|
|
||||||
if (!ctrlr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrlr->log = spdk_dma_zmalloc(sizeof(*ctrlr->log) * FTL_ANM_LOG_ENTRIES,
|
|
||||||
4096, NULL);
|
|
||||||
if (!ctrlr->log) {
|
|
||||||
goto free_ctrlr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pthread_mutex_init(&ctrlr->lock, NULL)) {
|
|
||||||
goto free_log;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the outstanding counter to force log page retrieval */
|
|
||||||
/* to consume events already present on the controller */
|
|
||||||
ctrlr->anm_outstanding = 1;
|
|
||||||
ctrlr->ctrlr = dev->ctrlr;
|
|
||||||
ctrlr->ns = dev->ns;
|
|
||||||
LIST_INIT(&ctrlr->pollers);
|
|
||||||
|
|
||||||
spdk_nvme_ctrlr_register_aer_callback(ctrlr->ctrlr, ftl_anm_aer_cb, ctrlr);
|
|
||||||
return ctrlr;
|
|
||||||
|
|
||||||
free_log:
|
|
||||||
free(ctrlr->log);
|
|
||||||
free_ctrlr:
|
|
||||||
free(ctrlr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct ftl_anm_ctrlr *
|
|
||||||
ftl_anm_find_ctrlr(struct ftl_anm *anm, struct spdk_nvme_ctrlr *ctrlr)
|
|
||||||
{
|
|
||||||
struct ftl_anm_ctrlr *anm_ctrlr;
|
|
||||||
|
|
||||||
LIST_FOREACH(anm_ctrlr, &anm->ctrlrs, list_entry) {
|
|
||||||
if (ctrlr == anm_ctrlr->ctrlr) {
|
|
||||||
return anm_ctrlr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ftl_anm_event_complete(struct ftl_anm_event *event)
|
|
||||||
{
|
|
||||||
free(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ftl_anm_register_device(struct spdk_ftl_dev *dev, ftl_anm_fn fn)
|
|
||||||
{
|
|
||||||
struct ftl_anm_poller *poller;
|
|
||||||
struct ftl_anm_ctrlr *ctrlr;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&g_anm.lock);
|
|
||||||
|
|
||||||
ctrlr = ftl_anm_find_ctrlr(&g_anm, dev->ctrlr);
|
|
||||||
if (!ctrlr) {
|
|
||||||
ctrlr = ftl_anm_ctrlr_alloc(dev);
|
|
||||||
if (!ctrlr) {
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
LIST_INSERT_HEAD(&g_anm.ctrlrs, ctrlr, list_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
poller = ftl_anm_alloc_poller(dev, fn);
|
|
||||||
if (!poller) {
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&ctrlr->lock);
|
|
||||||
LIST_INSERT_HEAD(&ctrlr->pollers, poller, list_entry);
|
|
||||||
pthread_mutex_unlock(&ctrlr->lock);
|
|
||||||
out:
|
|
||||||
pthread_mutex_unlock(&g_anm.lock);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ftl_anm_unregister_device_cb(void *ctx)
|
|
||||||
{
|
|
||||||
struct ftl_anm_init_ctx *init_ctx = ctx;
|
|
||||||
struct spdk_ftl_dev *dev = init_ctx->cb_arg;
|
|
||||||
struct ftl_anm_ctrlr *ctrlr;
|
|
||||||
struct ftl_anm_poller *poller, *temp_poller;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&g_anm.lock);
|
|
||||||
ctrlr = ftl_anm_find_ctrlr(&g_anm, dev->ctrlr);
|
|
||||||
assert(ctrlr != NULL);
|
|
||||||
pthread_mutex_lock(&ctrlr->lock);
|
|
||||||
|
|
||||||
LIST_FOREACH_SAFE(poller, &ctrlr->pollers, list_entry, temp_poller) {
|
|
||||||
if (poller->dev == dev) {
|
|
||||||
LIST_REMOVE(poller, list_entry);
|
|
||||||
free(poller);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&ctrlr->lock);
|
|
||||||
|
|
||||||
/* Release the controller if there are no more pollers */
|
|
||||||
if (LIST_EMPTY(&ctrlr->pollers)) {
|
|
||||||
if (!ctrlr->processing) {
|
|
||||||
LIST_REMOVE(ctrlr, list_entry);
|
|
||||||
ftl_anm_ctrlr_free(ctrlr);
|
|
||||||
} else {
|
|
||||||
pthread_mutex_unlock(&g_anm.lock);
|
|
||||||
spdk_thread_send_msg(g_anm.thread, ftl_anm_unregister_device_cb, ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_anm.lock);
|
|
||||||
|
|
||||||
init_ctx->cb(init_ctx->cb_arg, 0);
|
|
||||||
free(init_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ftl_anm_unregister_device(struct spdk_ftl_dev *dev, spdk_ftl_fn cb)
|
|
||||||
{
|
|
||||||
struct ftl_anm_init_ctx *ctx;
|
|
||||||
|
|
||||||
ctx = malloc(sizeof(*ctx));
|
|
||||||
if (!ctx) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->cb = cb;
|
|
||||||
ctx->cb_arg = dev;
|
|
||||||
|
|
||||||
spdk_thread_send_msg(g_anm.thread, ftl_anm_unregister_device_cb, ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ftl_anm_register_poller_cb(void *ctx)
|
|
||||||
{
|
|
||||||
struct ftl_anm_init_ctx *init_ctx = ctx;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
/* TODO: adjust polling timeout */
|
|
||||||
g_anm.poller = spdk_poller_register(ftl_anm_poller_cb, &g_anm, 1000);
|
|
||||||
if (!g_anm.poller) {
|
|
||||||
SPDK_ERRLOG("Unable to register ANM poller\n");
|
|
||||||
rc = -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_ctx->cb(init_ctx->cb_arg, rc);
|
|
||||||
free(init_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ftl_anm_init(struct spdk_thread *thread, spdk_ftl_fn cb, void *cb_arg)
|
|
||||||
{
|
|
||||||
struct ftl_anm_init_ctx *ctx;
|
|
||||||
|
|
||||||
ctx = malloc(sizeof(*ctx));
|
|
||||||
if (!ctx) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_anm.thread = thread;
|
|
||||||
ctx->cb = cb;
|
|
||||||
ctx->cb_arg = cb_arg;
|
|
||||||
|
|
||||||
spdk_thread_send_msg(thread, ftl_anm_register_poller_cb, ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ftl_anm_unregister_poller_cb(void *ctx)
|
|
||||||
{
|
|
||||||
struct ftl_anm_init_ctx *init_ctx = ctx;
|
|
||||||
|
|
||||||
spdk_poller_unregister(&g_anm.poller);
|
|
||||||
|
|
||||||
init_ctx->cb(init_ctx->cb_arg, 0);
|
|
||||||
free(init_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ftl_anm_free(spdk_ftl_fn cb, void *cb_arg)
|
|
||||||
{
|
|
||||||
struct ftl_anm_init_ctx *ctx;
|
|
||||||
|
|
||||||
ctx = malloc(sizeof(*ctx));
|
|
||||||
if (!ctx) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->cb = cb;
|
|
||||||
ctx->cb_arg = cb_arg;
|
|
||||||
|
|
||||||
spdk_thread_send_msg(g_anm.thread, ftl_anm_unregister_poller_cb, ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/*-
|
|
||||||
* BSD LICENSE
|
|
||||||
*
|
|
||||||
* Copyright (c) Intel Corporation.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in
|
|
||||||
* the documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
* * Neither the name of Intel Corporation nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived
|
|
||||||
* from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FTL_ANM_H
|
|
||||||
#define FTL_ANM_H
|
|
||||||
|
|
||||||
#include "spdk/thread.h"
|
|
||||||
#include "ftl_addr.h"
|
|
||||||
|
|
||||||
struct ftl_nvme_ctrlr;
|
|
||||||
struct ftl_anm_event;
|
|
||||||
struct spdk_ftl_dev;
|
|
||||||
|
|
||||||
typedef void (*ftl_anm_fn)(struct ftl_anm_event *event);
|
|
||||||
|
|
||||||
enum ftl_anm_range {
|
|
||||||
FTL_ANM_RANGE_LBK,
|
|
||||||
FTL_ANM_RANGE_CHK,
|
|
||||||
FTL_ANM_RANGE_PU,
|
|
||||||
FTL_ANM_RANGE_MAX,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ftl_anm_event {
|
|
||||||
/* Owner device */
|
|
||||||
struct spdk_ftl_dev *dev;
|
|
||||||
|
|
||||||
/* First block address */
|
|
||||||
struct ftl_addr addr;
|
|
||||||
|
|
||||||
/* Number of logical blocks */
|
|
||||||
size_t num_lbks;
|
|
||||||
};
|
|
||||||
|
|
||||||
int ftl_anm_init(struct spdk_thread *thread, spdk_ftl_fn cb, void *cb_arg);
|
|
||||||
int ftl_anm_free(spdk_ftl_fn cb, void *cb_arg);
|
|
||||||
int ftl_anm_register_device(struct spdk_ftl_dev *dev, ftl_anm_fn fn);
|
|
||||||
int ftl_anm_unregister_device(struct spdk_ftl_dev *dev, spdk_ftl_fn cb);
|
|
||||||
void ftl_anm_event_complete(struct ftl_anm_event *event);
|
|
||||||
|
|
||||||
#endif /* FTL_ANM_H */
|
|
@ -44,7 +44,6 @@
|
|||||||
#include "ftl_core.h"
|
#include "ftl_core.h"
|
||||||
#include "ftl_band.h"
|
#include "ftl_band.h"
|
||||||
#include "ftl_io.h"
|
#include "ftl_io.h"
|
||||||
#include "ftl_anm.h"
|
|
||||||
#include "ftl_rwb.h"
|
#include "ftl_rwb.h"
|
||||||
#include "ftl_debug.h"
|
#include "ftl_debug.h"
|
||||||
#include "ftl_reloc.h"
|
#include "ftl_reloc.h"
|
||||||
@ -2116,37 +2115,6 @@ spdk_ftl_flush(struct spdk_ftl_dev *dev, spdk_ftl_fn cb_fn, void *cb_arg)
|
|||||||
return ftl_flush_rwb(dev, cb_fn, cb_arg);
|
return ftl_flush_rwb(dev, cb_fn, cb_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
_ftl_process_anm_event(void *ctx)
|
|
||||||
{
|
|
||||||
ftl_process_anm_event((struct ftl_anm_event *)ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ftl_process_anm_event(struct ftl_anm_event *event)
|
|
||||||
{
|
|
||||||
struct spdk_ftl_dev *dev = event->dev;
|
|
||||||
struct ftl_band *band;
|
|
||||||
size_t lbkoff;
|
|
||||||
|
|
||||||
/* Drop any ANM requests until the device is initialized */
|
|
||||||
if (!dev->initialized) {
|
|
||||||
ftl_anm_event_complete(event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ftl_check_core_thread(dev)) {
|
|
||||||
spdk_thread_send_msg(ftl_get_core_thread(dev), _ftl_process_anm_event, event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
band = ftl_band_from_addr(dev, event->addr);
|
|
||||||
lbkoff = ftl_band_lbkoff_from_addr(band, event->addr);
|
|
||||||
|
|
||||||
ftl_reloc_add(dev->reloc, band, lbkoff, event->num_lbks, 0, false);
|
|
||||||
ftl_anm_event_complete(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ftl_addr_is_written(struct ftl_band *band, struct ftl_addr addr)
|
ftl_addr_is_written(struct ftl_band *band, struct ftl_addr addr)
|
||||||
{
|
{
|
||||||
|
@ -43,7 +43,6 @@
|
|||||||
#include "spdk/bdev_zone.h"
|
#include "spdk/bdev_zone.h"
|
||||||
|
|
||||||
#include "ftl_core.h"
|
#include "ftl_core.h"
|
||||||
#include "ftl_anm.h"
|
|
||||||
#include "ftl_io.h"
|
#include "ftl_io.h"
|
||||||
#include "ftl_reloc.h"
|
#include "ftl_reloc.h"
|
||||||
#include "ftl_rwb.h"
|
#include "ftl_rwb.h"
|
||||||
@ -662,10 +661,6 @@ _ftl_dev_init_thread(void *ctx)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spdk_get_thread() == ftl_get_core_thread(dev)) {
|
|
||||||
ftl_anm_register_device(dev, ftl_process_anm_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
thread->ioch = spdk_get_io_channel(dev);
|
thread->ioch = spdk_get_io_channel(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1233,39 +1228,19 @@ ftl_nv_cache_header_fini_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb
|
|||||||
spdk_thread_send_msg(dev->fini_ctx.thread, ftl_halt_complete_cb, dev);
|
spdk_thread_send_msg(dev->fini_ctx.thread, ftl_halt_complete_cb, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
_ftl_anm_unregister_cb(void *ctx)
|
|
||||||
{
|
|
||||||
struct spdk_ftl_dev *dev = ctx;
|
|
||||||
|
|
||||||
if (ftl_dev_has_nv_cache(dev)) {
|
|
||||||
ftl_nv_cache_write_header(&dev->nv_cache, true, ftl_nv_cache_header_fini_cb, dev);
|
|
||||||
} else {
|
|
||||||
dev->halt_complete_status = 0;
|
|
||||||
spdk_thread_send_msg(dev->fini_ctx.thread, ftl_halt_complete_cb, dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ftl_anm_unregister_cb(void *ctx, int status)
|
|
||||||
{
|
|
||||||
struct spdk_ftl_dev *dev = ctx;
|
|
||||||
|
|
||||||
spdk_thread_send_msg(ftl_get_core_thread(dev), _ftl_anm_unregister_cb, dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ftl_halt_poller(void *ctx)
|
ftl_halt_poller(void *ctx)
|
||||||
{
|
{
|
||||||
struct spdk_ftl_dev *dev = ctx;
|
struct spdk_ftl_dev *dev = ctx;
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!dev->core_thread.poller && !dev->read_thread.poller) {
|
if (!dev->core_thread.poller && !dev->read_thread.poller) {
|
||||||
rc = ftl_anm_unregister_device(dev, ftl_anm_unregister_cb);
|
spdk_poller_unregister(&dev->fini_ctx.poller);
|
||||||
if (spdk_unlikely(rc != 0)) {
|
|
||||||
SPDK_ERRLOG("Failed to unregister ANM device, will retry later\n");
|
if (ftl_dev_has_nv_cache(dev)) {
|
||||||
|
ftl_nv_cache_write_header(&dev->nv_cache, true, ftl_nv_cache_header_fini_cb, dev);
|
||||||
} else {
|
} else {
|
||||||
spdk_poller_unregister(&dev->fini_ctx.poller);
|
dev->halt_complete_status = 0;
|
||||||
|
spdk_thread_send_msg(dev->fini_ctx.thread, ftl_halt_complete_cb, dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1311,13 +1286,15 @@ spdk_ftl_dev_free(struct spdk_ftl_dev *dev, spdk_ftl_init_fn cb_fn, void *cb_arg
|
|||||||
int
|
int
|
||||||
spdk_ftl_module_init(const struct ftl_module_init_opts *opts, spdk_ftl_fn cb, void *cb_arg)
|
spdk_ftl_module_init(const struct ftl_module_init_opts *opts, spdk_ftl_fn cb, void *cb_arg)
|
||||||
{
|
{
|
||||||
return ftl_anm_init(opts->anm_thread, cb, cb_arg);
|
cb(cb_arg, 0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
spdk_ftl_module_fini(spdk_ftl_fn cb, void *cb_arg)
|
spdk_ftl_module_fini(spdk_ftl_fn cb, void *cb_arg)
|
||||||
{
|
{
|
||||||
return ftl_anm_free(cb, cb_arg);
|
cb(cb_arg, 0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDK_LOG_REGISTER_COMPONENT("ftl_init", SPDK_LOG_FTL_INIT)
|
SPDK_LOG_REGISTER_COMPONENT("ftl_init", SPDK_LOG_FTL_INIT)
|
||||||
|
Loading…
Reference in New Issue
Block a user