OCF: add OCF module

Add OCF module based on OCF meta-library
Open CAS Framwework (OCF) is high performance block storage
  caching meta-library
It is open-source, published at https://github.com/Open-CAS/ocf

With this patch OCF-enabled device is represented in SPDK
  as virtual bdev having core and caching devices as its base devices

This patch includes implementation of:
  * OCF top adapter          (vbdev_ocf.c)
  * OCF bottom adapter       (dobj.c, data.c)
  * Adaptation layer for OCF (env/)
  * OCF context abstractions (ctx.c)

Adaptation layer and context abstractions are not dependent on SPDK bdev

OCF bdev supports reads and writes, configured at startup
Other features will be added with separate patches

Change-Id: Ic2dcab378c8238d16f1e4b64d4374bdf257565bc
Signed-off-by: Vitaliy Mysak <vitaliy.mysak@intel.com>
Reviewed-on: https://review.gerrithub.io/c/435708
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Vitaliy Mysak 2018-09-20 16:54:49 +00:00 committed by Darek Stojaczyk
parent ec415110c1
commit d1fee489a7
21 changed files with 3584 additions and 0 deletions

5
CONFIG
View File

@ -124,3 +124,8 @@ CONFIG_FTL=n
# Build Intel IPSEC_MB library
CONFIG_IPSEC_MB=n
# Enable OCF module
CONFIG_OCF=n
CONFIG_OCF_PATH=
CONFIG_CUSTOMOCF=n

44
configure vendored
View File

@ -62,6 +62,10 @@ function usage()
echo " No path required."
echo " vtune Required to profile I/O under Intel VTune Amplifier XE."
echo " example: /opt/intel/vtune_amplifier_xe_version"
echo " ocf Required to build OCF module."
echo " If argument is directory, interpret it as root of OCF repo"
echo " If argument is file, interpret it as compiled OCF lib"
echo " example: /usr/src/ocf/"
echo ""
echo "Environment variables:"
echo ""
@ -269,6 +273,14 @@ for i in "$@"; do
--without-ftl)
CONFIG[FTL]=n
;;
--with-ocf=*)
CONFIG[OCF]=y
CONFIG[OCF_PATH]=$(readlink -f ${i#*=})
;;
--without-ocf)
CONFIG[OCF]=n
CONFIG[OCF_PATH]=
;;
--)
break
;;
@ -390,6 +402,38 @@ if [[ "${CONFIG[REDUCE]}" = "y" ]]; then
fi
fi
if [[ "${CONFIG[OCF]}" = "y" ]]; then
if [ -z "${CONFIG[OCF_PATH]}" ]; then
echo "When OCF module is enabled, you must specify"
echo "the OCF directory or path to OCF library using --with-ocf=path"
exit 1
fi
# If OCF_PATH is a file, assume it is a library and use it to compile with
if [ -f ${CONFIG[OCF_PATH]} ]; then
CONFIG[CUSTOMOCF]=y
else
CONFIG[CUSTOMOCF]=n
fi
# If OCF_PATH is not a library, we need to do sources export procedure using OCF Makefile
if [[ ${CONFIG[CUSTOMOCF]} = "n" ]]; then
echo "configuring OCF..."
rootdir=$(readlink -f $(dirname $0))
if pushd "${CONFIG[OCF_PATH]}" > /dev/null && \
make inc O="$rootdir/lib/bdev/ocf/env/" && \
make src O="$rootdir/lib/bdev/ocf/env/" CMD=cp 1>/dev/null && \
popd > /dev/null
then
echo "done configuring OCF"
else
echo "Could not configure OCF"
exit 1
fi
fi
fi
# We are now ready to generate final configuration. But first do sanity
# check to see if all keys in CONFIG array have its reflection in CONFIG file.
if [ $(egrep -c "^\s*CONFIG_[[:alnum:]_]+=" CONFIG) -ne ${#CONFIG[@]} ]; then

View File

@ -48,6 +48,12 @@ ifeq ($(CONFIG_CRYPTO),y)
DIRS-y += crypto
endif
ifeq ($(CONFIG_OCF), y)
DIRS-y += ocf
DIRS-y += ocf/env
DEPDIRS-ocf := ocf/env
endif
ifeq ($(OS),Linux)
DIRS-y += aio
DIRS-$(CONFIG_ISCSI_INITIATOR) += iscsi

47
lib/bdev/ocf/Makefile Normal file
View File

@ -0,0 +1,47 @@
#
# 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.
#
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
CFLAGS += $(ENV_CFLAGS) -I$(CURDIR)/env -I$(CURDIR)/env/include
C_SRCS = $(shell ls *.c)
LIBNAME := bdev_ocf
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk
SPDK_DEP_LIBS = $(call spdk_lib_list_to_static_libs,ocfenv)
$(LIB) : $(SPDK_DEP_LIBS)

413
lib/bdev/ocf/ctx.c Normal file
View File

@ -0,0 +1,413 @@
/*-
* 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_dma_malloc(sz, PAGE_SIZE, NULL);
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_dma_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(off, d->size);
d->seek = off;
break;
case ctx_data_seek_current:
off = MIN(off, 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);
}
}
}
/* OCF queue initialization procedure
* Called during ocf_cache_start */
static int
vbdev_ocf_ctx_queue_init(ocf_queue_t q)
{
return 0;
}
/* Called during ocf_submit_io, ocf_purge*
* and any other requests that need to submit io */
static void
vbdev_ocf_ctx_queue_kick(ocf_queue_t q)
{
}
/* OCF queue deinitialization
* Called at ocf_cache_stop */
static void
vbdev_ocf_ctx_queue_stop(ocf_queue_t q)
{
}
static int
vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c)
{
/* TODO [writeback]: implement with writeback mode support */
return 0;
}
static void
vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c)
{
/* TODO [writeback]: implement with writeback mode support */
}
static int vbdev_ocf_dobj_updater_init(ocf_metadata_updater_t mu)
{
/* TODO [metadata]: implement with persistent metadata support */
return 0;
}
static void vbdev_ocf_dobj_updater_stop(ocf_metadata_updater_t mu)
{
/* TODO [metadata]: implement with persistent metadata support */
}
static void vbdev_ocf_dobj_updater_kick(ocf_metadata_updater_t mu)
{
/* TODO [metadata]: implement with persistent metadata support */
}
static const struct ocf_ctx_ops vbdev_ocf_ctx_ops = {
.name = "OCF SPDK",
.data_alloc = vbdev_ocf_ctx_data_alloc,
.data_free = vbdev_ocf_ctx_data_free,
.data_mlock = vbdev_ocf_ctx_data_mlock,
.data_munlock = vbdev_ocf_ctx_data_munlock,
.data_rd = vbdev_ocf_ctx_data_rd,
.data_wr = vbdev_ocf_ctx_data_wr,
.data_zero = vbdev_ocf_ctx_data_zero,
.data_seek = vbdev_ocf_ctx_data_seek,
.data_cpy = vbdev_ocf_ctx_data_cpy,
.data_secure_erase = vbdev_ocf_ctx_data_secure_erase,
.queue_init = vbdev_ocf_ctx_queue_init,
.queue_kick = vbdev_ocf_ctx_queue_kick,
.queue_stop = vbdev_ocf_ctx_queue_stop,
.cleaner_init = vbdev_ocf_ctx_cleaner_init,
.cleaner_stop = vbdev_ocf_ctx_cleaner_stop,
.metadata_updater_init = vbdev_ocf_dobj_updater_init,
.metadata_updater_stop = vbdev_ocf_dobj_updater_stop,
.metadata_updater_kick = vbdev_ocf_dobj_updater_kick,
};
/* 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(const struct ocf_logger *logger,
ocf_logger_lvl_t lvl, const char *fmt, va_list args)
{
FILE *lfile = stdout;
if (lvl > log_info) {
return 0;
}
if (lvl <= log_warn) {
lfile = stderr;
}
return vfprintf(lfile, fmt, args);
}
static const struct ocf_logger logger = {
.printf = vbdev_ocf_ctx_log_printf,
.dump_stack = NULL,
};
int
vbdev_ocf_ctx_init(void)
{
int ret;
ret = ocf_ctx_init(&vbdev_ocf_ctx, &vbdev_ocf_ctx_ops);
if (ret < 0) {
return ret;
}
ocf_ctx_set_logger(vbdev_ocf_ctx, &logger);
return 0;
}
void
vbdev_ocf_ctx_cleanup(void)
{
ocf_ctx_exit(vbdev_ocf_ctx);
vbdev_ocf_ctx = NULL;
}
SPDK_LOG_REGISTER_COMPONENT("ocf_ocfctx", SPDK_LOG_OCFCTX)

48
lib/bdev/ocf/ctx.h Normal file
View File

@ -0,0 +1,48 @@
/*-
* 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 VBDEV_OCF_CTX_H
#define VBDEV_OCF_CTX_H
#include <ocf/ocf.h>
extern ocf_ctx_t vbdev_ocf_ctx;
#define OCF_WRITE_FLUSH 11
#define SPDK_OBJECT 0
int vbdev_ocf_ctx_init(void);
void vbdev_ocf_ctx_cleanup(void);
#endif

122
lib/bdev/ocf/data.c Normal file
View File

@ -0,0 +1,122 @@
/*-
* 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 "spdk/bdev.h"
#include "data.h"
struct bdev_ocf_data *
vbdev_ocf_data_alloc(uint32_t iovcnt)
{
struct bdev_ocf_data *data;
data = env_malloc(sizeof(*data), ENV_MEM_NOIO);
if (!data) {
return NULL;
}
data->seek = 0;
if (iovcnt) {
data->iovs = env_malloc(sizeof(*data->iovs) * iovcnt, ENV_MEM_NOIO);
if (!data->iovs) {
env_free(data);
return NULL;
}
}
data->iovcnt = 0;
data->iovalloc = iovcnt;
return data;
}
void
vbdev_ocf_data_free(struct bdev_ocf_data *data)
{
if (!data) {
return;
}
if (data->iovalloc != 0) {
env_free(data->iovs);
}
env_free(data);
}
void
vbdev_ocf_iovs_add(struct bdev_ocf_data *data, void *base, size_t len)
{
assert(NULL != data);
assert(data->iovalloc != -1);
if (data->iovcnt == data->iovalloc) {
/* TODO: Realloc iovs */
SPDK_ERRLOG("IOV error\n");
}
data->iovs[data->iovcnt].iov_base = base;
data->iovs[data->iovcnt].iov_len = len;
data->iovcnt++;
}
struct bdev_ocf_data *
vbdev_ocf_data_from_spdk_io(struct spdk_bdev_io *bdev_io)
{
struct bdev_ocf_data *data;
if (bdev_io == NULL) {
return NULL;
}
switch (bdev_io->type) {
case SPDK_BDEV_IO_TYPE_WRITE:
case SPDK_BDEV_IO_TYPE_READ:
assert(bdev_io->u.bdev.iovs);
break;
case SPDK_BDEV_IO_TYPE_FLUSH:
case SPDK_BDEV_IO_TYPE_UNMAP:
break;
default:
SPDK_ERRLOG("Unsupported IO type %d\n", bdev_io->type);
return NULL;
}
data = (struct bdev_ocf_data *)bdev_io->driver_ctx;
data->iovs = bdev_io->u.bdev.iovs;
data->iovcnt = bdev_io->u.bdev.iovcnt;
data->size = bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen;
return data;
}

