lvol: Logical volume implementation

Change-Id: Ia96ae78ff9530d953181ac5f7255a38f3c8ec430
Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Signed-off-by: Maciej Szwed <maciej.szwed@intel.com>
Signed-off-by: Piotr Pelplinski <piotr.pelplinski@intel.com>
Reviewed-on: https://review.gerrithub.io/375392
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Tomasz Zawadzki 2017-09-14 16:53:36 +02:00 committed by Jim Harris
parent 0caab4e1da
commit 27f44662ac
28 changed files with 2892 additions and 9 deletions

View File

@ -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

68
include/spdk/lvol.h Normal file
View File

@ -0,0 +1,68 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* Logical Volume Interface
*/
#ifndef SPDK_LVOL_H
#define SPDK_LVOL_H
#include "spdk/queue.h"
#include "spdk/blob.h"
#include <uuid/uuid.h>
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 */

View File

@ -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)
{

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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);

40
lib/bdev/lvol/Makefile Normal file
View File

@ -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

578
lib/bdev/lvol/vbdev_lvol.c Normal file
View File

@ -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);

View File

@ -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 */

View File

@ -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)

41
lib/lvol/Makefile Normal file
View File

@ -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

394
lib/lvol/lvol.c Normal file
View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -0,0 +1 @@
vbdev_lvol_ut

View File

@ -0,0 +1,57 @@
#
# BSD LICENSE
#
# Copyright (c) Intel Corporation.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
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

View File

@ -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;
}

View File

@ -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

1
test/unit/lib/lvol/lvol.c/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
lvol_ut

View File

@ -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

View File

@ -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;
}

View File

@ -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