From 27f44662ac3c678828bcd13fe8533ec97426082e Mon Sep 17 00:00:00 2001 From: Tomasz Zawadzki Date: Thu, 14 Sep 2017 16:53:36 +0200 Subject: [PATCH] lvol: Logical volume implementation Change-Id: Ia96ae78ff9530d953181ac5f7255a38f3c8ec430 Signed-off-by: Tomasz Zawadzki Signed-off-by: Maciej Szwed Signed-off-by: Piotr Pelplinski Reviewed-on: https://review.gerrithub.io/375392 Tested-by: SPDK Automated Test System Reviewed-by: Daniel Verkamp Reviewed-by: Jim Harris --- CHANGELOG.md | 11 + include/spdk/lvol.h | 68 +++ include/spdk_internal/bdev.h | 4 + include/spdk_internal/lvolstore.h | 93 +++ lib/Makefile | 2 +- lib/bdev/Makefile | 2 +- lib/bdev/bdev.c | 23 + lib/bdev/lvol/Makefile | 40 ++ lib/bdev/lvol/vbdev_lvol.c | 578 ++++++++++++++++++ lib/bdev/lvol/vbdev_lvol.h | 56 ++ lib/bdev/lvol/vbdev_lvol_rpc.c | 380 ++++++++++++ lib/lvol/Makefile | 41 ++ lib/lvol/lvol.c | 394 ++++++++++++ lib/rocksdb/spdk.rocksdb.mk | 3 +- mk/spdk.common.mk | 1 + mk/spdk.modules.mk | 5 +- scripts/pkgdep.sh | 6 +- scripts/rpc.py | 41 ++ test/unit/lib/Makefile | 2 +- test/unit/lib/bdev/Makefile | 2 +- test/unit/lib/bdev/vbdev_lvol.c/.gitignore | 1 + test/unit/lib/bdev/vbdev_lvol.c/Makefile | 57 ++ .../lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c | 505 +++++++++++++++ test/unit/lib/lvol/Makefile | 44 ++ test/unit/lib/lvol/lvol.c/.gitignore | 1 + test/unit/lib/lvol/lvol.c/Makefile | 56 ++ test/unit/lib/lvol/lvol.c/lvol_ut.c | 482 +++++++++++++++ unittest.sh | 3 + 28 files changed, 2892 insertions(+), 9 deletions(-) create mode 100644 include/spdk/lvol.h create mode 100644 include/spdk_internal/lvolstore.h create mode 100644 lib/bdev/lvol/Makefile create mode 100644 lib/bdev/lvol/vbdev_lvol.c create mode 100644 lib/bdev/lvol/vbdev_lvol.h create mode 100644 lib/bdev/lvol/vbdev_lvol_rpc.c create mode 100644 lib/lvol/Makefile create mode 100644 lib/lvol/lvol.c create mode 100644 test/unit/lib/bdev/vbdev_lvol.c/.gitignore create mode 100644 test/unit/lib/bdev/vbdev_lvol.c/Makefile create mode 100644 test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c create mode 100644 test/unit/lib/lvol/Makefile create mode 100644 test/unit/lib/lvol/lvol.c/.gitignore create mode 100644 test/unit/lib/lvol/lvol.c/Makefile create mode 100644 test/unit/lib/lvol/lvol.c/lvol_ut.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 36cb025cb4..cb49d31dba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## v17.10: (Upcoming Release) +### New dependency + +libuuid added as new depenency for logical volumes. + ### Block Device Abstraction Layer (bdev) An [fio](http://github.com/axboe/fio) plugin was added that can route @@ -80,6 +84,13 @@ which will show up in tools like `gdb`. The API spdk_trace_dump() now takes a new parameter to allow the caller to specify stdout or stderr for example. +### Logical Volumes + +Logical volumes library built on top of SPDK blobstore has been added. +It is possible create logical volumes on top of other devices using RPC. + +See [logical volumes](http://www.spdk.io/doc/lvol.html) documentation for more information. + ## v17.07: Build system improvements, userspace vhost-blk target, and GPT bdev ### Build System diff --git a/include/spdk/lvol.h b/include/spdk/lvol.h new file mode 100644 index 0000000000..72e03f664e --- /dev/null +++ b/include/spdk/lvol.h @@ -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. + */ + +/** \file + * Logical Volume Interface + */ + +#ifndef SPDK_LVOL_H +#define SPDK_LVOL_H + +#include "spdk/queue.h" +#include "spdk/blob.h" +#include + +struct spdk_lvol_store; +struct spdk_lvol; + +typedef void (*spdk_lvs_op_with_handle_complete)(void *cb_arg, struct spdk_lvol_store *lvol_store, + int lvserrno); +typedef void (*spdk_lvs_op_complete)(void *cb_arg, int lvserrno); +typedef void (*spdk_lvol_op_complete)(void *cb_arg, int lvolerrno); +typedef void (*spdk_lvol_op_with_handle_complete)(void *cb_arg, struct spdk_lvol *lvol, + int lvolerrno); + +int spdk_lvs_init(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg); +int spdk_lvs_unload(struct spdk_lvol_store *lvol_store, spdk_lvs_op_complete cb_fn, void *cb_arg); +int spdk_lvol_create(struct spdk_lvol_store *lvs, uint64_t sz, + spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg); +int spdk_lvol_resize(struct spdk_lvol *lvol, uint64_t sz, + spdk_lvol_op_complete cb_fn, void *cb_arg); +void spdk_lvol_destroy(struct spdk_lvol *lvol); +void spdk_lvol_close(struct spdk_lvol *lvol); +struct spdk_io_channel *spdk_lvol_get_io_channel(struct spdk_lvol *lvol); +struct lvol_store_bdev *vbdev_get_lvs_bdev_by_lvs(struct spdk_lvol_store *lvs_orig); +struct spdk_lvol *vbdev_get_lvol_by_name(const char *name); +struct spdk_lvol_store *vbdev_get_lvol_store_by_uuid(uuid_t uuid); + +#endif /* SPDK_LVOL_H */ diff --git a/include/spdk_internal/bdev.h b/include/spdk_internal/bdev.h index fbe498005b..a621b5f996 100644 --- a/include/spdk_internal/bdev.h +++ b/include/spdk_internal/bdev.h @@ -222,6 +222,8 @@ struct spdk_bdev { TAILQ_ENTRY(spdk_bdev) vbdev_link; + bool bdev_opened; + bool bdev_opened_for_write; /** @@ -425,6 +427,8 @@ void spdk_scsi_nvme_translate(const struct spdk_bdev_io *bdev_io, void spdk_bdev_module_list_add(struct spdk_bdev_module_if *bdev_module); +bool spdk_is_bdev_opened(struct spdk_bdev *bdev); + static inline struct spdk_bdev_io * spdk_bdev_io_from_ctx(void *ctx) { diff --git a/include/spdk_internal/lvolstore.h b/include/spdk_internal/lvolstore.h new file mode 100644 index 0000000000..1ab53f16d5 --- /dev/null +++ b/include/spdk_internal/lvolstore.h @@ -0,0 +1,93 @@ +/*- + * 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_INTERNAL_LVOLSTORE_H +#define SPDK_INTERNAL_LVOLSTORE_H + +#include "spdk/lvol.h" +#include "spdk_internal/bdev.h" + +struct spdk_lvol_store_req { + union { + struct { + spdk_lvs_op_complete cb_fn; + void *cb_arg; + struct spdk_bdev *base_bdev; + } lvs_basic; + + struct { + spdk_lvs_op_with_handle_complete cb_fn; + void *cb_arg; + struct spdk_lvol_store *lvol_store; + struct spdk_bs_dev *bs_dev; + struct spdk_bdev *base_bdev; + } lvs_handle; + + struct { + spdk_lvol_op_complete cb_fn; + void *cb_arg; + } lvol_basic; + + struct { + spdk_lvol_op_with_handle_complete cb_fn; + void *cb_arg; + struct spdk_lvol *lvol; + } lvol_handle; + } u; +}; + +struct spdk_lvol_store { + struct spdk_bs_dev *bs_dev; + struct spdk_blob_store *blobstore; + uuid_t uuid; + uint64_t page_size; + struct spdk_lvol_store_req *destruct_req; + TAILQ_HEAD(, spdk_lvol) lvols; +}; + +struct spdk_lvol { + struct spdk_lvol_store *lvol_store; + struct spdk_blob *blob; + uint64_t sz; + spdk_blob_id blob_id; + char *name; + bool close_only; + struct spdk_bdev *bdev; + TAILQ_ENTRY(spdk_lvol) link; +}; + +struct lvol_task { + enum spdk_bdev_io_status status; +}; + +#endif /* SPDK_INTERNAL_LVOLSTORE_H */ diff --git a/lib/Makefile b/lib/Makefile index 8787315ab3..e95b012346 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk DIRS-y += bdev blob blobfs conf copy cunit event json jsonrpc \ - log env_dpdk net rpc trace util nvme nvmf scsi ioat \ + log lvol env_dpdk net rpc trace util nvme nvmf scsi ioat \ ut_mock iscsi ifeq ($(OS),Linux) DIRS-y += nbd diff --git a/lib/bdev/Makefile b/lib/bdev/Makefile index 8b5811ddc1..5f0f7ac0b5 100644 --- a/lib/bdev/Makefile +++ b/lib/bdev/Makefile @@ -44,7 +44,7 @@ C_SRCS-$(CONFIG_VTUNE) += vtune.c LIBNAME = bdev -DIRS-y += error gpt malloc null nvme rpc split +DIRS-y += error gpt lvol malloc null nvme rpc split ifeq ($(OS),Linux) DIRS-y += aio virtio diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index f6a35d8003..3ca8e3cb66 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -1480,6 +1480,7 @@ _spdk_bdev_register(struct spdk_bdev *bdev) bdev->status = SPDK_BDEV_STATUS_READY; TAILQ_INIT(&bdev->open_descs); + bdev->bdev_opened = false; bdev->bdev_opened_for_write = false; TAILQ_INIT(&bdev->vbdevs); @@ -1573,6 +1574,24 @@ spdk_vbdev_unregister(struct spdk_bdev *vbdev) spdk_bdev_unregister(vbdev); } +bool +spdk_is_bdev_opened(struct spdk_bdev *bdev) +{ + struct spdk_bdev *base; + + if (bdev->bdev_opened) { + return true; + } + + TAILQ_FOREACH(base, &bdev->base_bdevs, base_bdev_link) { + if (spdk_is_bdev_opened(base)) { + return true; + } + } + + return false; +} + int spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_cb, void *remove_ctx, struct spdk_bdev_desc **_desc) @@ -1599,6 +1618,8 @@ spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_ bdev->bdev_opened_for_write = true; } + bdev->bdev_opened = true; + desc->bdev = bdev; desc->remove_cb = remove_cb; desc->remove_ctx = remove_ctx; @@ -1623,6 +1644,8 @@ spdk_bdev_close(struct spdk_bdev_desc *desc) bdev->bdev_opened_for_write = false; } + bdev->bdev_opened = false; + TAILQ_REMOVE(&bdev->open_descs, desc, link); free(desc); diff --git a/lib/bdev/lvol/Makefile b/lib/bdev/lvol/Makefile new file mode 100644 index 0000000000..25a0ad7fe4 --- /dev/null +++ b/lib/bdev/lvol/Makefile @@ -0,0 +1,40 @@ +# +# 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 + +C_SRCS = vbdev_lvol.c vbdev_lvol_rpc.c +LIBNAME = vbdev_lvol + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/lib/bdev/lvol/vbdev_lvol.c b/lib/bdev/lvol/vbdev_lvol.c new file mode 100644 index 0000000000..b963d6e956 --- /dev/null +++ b/lib/bdev/lvol/vbdev_lvol.c @@ -0,0 +1,578 @@ +/*- + * 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/blob_bdev.h" +#include "spdk/rpc.h" +#include "spdk_internal/bdev.h" +#include "spdk_internal/log.h" + +#include "vbdev_lvol.h" + +SPDK_DECLARE_BDEV_MODULE(lvol); + +static TAILQ_HEAD(, lvol_store_bdev) g_spdk_lvol_pairs = TAILQ_HEAD_INITIALIZER( + g_spdk_lvol_pairs); + +static void +_vbdev_lvs_create_cb(void *cb_arg, struct spdk_lvol_store *lvs, int lvserrno) +{ + struct spdk_lvol_store_req *req = cb_arg; + struct spdk_bs_dev *bs_dev = req->u.lvs_handle.bs_dev; + struct lvol_store_bdev *lvs_bdev; + struct spdk_bdev *bdev = req->u.lvs_handle.base_bdev; + + if (lvserrno != 0) { + assert(lvs == NULL); + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Cannot create lvol store bdev\n"); + bs_dev->destroy(bs_dev); + goto end; + } + + assert(lvs != NULL); + + lvs_bdev = calloc(1, sizeof(*lvs_bdev)); + if (!lvs_bdev) { + bs_dev->destroy(bs_dev); + lvserrno = -ENOMEM; + goto end; + } + lvs_bdev->lvs = lvs; + lvs_bdev->bdev = bdev; + + TAILQ_INSERT_TAIL(&g_spdk_lvol_pairs, lvs_bdev, lvol_stores); + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Lvol store bdev inserted\n"); + +end: + req->u.lvs_handle.cb_fn(req->u.lvs_handle.cb_arg, lvs, lvserrno); + free(req); + + return; +} + +int +vbdev_lvs_create(struct spdk_bdev *base_bdev, + spdk_lvs_op_with_handle_complete cb_fn, + void *cb_arg) +{ + struct spdk_bs_dev *bs_dev; + struct spdk_lvol_store_req *lvs_req; + int rc; + + lvs_req = calloc(1, sizeof(*lvs_req)); + if (!lvs_req) { + SPDK_ERRLOG("Cannot alloc memory for vbdev lvol store request pointer\n"); + return -ENOMEM; + } + + bs_dev = spdk_bdev_create_bs_dev(base_bdev); + if (!bs_dev) { + SPDK_ERRLOG("Cannot create blobstore device\n"); + free(lvs_req); + return -ENODEV; + } + + lvs_req->u.lvs_handle.bs_dev = bs_dev; + lvs_req->u.lvs_handle.base_bdev = base_bdev; + lvs_req->u.lvs_handle.cb_fn = cb_fn; + lvs_req->u.lvs_handle.cb_arg = cb_arg; + + rc = spdk_lvs_init(bs_dev, _vbdev_lvs_create_cb, lvs_req); + if (rc < 0) { + free(lvs_req); + bs_dev->destroy(bs_dev); + return rc; + } + + return 0; +} + +static void +_vbdev_lvs_destruct_cb(void *cb_arg, int lvserrno) +{ + struct spdk_lvol_store_req *req = cb_arg; + + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Lvol store bdev deleted\n"); + + if (req->u.lvs_basic.cb_fn != NULL) + req->u.lvs_basic.cb_fn(req->u.lvs_basic.cb_arg, lvserrno); + free(req); +} + +void +vbdev_lvs_destruct(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, + void *cb_arg) +{ + + struct spdk_lvol_store_req *req; + struct lvol_store_bdev *lvs_bdev; + struct spdk_lvol *lvol, *tmp; + + req = calloc(1, sizeof(*req)); + if (!req) { + SPDK_ERRLOG("Cannot alloc memory for vbdev lvol store request pointer\n"); + return; + } + req->u.lvs_basic.cb_fn = cb_fn; + req->u.lvs_basic.cb_arg = cb_arg; + + lvs_bdev = vbdev_get_lvs_bdev_by_lvs(lvs); + req->u.lvs_basic.base_bdev = lvs_bdev->bdev; + TAILQ_REMOVE(&g_spdk_lvol_pairs, lvs_bdev, lvol_stores); + + free(lvs_bdev); + + if (TAILQ_EMPTY(&lvs->lvols)) { + spdk_lvs_unload(lvs, _vbdev_lvs_destruct_cb, req); + } else { + lvs->destruct_req = req; + TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) { + lvol->close_only = true; + spdk_bdev_unregister(lvol->bdev); + } + } +} + +static struct lvol_store_bdev * +_vbdev_lvol_store_first(void) +{ + struct lvol_store_bdev *lvs_bdev; + + lvs_bdev = TAILQ_FIRST(&g_spdk_lvol_pairs); + if (lvs_bdev) { + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Starting lvolstore iteration at %p\n", lvs_bdev->lvs); + } + + return lvs_bdev; +} + +static struct lvol_store_bdev * +_vbdev_lvol_store_next(struct lvol_store_bdev *prev) +{ + struct lvol_store_bdev *lvs_bdev; + + lvs_bdev = TAILQ_NEXT(prev, lvol_stores); + if (lvs_bdev) { + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Continuing lvolstore iteration at %p\n", lvs_bdev->lvs); + } + + return lvs_bdev; +} + +struct spdk_lvol_store * +vbdev_get_lvol_store_by_uuid(uuid_t uuid) +{ + struct spdk_lvol_store *lvs = NULL; + struct lvol_store_bdev *lvs_bdev = _vbdev_lvol_store_first(); + + while (lvs_bdev != NULL) { + lvs = lvs_bdev->lvs; + if (uuid_compare(lvs->uuid, uuid) == 0) { + return lvs; + } + lvs_bdev = _vbdev_lvol_store_next(lvs_bdev); + } + return NULL; +} + +struct lvol_store_bdev * +vbdev_get_lvs_bdev_by_lvs(struct spdk_lvol_store *lvs_orig) +{ + struct spdk_lvol_store *lvs = NULL; + struct lvol_store_bdev *lvs_bdev = _vbdev_lvol_store_first(); + + while (lvs_bdev != NULL) { + lvs = lvs_bdev->lvs; + if (lvs == lvs_orig) { + return lvs_bdev; + } + lvs_bdev = _vbdev_lvol_store_next(lvs_bdev); + } + return NULL; +} + +struct spdk_lvol * +vbdev_get_lvol_by_name(const char *name) +{ + struct spdk_lvol *lvol, *tmp_lvol; + struct lvol_store_bdev *lvs_bdev, *tmp_lvs_bdev; + + TAILQ_FOREACH_SAFE(lvs_bdev, &g_spdk_lvol_pairs, lvol_stores, tmp_lvs_bdev) { + TAILQ_FOREACH_SAFE(lvol, &lvs_bdev->lvs->lvols, link, tmp_lvol) { + if (!strcmp(lvol->name, name)) { + return lvol; + } + } + } + + return NULL; +} + +static int +vbdev_lvol_destruct(void *ctx) +{ + struct spdk_lvol *lvol = ctx; + + assert(lvol != NULL); + free(lvol->bdev); + if (lvol->close_only) { + spdk_lvol_close(lvol); + } else { + spdk_lvol_destroy(lvol); + } + + return 0; +} + +static int +vbdev_lvol_dump_config_json(void *ctx, struct spdk_json_write_ctx *w) +{ + struct spdk_lvol *lvol = ctx; + struct lvol_store_bdev *lvs_bdev; + struct spdk_bdev *bdev; + + lvs_bdev = vbdev_get_lvs_bdev_by_lvs(lvol->lvol_store); + bdev = lvs_bdev->bdev; + + spdk_json_write_name(w, "base_bdev"); + spdk_json_write_string(w, spdk_bdev_get_name(bdev)); + + return 0; +} + +static struct spdk_io_channel * +vbdev_lvol_get_io_channel(void *ctx) +{ + struct spdk_lvol *lvol = ctx; + + return spdk_lvol_get_io_channel(lvol); +} + +static bool +vbdev_lvol_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) +{ + switch (io_type) { + case SPDK_BDEV_IO_TYPE_READ: + case SPDK_BDEV_IO_TYPE_WRITE: + case SPDK_BDEV_IO_TYPE_FLUSH: + case SPDK_BDEV_IO_TYPE_RESET: + return true; + case SPDK_BDEV_IO_TYPE_UNMAP: + case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: + default: + return false; + } +} + +static void +lvol_op_comp(void *cb_arg, int bserrno) +{ + struct lvol_task *task = cb_arg; + struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(task); + + if (bserrno != 0) { + task->status = SPDK_BDEV_IO_STATUS_FAILED; + } + + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Vbdev processing callback on device %s with type %d\n", + bdev_io->bdev->name, bdev_io->type); + spdk_bdev_io_complete(bdev_io, task->status); +} + +static void +lvol_read(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) +{ + uint64_t start_page, num_pages; + struct spdk_lvol *lvol = bdev_io->bdev->ctxt; + struct spdk_blob *blob = lvol->blob; + struct lvol_task *task = (struct lvol_task *)bdev_io->driver_ctx; + + start_page = bdev_io->u.read.offset_blocks; + num_pages = bdev_io->u.read.num_blocks; + + task->status = SPDK_BDEV_IO_STATUS_SUCCESS; + + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, + "Vbdev doing read at offset %" PRIu64 " using %" PRIu64 " pages on device %s\n", start_page, + num_pages, bdev_io->bdev->name); + spdk_bs_io_readv_blob(blob, ch, bdev_io->u.read.iovs, bdev_io->u.read.iovcnt, start_page, num_pages, + lvol_op_comp, task); +} + +static void +lvol_write(struct spdk_lvol *lvol, struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) +{ + uint64_t start_page, num_pages; + struct spdk_blob *blob = lvol->blob; + struct lvol_task *task = (struct lvol_task *)bdev_io->driver_ctx; + + start_page = bdev_io->u.write.offset_blocks; + num_pages = bdev_io->u.write.num_blocks; + + task->status = SPDK_BDEV_IO_STATUS_SUCCESS; + + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, + "Vbdev doing write at offset %" PRIu64 " using %" PRIu64 " pages on device %s\n", start_page, + num_pages, bdev_io->bdev->name); + spdk_bs_io_writev_blob(blob, ch, bdev_io->u.write.iovs, bdev_io->u.write.iovcnt, start_page, + num_pages, lvol_op_comp, task); +} + +static void +lvol_flush(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) +{ + struct lvol_task *task = (struct lvol_task *)bdev_io->driver_ctx; + + task->status = SPDK_BDEV_IO_STATUS_SUCCESS; + + spdk_bs_io_flush_channel(ch, lvol_op_comp, task); +} + +static int +lvol_reset(struct spdk_bdev_io *bdev_io) +{ + spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); + + return 0; +} + +static void +vbdev_lvol_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) +{ + struct spdk_lvol *lvol = bdev_io->bdev->ctxt; + + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Vbdev request type %d submitted\n", bdev_io->type); + + switch (bdev_io->type) { + case SPDK_BDEV_IO_TYPE_READ: + spdk_bdev_io_get_buf(bdev_io, lvol_read); + break; + case SPDK_BDEV_IO_TYPE_WRITE: + lvol_write(lvol, ch, bdev_io); + break; + case SPDK_BDEV_IO_TYPE_RESET: + lvol_reset(bdev_io); + break; + case SPDK_BDEV_IO_TYPE_FLUSH: + lvol_flush(ch, bdev_io); + break; + case SPDK_BDEV_IO_TYPE_UNMAP: + case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: + default: + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "lvol: unsupported I/O type %d\n", bdev_io->type); + spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); + return; + } + return; +} + +static struct spdk_bdev_fn_table vbdev_lvol_fn_table = { + .destruct = vbdev_lvol_destruct, + .io_type_supported = vbdev_lvol_io_type_supported, + .submit_request = vbdev_lvol_submit_request, + .get_io_channel = vbdev_lvol_get_io_channel, + .dump_config_json = vbdev_lvol_dump_config_json, +}; + +static struct spdk_bdev * +_create_lvol_disk(struct spdk_lvol *lvol) +{ + struct spdk_bdev *bdev; + struct lvol_store_bdev *lvs_bdev; + + if (!lvol->name) { + return NULL; + } + + lvs_bdev = vbdev_get_lvs_bdev_by_lvs(lvol->lvol_store); + if (lvs_bdev == NULL) { + SPDK_ERRLOG("No spdk lvs-bdev pair found for lvol %s\n", lvol->name); + return NULL; + } + + bdev = calloc(1, sizeof(struct spdk_bdev)); + if (!bdev) { + SPDK_ERRLOG("Cannot alloc memory for lvol bdev\n"); + return NULL; + } + + bdev->name = lvol->name; + bdev->product_name = "Logical Volume"; + bdev->write_cache = 1; + bdev->blocklen = lvol->lvol_store->page_size; + assert((lvol->sz % bdev->blocklen) == 0); + bdev->blockcnt = lvol->sz / bdev->blocklen; + + bdev->ctxt = lvol; + bdev->fn_table = &vbdev_lvol_fn_table; + bdev->module = SPDK_GET_BDEV_MODULE(lvol); + + spdk_bdev_register(bdev); + + return bdev; +} + +static void +_vbdev_lvol_create_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno) +{ + struct spdk_lvol_store_req *req = cb_arg; + struct spdk_bdev *bdev = NULL; + + if (lvolerrno < 0) { + goto end; + } + + bdev = _create_lvol_disk(lvol); + if (bdev == NULL) { + lvolerrno = -ENODEV; + goto end; + } + lvol->bdev = bdev; + +end: + req->u.lvol_handle.cb_fn(req->u.lvol_handle.cb_arg, lvol, lvolerrno); + free(req); +} + +int +vbdev_lvol_create(uuid_t uuid, size_t sz, + spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_lvol_store_req *req; + struct spdk_lvol_store *lvs; + int rc; + + lvs = vbdev_get_lvol_store_by_uuid(uuid); + if (lvs == NULL) { + return -ENODEV; + } + + req = calloc(1, sizeof(*req)); + if (req == NULL) { + return -ENOMEM; + } + req->u.lvol_handle.cb_fn = cb_fn; + req->u.lvol_handle.cb_arg = cb_arg; + + rc = spdk_lvol_create(lvs, sz, _vbdev_lvol_create_cb, req); + + return rc; +} + +static void +_vbdev_lvol_resize_cb(void *cb_arg, int lvolerrno) +{ + struct spdk_lvol_store_req *req = cb_arg; + + req->u.lvol_basic.cb_fn(req->u.lvol_basic.cb_arg, lvolerrno); + free(req); +} + +int +vbdev_lvol_resize(char *name, size_t sz, + spdk_lvol_op_complete cb_fn, void *cb_arg) +{ + struct spdk_lvol_store_req *req; + struct spdk_bdev *bdev; + struct spdk_lvol *lvol; + struct spdk_lvol_store *lvs; + uint64_t cluster_size; + int rc; + + lvol = vbdev_get_lvol_by_name(name); + if (lvol == NULL) { + SPDK_ERRLOG("lvol '%s' does not exist\n", name); + return -1; + } + + bdev = spdk_bdev_get_by_name(name); + if (bdev == NULL) { + SPDK_ERRLOG("bdev '%s' does not exist\n", name); + return -1; + } + + if (spdk_is_bdev_opened(bdev)) { + SPDK_ERRLOG("bdev '%s' cannot be resized because it is currently opened\n", name); + return -1; + } + + lvs = lvol->lvol_store; + cluster_size = spdk_bs_get_cluster_size(lvs->blobstore); + + req = calloc(1, sizeof(*req)); + if (req == NULL) { + cb_fn(cb_arg, -1); + return -ENOMEM; + } + req->u.lvol_basic.cb_fn = cb_fn; + req->u.lvol_basic.cb_arg = cb_arg; + + rc = spdk_lvol_resize(lvol, sz, _vbdev_lvol_resize_cb, req); + + if (rc == 0) { + bdev->blockcnt = sz * cluster_size / bdev->blocklen; + } + + return rc; +} + +static int +vbdev_lvs_init(void) +{ + return 0; +} + +static void +vbdev_lvs_fini(void) +{ + struct lvol_store_bdev *lvs_bdev, *tmp; + + TAILQ_FOREACH_SAFE(lvs_bdev, &g_spdk_lvol_pairs, lvol_stores, tmp) { + vbdev_lvs_destruct(lvs_bdev->lvs, NULL, NULL); + } +} + +static int +vbdev_lvs_get_ctx_size(void) +{ + return sizeof(struct lvol_task); +} + +static void +vbdev_lvs_examine(struct spdk_bdev *bdev) +{ + spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(lvol)); +} + +SPDK_BDEV_MODULE_REGISTER(lvol, vbdev_lvs_init, vbdev_lvs_fini, NULL, vbdev_lvs_get_ctx_size, + vbdev_lvs_examine) +SPDK_LOG_REGISTER_TRACE_FLAG("vbdev_lvol", SPDK_TRACE_VBDEV_LVOL); diff --git a/lib/bdev/lvol/vbdev_lvol.h b/lib/bdev/lvol/vbdev_lvol.h new file mode 100644 index 0000000000..1ce8d2f936 --- /dev/null +++ b/lib/bdev/lvol/vbdev_lvol.h @@ -0,0 +1,56 @@ +/*- + * 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_LVOL_H +#define SPDK_VBDEV_LVOL_H + +#include "spdk/lvol.h" +#include "spdk_internal/bdev.h" + +#include "spdk_internal/lvolstore.h" + +struct lvol_store_bdev { + struct spdk_lvol_store *lvs; + struct spdk_bdev *bdev; + + TAILQ_ENTRY(lvol_store_bdev) lvol_stores; +}; +int vbdev_lvs_create(struct spdk_bdev *base_bdev, spdk_lvs_op_with_handle_complete cb_fn, + void *cb_arg); +void vbdev_lvs_destruct(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void *cb_arg); + +int vbdev_lvol_create(uuid_t uuid, size_t sz, spdk_lvol_op_with_handle_complete cb_fn, + void *cb_arg); + +int vbdev_lvol_resize(char *name, size_t sz, spdk_lvol_op_complete cb_fn, void *cb_arg); +#endif /* SPDK_VBDEV_LVOL_H */ diff --git a/lib/bdev/lvol/vbdev_lvol_rpc.c b/lib/bdev/lvol/vbdev_lvol_rpc.c new file mode 100644 index 0000000000..0c958d42a7 --- /dev/null +++ b/lib/bdev/lvol/vbdev_lvol_rpc.c @@ -0,0 +1,380 @@ +/*- + * 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/rpc.h" +#include "spdk/bdev.h" +#include "spdk/util.h" +#include "vbdev_lvol.h" +#include "spdk/string.h" +#include "spdk_internal/log.h" + +SPDK_LOG_REGISTER_TRACE_FLAG("lvolrpc", SPDK_TRACE_LVOL_RPC) + +struct rpc_construct_lvol_store { + char *base_name; +}; + +static void +free_rpc_construct_lvol_store(struct rpc_construct_lvol_store *req) +{ + free(req->base_name); +} + +static const struct spdk_json_object_decoder rpc_construct_lvol_store_decoders[] = { + {"base_name", offsetof(struct rpc_construct_lvol_store, base_name), spdk_json_decode_string}, +}; + +static void +_spdk_rpc_lvol_store_construct_cb(void *cb_arg, struct spdk_lvol_store *lvol_store, int lvserrno) +{ + struct spdk_json_write_ctx *w; + char lvol_store_uuid[37]; + struct spdk_jsonrpc_request *request = cb_arg; + char buf[64]; + + if (lvserrno != 0) { + goto invalid; + } + + uuid_unparse(lvol_store->uuid, lvol_store_uuid); + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_array_begin(w); + spdk_json_write_string(w, lvol_store_uuid); + spdk_json_write_array_end(w); + spdk_jsonrpc_end_result(request, w); + return; + +invalid: + spdk_strerror_r(-lvserrno, buf, sizeof(buf)); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); +} + +static void +spdk_rpc_construct_lvol_store(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_construct_lvol_store req = {}; + struct spdk_bdev *bdev; + int rc; + char buf[64]; + + if (spdk_json_decode_object(params, rpc_construct_lvol_store_decoders, + SPDK_COUNTOF(rpc_construct_lvol_store_decoders), + &req)) { + SPDK_INFOLOG(SPDK_TRACE_LVOL_RPC, "spdk_json_decode_object failed\n"); + rc = -EINVAL; + goto invalid; + } + + if (req.base_name == NULL) { + SPDK_ERRLOG("missing name param\n"); + rc = -EINVAL; + goto invalid; + } + + bdev = spdk_bdev_get_by_name(req.base_name); + if (bdev == NULL) { + SPDK_ERRLOG("bdev '%s' does not exist\n", req.base_name); + rc = -ENODEV; + goto invalid; + } + + rc = vbdev_lvs_create(bdev, _spdk_rpc_lvol_store_construct_cb, request); + if (rc < 0) { + goto invalid; + } + free_rpc_construct_lvol_store(&req); + + return; + +invalid: + spdk_strerror_r(-rc, buf, sizeof(buf)); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); + free_rpc_construct_lvol_store(&req); +} +SPDK_RPC_REGISTER("construct_lvol_store", spdk_rpc_construct_lvol_store) + +struct rpc_destroy_lvol_store { + char *lvol_store_uuid; +}; + +static void +free_rpc_destroy_lvol_store(struct rpc_destroy_lvol_store *req) +{ + free(req->lvol_store_uuid); +} + +static const struct spdk_json_object_decoder rpc_destroy_lvol_store_decoders[] = { + {"lvol_store_uuid", offsetof(struct rpc_destroy_lvol_store, lvol_store_uuid), spdk_json_decode_string}, +}; + +static void +_spdk_rpc_lvol_store_destroy_cb(void *cb_arg, int lvserrno) +{ + struct spdk_json_write_ctx *w; + struct spdk_jsonrpc_request *request = cb_arg; + char buf[64]; + + if (lvserrno != 0) { + goto invalid; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); + return; + +invalid: + spdk_strerror_r(-lvserrno, buf, sizeof(buf)); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); +} + +static void +spdk_rpc_destroy_lvol_store(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_destroy_lvol_store req = {}; + struct spdk_lvol_store *lvs; + uuid_t lvol_store_uuid; + int rc; + char buf[64]; + + if (spdk_json_decode_object(params, rpc_destroy_lvol_store_decoders, + SPDK_COUNTOF(rpc_destroy_lvol_store_decoders), + &req)) { + SPDK_INFOLOG(SPDK_TRACE_LVOL_RPC, "spdk_json_decode_object failed\n"); + rc = -EINVAL; + goto invalid; + } + + if (uuid_parse(req.lvol_store_uuid, lvol_store_uuid)) { + SPDK_INFOLOG(SPDK_TRACE_LVOL_RPC, "incorrect UUID '%s'\n", req.lvol_store_uuid); + rc = -EINVAL; + goto invalid; + } + + lvs = vbdev_get_lvol_store_by_uuid(lvol_store_uuid); + if (lvs == NULL) { + SPDK_INFOLOG(SPDK_TRACE_LVOL_RPC, "blobstore with UUID '%p' not found\n", &lvol_store_uuid); + rc = -ENODEV; + goto invalid; + } + + vbdev_lvs_destruct(lvs, _spdk_rpc_lvol_store_destroy_cb, request); + + free_rpc_destroy_lvol_store(&req); + + return; + +invalid: + spdk_strerror_r(-rc, buf, sizeof(buf)); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); + free_rpc_destroy_lvol_store(&req); +} +SPDK_RPC_REGISTER("destroy_lvol_store", spdk_rpc_destroy_lvol_store) + +struct rpc_construct_lvol_bdev { + char *lvol_store_uuid; + uint64_t size; +}; + +static void +free_rpc_construct_lvol_bdev(struct rpc_construct_lvol_bdev *req) +{ + free(req->lvol_store_uuid); +} + +static const struct spdk_json_object_decoder rpc_construct_lvol_bdev_decoders[] = { + {"lvol_store_uuid", offsetof(struct rpc_construct_lvol_bdev, lvol_store_uuid), spdk_json_decode_string}, + {"size", offsetof(struct rpc_construct_lvol_bdev, size), spdk_json_decode_uint64}, +}; + +static void +_spdk_rpc_construct_lvol_bdev_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno) +{ + struct spdk_json_write_ctx *w; + struct spdk_jsonrpc_request *request = cb_arg; + char buf[64]; + + if (lvolerrno != 0) { + goto invalid; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_array_begin(w); + spdk_json_write_string(w, lvol->name); + spdk_json_write_array_end(w); + spdk_jsonrpc_end_result(request, w); + return; + +invalid: + spdk_strerror_r(-lvolerrno, buf, sizeof(buf)); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); +} + +static void +spdk_rpc_construct_lvol_bdev(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_construct_lvol_bdev req = {}; + uuid_t lvol_store_uuid; + size_t sz; + int rc; + char buf[64]; + + SPDK_INFOLOG(SPDK_TRACE_LVOL_RPC, "Creating blob\n"); + + if (spdk_json_decode_object(params, rpc_construct_lvol_bdev_decoders, + SPDK_COUNTOF(rpc_construct_lvol_bdev_decoders), + &req)) { + SPDK_INFOLOG(SPDK_TRACE_LVOL_RPC, "spdk_json_decode_object failed\n"); + rc = -EINVAL; + goto invalid; + } + + if (uuid_parse(req.lvol_store_uuid, lvol_store_uuid)) { + SPDK_INFOLOG(SPDK_TRACE_LVOL_RPC, "incorrect UUID '%s'\n", req.lvol_store_uuid); + rc = -EINVAL; + goto invalid; + } + + sz = (size_t)req.size; + + rc = vbdev_lvol_create(lvol_store_uuid, sz, _spdk_rpc_construct_lvol_bdev_cb, request); + if (rc < 0) { + goto invalid; + } + + free_rpc_construct_lvol_bdev(&req); + return; + +invalid: + spdk_strerror_r(-rc, buf, sizeof(buf)); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); + free_rpc_construct_lvol_bdev(&req); +} + +SPDK_RPC_REGISTER("construct_lvol_bdev", spdk_rpc_construct_lvol_bdev) + +struct rpc_resize_lvol_bdev { + char *name; + uint64_t size; +}; + +static void +free_rpc_resize_lvol_bdev(struct rpc_resize_lvol_bdev *req) +{ + free(req->name); +} + +static const struct spdk_json_object_decoder rpc_resize_lvol_bdev_decoders[] = { + {"name", offsetof(struct rpc_resize_lvol_bdev, name), spdk_json_decode_string}, + {"size", offsetof(struct rpc_resize_lvol_bdev, size), spdk_json_decode_uint64}, +}; + +static void +_spdk_rpc_resize_lvol_bdev_cb(void *cb_arg, int lvolerrno) +{ + struct spdk_json_write_ctx *w; + struct spdk_jsonrpc_request *request = cb_arg; + char buf[64]; + + if (lvolerrno != 0) { + goto invalid; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); + return; + +invalid: + spdk_strerror_r(-lvolerrno, buf, sizeof(buf)); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); +} + +static void +spdk_rpc_resize_lvol_bdev(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_resize_lvol_bdev req = {}; + int rc = 0; + char buf[64]; + + SPDK_INFOLOG(SPDK_TRACE_LVOL_RPC, "Resizing lvol\n"); + + if (spdk_json_decode_object(params, rpc_resize_lvol_bdev_decoders, + SPDK_COUNTOF(rpc_resize_lvol_bdev_decoders), + &req)) { + SPDK_INFOLOG(SPDK_TRACE_LVOL_RPC, "spdk_json_decode_object failed\n"); + rc = -EINVAL; + goto invalid; + } + + if (req.name == NULL) { + SPDK_ERRLOG("missing name param\n"); + goto invalid; + } + + rc = vbdev_lvol_resize(req.name, (size_t)req.size, _spdk_rpc_resize_lvol_bdev_cb, request); + if (rc < 0) { + goto invalid; + } + + free_rpc_resize_lvol_bdev(&req); + return; + +invalid: + spdk_strerror_r(-rc, buf, sizeof(buf)); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf); + free_rpc_resize_lvol_bdev(&req); +} + +SPDK_RPC_REGISTER("resize_lvol_bdev", spdk_rpc_resize_lvol_bdev) diff --git a/lib/lvol/Makefile b/lib/lvol/Makefile new file mode 100644 index 0000000000..ee3f0e437d --- /dev/null +++ b/lib/lvol/Makefile @@ -0,0 +1,41 @@ +# +# 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) +C_SRCS = lvol.c +LIBNAME = lvol + +include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk diff --git a/lib/lvol/lvol.c b/lib/lvol/lvol.c new file mode 100644 index 0000000000..ac44edb939 --- /dev/null +++ b/lib/lvol/lvol.c @@ -0,0 +1,394 @@ +/*- + * 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_internal/lvolstore.h" +#include "spdk_internal/log.h" +#include "spdk/string.h" +#include "spdk/io_channel.h" + +/* Length of string returned from uuid_unparse() */ +#define UUID_STRING_LEN 37 + +SPDK_LOG_REGISTER_TRACE_FLAG("lvol", SPDK_TRACE_LVOL) + +static void +_lvs_init_cb(void *cb_arg, struct spdk_blob_store *bs, int lvserrno) +{ + struct spdk_lvol_store_req *lvs_req = cb_arg; + struct spdk_lvol_store *lvs = lvs_req->u.lvs_handle.lvol_store; + + if (lvserrno != 0) { + assert(bs == NULL); + SPDK_ERRLOG("Lvol store init failed: could not initialize blobstore\n"); + free(lvs); + lvs = NULL; + } else { + assert(bs != NULL); + lvs->blobstore = bs; + lvs->page_size = spdk_bs_get_page_size(bs); + TAILQ_INIT(&lvs->lvols); + + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Lvol store initialized\n"); + } + assert(lvs_req->u.lvs_handle.cb_fn != NULL); + lvs_req->u.lvs_handle.cb_fn(lvs_req->u.lvs_handle.cb_arg, lvs, lvserrno); + free(lvs_req); +} + +int +spdk_lvs_init(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, + void *cb_arg) +{ + struct spdk_lvol_store *lvs; + struct spdk_lvol_store_req *lvs_req; + + if (bs_dev == NULL) { + SPDK_ERRLOG("Blobstore device does not exist\n"); + return -ENODEV; + } + + lvs = calloc(1, sizeof(*lvs)); + if (!lvs) { + SPDK_ERRLOG("Cannot alloc memory for lvol store base pointer\n"); + return -ENOMEM; + } + + uuid_generate_time(lvs->uuid); + + lvs_req = calloc(1, sizeof(*lvs_req)); + if (!lvs_req) { + free(lvs); + SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n"); + return -ENOMEM; + } + + lvs_req->u.lvs_handle.cb_fn = cb_fn; + lvs_req->u.lvs_handle.cb_arg = cb_arg; + lvs_req->u.lvs_handle.lvol_store = lvs; + lvs->bs_dev = bs_dev; + + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Initializing lvol store\n"); + spdk_bs_init(bs_dev, NULL, _lvs_init_cb, lvs_req); + + return 0; +} + +static void +_lvs_unload_cb(void *cb_arg, int lvserrno) +{ + struct spdk_lvol_store_req *lvs_req = cb_arg; + + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Lvol store unloaded\n"); + assert(lvs_req->u.lvs_basic.cb_fn != NULL); + lvs_req->u.lvs_basic.cb_fn(lvs_req->u.lvs_basic.cb_arg, lvserrno); + free(lvs_req); +} + +int +spdk_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, + void *cb_arg) +{ + struct spdk_lvol_store_req *lvs_req; + + if (lvs == NULL) { + SPDK_ERRLOG("Lvol store is NULL\n"); + return -ENODEV; + } + + lvs_req = calloc(1, sizeof(*lvs_req)); + if (!lvs_req) { + SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n"); + return -ENOMEM; + } + + lvs_req->u.lvs_basic.cb_fn = cb_fn; + lvs_req->u.lvs_basic.cb_arg = cb_arg; + + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Unloading lvol store\n"); + spdk_bs_unload(lvs->blobstore, _lvs_unload_cb, lvs_req); + free(lvs); + + return 0; +} + +static void +_spdk_lvol_return_to_caller(void *cb_arg, int lvolerrno) +{ + struct spdk_lvol_store_req *req = cb_arg; + + assert(req->u.lvol_handle.cb_fn != NULL); + req->u.lvol_handle.cb_fn(req->u.lvol_handle.cb_arg, req->u.lvol_handle.lvol, lvolerrno); + free(req); +} + +static void +_spdk_lvs_destruct_cb(void *cb_arg, int lvserrno) +{ + struct spdk_lvol_store_req *req = cb_arg; + + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Lvol store bdev deleted\n"); + + if (req->u.lvs_basic.cb_fn != NULL) + req->u.lvs_basic.cb_fn(req->u.lvs_basic.cb_arg, lvserrno); + free(req); +} + +static void +_spdk_lvol_close_blob_cb(void *cb_arg, int lvolerrno) +{ + struct spdk_lvol *lvol = cb_arg; + + if (lvolerrno < 0) { + SPDK_ERRLOG("Could not close blob on lvol\n"); + return; + } + + TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link); + + if (lvol->lvol_store->destruct_req && TAILQ_EMPTY(&lvol->lvol_store->lvols)) { + spdk_lvs_unload(lvol->lvol_store, _spdk_lvs_destruct_cb, lvol->lvol_store->destruct_req); + } + + free(lvol->name); + free(lvol); + + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Blob closed on lvol\n"); +} + +static void +_spdk_lvol_delete_blob_cb(void *cb_arg, int lvolerrno) +{ + struct spdk_lvol *lvol = cb_arg; + struct spdk_blob_store *bs = lvol->lvol_store->blobstore; + + if (lvolerrno < 0) { + SPDK_ERRLOG("Could not delete blob on lvol\n"); + return; + } + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Blob closed on lvol\n"); + spdk_bs_md_delete_blob(bs, lvol->blob_id, _spdk_lvol_close_blob_cb, lvol); +} + +static void +_spdk_lvol_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno) +{ + struct spdk_lvol_store_req *req = cb_arg; + spdk_blob_id blob_id = spdk_blob_get_id(blob); + struct spdk_lvol *lvol = req->u.lvol_handle.lvol; + uint64_t cluster_size = spdk_bs_get_cluster_size(lvol->lvol_store->blobstore); + uint64_t number_of_clusters = lvol->sz / cluster_size; + char uuid[UUID_STRING_LEN]; + + if (lvolerrno < 0) { + free(lvol); + goto invalid; + } + + lvol->blob = blob; + lvol->blob_id = blob_id; + + uuid_unparse(lvol->lvol_store->uuid, uuid); + lvol->name = spdk_sprintf_alloc("%s_%"PRIu64, uuid, (uint64_t)blob_id); + if (!lvol->name) { + spdk_bs_md_close_blob(&blob, _spdk_lvol_delete_blob_cb, lvol); + goto invalid; + } + + lvolerrno = spdk_bs_md_resize_blob(blob, number_of_clusters); + if (lvolerrno < 0) { + spdk_bs_md_close_blob(&blob, _spdk_lvol_delete_blob_cb, lvol); + goto invalid; + } + + TAILQ_INSERT_TAIL(&lvol->lvol_store->lvols, lvol, link); + + spdk_bs_md_sync_blob(blob, _spdk_lvol_return_to_caller, req); + + return; + +invalid: + assert(req->u.lvol_handle.cb_fn != NULL); + req->u.lvol_handle.cb_fn(req->u.lvol_handle.cb_arg, NULL, lvolerrno); + free(req); + return; + +} + +static void +_spdk_lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno) +{ + struct spdk_lvol_store_req *req = cb_arg; + struct spdk_blob_store *bs; + + if (lvolerrno < 0) { + free(req->u.lvol_handle.lvol); + assert(req->u.lvol_handle.cb_fn != NULL); + req->u.lvol_handle.cb_fn(req->u.lvol_handle.cb_arg, NULL, lvolerrno); + free(req); + return; + } + + bs = req->u.lvol_handle.lvol->lvol_store->blobstore; + + spdk_bs_md_open_blob(bs, blobid, _spdk_lvol_create_open_cb, req); +} + +int +spdk_lvol_create(struct spdk_lvol_store *lvs, uint64_t sz, + spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_lvol_store_req *req; + struct spdk_lvol *lvol; + uint64_t free_clusters; + + if (lvs == NULL) { + SPDK_ERRLOG("lvol store does not exist\n"); + return -ENODEV; + } + + free_clusters = spdk_bs_free_cluster_count(lvs->blobstore); + if (sz > free_clusters) { + SPDK_ERRLOG("Not enough free clusters left on lvol store to add lvol with %zu clusters\n", sz); + return -ENOMEM; + } + + req = calloc(1, sizeof(*req)); + if (!req) { + SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n"); + return -ENOMEM; + } + req->u.lvol_handle.cb_fn = cb_fn; + req->u.lvol_handle.cb_arg = cb_arg; + + lvol = calloc(1, sizeof(*lvol)); + if (!lvol) { + free(req); + SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n"); + return -ENOMEM; + } + + lvol->lvol_store = lvs; + lvol->sz = sz * spdk_bs_get_cluster_size(lvs->blobstore); + lvol->close_only = false; + req->u.lvol_handle.lvol = lvol; + + spdk_bs_md_create_blob(lvs->blobstore, _spdk_lvol_create_cb, req); + + return 0; +} + +static void +_spdk_lvol_resize_cb(void *cb_arg, int lvolerrno) +{ + struct spdk_lvol_store_req *req = cb_arg; + + req->u.lvol_basic.cb_fn(req->u.lvol_basic.cb_arg, lvolerrno); + free(req); +} + +int +spdk_lvol_resize(struct spdk_lvol *lvol, uint64_t sz, + spdk_lvol_op_complete cb_fn, void *cb_arg) +{ + int rc; + struct spdk_blob *blob = lvol->blob; + struct spdk_lvol_store *lvs = lvol->lvol_store; + struct spdk_lvol_store_req *req; + uint64_t cluster_size = spdk_bs_get_cluster_size(lvs->blobstore); + uint64_t free_clusters = spdk_bs_free_cluster_count(lvs->blobstore); + uint64_t used_clusters = lvol->sz / cluster_size; + + /* Check if size of lvol increasing */ + if (sz > used_clusters) { + /* Check if there is enough clusters left to resize */ + if (sz - used_clusters > free_clusters) { + SPDK_ERRLOG("Not enough free clusters left on lvol store to resize lvol to %zu clusters\n", sz); + return -ENOMEM; + } + } + + req = calloc(1, sizeof(*req)); + if (!req) { + SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n"); + return -ENOMEM; + } + req->u.lvol_basic.cb_fn = cb_fn; + req->u.lvol_basic.cb_arg = cb_arg; + + rc = spdk_bs_md_resize_blob(blob, sz); + if (rc < 0) { + goto invalid; + } + + lvol->sz = sz * cluster_size; + + spdk_blob_md_set_xattr(blob, "length", &sz, sizeof(sz)); + + spdk_bs_md_sync_blob(blob, _spdk_lvol_resize_cb, req); + + return rc; + +invalid: + req->u.lvol_basic.cb_fn(req->u.lvol_basic.cb_arg, rc); + free(req); + return rc; +} + +void +spdk_lvol_destroy(struct spdk_lvol *lvol) +{ + if (lvol == NULL) { + SPDK_ERRLOG("lvol does not exist\n"); + return; + } + + TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link); + spdk_bs_md_close_blob(&(lvol->blob), _spdk_lvol_delete_blob_cb, lvol); +} + +void +spdk_lvol_close(struct spdk_lvol *lvol) +{ + if (lvol == NULL) { + SPDK_ERRLOG("lvol does not exist\n"); + return; + } + + spdk_bs_md_close_blob(&(lvol->blob), _spdk_lvol_close_blob_cb, lvol); +} + +struct spdk_io_channel * +spdk_lvol_get_io_channel(struct spdk_lvol *lvol) +{ + return spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore); +} diff --git a/lib/rocksdb/spdk.rocksdb.mk b/lib/rocksdb/spdk.rocksdb.mk index 0222213d5d..b415b2b57d 100644 --- a/lib/rocksdb/spdk.rocksdb.mk +++ b/lib/rocksdb/spdk.rocksdb.mk @@ -54,11 +54,12 @@ CXXFLAGS += -fno-sanitize=address endif SPDK_LIB_LIST = event_bdev event_copy event_rpc -SPDK_LIB_LIST += blobfs blob bdev blob_bdev copy event util conf trace \ +SPDK_LIB_LIST += blobfs bdev copy event util conf trace \ log jsonrpc json rpc AM_LINK += $(COPY_MODULES_LINKER_ARGS) $(BLOCKDEV_MODULES_LINKER_ARGS) AM_LINK += $(SPDK_LIB_LINKER_ARGS) $(ENV_LINKER_ARGS) +AM_LINK += -luuid ifeq ($(CONFIG_UBSAN),y) AM_LINK += -fsanitize=undefined diff --git a/mk/spdk.common.mk b/mk/spdk.common.mk index 2072122870..4796d6a702 100644 --- a/mk/spdk.common.mk +++ b/mk/spdk.common.mk @@ -127,6 +127,7 @@ CFLAGS += $(COMMON_CFLAGS) -Wno-pointer-sign -Wstrict-prototypes -Wold-style-d CXXFLAGS += $(COMMON_CFLAGS) -std=c++0x SYS_LIBS += -lrt +SYS_LIBS += -luuid MAKEFLAGS += --no-print-directory diff --git a/mk/spdk.modules.mk b/mk/spdk.modules.mk index ebb1f4ba51..bc1e8c062f 100644 --- a/mk/spdk.modules.mk +++ b/mk/spdk.modules.mk @@ -31,7 +31,10 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -BLOCKDEV_MODULES_LIST = bdev_malloc bdev_null bdev_nvme nvme vbdev_error vbdev_gpt vbdev_split +BLOCKDEV_MODULES_LIST = bdev_malloc bdev_null bdev_nvme nvme vbdev_error vbdev_gpt vbdev_lvol vbdev_split + +# Modules below are added as dependency for vbdev_lvol +BLOCKDEV_MODULES_LIST += blob blob_bdev lvol ifeq ($(CONFIG_RDMA),y) BLOCKDEV_MODULES_DEPS += -libverbs -lrdmacm diff --git a/scripts/pkgdep.sh b/scripts/pkgdep.sh index ab02564d39..00510b1de1 100755 --- a/scripts/pkgdep.sh +++ b/scripts/pkgdep.sh @@ -10,7 +10,7 @@ if [ -s /etc/redhat-release ]; then yum --enablerepo=extras install -y epel-release fi yum install -y gcc gcc-c++ make CUnit-devel libaio-devel openssl-devel \ - git astyle-devel python-pep8 lcov python clang-analyzer + git astyle-devel python-pep8 lcov python clang-analyzer libuuid-devel # Additional dependencies for NVMe over Fabrics yum install -y libibverbs-devel librdmacm-devel # Additional dependencies for building docs @@ -18,14 +18,14 @@ if [ -s /etc/redhat-release ]; then elif [ -f /etc/debian_version ]; then # Includes Ubuntu, Debian apt-get install -y gcc g++ make libcunit1-dev libaio-dev libssl-dev \ - git astyle pep8 lcov clang + git astyle pep8 lcov clang uuid-dev # Additional dependencies for NVMe over Fabrics apt-get install -y libibverbs-dev librdmacm-dev # Additional dependencies for building docs apt-get install -y doxygen mscgen elif [ $SYSTEM = "FreeBSD" ] ; then pkg install gmake cunit openssl git devel/astyle bash devel/pep8 \ - python + python misc/e2fsprogs-libuuid # Additional dependencies for building docs pkg install doxygen mscgen else diff --git a/scripts/rpc.py b/scripts/rpc.py index 403cb0f395..c68157abaf 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -247,6 +247,47 @@ p = subparsers.add_parser('construct_error_bdev', help='Add bdev with error inje p.add_argument('base_name', help='base bdev name') p.set_defaults(func=construct_error_bdev) + +def construct_lvol_store(args): + params = {'base_name': args.base_name} + print_array(jsonrpc_call('construct_lvol_store', params)) +p = subparsers.add_parser('construct_lvol_store', help='Add logical volume store on base bdev') +p.add_argument('base_name', help='base bdev name') +p.set_defaults(func=construct_lvol_store) + + +def construct_lvol_bdev(args): + params = { + 'lvol_store_uuid': args.lvol_store_uuid, + 'size': args.size, + } + print_array(jsonrpc_call('construct_lvol_bdev', params)) +p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend') +p.add_argument('lvol_store_uuid', help='lvol store UUID') +p.add_argument('size', help='size in MiB for this bdev', type=int) +p.set_defaults(func=construct_lvol_bdev) + + +def resize_lvol_bdev(args): + params = { + 'name': args.name, + 'size': args.size, + } + jsonrpc_call('resize_lvol_bdev', params) +p = subparsers.add_parser('resize_lvol_bdev', help='Resize existing lvol bdev') +p.add_argument('name', help='lvol bdev name') +p.add_argument('size', help='new size in MiB for this bdev', type=int) +p.set_defaults(func=resize_lvol_bdev) + + +def destroy_lvol_store(args): + params = {'lvol_store_uuid': args.lvol_store_uuid} + jsonrpc_call('destroy_lvol_store', params) +p = subparsers.add_parser('destroy_lvol_store', help='Destroy an logical volume store') +p.add_argument('lvol_store_uuid', help='lvol store UUID') +p.set_defaults(func=destroy_lvol_store) + + def set_trace_flag(args): params = {'flag': args.flag} jsonrpc_call('set_trace_flag', params) diff --git a/test/unit/lib/Makefile b/test/unit/lib/Makefile index 180be1d5aa..462a077ed0 100644 --- a/test/unit/lib/Makefile +++ b/test/unit/lib/Makefile @@ -34,7 +34,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk -DIRS-y = bdev blob blobfs event ioat iscsi json jsonrpc log nvme nvmf scsi util +DIRS-y = bdev blob blobfs event ioat iscsi json jsonrpc log lvol nvme nvmf scsi util ifeq ($(OS),Linux) DIRS-$(CONFIG_VHOST) += vhost endif diff --git a/test/unit/lib/bdev/Makefile b/test/unit/lib/bdev/Makefile index 511c555fa3..0af8e8aa55 100644 --- a/test/unit/lib/bdev/Makefile +++ b/test/unit/lib/bdev/Makefile @@ -34,7 +34,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk -DIRS-y = bdev.c scsi_nvme.c gpt +DIRS-y = bdev.c scsi_nvme.c gpt vbdev_lvol.c .PHONY: all clean $(DIRS-y) diff --git a/test/unit/lib/bdev/vbdev_lvol.c/.gitignore b/test/unit/lib/bdev/vbdev_lvol.c/.gitignore new file mode 100644 index 0000000000..5f2f6fdff4 --- /dev/null +++ b/test/unit/lib/bdev/vbdev_lvol.c/.gitignore @@ -0,0 +1 @@ +vbdev_lvol_ut diff --git a/test/unit/lib/bdev/vbdev_lvol.c/Makefile b/test/unit/lib/bdev/vbdev_lvol.c/Makefile new file mode 100644 index 0000000000..03a4eca21b --- /dev/null +++ b/test/unit/lib/bdev/vbdev_lvol.c/Makefile @@ -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. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../../) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk +include $(SPDK_ROOT_DIR)/mk/spdk.app.mk + +APP = vbdev_lvol_ut + +C_SRCS := vbdev_lvol_ut.c +CFLAGS += -I$(SPDK_ROOT_DIR)/test +CFLAGS += -I$(SPDK_ROOT_DIR)/lib/bdev/lvol +CFLAGS += -I$(SPDK_ROOT_DIR)/lib/lvol/bdev + +SPDK_LIB_LIST = log util + +LIBS += $(SPDK_LIB_LINKER_ARGS) -lcunit + +all : $(APP) + +$(APP) : $(OBJS) $(SPDK_LIB_FILES) + $(LINK_C) + +clean : + $(CLEAN_C) $(APP) + +include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk diff --git a/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c b/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c new file mode 100644 index 0000000000..f0b371352d --- /dev/null +++ b/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c @@ -0,0 +1,505 @@ +/*- + * 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_cunit.h" +#include "spdk/string.h" + +#include "vbdev_lvol.c" + +int g_lvolerrno; +int g_lvserrno; +int g_cluster_size; +struct spdk_lvol_store *g_lvs = NULL; +struct spdk_lvol *g_lvol = NULL; +struct lvol_store_bdev *g_lvs_bdev = NULL; +struct spdk_bdev *g_base_bdev = NULL; + + +static struct spdk_bdev g_bdev = {}; +static struct spdk_bs_dev *g_bs_dev = NULL; +static struct spdk_lvol_store *g_lvol_store = NULL; +bool lvol_store_initialize_fail = false; +bool lvol_store_initialize_cb_fail = false; +bool lvol_already_opened = false; + +void +spdk_bdev_unregister(struct spdk_bdev *bdev) +{ + return; +} + +static void +bdev_blob_destroy(struct spdk_bs_dev *bs_dev) +{ + CU_ASSERT(g_bs_dev != NULL); + CU_ASSERT(bs_dev != NULL); + CU_ASSERT(g_bs_dev == bs_dev); + free(bs_dev); + g_bs_dev = NULL; + lvol_already_opened = false; +} + +struct spdk_bs_dev * +spdk_bdev_create_bs_dev(struct spdk_bdev *bdev) +{ + struct spdk_bs_dev *bs_dev; + + if (lvol_already_opened == true) + return NULL; + + lvol_already_opened = true; + + bs_dev = calloc(1, sizeof(*bs_dev)); + bs_dev->destroy = bdev_blob_destroy; + + CU_ASSERT(g_bs_dev == NULL); + g_bs_dev = bs_dev; + return bs_dev; +} + +int +spdk_lvs_init(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_lvol_store *lvs; + int error = 0; + + if (lvol_store_initialize_fail) + return -1; + + if (lvol_store_initialize_cb_fail) { + lvs = NULL; + error = -1; + } else { + lvs = calloc(1, sizeof(*lvs)); + lvs->bs_dev = bs_dev; + error = 0; + } + cb_fn(cb_arg, lvs, error); + + return 0; +} + +int +spdk_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, + void *cb_arg) +{ + struct spdk_lvol_store_req *req = cb_arg; + free(req); + free(lvs); + + return 0; +} + +int +spdk_lvol_resize(struct spdk_lvol *lvol, size_t sz, + spdk_lvol_op_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, 0); + + return 0; +} + +uint64_t +spdk_bs_get_cluster_size(struct spdk_blob_store *bs) +{ + return g_cluster_size; +} + +struct spdk_bdev * +spdk_bdev_get_by_name(const char *bdev_name) +{ + if (!strcmp(g_base_bdev->name, bdev_name)) { + return g_base_bdev; + } + + return NULL; +} + +void +spdk_lvol_close(struct spdk_lvol *lvol) +{ +} + +void +spdk_lvol_destroy(struct spdk_lvol *lvol) +{ + SPDK_CU_ASSERT_FATAL(lvol == g_lvol); + free(lvol->name); + free(lvol); + g_lvol = NULL; +} + +bool +spdk_is_bdev_opened(struct spdk_bdev *bdev) +{ + struct spdk_bdev *base; + + if (bdev->bdev_opened) { + return true; + } + + TAILQ_FOREACH(base, &bdev->base_bdevs, base_bdev_link) { + if (spdk_is_bdev_opened(base)) { + return true; + } + } + + return false; +} + +void +spdk_bdev_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status status) +{ +} + +struct spdk_io_channel *spdk_lvol_get_io_channel(struct spdk_lvol *lvol) +{ + return NULL; +} + +void +spdk_bdev_io_get_buf(struct spdk_bdev_io *bdev_io, spdk_bdev_io_get_buf_cb cb) +{ +} + +void +spdk_bs_io_read_blob(struct spdk_blob *blob, struct spdk_io_channel *channel, + void *payload, uint64_t offset, uint64_t length, + spdk_blob_op_complete cb_fn, void *cb_arg) +{ +} + +void +spdk_bs_io_write_blob(struct spdk_blob *blob, struct spdk_io_channel *channel, + void *payload, uint64_t offset, uint64_t length, + spdk_blob_op_complete cb_fn, void *cb_arg) +{ +} + +void +spdk_bs_io_writev_blob(struct spdk_blob *blob, struct spdk_io_channel *channel, + struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length, + spdk_blob_op_complete cb_fn, void *cb_arg) +{ +} + +void +spdk_bs_io_readv_blob(struct spdk_blob *blob, struct spdk_io_channel *channel, + struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length, + spdk_blob_op_complete cb_fn, void *cb_arg) +{ +} + +void +spdk_bs_io_flush_channel(struct spdk_io_channel *channel, spdk_blob_op_complete cb_fn, void *cb_arg) +{ +} + +void +spdk_bdev_module_list_add(struct spdk_bdev_module_if *bdev_module) +{ +} + +int +spdk_json_write_name(struct spdk_json_write_ctx *w, const char *name) +{ + return 0; +} + +int +spdk_json_write_string(struct spdk_json_write_ctx *w, const char *val) +{ + return 0; +} + +const char * +spdk_bdev_get_name(const struct spdk_bdev *bdev) +{ + return "test"; +} + +void +spdk_bdev_register(struct spdk_bdev *bdev) +{ +} + +void +spdk_bdev_module_examine_done(struct spdk_bdev_module_if *module) +{ +} + +int +spdk_lvol_create(struct spdk_lvol_store *lvs, size_t sz, spdk_lvol_op_with_handle_complete cb_fn, + void *cb_arg) +{ + struct spdk_lvol *lvol = calloc(1, sizeof(*lvol)); + + SPDK_CU_ASSERT_FATAL(lvol != NULL); + + + lvol->lvol_store = lvs; + lvol->sz = sz * 1024 * 1024; + lvol->name = spdk_sprintf_alloc("%s", "UNIT_TEST_UUID"); + SPDK_CU_ASSERT_FATAL(lvol->name != NULL); + + TAILQ_INIT(&lvs->lvols); + TAILQ_INSERT_TAIL(&lvol->lvol_store->lvols, lvol, link); + + cb_fn(cb_arg, lvol, 0); + + return 0; +} + +static void +lvol_store_op_complete(void *cb_arg, int lvserrno) +{ + g_lvserrno = lvserrno; + return; +} + +static void +lvol_store_op_with_handle_complete(void *cb_arg, struct spdk_lvol_store *lvs, int lvserrno) +{ + g_lvserrno = lvserrno; + g_lvol_store = lvs; + return; +} + +static void +vbdev_lvol_create_complete(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno) +{ + g_lvolerrno = lvolerrno; + g_lvol = lvol; +} + +static void +vbdev_lvol_resize_complete(void *cb_arg, int lvolerrno) +{ + g_lvolerrno = lvolerrno; +} + +static void +ut_lvol_init(void) +{ + uuid_t wrong_uuid; + int sz = 10; + int rc; + + g_lvs = calloc(1, sizeof(*g_lvs)); + g_lvs_bdev = calloc(1, sizeof(*g_lvs_bdev)); + g_base_bdev = calloc(1, sizeof(*g_base_bdev)); + + g_lvs_bdev->lvs = g_lvs; + g_lvs_bdev->bdev = g_base_bdev; + + SPDK_CU_ASSERT_FATAL(g_lvs != NULL); + + uuid_generate_time(g_lvs->uuid); + uuid_generate_time(wrong_uuid); + g_lvs->page_size = 4096; + + /* Incorrect uuid set */ + g_lvolerrno = 0; + rc = vbdev_lvol_create(wrong_uuid, sz, vbdev_lvol_create_complete, NULL); + CU_ASSERT(rc == -ENODEV); + + TAILQ_INSERT_TAIL(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores); + + /* Successful lvol create */ + g_lvolerrno = -1; + rc = vbdev_lvol_create(g_lvs->uuid, sz, vbdev_lvol_create_complete, NULL); + SPDK_CU_ASSERT_FATAL(rc == 0); + CU_ASSERT(g_lvol != NULL); + CU_ASSERT(g_lvolerrno == 0); + + /* Successful lvol destruct */ + vbdev_lvol_destruct(g_lvol); + CU_ASSERT(g_lvol == NULL); + + TAILQ_REMOVE(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores); + + free(g_lvs); + free(g_lvs_bdev); + free(g_base_bdev); + + +} +static void +ut_lvol_resize(void) +{ + int sz = 10; + int rc = 0; + + g_lvs = calloc(1, sizeof(*g_lvs)); + g_lvs_bdev = calloc(1, sizeof(*g_lvs_bdev)); + g_base_bdev = calloc(1, sizeof(*g_base_bdev)); + g_lvs_bdev->lvs = g_lvs; + g_lvs_bdev->bdev = g_base_bdev; + + + uuid_generate_time(g_lvs->uuid); + g_lvs->page_size = 4096; + g_base_bdev->blocklen = 4096; + TAILQ_INSERT_TAIL(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores); + + /* Successful lvol create */ + g_lvolerrno = -1; + rc = vbdev_lvol_create(g_lvs->uuid, sz, vbdev_lvol_create_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvolerrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + g_base_bdev->bdev_opened = false; + g_base_bdev->ctxt = g_lvol; + + g_base_bdev->name = spdk_sprintf_alloc("%s", g_lvol->name); + + /* Successful lvol resize */ + rc = vbdev_lvol_resize(g_lvol->name, 20, vbdev_lvol_resize_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_base_bdev->blockcnt == 20 * g_cluster_size / g_base_bdev->blocklen); + + /* Resize while bdev is open */ + g_base_bdev->bdev_opened = true; + rc = vbdev_lvol_resize(g_lvol->name, 20, vbdev_lvol_resize_complete, NULL); + CU_ASSERT(rc != 0); + + /* Resize with wrong bdev name */ + g_base_bdev->bdev_opened = false; + rc = vbdev_lvol_resize("wrong name", 20, vbdev_lvol_resize_complete, NULL); + CU_ASSERT(rc != 0); + + /* Resize with correct bdev name, but wrong lvol name */ + sprintf(g_lvol->name, "wrong name"); + rc = vbdev_lvol_resize(g_base_bdev->name, 20, vbdev_lvol_resize_complete, NULL); + CU_ASSERT(rc != 0); + + /* Successful lvol destruct */ + vbdev_lvol_destruct(g_lvol); + CU_ASSERT(g_lvol == NULL); + + TAILQ_REMOVE(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores); + free(g_lvs); + free(g_lvs_bdev); + free(g_base_bdev->name); + free(g_base_bdev); +} + +static void +ut_lvs_init(void) +{ + int rc = 0; + struct spdk_lvol_store *lvs; + struct spdk_bs_dev *bs_dev_temp; + + /* spdk_lvs_init() fails */ + lvol_store_initialize_fail = true; + + rc = vbdev_lvs_create(&g_bdev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(g_bs_dev == NULL); + + lvol_store_initialize_fail = false; + + /* spdk_lvs_init_cb() fails */ + lvol_store_initialize_cb_fail = true; + + rc = vbdev_lvs_create(&g_bdev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno != 0); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(g_bs_dev == NULL); + + lvol_store_initialize_cb_fail = false; + + /* Lvol store is succesfully created */ + rc = vbdev_lvs_create(&g_bdev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(g_lvol_store != NULL); + CU_ASSERT(g_bs_dev != NULL); + + lvs = g_lvol_store; + g_lvol_store = NULL; + bs_dev_temp = g_bs_dev; + g_bs_dev = NULL; + + /* Bdev with lvol store already claimed */ + rc = vbdev_lvs_create(&g_bdev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(g_bs_dev == NULL); + + /* Destruct lvol store */ + g_bs_dev = bs_dev_temp; + + vbdev_lvs_destruct(lvs, lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(g_lvol_store == NULL); + free(g_bs_dev); + +} + +int main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + if (CU_initialize_registry() != CUE_SUCCESS) { + return CU_get_error(); + } + + suite = CU_add_suite("lvol", NULL, NULL); + if (suite == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + CU_add_test(suite, "ut_lvs_init", ut_lvs_init) == NULL || + CU_add_test(suite, "ut_lvol_init", ut_lvol_init) == NULL || + CU_add_test(suite, "ut_lvol_resize", ut_lvol_resize) == NULL + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + return num_failures; +} diff --git a/test/unit/lib/lvol/Makefile b/test/unit/lib/lvol/Makefile new file mode 100644 index 0000000000..c9276de473 --- /dev/null +++ b/test/unit/lib/lvol/Makefile @@ -0,0 +1,44 @@ +# +# 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 + +DIRS-y = lvol.c + +.PHONY: all clean $(DIRS-y) + +all: $(DIRS-y) +clean: $(DIRS-y) + +include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk diff --git a/test/unit/lib/lvol/lvol.c/.gitignore b/test/unit/lib/lvol/lvol.c/.gitignore new file mode 100644 index 0000000000..57e92bfe1d --- /dev/null +++ b/test/unit/lib/lvol/lvol.c/.gitignore @@ -0,0 +1 @@ +lvol_ut diff --git a/test/unit/lib/lvol/lvol.c/Makefile b/test/unit/lib/lvol/lvol.c/Makefile new file mode 100644 index 0000000000..71123992e9 --- /dev/null +++ b/test/unit/lib/lvol/lvol.c/Makefile @@ -0,0 +1,56 @@ +# +# 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 +include $(SPDK_ROOT_DIR)/mk/spdk.app.mk + +SPDK_LIB_LIST = util log + +CFLAGS += -I$(SPDK_ROOT_DIR)/test +CFLAGS += -I$(SPDK_ROOT_DIR)/lib/lvol +LIBS += $(SPDK_LIB_LINKER_ARGS) +LIBS += -lcunit + +APP = lvol_ut +C_SRCS := lvol_ut.c + +all : $(APP) + +$(APP) : $(OBJS) $(SPDK_LIB_FILES) + $(LINK_C) + +clean : + $(CLEAN_C) $(APP) + +include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk diff --git a/test/unit/lib/lvol/lvol.c/lvol_ut.c b/test/unit/lib/lvol/lvol.c/lvol_ut.c new file mode 100644 index 0000000000..b59d5214b0 --- /dev/null +++ b/test/unit/lib/lvol/lvol.c/lvol_ut.c @@ -0,0 +1,482 @@ +/*- + * 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_cunit.h" +#include "spdk/blob.h" +#include "spdk/io_channel.h" + +#include "lib/test_env.c" + +#include "lvol.c" + +#define DEV_BUFFER_SIZE (64 * 1024 * 1024) +#define DEV_BUFFER_BLOCKLEN (4096) +#define DEV_BUFFER_BLOCKCNT (DEV_BUFFER_SIZE / DEV_BUFFER_BLOCKLEN) +#define DEV_FREE_CLUSTERS 0xFFFF + +int g_lvserrno; +int g_resize_rc; +struct spdk_lvol_store *g_lvol_store; +struct spdk_lvol *g_lvol; +struct spdk_blob_store {}; + +struct spdk_io_channel *spdk_bs_alloc_io_channel(struct spdk_blob_store *bs) +{ + return NULL; +} + +int +spdk_blob_md_set_xattr(struct spdk_blob *blob, const char *name, const void *value, + uint16_t value_len) +{ + return 0; +} + +uint64_t +spdk_bs_get_page_size(struct spdk_blob_store *bs) +{ + return 0; +} + +static void +init_dev(struct spdk_bs_dev *dev) +{ + dev->blockcnt = DEV_BUFFER_BLOCKCNT; + dev->blocklen = DEV_BUFFER_BLOCKLEN; + return; +} + +void +spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o, + spdk_bs_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_blob_store *bs; + + bs = calloc(1, sizeof(*bs)); + + cb_fn(cb_arg, bs, 0); +} + +void +spdk_bs_unload(struct spdk_blob_store *bs, spdk_bs_op_complete cb_fn, void *cb_arg) +{ + free(bs); + + cb_fn(cb_arg, 0); +} + +void +spdk_bs_md_delete_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, + spdk_blob_op_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, 0); +} + +spdk_blob_id +spdk_blob_get_id(struct spdk_blob *blob) +{ + spdk_blob_id id = 0; + return id; +} + +uint64_t +spdk_bs_get_cluster_size(struct spdk_blob_store *bs) +{ + return DEV_BUFFER_BLOCKLEN; +} + +void spdk_bs_md_close_blob(struct spdk_blob **b, + spdk_blob_op_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, 0); +} + +int +spdk_bs_md_resize_blob(struct spdk_blob *blob, uint64_t sz) +{ + return g_resize_rc; +} + +void +spdk_bs_md_sync_blob(struct spdk_blob *blob, + spdk_blob_op_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, 0); +} + +void +spdk_bs_md_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, + spdk_blob_op_with_handle_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, NULL, 0); +} + +uint64_t +spdk_bs_free_cluster_count(struct spdk_blob_store *bs) +{ + return DEV_FREE_CLUSTERS; +} + +void +spdk_bs_md_create_blob(struct spdk_blob_store *bs, + spdk_blob_op_with_id_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, 0, 0); +} + +static void +_lvol_send_msg(spdk_thread_fn fn, void *ctx, void *thread_ctx) +{ + fn(ctx); +} + +static void +lvol_store_op_with_handle_complete(void *cb_arg, struct spdk_lvol_store *lvol_store, int lvserrno) +{ + g_lvol_store = lvol_store; + g_lvserrno = lvserrno; +} +static void +lvol_op_with_handle_complete(void *cb_arg, struct spdk_lvol *lvol, int lvserrno) +{ + g_lvol = lvol; + g_lvserrno = lvserrno; +} + +static void +lvol_store_op_complete(void *cb_arg, int lvserrno) +{ + g_lvserrno = lvserrno; +} + +static void +lvs_init_unload_success(void) +{ + struct spdk_bs_dev bs_dev; + int rc = 0; + + init_dev(&bs_dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + g_lvserrno = -1; + rc = spdk_lvs_init(&bs_dev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +static void +lvs_unload_lvs_is_null_fail(void) +{ + int rc = 0; + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + g_lvserrno = -1; + rc = spdk_lvs_unload(NULL, lvol_store_op_complete, NULL); + CU_ASSERT(rc == -ENODEV); + CU_ASSERT(g_lvserrno == -1); + + spdk_free_thread(); +} + +static void +lvol_create_destroy_success(void) +{ + struct spdk_bs_dev bs_dev; + int rc = 0; + + init_dev(&bs_dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + g_lvserrno = -1; + rc = spdk_lvs_init(&bs_dev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, 10, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + spdk_lvol_destroy(g_lvol); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +static void +lvol_create_fail(void) +{ + struct spdk_bs_dev bs_dev; + int rc = 0; + + init_dev(&bs_dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + g_lvol_store = NULL; + g_lvserrno = 0; + rc = spdk_lvs_init(NULL, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvol_store == NULL); + + rc = spdk_lvs_init(&bs_dev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + g_lvol = NULL; + rc = spdk_lvol_create(NULL, 10, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvol == NULL); + + rc = spdk_lvol_create(g_lvol_store, DEV_FREE_CLUSTERS + 1, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvol == NULL); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +static void +lvol_destroy_fail(void) +{ + struct spdk_bs_dev bs_dev; + int rc = 0; + + init_dev(&bs_dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + rc = spdk_lvs_init(&bs_dev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, 10, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + spdk_lvol_destroy(g_lvol); + // nothing to check here... it should just still work + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +static void +lvol_close_fail(void) +{ + struct spdk_bs_dev bs_dev; + int rc = 0; + + init_dev(&bs_dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + rc = spdk_lvs_init(&bs_dev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, 10, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + spdk_lvol_close(g_lvol); + // nothing to check here... it should just still work + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +static void +lvol_close_success(void) +{ + struct spdk_bs_dev bs_dev; + int rc = 0; + + init_dev(&bs_dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + g_lvserrno = -1; + rc = spdk_lvs_init(&bs_dev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, 10, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + spdk_lvol_close(g_lvol); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +static void +lvol_resize(void) +{ + struct spdk_bs_dev bs_dev; + int rc = 0; + + init_dev(&bs_dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + g_resize_rc = 0; + g_lvserrno = -1; + rc = spdk_lvs_init(&bs_dev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, 10, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + /* Resize to same size */ + rc = spdk_lvol_resize(g_lvol, 10, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + + /* Resize to smaller size */ + rc = spdk_lvol_resize(g_lvol, 5, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + + /* Resize to bigger size */ + rc = spdk_lvol_resize(g_lvol, 15, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + + /* Resize to size = 0 */ + rc = spdk_lvol_resize(g_lvol, 0, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + + /* Resize to bigger size than available */ + rc = spdk_lvol_resize(g_lvol, 0xFFFFFFFF, lvol_store_op_complete, NULL); + CU_ASSERT(rc != 0); + + /* Fail resize */ + g_resize_rc = -1; + g_lvserrno = 0; + rc = spdk_lvol_resize(g_lvol, 10, lvol_store_op_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvserrno != 0); + + spdk_lvol_destroy(g_lvol); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +int main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + if (CU_initialize_registry() != CUE_SUCCESS) { + return CU_get_error(); + } + + suite = CU_add_suite("lvol", NULL, NULL); + if (suite == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + CU_add_test(suite, "lvs_init_unload_success", lvs_init_unload_success) == NULL || + CU_add_test(suite, "lvs_unload_lvs_is_null_fail", lvs_unload_lvs_is_null_fail) == NULL || + CU_add_test(suite, "lvol_create_destroy_success", lvol_create_destroy_success) == NULL || + CU_add_test(suite, "lvol_create_fail", lvol_create_fail) == NULL || + CU_add_test(suite, "lvol_destroy_fail", lvol_destroy_fail) == NULL || + CU_add_test(suite, "lvol_close_fail", lvol_close_fail) == NULL || + CU_add_test(suite, "lvol_close_success", lvol_close_success) == NULL || + CU_add_test(suite, "lvol_resize", lvol_resize) == NULL + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return num_failures; +} diff --git a/unittest.sh b/unittest.sh index 4e8a5f5cc0..01a0c10f64 100755 --- a/unittest.sh +++ b/unittest.sh @@ -44,6 +44,7 @@ fi $valgrind test/unit/lib/bdev/bdev.c/bdev_ut $valgrind test/unit/lib/bdev/scsi_nvme.c/scsi_nvme_ut $valgrind test/unit/lib/bdev/gpt/gpt.c/gpt_ut +$valgrind test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut $valgrind test/unit/lib/blob/blob.c/blob_ut $valgrind test/unit/lib/blobfs/tree.c/tree_ut @@ -84,6 +85,8 @@ $valgrind test/unit/lib/scsi/lun.c/lun_ut $valgrind test/unit/lib/scsi/scsi.c/scsi_ut $valgrind test/unit/lib/scsi/scsi_bdev.c/scsi_bdev_ut +$valgrind test/unit/lib/lvol/lvol.c/lvol_ut + $valgrind test/unit/lib/iscsi/param.c/param_ut $valgrind test/unit/lib/iscsi/tgt_node.c/tgt_node_ut test/unit/lib/iscsi/tgt_node.c/tgt_node.conf $valgrind test/unit/lib/iscsi/iscsi.c/iscsi_ut