summaryrefslogtreecommitdiffstats
path: root/src/spdk/module/bdev/ocf/ctx.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/spdk/module/bdev/ocf/ctx.c
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/module/bdev/ocf/ctx.c')
-rw-r--r--src/spdk/module/bdev/ocf/ctx.c565
1 files changed, 565 insertions, 0 deletions
diff --git a/src/spdk/module/bdev/ocf/ctx.c b/src/spdk/module/bdev/ocf/ctx.c
new file mode 100644
index 000000000..5bf4c8fee
--- /dev/null
+++ b/src/spdk/module/bdev/ocf/ctx.c
@@ -0,0 +1,565 @@
+/*-
+ * 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 <ocf/ocf.h>
+#include <execinfo.h>
+
+#include "spdk/env.h"
+#include "spdk_internal/log.h"
+
+#include "ctx.h"
+#include "ocf_env.h"
+#include "data.h"
+
+ocf_ctx_t vbdev_ocf_ctx;
+
+static ctx_data_t *
+vbdev_ocf_ctx_data_alloc(uint32_t pages)
+{
+ struct bdev_ocf_data *data;
+ void *buf;
+ uint32_t sz;
+
+ data = vbdev_ocf_data_alloc(1);
+
+ sz = pages * PAGE_SIZE;
+ buf = spdk_malloc(sz, PAGE_SIZE, NULL,
+ SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ vbdev_ocf_iovs_add(data, buf, sz);
+
+ data->size = sz;
+
+ return data;
+}
+
+static void
+vbdev_ocf_ctx_data_free(ctx_data_t *ctx_data)
+{
+ struct bdev_ocf_data *data = ctx_data;
+ int i;
+
+ if (!data) {
+ return;
+ }
+
+ for (i = 0; i < data->iovcnt; i++) {
+ spdk_free(data->iovs[i].iov_base);
+ }
+
+ vbdev_ocf_data_free(data);
+}
+
+static int
+vbdev_ocf_ctx_data_mlock(ctx_data_t *ctx_data)
+{
+ /* TODO [mlock]: add mlock option */
+ return 0;
+}
+
+static void
+vbdev_ocf_ctx_data_munlock(ctx_data_t *ctx_data)
+{
+ /* TODO [mlock]: add mlock option */
+}
+
+static size_t
+iovec_flatten(struct iovec *iov, size_t iovcnt, void *buf, size_t size, size_t offset)
+{
+ size_t i, len, done = 0;
+
+ for (i = 0; i < iovcnt; i++) {
+ if (offset >= iov[i].iov_len) {
+ offset -= iov[i].iov_len;
+ continue;
+ }
+
+ if (iov[i].iov_base == NULL) {
+ continue;
+ }
+
+ if (done >= size) {
+ break;
+ }
+
+ len = MIN(size - done, iov[i].iov_len - offset);
+ memcpy(buf, iov[i].iov_base + offset, len);
+ buf += len;
+ done += len;
+ offset = 0;
+ }
+
+ return done;
+}
+
+static uint32_t
+vbdev_ocf_ctx_data_rd(void *dst, ctx_data_t *src, uint32_t size)
+{
+ struct bdev_ocf_data *s = src;
+ uint32_t size_local;
+
+ size_local = iovec_flatten(s->iovs, s->iovcnt, dst, size, s->seek);
+ s->seek += size_local;
+
+ return size_local;
+}
+
+static size_t
+buf_to_iovec(const void *buf, size_t size, struct iovec *iov, size_t iovcnt, size_t offset)
+{
+ size_t i, len, done = 0;
+
+ for (i = 0; i < iovcnt; i++) {
+ if (offset >= iov[i].iov_len) {
+ offset -= iov[i].iov_len;
+ continue;
+ }
+
+ if (iov[i].iov_base == NULL) {
+ continue;
+ }
+
+ if (done >= size) {
+ break;
+ }
+
+ len = MIN(size - done, iov[i].iov_len - offset);
+ memcpy(iov[i].iov_base + offset, buf, len);
+ buf += len;
+ done += len;
+ offset = 0;
+ }
+
+ return done;
+}
+
+static uint32_t
+vbdev_ocf_ctx_data_wr(ctx_data_t *dst, const void *src, uint32_t size)
+{
+ struct bdev_ocf_data *d = dst;
+ uint32_t size_local;
+
+ size_local = buf_to_iovec(src, size, d->iovs, d->iovcnt, d->seek);
+ d->seek += size_local;
+
+ return size_local;
+}
+
+static size_t
+iovset(struct iovec *iov, size_t iovcnt, int byte, size_t size, size_t offset)
+{
+ size_t i, len, done = 0;
+
+ for (i = 0; i < iovcnt; i++) {
+ if (offset >= iov[i].iov_len) {
+ offset -= iov[i].iov_len;
+ continue;
+ }
+
+ if (iov[i].iov_base == NULL) {
+ continue;
+ }
+
+ if (done >= size) {
+ break;
+ }
+
+ len = MIN(size - done, iov[i].iov_len - offset);
+ memset(iov[i].iov_base + offset, byte, len);
+ done += len;
+ offset = 0;
+ }
+
+ return done;
+}
+
+static uint32_t
+vbdev_ocf_ctx_data_zero(ctx_data_t *dst, uint32_t size)
+{
+ struct bdev_ocf_data *d = dst;
+ uint32_t size_local;
+
+ size_local = iovset(d->iovs, d->iovcnt, 0, size, d->seek);
+ d->seek += size_local;
+
+ return size_local;
+}
+
+static uint32_t
+vbdev_ocf_ctx_data_seek(ctx_data_t *dst, ctx_data_seek_t seek, uint32_t offset)
+{
+ struct bdev_ocf_data *d = dst;
+ uint32_t off = 0;
+
+ switch (seek) {
+ case ctx_data_seek_begin:
+ off = MIN(offset, d->size);
+ d->seek = off;
+ break;
+ case ctx_data_seek_current:
+ off = MIN(offset, d->size - d->seek);
+ d->seek += off;
+ break;
+ }
+
+ return off;
+}
+
+static uint64_t
+vbdev_ocf_ctx_data_cpy(ctx_data_t *dst, ctx_data_t *src, uint64_t to,
+ uint64_t from, uint64_t bytes)
+{
+ struct bdev_ocf_data *s = src;
+ struct bdev_ocf_data *d = dst;
+ uint32_t it_iov = 0;
+ uint32_t it_off = 0;
+ uint32_t n, sz;
+
+ bytes = MIN(bytes, s->size - from);
+ bytes = MIN(bytes, d->size - to);
+ sz = bytes;
+
+ while (from || bytes) {
+ if (s->iovs[it_iov].iov_len == it_off) {
+ it_iov++;
+ it_off = 0;
+ continue;
+ }
+
+ if (from) {
+ n = MIN(from, s->iovs[it_iov].iov_len);
+ from -= n;
+ } else {
+ n = MIN(bytes, s->iovs[it_iov].iov_len);
+ buf_to_iovec(s->iovs[it_iov].iov_base + it_off, n, d->iovs, d->iovcnt, to);
+ bytes -= n;
+ to += n;
+ }
+
+ it_off += n;
+ }
+
+ return sz;
+}
+
+static void
+vbdev_ocf_ctx_data_secure_erase(ctx_data_t *ctx_data)
+{
+ struct bdev_ocf_data *data = ctx_data;
+ struct iovec *iovs = data->iovs;
+ int i;
+
+ for (i = 0; i < data->iovcnt; i++) {
+ if (env_memset(iovs[i].iov_base, iovs[i].iov_len, 0)) {
+ assert(false);
+ }
+ }
+}
+
+int vbdev_ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops)
+{
+ int rc;
+ struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
+
+ pthread_mutex_lock(&ctx->lock);
+ rc = ocf_queue_create(cache, queue, ops);
+ pthread_mutex_unlock(&ctx->lock);
+ return rc;
+}
+
+void vbdev_ocf_queue_put(ocf_queue_t queue)
+{
+ ocf_cache_t cache = ocf_queue_get_cache(queue);
+ struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
+
+ pthread_mutex_lock(&ctx->lock);
+ ocf_queue_put(queue);
+ pthread_mutex_unlock(&ctx->lock);
+}
+
+void vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx)
+{
+ if (env_atomic_dec_return(&ctx->refcnt) == 0) {
+ pthread_mutex_destroy(&ctx->lock);
+ free(ctx);
+ }
+}
+
+void vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx)
+{
+ env_atomic_inc(&ctx->refcnt);
+}
+
+struct cleaner_priv {
+ struct spdk_poller *poller;
+ ocf_queue_t queue;
+ uint64_t next_run;
+};
+
+static int
+cleaner_poll(void *arg)
+{
+ ocf_cleaner_t cleaner = arg;
+ struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
+ uint32_t iono = ocf_queue_pending_io(priv->queue);
+ int i, max = spdk_min(32, iono);
+
+ for (i = 0; i < max; i++) {
+ ocf_queue_run_single(priv->queue);
+ }
+
+ if (spdk_get_ticks() >= priv->next_run) {
+ ocf_cleaner_run(cleaner, priv->queue);
+ return SPDK_POLLER_BUSY;
+ }
+
+ if (iono > 0) {
+ return SPDK_POLLER_BUSY;
+ } else {
+ return SPDK_POLLER_IDLE;
+ }
+}
+
+static void
+cleaner_cmpl(ocf_cleaner_t c, uint32_t interval)
+{
+ struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
+
+ priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000);
+}
+
+static void
+cleaner_queue_kick(ocf_queue_t q)
+{
+}
+
+static void
+cleaner_queue_stop(ocf_queue_t q)
+{
+ struct cleaner_priv *cpriv = ocf_queue_get_priv(q);
+
+ if (cpriv) {
+ spdk_poller_unregister(&cpriv->poller);
+ free(cpriv);
+ }
+}
+
+const struct ocf_queue_ops cleaner_queue_ops = {
+ .kick_sync = cleaner_queue_kick,
+ .kick = cleaner_queue_kick,
+ .stop = cleaner_queue_stop,
+};
+
+static int
+vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c)
+{
+ int rc;
+ struct cleaner_priv *priv = calloc(1, sizeof(*priv));
+ ocf_cache_t cache = ocf_cleaner_get_cache(c);
+ struct vbdev_ocf_cache_ctx *cctx = ocf_cache_get_priv(cache);
+
+ if (priv == NULL) {
+ return -ENOMEM;
+ }
+
+ rc = vbdev_ocf_queue_create(cache, &priv->queue, &cleaner_queue_ops);
+ if (rc) {
+ free(priv);
+ return rc;
+ }
+
+ ocf_queue_set_priv(priv->queue, priv);
+
+ cctx->cleaner_queue = priv->queue;
+
+ ocf_cleaner_set_cmpl(c, cleaner_cmpl);
+ ocf_cleaner_set_priv(c, priv);
+
+ return 0;
+}
+
+static void
+vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c)
+{
+ struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
+
+ vbdev_ocf_queue_put(priv->queue);
+}
+
+static void
+vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner)
+{
+ struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
+
+ if (priv->poller) {
+ return;
+ }
+
+ /* We start cleaner poller at the same thread where cache was created
+ * TODO: allow user to specify core at which cleaner should run */
+ priv->poller = SPDK_POLLER_REGISTER(cleaner_poll, cleaner, 0);
+}
+
+static void
+vbdev_ocf_md_kick(void *ctx)
+{
+ ocf_metadata_updater_t mu = ctx;
+ ocf_cache_t cache = ocf_metadata_updater_get_cache(mu);
+
+ if (ocf_cache_is_running(cache)) {
+ ocf_metadata_updater_run(mu);
+ }
+}
+
+static int
+vbdev_ocf_volume_updater_init(ocf_metadata_updater_t mu)
+{
+ struct spdk_thread *md_thread = spdk_get_thread();
+
+ ocf_metadata_updater_set_priv(mu, md_thread);
+
+ return 0;
+}
+
+static void
+vbdev_ocf_volume_updater_stop(ocf_metadata_updater_t mu)
+{
+
+}
+
+static void
+vbdev_ocf_volume_updater_kick(ocf_metadata_updater_t mu)
+{
+ struct spdk_thread *md_thread = ocf_metadata_updater_get_priv(mu);
+
+ /* We need to send message to updater thread because
+ * kick can happen from any thread */
+ spdk_thread_send_msg(md_thread, vbdev_ocf_md_kick, mu);
+}
+
+/* This function is main way by which OCF communicates with user
+ * We don't want to use SPDK_LOG here because debugging information that is
+ * associated with every print message is not helpful in callback that only prints info
+ * while the real source is somewhere in OCF code */
+static int
+vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl,
+ const char *fmt, va_list args)
+{
+ int spdk_lvl;
+
+ switch (lvl) {
+ case log_emerg:
+ case log_alert:
+ case log_crit:
+ case log_err:
+ spdk_lvl = SPDK_LOG_ERROR;
+ break;
+
+ case log_warn:
+ spdk_lvl = SPDK_LOG_WARN;
+ break;
+
+ case log_notice:
+ spdk_lvl = SPDK_LOG_NOTICE;
+ break;
+
+ case log_info:
+ case log_debug:
+ default:
+ spdk_lvl = SPDK_LOG_INFO;
+ }
+
+ spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args);
+ return 0;
+}
+
+static const struct ocf_ctx_config vbdev_ocf_ctx_cfg = {
+ .name = "OCF SPDK",
+
+ .ops = {
+ .data = {
+ .alloc = vbdev_ocf_ctx_data_alloc,
+ .free = vbdev_ocf_ctx_data_free,
+ .mlock = vbdev_ocf_ctx_data_mlock,
+ .munlock = vbdev_ocf_ctx_data_munlock,
+ .read = vbdev_ocf_ctx_data_rd,
+ .write = vbdev_ocf_ctx_data_wr,
+ .zero = vbdev_ocf_ctx_data_zero,
+ .seek = vbdev_ocf_ctx_data_seek,
+ .copy = vbdev_ocf_ctx_data_cpy,
+ .secure_erase = vbdev_ocf_ctx_data_secure_erase,
+ },
+
+ .metadata_updater = {
+ .init = vbdev_ocf_volume_updater_init,
+ .stop = vbdev_ocf_volume_updater_stop,
+ .kick = vbdev_ocf_volume_updater_kick,
+ },
+
+ .cleaner = {
+ .init = vbdev_ocf_ctx_cleaner_init,
+ .stop = vbdev_ocf_ctx_cleaner_stop,
+ .kick = vbdev_ocf_ctx_cleaner_kick,
+ },
+
+ .logger = {
+ .print = vbdev_ocf_ctx_log_printf,
+ .dump_stack = NULL,
+ },
+
+ },
+};
+
+int
+vbdev_ocf_ctx_init(void)
+{
+ int ret;
+
+ ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+void
+vbdev_ocf_ctx_cleanup(void)
+{
+ ocf_ctx_put(vbdev_ocf_ctx);
+ vbdev_ocf_ctx = NULL;
+}
+
+SPDK_LOG_REGISTER_COMPONENT("ocf_ocfctx", SPDK_LOG_OCFCTX)