57
lib/bdev/ocf/data.h Normal file
View File

@ -0,0 +1,57 @@
/*-
* 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 VBDEV_OCF_DATA_H
#define VBDEV_OCF_DATA_H
#include "spdk/bdev_module.h"
struct bdev_ocf_data {
struct iovec *iovs;
int iovcnt;
int iovalloc;
uint32_t size;
uint32_t seek;
};
struct bdev_ocf_data *vbdev_ocf_data_from_spdk_io(struct spdk_bdev_io *bdev_io);
struct bdev_ocf_data *vbdev_ocf_data_alloc(uint32_t nvecs);
void vbdev_ocf_data_free(struct bdev_ocf_data *data);
struct bdev_ocf_data *vbdev_ocf_data_from_iov(struct iovec *iovs);
void vbdev_ocf_iovs_add(struct bdev_ocf_data *data, void *base, size_t len);
#endif

402
lib/bdev/ocf/dobj.c Normal file
View File

@ -0,0 +1,402 @@
/*-
* 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 "spdk/bdev_module.h"
#include "spdk/env.h"
#include "spdk/io_channel.h"
#include "spdk_internal/log.h"
#include "data.h"
#include "dobj.h"
#include "ctx.h"
#include "vbdev_ocf.h"
static int
vbdev_ocf_dobj_open(ocf_data_obj_t obj)
{
struct vbdev_ocf_base *base = vbdev_ocf_get_base_by_name(ocf_data_obj_get_uuid(obj)->data);
if (base == NULL) {
assert(false);
return -EINVAL;
}
ocf_data_obj_set_priv(obj, base);
return 0;
}
static void
vbdev_ocf_dobj_close(ocf_data_obj_t obj)
{
}
static uint64_t
vbdev_ocf_dobj_get_length(ocf_data_obj_t obj)
{
struct vbdev_ocf_base *base = ocf_data_obj_get_priv(obj);
uint64_t len;
len = base->bdev->blocklen * base->bdev->blockcnt;
return len;
}
static int
vbdev_ocf_dobj_io_set_data(struct ocf_io *io, ctx_data_t *data,
uint32_t offset)
{
struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
io_ctx->offset = offset;
io_ctx->data = data;
if (io_ctx->data && offset >= io_ctx->data->size) {
return -ENOBUFS;
}
return 0;
}
static ctx_data_t *
vbdev_ocf_dobj_io_get_data(struct ocf_io *io)
{
return ocf_get_io_ctx(io)->data;
}
static void
vbdev_ocf_dobj_io_get(struct ocf_io *io)
{
struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
io_ctx->ref++;
}
static void
vbdev_ocf_dobj_io_put(struct ocf_io *io)
{
struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
if (--io_ctx->ref) {
return;
}
ocf_data_obj_del_io(io);
}
static const struct ocf_io_ops vbdev_ocf_dobj_io_ops = {
.set_data = vbdev_ocf_dobj_io_set_data,
.get_data = vbdev_ocf_dobj_io_get_data,
.get = vbdev_ocf_dobj_io_get,
.put = vbdev_ocf_dobj_io_put,
};
static struct ocf_io *
vbdev_ocf_dobj_new_io(ocf_data_obj_t obj)
{
struct ocf_io *io;
struct ocf_io_ctx *io_ctx;
io = ocf_data_obj_new_io(obj);
if (io == NULL) {
return NULL;
}
io->ops = &vbdev_ocf_dobj_io_ops;
io_ctx = ocf_get_io_ctx(io);
io_ctx->rq_cnt = 0;
io_ctx->ref = 1;
io_ctx->error = 0;
return io;
}
static int
get_starting_vec(struct iovec *iovs, int iovcnt, int *offset)
{
int i;
size_t off;
off = *offset;
for (i = 0; i < iovcnt; i++) {
if (off < iovs[i].iov_len) {
*offset = off;
return i;
}
off -= iovs[i].iov_len;
}
return -1;
}
static void
initialize_cpy_vector(struct iovec *cpy_vec, int cpy_vec_len, struct iovec *orig_vec,
int orig_vec_len,
size_t offset, size_t bytes)
{
void *curr_base;
int len, i;
i = 0;
while (bytes > 0) {
curr_base = orig_vec[i].iov_base + offset;
len = MIN(bytes, orig_vec[i].iov_len - offset);
cpy_vec[i].iov_base = curr_base;
cpy_vec[i].iov_len = len;
bytes -= len;
offset = 0;
i++;
}
}
static void
vbdev_ocf_dobj_submit_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
{
struct ocf_io *io;
struct ocf_io_ctx *io_ctx;
assert(opaque);
io = opaque;
io_ctx = ocf_get_io_ctx(io);
assert(io_ctx != NULL);
if (!success) {
io_ctx->error |= 1;
}
if (io_ctx->offset && bdev_io != NULL) {
switch (bdev_io->type) {
case SPDK_BDEV_IO_TYPE_READ:
case SPDK_BDEV_IO_TYPE_WRITE:
env_free(bdev_io->u.bdev.iovs);
break;
default:
assert(false);
break;
}
}
if (io_ctx->error) {
SPDK_DEBUGLOG(SPDK_TRACE_VBDEV_OCF_DOBJ,
"base returned error on io submission: %d\n", io_ctx->error);
}
if (io->io_queue == 0 && io_ctx->ch != NULL) {
spdk_put_io_channel(io_ctx->ch);
}
vbdev_ocf_dobj_io_put(io);
if (bdev_io) {
spdk_bdev_free_io(bdev_io);
}
if (--io_ctx->rq_cnt == 0) {
io->end(io, io_ctx->error);
}
}
static int
prepare_submit(struct ocf_io *io)
{
struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
struct vbdev_ocf_qcxt *qctx;
struct vbdev_ocf_base *base;
ocf_queue_t q;
int rc;
io_ctx->rq_cnt++;
if (io_ctx->rq_cnt != 1) {
return 0;
}
vbdev_ocf_dobj_io_get(io);
base = ocf_data_obj_get_priv(io->obj);
if (io->io_queue == 0) {
/* In SPDK we never set queue id to 0
* but OCF sometimes gives it to us (not a bug)
* In such cases we cannot determine on which queue we are now
* So to get io channel that is usually passed as queue context
* we have to reallocate it using global method */
io_ctx->ch = spdk_bdev_get_io_channel(base->desc);
if (io_ctx->ch == NULL) {
return -EPERM;
}
return 0;
}
rc = ocf_cache_get_queue(base->parent->ocf_cache, io->io_queue, &q);
if (rc) {
SPDK_ERRLOG("Could not get queue #%d\n", io->io_queue);
return rc;
}
qctx = ocf_queue_get_priv(q);
if (base->is_cache) {
io_ctx->ch = qctx->cache_ch;
} else {
io_ctx->ch = qctx->core_ch;
}
return rc;
}
static void
vbdev_ocf_dobj_submit_flush(struct ocf_io *io)
{
}
static void
vbdev_ocf_dobj_submit_io(struct ocf_io *io)
{
struct vbdev_ocf_base *base = ocf_data_obj_get_priv(io->obj);
struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
struct iovec *iovs;
int iovcnt, status = 0, i, offset;
uint64_t addr, len;
if (io->flags == OCF_WRITE_FLUSH) {
vbdev_ocf_dobj_submit_flush(io);
return;
}
prepare_submit(io);
/* IO fields */
addr = io->addr;
len = io->bytes;
offset = io_ctx->offset;
if (offset) {
i = get_starting_vec(io_ctx->data->iovs, io_ctx->data->iovcnt, &offset);
if (i < 0) {
SPDK_ERRLOG("offset bigger than data size\n");
vbdev_ocf_dobj_submit_io_cb(NULL, false, io);
return;
}
iovcnt = io_ctx->data->iovcnt - i;
iovs = env_malloc(sizeof(*iovs) * iovcnt, ENV_MEM_NOIO);
if (!iovs) {
SPDK_ERRLOG("allocation failed\n");
vbdev_ocf_dobj_submit_io_cb(NULL, false, io);
return;
}
initialize_cpy_vector(iovs, io_ctx->data->iovcnt, &io_ctx->data->iovs[i],
iovcnt, offset, len);
} else {
iovs = io_ctx->data->iovs;
iovcnt = io_ctx->data->iovcnt;
}
if (io->dir == OCF_READ) {
status = spdk_bdev_readv(base->desc, io_ctx->ch,
iovs, iovcnt, addr, len, vbdev_ocf_dobj_submit_io_cb, io);
} else if (io->dir == OCF_WRITE) {
status = spdk_bdev_writev(base->desc, io_ctx->ch,
iovs, iovcnt, addr, len, vbdev_ocf_dobj_submit_io_cb, io);
}
if (status) {
/* TODO [ENOMEM]: implement ENOMEM handling when submitting IO to base device */
/* Since callback is not called, we need to do it manually to free io structures */
SPDK_ERRLOG("submission failed with status=%d\n", status);
vbdev_ocf_dobj_submit_io_cb(NULL, false, io);
}
}
static void
vbdev_ocf_dobj_submit_discard(struct ocf_io *io)
{
/* TODO [unmap support] */
io->end(io, 0);
}
static void
vbdev_ocf_dobj_submit_metadata(struct ocf_io *io)
{
/* Implement with persistent metadata support */
}
static unsigned int
vbdev_ocf_dobj_get_max_io_size(ocf_data_obj_t obj)
{
return 256;
}
static struct ocf_data_obj_properties vbdev_ocf_dobj_props = {
.name = "SPDK block device",
.io_context_size = sizeof(struct ocf_io_ctx),
.caps = {
.atomic_writes = 0 /* to enable need to have ops->submit_metadata */
},
.ops = {
.new_io = vbdev_ocf_dobj_new_io,
.open = vbdev_ocf_dobj_open,
.close = vbdev_ocf_dobj_close,
.get_length = vbdev_ocf_dobj_get_length,
.submit_io = vbdev_ocf_dobj_submit_io,
.submit_discard = vbdev_ocf_dobj_submit_discard,
.submit_flush = vbdev_ocf_dobj_submit_flush,
.get_max_io_size = vbdev_ocf_dobj_get_max_io_size,
.submit_metadata = vbdev_ocf_dobj_submit_metadata,
}
};
int
vbdev_ocf_dobj_init(void)
{
return ocf_ctx_register_data_obj_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_ocf_dobj_props);
}
void
vbdev_ocf_dobj_cleanup(void)
{
ocf_ctx_unregister_data_obj_type(vbdev_ocf_ctx, SPDK_OBJECT);
}
SPDK_LOG_REGISTER_COMPONENT("vbdev_ocf_dobj", SPDK_TRACE_VBDEV_OCF_DOBJ)

62
lib/bdev/ocf/dobj.h Normal file
View File

@ -0,0 +1,62 @@
/*-
* 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 VBDEV_OCF_DOBJ_H
#define VBDEV_OCF_DOBJ_H
#include <ocf/ocf.h>
#include "ocf_env.h"
#include "ctx.h"
#include "data.h"
/* ocf_io context
* It is initialized from io size and offset */
struct ocf_io_ctx {
struct bdev_ocf_data *data;
struct spdk_io_channel *ch;
uint32_t offset;
int ref;
int rq_cnt;
int error;
};
int vbdev_ocf_dobj_init(void);
void vbdev_ocf_dobj_cleanup(void);
static inline struct ocf_io_ctx *ocf_get_io_ctx(struct ocf_io *io)
{
return ocf_data_obj_get_data_from_io(io);
}
#endif

2
lib/bdev/ocf/env/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
src/
include/

75
lib/bdev/ocf/env/Makefile vendored Normal file
View File

@ -0,0 +1,75 @@
#
# 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.
#
# OCF requires users to build with their sources
# If SPDK is configured with OCF source directory,
# we export its files and then compile SPDK LIB with them
# Else if SPDK is configured with OCF precompiled library
# we just use it as SPDK lib by copying it to /build/lib/
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
OCFDIR=$(CONFIG_OCF_DIR)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
LIBNAME := ocfenv
ifeq ($(CONFIG_CUSTOMOCF),n)
CFLAGS += $(ENV_CFLAGS) -I$(CURDIR) -I$(CURDIR)/include -w
C_SRCS = $(shell find -name \*.c)
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk
else
LIB = $(call spdk_lib_list_to_static_libs,$(LIBNAME))
all: $(LIB)
$(LIB):
cp $(CONFIG_OCF_PATH) $(LIB)
clean:
$(Q)rm -f $(LIB)
install:
endif
exportlib: $(LIB)
@ if [ -z $(O) ]; then echo "No output specified"; exit 1; fi
cp $(LIB) $(O)
help:
@ echo "all Default"
@ echo "exportlib O=<outpath> Default build to specified outpath"

144
lib/bdev/ocf/env/ocf_env.c vendored Normal file
View File

@ -0,0 +1,144 @@
/*-
* 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_def.h"
#include "ocf_env.h"
#include "spdk/crc32.h"
#include "spdk/env.h"
#include "spdk_internal/log.h"
struct _env_allocator {
/* Memory pool ID unique name */
char *name;
/* Size of specific item of memory pool */
uint32_t item_size;
/* Number of currently allocated items in pool */
env_atomic count;
};
struct _env_allocator_item {
uint32_t flags;
uint32_t cpu;
char data[];
};
void *
env_allocator_new(env_allocator *allocator)
{
struct _env_allocator_item *item = NULL;
item = spdk_dma_zmalloc(allocator->item_size, 0, NULL);
if (item) {
item->cpu = 0;
env_atomic_inc(&allocator->count);
} else {
return NULL;
}
return &item->data;
}
env_allocator *
env_allocator_create(uint32_t size, const char *name)
{
size_t name_size;
env_allocator *allocator;
allocator = spdk_dma_zmalloc(sizeof(*allocator), 0, NULL);
allocator->item_size = size + sizeof(struct _env_allocator_item);
allocator->name = env_strdup(name, 0);
return allocator;
}
void
env_allocator_del(env_allocator *allocator, void *obj)
{
struct _env_allocator_item *item = container_of(obj, struct _env_allocator_item, data);
env_atomic_dec(&allocator->count);
spdk_dma_free(item);
}
void
env_allocator_destroy(env_allocator *allocator)
{
if (allocator) {
if (env_atomic_read(&allocator->count)) {
SPDK_ERRLOG("Not all objects deallocated\n");
assert(false);
}
spdk_dma_free(allocator->name);
spdk_dma_free(allocator);
}
}
uint32_t
env_allocator_item_count(env_allocator *allocator)
{
return env_atomic_read(&allocator->count);
}
/* *** COMPLETION *** */
void
env_completion_init(env_completion *completion)
{
atomic_set(&completion->atom, 1);
}
void
env_completion_wait(env_completion *completion)
{
while (atomic_read(&completion->atom));
}
void
env_completion_complete(env_completion *completion)
{
atomic_set(&completion->atom, 0);
}
/* *** CRC *** */
uint32_t
env_crc32(uint32_t crc, uint8_t const *message, size_t len)
{
return spdk_crc32_ieee_update(message, len, crc);
}

746
lib/bdev/ocf/env/ocf_env.h vendored Normal file
View File

@ -0,0 +1,746 @@
/*-
* 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 __LIBOCF_ENV_H__
#define __LIBOCF_ENV_H__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <linux/limits.h>
#include <linux/stddef.h>
#include "spdk/stdinc.h"
#include "spdk/likely.h"
#include "spdk/env.h"
#include "spdk/util.h"
#include "spdk_internal/log.h"
#include "ocf_env_list.h"
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef uint64_t sector_t;
#define __packed __attribute__((packed))
#define __aligned(x) __attribute__((aligned(x)))
/* linux sector 512-bytes */
#define ENV_SECTOR_SHIFT 9
#define ENV_SECTOR_SIZE (1<<ENV_SECTOR_SHIFT)
#define BYTES_TO_SECTOR(x) ((x) >> ENV_SECTOR_SHIFT)
/* *** MEMORY MANAGEMENT *** */
#define ENV_MEM_NORMAL 0
#define ENV_MEM_NOIO 0
#define ENV_MEM_ATOMIC 0
#define likely spdk_likely
#define unlikely spdk_unlikely
#define min(x, y) MIN(x, y)
#ifndef MIN
#define MIN(x, y) spdk_min(x, y)
#endif
#define ARRAY_SIZE(x) SPDK_COUNTOF(x)
/* LOGGING */
#define ENV_PRIu64 PRIu64
#define ENV_WARN(cond, fmt, args...) ({ \
if (spdk_unlikely((uintptr_t)(cond))) \
SPDK_NOTICELOG("WARNING" fmt, ##args); \
})
#define ENV_WARN_ON(cond) ({ \
if (spdk_unlikely((uintptr_t)(cond))) \
SPDK_NOTICELOG("WARNING\n"); \
})
#define ENV_BUG() ({ \
SPDK_ERRLOG("BUG\n"); \
assert(0); \
abort(); \
})
#define ENV_BUG_ON(cond) ({ \
if (spdk_unlikely((uintptr_t)(cond))) { \
SPDK_ERRLOG("BUG\n"); \
assert(0); \
abort(); \
} \
})
#define container_of(ptr, type, member) SPDK_CONTAINEROF(ptr, type, member)
static inline void *env_malloc(size_t size, int flags)
{
return spdk_dma_malloc(size, 0, NULL);
}
static inline void *env_zalloc(size_t size, int flags)
{
return spdk_dma_zmalloc(size, 0, NULL);
}
static inline void env_free(const void *ptr)
{
return spdk_dma_free((void *)ptr);
}
static inline void *env_vmalloc(size_t size)
{
return spdk_dma_malloc(size, 0, NULL);
}
static inline void *env_vzalloc(size_t size)
{
/* TODO: raw_ram init can request huge amount of memory to store
* hashtable in it. need to ensure that allocation succedds */
return spdk_dma_zmalloc(size, 0, NULL);
}
static inline void env_vfree(const void *ptr)
{
return spdk_dma_free((void *)ptr);
}
static inline uint64_t env_get_free_memory(void)
{
/* TODO: do we need implementation for this function? */
return sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
}
/* *** ALLOCATOR *** */
#define OCF_ALLOCATOR_NAME_MAX 128
typedef struct _env_allocator env_allocator;
env_allocator *env_allocator_create(uint32_t size, const char *name);
void env_allocator_destroy(env_allocator *allocator);
void *env_allocator_new(env_allocator *allocator);
void env_allocator_del(env_allocator *allocator, void *item);
uint32_t env_allocator_item_count(env_allocator *allocator);
/* *** MUTEX *** */
typedef struct {
pthread_mutex_t m;
} env_mutex;
static inline int env_mutex_init(env_mutex *mutex)
{
return !!pthread_mutex_init(&mutex->m, NULL);
}
static inline void env_mutex_lock(env_mutex *mutex)
{
ENV_BUG_ON(pthread_mutex_lock(&mutex->m));
}
static inline int env_mutex_lock_interruptible(env_mutex *mutex)
{
env_mutex_lock(mutex);
return 0;
}
static inline int env_mutex_trylock(env_mutex *mutex)
{
if (pthread_mutex_trylock(&mutex->m) == 0) {
return 1;
}
return 0;
}
static inline void env_mutex_unlock(env_mutex *mutex)
{
ENV_BUG_ON(pthread_mutex_unlock(&mutex->m));
}
static inline int env_mutex_is_locked(env_mutex *mutex)
{
if (env_mutex_trylock(mutex)) {
env_mutex_unlock(mutex);
return 0;
}
return 1;
}
/* *** RECURSIVE MUTEX *** */
typedef env_mutex env_rmutex;
static inline int env_rmutex_init(env_rmutex *rmutex)
{
return env_mutex_init(rmutex);
}
static inline void env_rmutex_lock(env_rmutex *rmutex)
{
env_mutex_lock(rmutex);
}
static inline int env_rmutex_lock_interruptible(env_rmutex *rmutex)
{
return env_mutex_lock_interruptible(rmutex);
}
static inline int env_rmutex_trylock(env_rmutex *rmutex)
{
return env_mutex_trylock(rmutex);
}
static inline void env_rmutex_unlock(env_rmutex *rmutex)
{
env_mutex_unlock(rmutex);
}
static inline int env_rmutex_is_locked(env_rmutex *rmutex)
{
return env_mutex_is_locked(rmutex);
}
/* *** RW SEMAPHORE *** */
typedef struct {
pthread_rwlock_t lock;
} env_rwsem;
static inline int env_rwsem_init(env_rwsem *s)
{
return !!pthread_rwlock_init(&s->lock, NULL);
}
static inline void env_rwsem_up_read(env_rwsem *s)
{
ENV_BUG_ON(pthread_rwlock_unlock(&s->lock));
}
static inline void env_rwsem_down_read(env_rwsem *s)
{
ENV_BUG_ON(pthread_rwlock_rdlock(&s->lock));
}
static inline int env_rwsem_down_read_trylock(env_rwsem *s)
{
int result = pthread_rwlock_tryrdlock(&s->lock);
if (result == 0) {
return 1;
} else {
return 0;
}
}
static inline void env_rwsem_up_write(env_rwsem *s)
{
ENV_BUG_ON(pthread_rwlock_unlock(&s->lock));
}
static inline void env_rwsem_down_write(env_rwsem *s)
{
ENV_BUG_ON(pthread_rwlock_wrlock(&s->lock));
}
static inline int env_rwsem_down_write_trylock(env_rwsem *s)
{
int result = pthread_rwlock_trywrlock(&s->lock);
if (result == 0) {
return 1;
} else {
return 0;
}
}
static inline int env_rwsem_is_locked(env_rwsem *s)
{
if (env_rwsem_down_write_trylock(s)) {
env_rwsem_up_write(s);
return 1;
}
if (env_rwsem_down_read_trylock(s)) {
env_rwsem_up_read(s);
return 1;
}
return 0;
}
static inline int env_rwsem_down_read_interruptible(env_rwsem *s)
{
return pthread_rwlock_rdlock(&s->lock);
}
static inline int env_rwsem_down_write_interruptible(env_rwsem *s)
{
return pthread_rwlock_wrlock(&s->lock);
}
/* *** ATOMIC VARIABLES *** */
typedef int env_atomic;
typedef long env_atomic64;
#ifndef atomic_read
#define atomic_read(ptr) (*(__typeof__(*ptr) *volatile) (ptr))
#endif
#ifndef atomic_set
#define atomic_set(ptr, i) ((*(__typeof__(*ptr) *volatile) (ptr)) = (i))
#endif
#define atomic_inc(ptr) ((void) __sync_fetch_and_add(ptr, 1))
#define atomic_dec(ptr) ((void) __sync_fetch_and_add(ptr, -1))
#define atomic_add(ptr, n) ((void) __sync_fetch_and_add(ptr, n))
#define atomic_sub(ptr, n) ((void) __sync_fetch_and_sub(ptr, n))
#define atomic_cmpxchg __sync_val_compare_and_swap
static inline int env_atomic_read(const env_atomic *a)
{
return atomic_read(a);
}
static inline void env_atomic_set(env_atomic *a, int i)
{
atomic_set(a, i);
}
static inline void env_atomic_add(int i, env_atomic *a)
{
atomic_add(a, i);
}
static inline void env_atomic_sub(int i, env_atomic *a)
{
atomic_sub(a, i);
}
static inline bool env_atomic_sub_and_test(int i, env_atomic *a)
{
return __sync_sub_and_fetch(a, i) == 0;
}
static inline void env_atomic_inc(env_atomic *a)
{
atomic_inc(a);
}
static inline void env_atomic_dec(env_atomic *a)
{
atomic_dec(a);
}
static inline bool env_atomic_dec_and_test(env_atomic *a)
{
return __sync_sub_and_fetch(a, 1) == 0;
}
static inline bool env_atomic_inc_and_test(env_atomic *a)
{
return __sync_add_and_fetch(a, 1) == 0;
}
static inline int env_atomic_add_return(int i, env_atomic *a)
{
return __sync_add_and_fetch(a, i);
}
static inline int env_atomic_sub_return(int i, env_atomic *a)
{
return __sync_sub_and_fetch(a, i);
}
static inline int env_atomic_inc_return(env_atomic *a)
{
return env_atomic_add_return(1, a);
}
static inline int env_atomic_dec_return(env_atomic *a)
{
return env_atomic_sub_return(1, a);
}
static inline int env_atomic_cmpxchg(env_atomic *a, int old, int new_value)
{
return atomic_cmpxchg(a, old, new_value);
}
static inline int env_atomic_add_unless(env_atomic *a, int i, int u)
{
int c, old;
c = env_atomic_read(a);
for (;;) {
if (spdk_unlikely(c == (u))) {
break;
}
old = env_atomic_cmpxchg((a), c, c + (i));
if (spdk_likely(old == c)) {
break;
}
c = old;
}
return c != (u);
}
static inline long env_atomic64_read(const env_atomic64 *a)
{
return atomic_read(a);
}
static inline void env_atomic64_set(env_atomic64 *a, long i)
{
atomic_set(a, i);
}
static inline void env_atomic64_add(long i, env_atomic64 *a)
{
atomic_add(a, i);
}
static inline void env_atomic64_sub(long i, env_atomic64 *a)
{
atomic_sub(a, i);
}
static inline void env_atomic64_inc(env_atomic64 *a)
{
atomic_inc(a);
}
static inline void env_atomic64_dec(env_atomic64 *a)
{
atomic_dec(a);
}
static inline long env_atomic64_cmpxchg(env_atomic64 *a, long old, long new)
{
return atomic_cmpxchg(a, old, new);
}
/* *** COMPLETION *** */
struct completion {
env_atomic atom;
};
typedef struct completion env_completion;
void env_completion_init(env_completion *completion);
void env_completion_wait(env_completion *completion);
void env_completion_complete(env_completion *completion);
/* *** SPIN LOCKS *** */
typedef env_mutex env_spinlock;
static inline void env_spinlock_init(env_spinlock *l)
{
env_mutex_init(l);
}
static inline void env_spinlock_lock(env_spinlock *l)
{
env_mutex_lock(l);
}
static inline void env_spinlock_unlock(env_spinlock *l)
{
env_mutex_unlock(l);
}
static inline void env_spinlock_lock_irq(env_spinlock *l)
{
env_spinlock_lock(l);
}
static inline void env_spinlock_unlock_irq(env_spinlock *l)
{
env_spinlock_unlock(l);
}
static inline void env_spinlock_lock_irqsave(env_spinlock *l, int flags)
{
env_spinlock_lock(l);
(void)flags;
}
static inline void env_spinlock_unlock_irqrestore(env_spinlock *l, int flags)
{
env_spinlock_unlock(l);
(void)flags;
}
/* *** RW LOCKS *** */
typedef env_rwsem env_rwlock;
static inline void env_rwlock_init(env_rwlock *l)
{
env_rwsem_init(l);
}
static inline void env_rwlock_read_lock(env_rwlock *l)
{
env_rwsem_down_read(l);
}
static inline void env_rwlock_read_unlock(env_rwlock *l)
{
env_rwsem_up_read(l);
}
static inline void env_rwlock_write_lock(env_rwlock *l)
{
env_rwsem_down_write(l);
}
static inline void env_rwlock_write_unlock(env_rwlock *l)
{
env_rwsem_up_write(l);
}
static inline void env_bit_set(int nr, volatile void *addr)
{
char *byte = (char *)addr + (nr >> 3);
char mask = 1 << (nr & 7);
__sync_or_and_fetch(byte, mask);
}
static inline void env_bit_clear(int nr, volatile void *addr)
{
char *byte = (char *)addr + (nr >> 3);
char mask = 1 << (nr & 7);
mask = ~mask;
__sync_and_and_fetch(byte, mask);
}
static inline bool env_bit_test(int nr, const volatile unsigned long *addr)
{
const char *byte = (char *)addr + (nr >> 3);
char mask = 1 << (nr & 7);
return !!(*byte & mask);
}
/* *** WAITQUEUE *** */
typedef struct {
sem_t sem;
} env_waitqueue;
static inline void env_waitqueue_init(env_waitqueue *w)
{
sem_init(&w->sem, 0, 0);
}
static inline void env_waitqueue_wake_up(env_waitqueue *w)
{
sem_post(&w->sem);
}
#define env_waitqueue_wait(w, condition) \
({ \
int __ret = 0; \
if (!(condition)) \
sem_wait(&w.sem); \
__ret = __ret; \
})
/* *** SCHEDULING *** */
/* CAS does not need this while in user-space */
static inline void env_schedule(void)
{
}
#define env_cond_resched env_schedule
static inline int env_in_interrupt(void)
{
return 0;
}
static inline uint64_t env_get_tick_count(void)
{
return spdk_get_ticks();
}
static inline uint64_t env_ticks_to_secs(uint64_t j)
{
return j / spdk_get_ticks_hz();
}
static inline uint64_t env_ticks_to_msecs(uint64_t j)
{
return env_ticks_to_secs(j) * 1000;
}
static inline uint64_t env_secs_to_ticks(uint64_t j)
{
return j * spdk_get_ticks_hz();
}
/* *** STRING OPERATIONS *** */
/* 256 KB is sufficient amount of memory for OCF operations */
#define ENV_MAX_MEM (256 * 1024)
static inline int env_memset(void *dest, size_t len, uint8_t value)
{
if (dest == NULL || len == 0) {
return 1;
}
memset(dest, value, len);
return 0;
}
static inline int env_memcpy(void *dest, size_t dmax, const void *src, size_t len)
{
if (dest == NULL || src == NULL) {
return 1;
}
if (dmax == 0 || dmax > ENV_MAX_MEM) {
return 1;
}
if (len == 0 || len > dmax) {
return 1;
}
memcpy(dest, src, len);
return 0;
}
static inline int env_memcmp(const void *aptr, size_t dmax, const void *bptr, size_t len,
int *diff)
{
if (diff == NULL || aptr == NULL || bptr == NULL) {
return 1;
}
if (dmax == 0 || dmax > ENV_MAX_MEM) {
return 1;
}
if (len == 0 || len > dmax) {
return 1;
}
*diff = memcmp(aptr, bptr, len);
return 0;
}
/* 4096 is sufficient max length for any OCF operation on string */
#define ENV_MAX_STR (4 * 1024)
static inline size_t env_strnlen(const char *src, size_t dmax)
{
return strnlen(src, dmax);
}
static inline int env_strncpy(char *dest, size_t dmax, const char *src, size_t len)
{
if (dest == NULL || src == NULL) {
return 1;
}
if (dmax == 0 || dmax > ENV_MAX_STR) {
return 1;
}
if (len == 0 || len > dmax) {
return 1;
}
strncpy(dest, src, len);
return 0;
}
#define env_strncmp strncmp
static inline char *env_strdup(const char *src, int flags)
{
int len;
char *ret;
if (src == NULL) {
return NULL;
}
len = env_strnlen(src, ENV_MAX_STR) + 1;
ret = env_malloc(len, flags);
if (env_strncpy(ret, ENV_MAX_STR, src, len)) {
return NULL;
} else {
return ret;
}
}
/* *** SORTING *** */
static inline void env_sort(void *base, size_t num, size_t size,
int (*cmp_fn)(const void *, const void *),
void (*swap_fn)(void *, void *, int size))
{
qsort(base, num, size, cmp_fn);
}
static inline void env_msleep(uint64_t n)
{
usleep(n * 1000);
}
static inline void env_touch_softlockup_wd(void)
{
}
/* *** CRC *** */
uint32_t env_crc32(uint32_t crc, uint8_t const *data, size_t len);
#endif /* __OCF_ENV_H__ */

43
lib/bdev/ocf/env/ocf_env_headers.h vendored Normal file
View File

@ -0,0 +1,43 @@
/*-
* 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 __OCF_ENV_HEADERS_H__
#define __OCF_ENV_HEADERS_H__
#include "spdk/stdinc.h"
#define OCF_VERSION_MAIN 3
#define OCF_VERSION_MAJOR 8
#define OCF_VERSION_MINOR 0
#endif /* __OCF_ENV_HEADERS_H__ */

185
lib/bdev/ocf/env/ocf_env_list.h vendored Normal file
View File

@ -0,0 +1,185 @@
/*-
* 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 __OCF_LIST_H__
#define __OCF_LIST_H__
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
/**
* List entry structure mimicking linux kernel based one.
*/
struct list_head {
struct list_head *next;
struct list_head *prev;
};
/**
* start an empty list
*/
#define INIT_LIST_HEAD(l) { (l)->prev = l; (l)->next = l; }
/**
* Add item to list head.
* @param it list entry to be added
* @param l1 list main node (head)
*/
static inline void list_add(struct list_head *it, struct list_head *l1)
{
it->prev = l1;
it->next = l1->next;
l1->next->prev = it;
l1->next = it;
}
/**
* Add item it to tail.
* @param it list entry to be added
* @param l1 list main node (head)
*/
static inline void list_add_tail(struct list_head *it, struct list_head *l1)
{
it->prev = l1->prev;
it->next = l1;
l1->prev->next = it;
l1->prev = it;
}
/**
* check if a list is empty (return true)
*/
static inline int list_empty(struct list_head *it)
{
return it->next == it;
}
/**
* delete an entry from a list
*/
static inline void list_del(struct list_head *it)
{
it->next->prev = it->prev;
it->prev->next = it->next;
}
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
list_del(list);
list_add_tail(list, head);
}
static inline void list_move(struct list_head *list,
struct list_head *head)
{
list_del(list);
list_add(list, head);
}
/**
* Extract an entry.
* @param list_head_i list head item, from which entry is extracted
* @param item_type type (struct) of list entry
* @param field_name name of list_head field within item_type
*/
#define list_entry(list_head_i, item_type, field_name) \
(item_type *)(((void*)(list_head_i)) - offsetof(item_type, field_name))
#define list_first_entry(list_head_i, item_type, field_name) \
list_entry((list_head_i)->next, item_type, field_name)
/**
* @param iterator uninitialized list_head pointer, to be used as iterator
* @param plist list head (main node)
*/
#define list_for_each(iterator, plist) \
for (iterator = (plist)->next; \
(iterator)->next != (plist)->next; \
iterator = (iterator)->next)
/**
* Safe version of list_for_each which works even if entries are deleted during
* loop.
* @param iterator uninitialized list_head pointer, to be used as iterator
* @param q another uninitialized list_head, used as helper
* @param plist list head (main node)
*/
/*
* Algorithm handles situation, where q is deleted.
* consider in example 3 element list with header h:
*
* h -> 1 -> 2 -> 3 ->
*1. i q
*
*2. i q
*
*3. q i
*/
#define list_for_each_safe(iterator, q, plist) \
for (iterator = (q = (plist)->next->next)->prev; \
(q) != (plist)->next; \
iterator = (q = (q)->next)->prev)
#define _list_entry_helper(item, head, field_name) list_entry(head, typeof(*item), field_name)
/**
* Iterate over list entries.
* @param list pointer to list item (iterator)
* @param plist pointer to list_head item
* @param field_name name of list_head field in list entry
*/
#define list_for_each_entry(item, plist, field_name) \
for (item = _list_entry_helper(item, (plist)->next, field_name); \
_list_entry_helper(item, (item)->field_name.next, field_name) !=\
_list_entry_helper(item, (plist)->next, field_name); \
item = _list_entry_helper(item, (item)->field_name.next, field_name))
/**
* Safe version of list_for_each_entry which works even if entries are deleted
* during loop.
* @param list pointer to list item (iterator)
* @param q another pointer to list item, used as helper
* @param plist pointer to list_head item
* @param field_name name of list_head field in list entry
*/
#define list_for_each_entry_safe(item, q, plist, field_name) \
for (item = _list_entry_helper(item, (plist)->next, field_name), \
q = _list_entry_helper(item, (item)->field_name.next, field_name); \
_list_entry_helper(item, (item)->field_name.next, field_name) != \
_list_entry_helper(item, (plist)->next, field_name); \
item = q, q = _list_entry_helper(q, (q)->field_name.next, field_name))
#endif

68
lib/bdev/ocf/utils.c Normal file
View File

@ -0,0 +1,68 @@
/*-
* 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 "utils.h"
static char *cache_modes[ocf_cache_mode_max] = {
[ocf_cache_mode_wt] = "wt",
[ocf_cache_mode_wb] = "wb",
[ocf_cache_mode_wa] = "wa",
[ocf_cache_mode_pt] = "pt",
[ocf_cache_mode_wi] = "wi"
};
ocf_cache_mode_t
ocf_get_cache_mode(const char *cache_mode)
{
int i;
for (i = 0; i < ocf_cache_mode_max; i++) {
if (strcmp(cache_mode, cache_modes[i]) == 0) {
return i;
}
}
return ocf_cache_mode_none;
}
const char *
ocf_get_cache_modename(ocf_cache_mode_t mode)
{
if (mode > ocf_cache_mode_none && mode < ocf_cache_mode_max) {
return cache_modes[mode];
} else {
return NULL;
}
}

42
lib/bdev/ocf/utils.h Normal file
View File

@ -0,0 +1,42 @@
/*-
* 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 VBDEV_OCF_UTILS_H
#define VBDEV_OCF_UTILS_H
#include <ocf/ocf.h>
ocf_cache_mode_t ocf_get_cache_mode(const char *cache_mode);
const char *ocf_get_cache_modename(ocf_cache_mode_t mode);
#endif

911
lib/bdev/ocf/vbdev_ocf.c Normal file
View File

@ -0,0 +1,911 @@
/*-
* 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 <ocf/ocf_types.h>
#include <ocf/ocf_mngt.h>
#include "ctx.h"
#include "data.h"
#include "dobj.h"
#include "utils.h"
#include "vbdev_ocf.h"
#include "spdk/bdev_module.h"
#include "spdk/conf.h"
#include "spdk/io_channel.h"
#include "spdk/string.h"
#include "spdk_internal/log.h"
#include "spdk/cpuset.h"
static struct spdk_bdev_module ocf_if;
/* Set number of OCF queues to maximum numbers of cores
* that SPDK supports, so we never run out of them */
static int g_queues_count = SPDK_CPUSET_SIZE;
static TAILQ_HEAD(, vbdev_ocf) g_ocf_vbdev_head
= TAILQ_HEAD_INITIALIZER(g_ocf_vbdev_head);
/* Free allocated strings and structure itself
* Used at shutdown only */
static void
free_vbdev(struct vbdev_ocf *vbdev)
{
if (!vbdev) {
return;
}
pthread_mutex_destroy(&vbdev->_lock);
free(vbdev->name);
free(vbdev->cache.name);
free(vbdev->core.name);
free(vbdev);
}
/* Stop OCF cache object
* vbdev_ocf is not operational after this */
static int
stop_vbdev(struct vbdev_ocf *vbdev)
{
int rc;
if (vbdev == NULL) {
return -EFAULT;
}
if (vbdev->ocf_cache == NULL) {
return -EFAULT;
}
if (!ocf_cache_is_running(vbdev->ocf_cache)) {
return -EINVAL;
}
/* This function blocks execution until all OCF requests are finished
* But we don't have to worry about possible deadlocks because in
* supported modes (WT and PT) all OCF requests are finished before
* SPDK bdev io requests */
rc = ocf_mngt_cache_stop(vbdev->ocf_cache);
if (rc) {
SPDK_ERRLOG("Could not stop cache for '%s'\n", vbdev->name);
return rc;
}
return rc;
}
/* Release SPDK and OCF objects associated with base */
static int
remove_base(struct vbdev_ocf_base *base)
{
int rc = 0;
if (base == NULL) {
return -EFAULT;
}
assert(base->attached);
/* Release OCF-part */
if (base->parent->ocf_cache && ocf_cache_is_running(base->parent->ocf_cache)) {
if (base->is_cache) {
rc = stop_vbdev(base->parent);
} else {
rc = ocf_mngt_cache_remove_core(base->parent->ocf_cache, base->id, false);
}
}
/* Release SPDK-part */
spdk_bdev_module_release_bdev(base->bdev);
spdk_bdev_close(base->desc);
base->attached = false;
return rc;
}
/* Free OCF resources, close base bdevs, unregister io device
* This function is called during spdk_bdev_unregister */
static int
vbdev_ocf_destruct(void *opaque)
{
struct vbdev_ocf *vbdev = opaque;
int status = 0;
if (vbdev->state.doing_finish) {
return -EALREADY;
}
vbdev->state.doing_finish = true;
if (vbdev->state.started) {
status = stop_vbdev(vbdev);
}
if (vbdev->core.attached) {
remove_base(&vbdev->core);
}
if (vbdev->cache.attached) {
remove_base(&vbdev->cache);
}
if (vbdev->state.started) {
spdk_io_device_unregister(vbdev, NULL);
}
return status;
}
/* Stop OCF cache and unregister SPDK bdev */
int
vbdev_ocf_delete(struct vbdev_ocf *vbdev)
{
int rc = 0;
if (vbdev->state.started) {
spdk_bdev_unregister(&vbdev->exp_bdev, NULL, NULL);
} else {
rc = vbdev_ocf_destruct(vbdev);
}
return rc;
}
/* If vbdev is online, return its object */
struct vbdev_ocf *
vbdev_ocf_get_by_name(const char *name)
{
struct vbdev_ocf *vbdev;
if (name == NULL) {
assert(false);
return NULL;
}
TAILQ_FOREACH(vbdev, &g_ocf_vbdev_head, tailq) {
if (vbdev->name == NULL || vbdev->state.doing_finish) {
continue;
}
if (strcmp(vbdev->name, name) == 0) {
return vbdev;
}
}
return NULL;
}
/* Return matching base if parent vbdev is online */
struct vbdev_ocf_base *
vbdev_ocf_get_base_by_name(const char *name)
{
struct vbdev_ocf *vbdev;
if (name == NULL) {
assert(false);
return NULL;
}
TAILQ_FOREACH(vbdev, &g_ocf_vbdev_head, tailq) {
if (vbdev->state.doing_finish) {
continue;
}
if (vbdev->cache.name && strcmp(vbdev->cache.name, name) == 0) {
return &vbdev->cache;
}
if (vbdev->core.name && strcmp(vbdev->core.name, name) == 0) {
return &vbdev->core;
}
}
return NULL;
}
/* Called from OCF when SPDK_IO is completed */
static void
vbdev_ocf_io_submit_cb(struct ocf_io *io, int error)
{
struct spdk_bdev_io *bdev_io = io->priv1;
if (error == 0) {
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
} else if (error == -ENOMEM) {
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
} else {
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
}
ocf_io_put(io);
}
/* Configure io parameters and send it to OCF */
static int
io_submit_to_ocf(struct spdk_bdev_io *bdev_io, struct ocf_io *io)
{
int dir;
uint64_t len = bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen;
uint64_t offset = bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen;
switch (bdev_io->type) {
case SPDK_BDEV_IO_TYPE_WRITE:
case SPDK_BDEV_IO_TYPE_READ:
dir = OCF_READ;
if (bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
dir = OCF_WRITE;
}
ocf_io_configure(io, offset, len, dir, 0, 0);
return ocf_submit_io(io);
case SPDK_BDEV_IO_TYPE_FLUSH:
case SPDK_BDEV_IO_TYPE_UNMAP:
case SPDK_BDEV_IO_TYPE_RESET:
case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
default:
SPDK_ERRLOG("Unsupported IO type: %d\n", bdev_io->type);
return -EINVAL;
}
}
/* Submit SPDK-IO to OCF */
static void
io_handle(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
{
struct vbdev_ocf *vbdev = bdev_io->bdev->ctxt;
struct ocf_io *io;
struct bdev_ocf_data *data = NULL;
struct vbdev_ocf_qcxt *qctx = spdk_io_channel_get_ctx(ch);
int err;
io = ocf_new_io(vbdev->ocf_core);
if (!io) {
err = -ENOMEM;
goto fail;
}
ocf_io_set_queue(io, ocf_queue_get_id(qctx->queue));
data = vbdev_ocf_data_from_spdk_io(bdev_io);
if (!data) {
err = -ENOMEM;
goto fail;
}
err = ocf_io_set_data(io, data, 0);
if (err) {
goto fail;
}
ocf_io_set_cmpl(io, bdev_io, NULL, vbdev_ocf_io_submit_cb);
err = io_submit_to_ocf(bdev_io, io);
if (err) {
goto fail;
}
return;
fail:
if (io) {
ocf_io_put(io);
}
if (err == -ENOMEM) {
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
} else {
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
}
}
/* Called from bdev layer when an io to Cache vbdev is submitted */
static void
vbdev_ocf_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
{
switch (bdev_io->type) {
case SPDK_BDEV_IO_TYPE_READ:
/* User does not have to allocate io vectors for the request,
* so in case they are not allocated, we allocate them here */
spdk_bdev_io_get_buf(bdev_io, io_handle,
bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
break;
case SPDK_BDEV_IO_TYPE_WRITE:
io_handle(ch, bdev_io);
break;
case SPDK_BDEV_IO_TYPE_UNMAP:
case SPDK_BDEV_IO_TYPE_FLUSH:
case SPDK_BDEV_IO_TYPE_RESET:
case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
default:
SPDK_ERRLOG("Unknown I/O type %d\n", bdev_io->type);
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
break;
}
}
/* Called from bdev layer */
static bool
vbdev_ocf_io_type_supported(void *opaque, enum spdk_bdev_io_type io_type)
{
switch (io_type) {
case SPDK_BDEV_IO_TYPE_READ:
case SPDK_BDEV_IO_TYPE_WRITE:
return true;
case SPDK_BDEV_IO_TYPE_UNMAP:
case SPDK_BDEV_IO_TYPE_FLUSH:
case SPDK_BDEV_IO_TYPE_RESET:
case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
default:
return false;
}
}
/* Called from bdev layer */
static struct spdk_io_channel *
vbdev_ocf_get_io_channel(void *opaque)
{
struct vbdev_ocf *bdev = opaque;
return spdk_get_io_channel(bdev);
}
static int
vbdev_ocf_dump_config_info(void *opaque, struct spdk_json_write_ctx *w)
{
return 0;
}
/* Cache vbdev function table
* Used by bdev layer */
static struct spdk_bdev_fn_table cache_dev_fn_table = {
.destruct = vbdev_ocf_destruct,
.io_type_supported = vbdev_ocf_io_type_supported,
.submit_request = vbdev_ocf_submit_request,
.get_io_channel = vbdev_ocf_get_io_channel,
.dump_info_json = vbdev_ocf_dump_config_info,
};
/* Start OCF cache, attach caching device */
static int
start_cache(struct vbdev_ocf *vbdev)
{
int rc;
rc = ocf_mngt_cache_start(vbdev_ocf_ctx, &vbdev->ocf_cache, &vbdev->cfg.cache);
if (rc) {
SPDK_ERRLOG("Failed to start cache instance\n");
return rc;
}
vbdev->cache.id = ocf_cache_get_id(vbdev->ocf_cache);
rc = ocf_mngt_cache_attach(vbdev->ocf_cache, &vbdev->cfg.device);
if (rc) {
SPDK_ERRLOG("Failed to attach cache device\n");
return rc;
}
return 0;
}
/* Add core for existing OCF cache instance */
static int
add_core(struct vbdev_ocf *vbdev)
{
int rc;
rc = ocf_mngt_cache_add_core(vbdev->ocf_cache, &vbdev->ocf_core, &vbdev->cfg.core);
if (rc) {
SPDK_ERRLOG("Failed to add core device to cache instance\n");
return rc;
}
vbdev->core.id = ocf_core_get_id(vbdev->ocf_core);
return 0;
}
/* Poller function for the OCF queue
* We execute OCF requests here synchronously */
static int queue_poll(void *opaque)
{
struct vbdev_ocf_qcxt *qctx = opaque;
uint32_t iono = ocf_queue_pending_io(qctx->queue);
ocf_queue_run(qctx->queue);
if (iono > 0) {
return 1;
} else {
return 0;
}
}
/* Find queue index that is not taken */
static int
get_free_queue_id(struct vbdev_ocf *vbdev)
{
struct vbdev_ocf_qcxt *qctx;
int i, tmp;
for (i = 1; i < (int)vbdev->cfg.cache.io_queues; i++) {
tmp = i;
TAILQ_FOREACH(qctx, &vbdev->queues, tailq) {
tmp = ocf_queue_get_id(qctx->queue);
if (tmp == i) {
tmp = -1;
break;
}
}
if (tmp > 0) {
return i;
}
}
return -1;
}
/* Called on cache vbdev creation at every thread
* We determine on which OCF queue IOs from this thread will be running
* and allocate resources for that queue
* This is also where queue poller gets registered */
static int
io_device_create_cb(void *io_device, void *ctx_buf)
{
struct vbdev_ocf *vbdev = io_device;
struct vbdev_ocf_qcxt *qctx = ctx_buf;
int queue_id = 0, rc;
/* Modifying state of vbdev->queues needs to be synchronous
* We use vbdev private lock to achive that */
pthread_mutex_lock(&vbdev->_lock);
queue_id = get_free_queue_id(vbdev);
if (queue_id < 0) {
SPDK_ERRLOG("OCF queues count is too small, try to allocate more than %d\n",
vbdev->cfg.cache.io_queues);
rc = -EINVAL;
goto end;
}
rc = ocf_cache_get_queue(vbdev->ocf_cache, queue_id, &qctx->queue);
if (rc) {
SPDK_ERRLOG("Could not get OCF queue #%d\n", queue_id);
goto end;
}
ocf_queue_set_priv(qctx->queue, qctx);
qctx->vbdev = vbdev;
qctx->cache_ch = spdk_bdev_get_io_channel(vbdev->cache.desc);
qctx->core_ch = spdk_bdev_get_io_channel(vbdev->core.desc);
qctx->poller = spdk_poller_register(queue_poll, qctx, 0);
TAILQ_INSERT_TAIL(&vbdev->queues, qctx, tailq);
end:
pthread_mutex_unlock(&vbdev->_lock);
return rc;
}
/* Called per thread
* We free resources associated with OCF queue here
* and close base devices channels */
static void
io_device_destroy_cb(void *io_device, void *ctx_buf)
{
struct vbdev_ocf_qcxt *qctx = ctx_buf;
spdk_put_io_channel(qctx->cache_ch);
spdk_put_io_channel(qctx->core_ch);
spdk_poller_unregister(&qctx->poller);
pthread_mutex_lock(&qctx->vbdev->_lock);
TAILQ_REMOVE(&qctx->vbdev->queues, qctx, tailq);
pthread_mutex_unlock(&qctx->vbdev->_lock);
}
/* Start OCF cache and register vbdev_ocf at bdev layer */
static int
register_vbdev(struct vbdev_ocf *vbdev)
{
int result;
if (!vbdev->cache.attached || !vbdev->core.attached) {
return -EPERM;
}
result = start_cache(vbdev);
if (result) {
SPDK_ERRLOG("Failed to start cache instance\n");
return result;
}
result = add_core(vbdev);
if (result) {
SPDK_ERRLOG("Failed to add core to cache instance\n");
return result;
}
/* Create exported spdk object */
/* Copy properties of the base bdev */
vbdev->exp_bdev.blocklen = vbdev->core.bdev->blocklen;
vbdev->exp_bdev.write_cache = vbdev->core.bdev->write_cache;
vbdev->exp_bdev.required_alignment = vbdev->core.bdev->required_alignment;
vbdev->exp_bdev.name = vbdev->name;
vbdev->exp_bdev.product_name = "SPDK OCF";
vbdev->exp_bdev.blockcnt = vbdev->core.bdev->blockcnt;
vbdev->exp_bdev.ctxt = vbdev;
vbdev->exp_bdev.fn_table = &cache_dev_fn_table;
vbdev->exp_bdev.module = &ocf_if;
/* Finally register vbdev in SPDK */
spdk_io_device_register(vbdev, io_device_create_cb, io_device_destroy_cb,
sizeof(struct vbdev_ocf_qcxt), vbdev->name);
result = spdk_bdev_register(&vbdev->exp_bdev);
if (result) {
SPDK_ERRLOG("Could not register exposed bdev\n");
return result;
}
vbdev->state.started = true;
return result;
}
/* Init OCF configuration options
* for core and cache devices */
static void
init_vbdev_config(struct vbdev_ocf *vbdev)
{
struct vbdev_ocf_config *cfg = &vbdev->cfg;
/* Id 0 means OCF decides the id */
cfg->cache.id = 0;
cfg->cache.name = vbdev->name;
cfg->cache.name_size = strlen(vbdev->name) + 1;
/* TODO [metadata]: make configurable with persistent
* metadata support */
cfg->cache.metadata_volatile = true;
/* TODO [cache line size]: make cache line size configurable
* Using standard 4KiB for now */
cfg->cache.cache_line_size = ocf_cache_line_size_4;
/* This are suggested values that
* should be sufficient for most use cases */
cfg->cache.backfill.max_queue_size = 65536;
cfg->cache.backfill.queue_unblock_size = 60000;
/* At this moment OCF queues count is static
* so we choose some value for it
* It has to be bigger than SPDK thread count */
cfg->cache.io_queues = g_queues_count;
/* TODO [cache line size] */
cfg->device.cache_line_size = ocf_cache_line_size_4;
cfg->device.force = true;
cfg->device.min_free_ram = 0;
cfg->device.perform_test = false;
cfg->device.discard_on_start = false;
cfg->core.data_obj_type = SPDK_OBJECT;
cfg->device.uuid.size = strlen(vbdev->cache.name) + 1;
cfg->device.uuid.data = vbdev->cache.name;
cfg->core.uuid.size = strlen(vbdev->core.name) + 1;
cfg->core.uuid.data = vbdev->core.name;
}
/* Allocate vbdev structure object and add it to the global list */
static int
init_vbdev(const char *vbdev_name,
const char *cache_mode_name,
const char *cache_name,
const char *core_name)
{
struct vbdev_ocf *vbdev;
int rc = 0;
if (spdk_bdev_get_by_name(vbdev_name) || vbdev_ocf_get_by_name(vbdev_name)) {
SPDK_ERRLOG("Device with name '%s' already exists", vbdev_name);
return -EPERM;
}
vbdev = calloc(1, sizeof(*vbdev));
if (!vbdev) {
goto error_mem;
}
vbdev->cache.parent = vbdev;
vbdev->core.parent = vbdev;
vbdev->cache.is_cache = true;
vbdev->core.is_cache = false;
pthread_mutex_init(&vbdev->_lock, NULL);
TAILQ_INIT(&vbdev->queues);
if (cache_mode_name) {
vbdev->cfg.cache.cache_mode
= ocf_get_cache_mode(cache_mode_name);
} else {
SPDK_ERRLOG("No cache mode specified\n");
rc = -EINVAL;
goto error_free;
}
if (vbdev->cfg.cache.cache_mode < 0) {
SPDK_ERRLOG("Incorrect cache mode '%s'\n", cache_mode_name);
rc = -EINVAL;
goto error_free;
}
vbdev->name = strdup(vbdev_name);
if (!vbdev->name) {
goto error_mem;
}
vbdev->cache.name = strdup(cache_name);
if (!vbdev->cache.name) {
goto error_mem;
}
vbdev->core.name = strdup(core_name);
if (!vbdev->core.name) {
goto error_mem;
}
init_vbdev_config(vbdev);
TAILQ_INSERT_TAIL(&g_ocf_vbdev_head, vbdev, tailq);
return rc;
error_mem:
rc = -ENOMEM;
error_free:
free_vbdev(vbdev);
return rc;
}
/* Read configuration file at the start of SPDK application
* This adds vbdevs to global list if some mentioned in config */
static int
vbdev_ocf_init(void)
{
const char *vbdev_name, *modename, *cache_name, *core_name;
struct spdk_conf_section *sp;
int status;
status = vbdev_ocf_ctx_init();
if (status) {
SPDK_ERRLOG("OCF ctx initialization failed with=%d\n", status);
return status;
}
status = vbdev_ocf_dobj_init();
if (status) {
vbdev_ocf_ctx_cleanup();
SPDK_ERRLOG("OCF dobj initialization failed with=%d\n", status);
return status;
}
sp = spdk_conf_find_section(NULL, "OCF");
if (sp == NULL) {
return 0;
}
for (int i = 0; ; i++) {
if (!spdk_conf_section_get_nval(sp, "OCF", i)) {
break;
}
vbdev_name = spdk_conf_section_get_nmval(sp, "OCF", i, 0);
if (!vbdev_name) {
SPDK_ERRLOG("No vbdev name specified\n");
continue;
}
modename = spdk_conf_section_get_nmval(sp, "OCF", i, 1);
if (!modename) {
SPDK_ERRLOG("No modename specified for OCF vbdev '%s'\n", vbdev_name);
continue;
}
cache_name = spdk_conf_section_get_nmval(sp, "OCF", i, 2);
if (!cache_name) {
SPDK_ERRLOG("No cache device specified for OCF vbdev '%s'\n", vbdev_name);
continue;
}
core_name = spdk_conf_section_get_nmval(sp, "OCF", i, 3);
if (!core_name) {
SPDK_ERRLOG("No core devices specified for OCF vbdev '%s'\n", vbdev_name);
continue;
}
status = init_vbdev(vbdev_name, modename, cache_name, core_name);
if (status) {
SPDK_ERRLOG("Config initialization failed with code: %d\n", status);
}
}
return status;
}
/* Called after application shutdown started
* Release memory of allocated structures here */
static void
vbdev_ocf_module_fini(void)
{
struct vbdev_ocf *vbdev;
while ((vbdev = TAILQ_FIRST(&g_ocf_vbdev_head))) {
TAILQ_REMOVE(&g_ocf_vbdev_head, vbdev, tailq);
free_vbdev(vbdev);
}
vbdev_ocf_dobj_cleanup();
vbdev_ocf_ctx_cleanup();
}
/* Open base SPDK bdev and claim it */
static int
attach_base(struct vbdev_ocf_base *base)
{
int status;
if (base->attached) {
return -EALREADY;
}
status = spdk_bdev_open(base->bdev, true, NULL, NULL, &base->desc);
if (status) {
SPDK_ERRLOG("Unable to open device '%s' for writing\n", base->name);
return status;
}
status = spdk_bdev_module_claim_bdev(base->bdev, base->desc,
&ocf_if);
if (status) {
SPDK_ERRLOG("Unable to claim device '%s'\n", base->name);
spdk_bdev_close(base->desc);
return status;
}
base->attached = true;
return status;
}
/* Attach base bdevs
* If they attached, start vbdev
* otherwise wait for them to appear at examine */
static int
create_from_bdevs(struct vbdev_ocf *vbdev,
struct spdk_bdev *cache_bdev, struct spdk_bdev *core_bdev)
{
int rc = 0;
if (cache_bdev) {
vbdev->cache.bdev = cache_bdev;
rc |= attach_base(&vbdev->cache);
}
if (core_bdev) {
vbdev->core.bdev = core_bdev;
rc |= attach_base(&vbdev->core);
}
if (rc == 0 && vbdev->core.attached && vbdev->cache.attached) {
rc = register_vbdev(vbdev);
}
return rc;
}
/* Init and then start vbdev if all base devices are present */
int
vbdev_ocf_construct(const char *vbdev_name,
const char *cache_mode_name,
const char *cache_name,
const char *core_name)
{
int rc;
struct spdk_bdev *cache_bdev = spdk_bdev_get_by_name(cache_name);
struct spdk_bdev *core_bdev = spdk_bdev_get_by_name(core_name);
struct vbdev_ocf *vbdev;
rc = init_vbdev(vbdev_name, cache_mode_name, cache_name, core_name);
if (rc) {
return rc;
}
vbdev = vbdev_ocf_get_by_name(vbdev_name);
if (vbdev == NULL) {
return -ENODEV;
}
if (cache_bdev == NULL) {
SPDK_NOTICELOG("OCF bdev '%s' is waiting for cache device '%s' to connect\n",
vbdev->name, cache_name);
}
if (core_bdev == NULL) {
SPDK_NOTICELOG("OCF bdev '%s' is waiting for core device '%s' to connect\n",
vbdev->name, core_name);
}
return create_from_bdevs(vbdev, cache_bdev, core_bdev);
}
/* This called if new device is created in SPDK application
* If that device named as one of base bdevs of cache_vbdev,
* attach them
* If last device attached here, vbdev starts here */
static void
vbdev_ocf_examine(struct spdk_bdev *bdev)
{
const char *bdev_name = spdk_bdev_get_name(bdev);
struct vbdev_ocf *vbdev;
TAILQ_FOREACH(vbdev, &g_ocf_vbdev_head, tailq) {
if (vbdev->state.doing_finish) {
continue;
}
if (!strcmp(bdev_name, vbdev->cache.name)) {
create_from_bdevs(vbdev, bdev, NULL);
break;
}
if (!strcmp(bdev_name, vbdev->core.name)) {
create_from_bdevs(vbdev, NULL, bdev);
break;
}
}
spdk_bdev_module_examine_done(&ocf_if);
}
static int
vbdev_ocf_get_ctx_size(void)
{
return sizeof(struct bdev_ocf_data);
}
/* Module-global function table
* Does not relate to vbdev instances */
static struct spdk_bdev_module ocf_if = {
.name = "ocf",
.module_init = vbdev_ocf_init,
.fini_start = NULL,
.module_fini = vbdev_ocf_module_fini,
.config_text = NULL,
.get_ctx_size = vbdev_ocf_get_ctx_size,
.examine_config = vbdev_ocf_examine,
};
SPDK_BDEV_MODULE_REGISTER(&ocf_if);
SPDK_LOG_REGISTER_COMPONENT("vbdev_ocf", SPDK_TRACE_VBDEV_OCF)

157
lib/bdev/ocf/vbdev_ocf.h Normal file
View File

@ -0,0 +1,157 @@
/*-
* 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 SPDK_VBDEV_OCF_H
#define SPDK_VBDEV_OCF_H
#include <ocf/ocf.h>
#include "spdk/bdev.h"
#include "spdk/bdev_module.h"
struct vbdev_ocf;
/* Context for OCF queue poller
* Used for mapping SPDK threads to OCF queues */
struct vbdev_ocf_qcxt {
/* OCF queue. Contains OCF requests */
struct ocf_queue *queue;
/* Poller for OCF queue. Runs OCF requests */
struct spdk_poller *poller;
/* Reference to parent vbdev */
struct vbdev_ocf *vbdev;
/* Base devices channels */
struct spdk_io_channel *cache_ch;
struct spdk_io_channel *core_ch;
/* Link to per-bdev list of queue contexts */
TAILQ_ENTRY(vbdev_ocf_qcxt) tailq;
};
/* Important states */
struct vbdev_ocf_state {
/* From the moment when finish started */
bool doing_finish;
/* From the moment when reset IO recieved, until it is completed */
bool doing_reset;
/* From the moment when exp_bdev is registered */
bool started;
};
/*
* OCF cache configuration options
*/
struct vbdev_ocf_config {
/* Initial cache configuration */
struct ocf_mngt_cache_config cache;
/* Cache device config */
struct ocf_mngt_cache_device_config device;
/* Core initial config */
struct ocf_mngt_core_config core;
};
/* Base device info */
struct vbdev_ocf_base {
/* OCF unique internal id */
int id;
/* OCF internal name */
char *name;
/* True if this is a caching device */
bool is_cache;
/* Connected SPDK block device */
struct spdk_bdev *bdev;
/* SPDK device io handle */
struct spdk_bdev_desc *desc;
/* True if SPDK bdev has been claimed and opened for writing */
bool attached;
/* Reference to main vbdev */
struct vbdev_ocf *parent;
};
/*
* The main information provider
* It's also registered as io_device
*/
struct vbdev_ocf {
/* Exposed unique name */
char *name;
/* Base bdevs */
struct vbdev_ocf_base cache;
struct vbdev_ocf_base core;
/* Base bdevs OCF objects */
ocf_cache_t ocf_cache;
ocf_core_t ocf_core;
/* Parameters */
struct vbdev_ocf_config cfg;
struct vbdev_ocf_state state;
/* Exposed SPDK bdev. Registered in bdev layer */
struct spdk_bdev exp_bdev;
/* Link to global list of this type structures */
TAILQ_ENTRY(vbdev_ocf) tailq;
/* List of queues contexts
* New items are added at io_channel creation */
TAILQ_HEAD(, vbdev_ocf_qcxt) queues;
/* Private per-bdev lock */
pthread_mutex_t _lock;
};
int vbdev_ocf_construct(
const char *vbdev_name,
const char *cache_mode_name,
const char *cache_name,
const char *core_name);
/* If vbdev is online, return its object */
struct vbdev_ocf *vbdev_ocf_get_by_name(const char *name);
/* Return matching base if parent vbdev is online */
struct vbdev_ocf_base *vbdev_ocf_get_base_by_name(const char *name);
/* Stop OCF cache and unregister SPDK bdev */
int vbdev_ocf_delete(struct vbdev_ocf *vbdev);
#endif

View File

@ -39,6 +39,11 @@ ifeq ($(CONFIG_CRYPTO),y)
BLOCKDEV_MODULES_LIST += bdev_crypto
endif
ifeq ($(CONFIG_OCF),y)
BLOCKDEV_MODULES_LIST += bdev_ocf
BLOCKDEV_MODULES_LIST += ocfenv
endif
ifeq ($(CONFIG_RDMA),y)
SYS_LIBS += -libverbs -lrdmacm
endif