bdev/zone: Register/unregister zoned bdev
Add registration and unregistration of block zoned bdev. Attach it to the underlying bdev during creation and unattach at deletion. Signed-off-by: Mateusz Kozlowski <mateusz.kozlowski@intel.com> Change-Id: I773aff6c7609952f28c02dd1794f0529a781b2e1 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/468033 Community-CI: Broadcom SPDK FC-NVMe CI <spdk-ci.pdl@broadcom.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
76be5ff6f0
commit
cabbe1b179
@ -112,7 +112,6 @@ DEPDIRS-bdev_gpt := bdev conf json log thread util
|
||||
|
||||
DEPDIRS-bdev_lvol := $(BDEV_DEPS) lvol blob blob_bdev
|
||||
DEPDIRS-bdev_rpc := $(BDEV_DEPS)
|
||||
DEPDIRS-bdev_zone_block := $(BDEV_DEPS)
|
||||
|
||||
DEPDIRS-bdev_error := $(BDEV_DEPS_CONF)
|
||||
DEPDIRS-bdev_malloc := $(BDEV_DEPS_CONF) copy
|
||||
@ -120,6 +119,7 @@ DEPDIRS-bdev_split := $(BDEV_DEPS_CONF)
|
||||
|
||||
DEPDIRS-bdev_compress := $(BDEV_DEPS_THREAD) reduce
|
||||
DEPDIRS-bdev_delay := $(BDEV_DEPS_THREAD)
|
||||
DEPDIRS-bdev_zone_block := $(BDEV_DEPS_THREAD)
|
||||
|
||||
DEPDIRS-bdev_aio := $(BDEV_DEPS_CONF_THREAD)
|
||||
DEPDIRS-bdev_crypto := $(BDEV_DEPS_CONF_THREAD)
|
||||
|
@ -40,6 +40,374 @@
|
||||
|
||||
#include "spdk_internal/log.h"
|
||||
|
||||
static int zone_block_init(void);
|
||||
static int zone_block_get_ctx_size(void);
|
||||
static void zone_block_finish(void);
|
||||
static int zone_block_config_json(struct spdk_json_write_ctx *w);
|
||||
static void zone_block_examine(struct spdk_bdev *bdev);
|
||||
|
||||
static struct spdk_bdev_module bdev_zoned_if = {
|
||||
.name = "bdev_zoned_block",
|
||||
.module_init = zone_block_init,
|
||||
.module_fini = zone_block_finish,
|
||||
.config_text = NULL,
|
||||
.config_json = zone_block_config_json,
|
||||
.examine_config = zone_block_examine,
|
||||
.get_ctx_size = zone_block_get_ctx_size,
|
||||
};
|
||||
|
||||
SPDK_BDEV_MODULE_REGISTER(bdev_zoned_block, &bdev_zoned_if)
|
||||
|
||||
/* List of block vbdev names and their base bdevs via configuration file.
|
||||
* Used so we can parse the conf once at init and use this list in examine().
|
||||
*/
|
||||
struct bdev_zone_block_config {
|
||||
char *vbdev_name;
|
||||
char *bdev_name;
|
||||
uint64_t zone_capacity;
|
||||
uint64_t optimal_open_zones;
|
||||
TAILQ_ENTRY(bdev_zone_block_config) link;
|
||||
};
|
||||
static TAILQ_HEAD(, bdev_zone_block_config) g_bdev_configs = TAILQ_HEAD_INITIALIZER(g_bdev_configs);
|
||||
|
||||
/* List of block vbdevs and associated info for each. */
|
||||
struct bdev_zone_block {
|
||||
struct spdk_bdev bdev; /* the block zoned bdev */
|
||||
struct spdk_bdev_desc *base_desc; /* its descriptor we get from open */
|
||||
uint64_t zone_capacity; /* zone capacity */
|
||||
TAILQ_ENTRY(bdev_zone_block) link;
|
||||
};
|
||||
static TAILQ_HEAD(, bdev_zone_block) g_bdev_nodes = TAILQ_HEAD_INITIALIZER(g_bdev_nodes);
|
||||
|
||||
struct zone_block_io_channel {
|
||||
struct spdk_io_channel *base_ch; /* IO channel of base device */
|
||||
};
|
||||
|
||||
struct zone_block_io {
|
||||
/* bdev IO was issued to */
|
||||
struct bdev_zone_block *bdev_zone_block;
|
||||
};
|
||||
|
||||
static int
|
||||
zone_block_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
zone_block_remove_config(struct bdev_zone_block_config *name)
|
||||
{
|
||||
TAILQ_REMOVE(&g_bdev_configs, name, link);
|
||||
free(name->bdev_name);
|
||||
free(name->vbdev_name);
|
||||
free(name);
|
||||
}
|
||||
|
||||
static void
|
||||
zone_block_finish(void)
|
||||
{
|
||||
struct bdev_zone_block_config *name;
|
||||
|
||||
while ((name = TAILQ_FIRST(&g_bdev_configs))) {
|
||||
zone_block_remove_config(name);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
zone_block_get_ctx_size(void)
|
||||
{
|
||||
return sizeof(struct zone_block_io);
|
||||
}
|
||||
|
||||
static int
|
||||
zone_block_config_json(struct spdk_json_write_ctx *w)
|
||||
{
|
||||
struct bdev_zone_block *bdev_node;
|
||||
struct spdk_bdev *base_bdev = NULL;
|
||||
|
||||
TAILQ_FOREACH(bdev_node, &g_bdev_nodes, link) {
|
||||
base_bdev = spdk_bdev_desc_get_bdev(bdev_node->base_desc);
|
||||
spdk_json_write_object_begin(w);
|
||||
spdk_json_write_named_string(w, "method", "bdev_zone_block_create");
|
||||
spdk_json_write_named_object_begin(w, "params");
|
||||
spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(base_bdev));
|
||||
spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&bdev_node->bdev));
|
||||
spdk_json_write_named_uint64(w, "zone_capacity", bdev_node->zone_capacity);
|
||||
spdk_json_write_named_uint64(w, "optimal_open_zones", bdev_node->bdev.optimal_open_zones);
|
||||
spdk_json_write_object_end(w);
|
||||
spdk_json_write_object_end(w);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Callback for unregistering the IO device. */
|
||||
static void
|
||||
_device_unregister_cb(void *io_device)
|
||||
{
|
||||
struct bdev_zone_block *bdev_node = io_device;
|
||||
|
||||
free(bdev_node->bdev.name);
|
||||
free(bdev_node);
|
||||
}
|
||||
|
||||
static int
|
||||
zone_block_destruct(void *ctx)
|
||||
{
|
||||
struct bdev_zone_block *bdev_node = (struct bdev_zone_block *)ctx;
|
||||
|
||||
TAILQ_REMOVE(&g_bdev_nodes, bdev_node, link);
|
||||
|
||||
/* Unclaim the underlying bdev. */
|
||||
spdk_bdev_module_release_bdev(spdk_bdev_desc_get_bdev(bdev_node->base_desc));
|
||||
|
||||
/* Close the underlying bdev. */
|
||||
spdk_bdev_close(bdev_node->base_desc);
|
||||
|
||||
/* Unregister the io_device. */
|
||||
spdk_io_device_unregister(bdev_node, _device_unregister_cb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
zone_block_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
||||
{
|
||||
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
||||
}
|
||||
|
||||
static bool
|
||||
zone_block_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct spdk_io_channel *
|
||||
zone_block_get_io_channel(void *ctx)
|
||||
{
|
||||
struct bdev_zone_block *bdev_node = (struct bdev_zone_block *)ctx;
|
||||
|
||||
return spdk_get_io_channel(bdev_node);
|
||||
}
|
||||
|
||||
static int
|
||||
zone_block_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
|
||||
{
|
||||
struct bdev_zone_block *bdev_node = (struct bdev_zone_block *)ctx;
|
||||
struct spdk_bdev *base_bdev = spdk_bdev_desc_get_bdev(bdev_node->base_desc);
|
||||
|
||||
spdk_json_write_name(w, "zoned_block");
|
||||
spdk_json_write_object_begin(w);
|
||||
spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&bdev_node->bdev));
|
||||
spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(base_bdev));
|
||||
spdk_json_write_named_uint64(w, "zone_capacity", bdev_node->zone_capacity);
|
||||
spdk_json_write_named_uint64(w, "optimal_open_zones", bdev_node->bdev.optimal_open_zones);
|
||||
spdk_json_write_object_end(w);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* When we register our vbdev this is how we specify our entry points. */
|
||||
static const struct spdk_bdev_fn_table zone_block_fn_table = {
|
||||
.destruct = zone_block_destruct,
|
||||
.submit_request = zone_block_submit_request,
|
||||
.io_type_supported = zone_block_io_type_supported,
|
||||
.get_io_channel = zone_block_get_io_channel,
|
||||
.dump_info_json = zone_block_dump_info_json,
|
||||
};
|
||||
|
||||
static void
|
||||
zone_block_base_bdev_hotremove_cb(void *ctx)
|
||||
{
|
||||
struct bdev_zone_block *bdev_node, *tmp;
|
||||
struct spdk_bdev *bdev_find = ctx;
|
||||
|
||||
TAILQ_FOREACH_SAFE(bdev_node, &g_bdev_nodes, link, tmp) {
|
||||
if (bdev_find == spdk_bdev_desc_get_bdev(bdev_node->base_desc)) {
|
||||
spdk_bdev_unregister(&bdev_node->bdev, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_zone_block_ch_create_cb(void *io_device, void *ctx_buf)
|
||||
{
|
||||
struct zone_block_io_channel *bdev_ch = ctx_buf;
|
||||
struct bdev_zone_block *bdev_node = io_device;
|
||||
|
||||
bdev_ch->base_ch = spdk_bdev_get_io_channel(bdev_node->base_desc);
|
||||
if (!bdev_ch->base_ch) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_zone_block_ch_destroy_cb(void *io_device, void *ctx_buf)
|
||||
{
|
||||
struct zone_block_io_channel *bdev_ch = ctx_buf;
|
||||
|
||||
spdk_put_io_channel(bdev_ch->base_ch);
|
||||
}
|
||||
|
||||
static int
|
||||
zone_block_insert_name(const char *bdev_name, const char *vbdev_name, uint64_t zone_capacity,
|
||||
uint64_t optimal_open_zones)
|
||||
{
|
||||
struct bdev_zone_block_config *name;
|
||||
|
||||
TAILQ_FOREACH(name, &g_bdev_configs, link) {
|
||||
if (strcmp(vbdev_name, name->vbdev_name) == 0) {
|
||||
SPDK_ERRLOG("block zoned bdev %s already exists\n", vbdev_name);
|
||||
return -EEXIST;
|
||||
}
|
||||
if (strcmp(bdev_name, name->bdev_name) == 0) {
|
||||
SPDK_ERRLOG("base bdev %s already claimed\n", bdev_name);
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
name = calloc(1, sizeof(*name));
|
||||
if (!name) {
|
||||
SPDK_ERRLOG("could not allocate bdev_names\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
name->bdev_name = strdup(bdev_name);
|
||||
if (!name->bdev_name) {
|
||||
SPDK_ERRLOG("could not allocate name->bdev_name\n");
|
||||
free(name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
name->vbdev_name = strdup(vbdev_name);
|
||||
if (!name->vbdev_name) {
|
||||
SPDK_ERRLOG("could not allocate name->vbdev_name\n");
|
||||
free(name->bdev_name);
|
||||
free(name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
name->zone_capacity = zone_capacity;
|
||||
name->optimal_open_zones = optimal_open_zones;
|
||||
|
||||
TAILQ_INSERT_TAIL(&g_bdev_configs, name, link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
zone_block_register(struct spdk_bdev *base_bdev)
|
||||
{
|
||||
struct bdev_zone_block_config *name, *tmp;
|
||||
struct bdev_zone_block *bdev_node;
|
||||
int rc = 0;
|
||||
|
||||
/* Check our list of names from config versus this bdev and if
|
||||
* there's a match, create the bdev_node & bdev accordingly.
|
||||
*/
|
||||
TAILQ_FOREACH_SAFE(name, &g_bdev_configs, link, tmp) {
|
||||
if (strcmp(name->bdev_name, base_bdev->name) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spdk_bdev_is_zoned(base_bdev)) {
|
||||
SPDK_ERRLOG("Base bdev %s is already a zoned bdev\n", base_bdev->name);
|
||||
rc = -EEXIST;
|
||||
goto free_config;
|
||||
}
|
||||
|
||||
bdev_node = calloc(1, sizeof(struct bdev_zone_block));
|
||||
if (!bdev_node) {
|
||||
rc = -ENOMEM;
|
||||
SPDK_ERRLOG("could not allocate bdev_node\n");
|
||||
goto free_config;
|
||||
}
|
||||
|
||||
/* The base bdev that we're attaching to. */
|
||||
bdev_node->bdev.name = strdup(name->vbdev_name);
|
||||
if (!bdev_node->bdev.name) {
|
||||
rc = -ENOMEM;
|
||||
SPDK_ERRLOG("could not allocate bdev_node name\n");
|
||||
goto strdup_failed;
|
||||
}
|
||||
bdev_node->bdev.product_name = "zone_block";
|
||||
|
||||
/* Copy some properties from the underlying base bdev. */
|
||||
bdev_node->bdev.write_cache = base_bdev->write_cache;
|
||||
bdev_node->bdev.required_alignment = base_bdev->required_alignment;
|
||||
bdev_node->bdev.optimal_io_boundary = base_bdev->optimal_io_boundary;
|
||||
bdev_node->bdev.blocklen = base_bdev->blocklen;
|
||||
bdev_node->bdev.blockcnt = base_bdev->blockcnt;
|
||||
bdev_node->bdev.write_unit_size = base_bdev->write_unit_size;
|
||||
|
||||
bdev_node->bdev.md_interleave = base_bdev->md_interleave;
|
||||
bdev_node->bdev.md_len = base_bdev->md_len;
|
||||
bdev_node->bdev.dif_type = base_bdev->dif_type;
|
||||
bdev_node->bdev.dif_is_head_of_md = base_bdev->dif_is_head_of_md;
|
||||
bdev_node->bdev.dif_check_flags = base_bdev->dif_check_flags;
|
||||
|
||||
bdev_node->bdev.zoned = true;
|
||||
bdev_node->bdev.ctxt = bdev_node;
|
||||
bdev_node->bdev.fn_table = &zone_block_fn_table;
|
||||
bdev_node->bdev.module = &bdev_zoned_if;
|
||||
|
||||
/* bdev specific info */
|
||||
bdev_node->bdev.zone_size = spdk_align64pow2(name->zone_capacity);
|
||||
if (bdev_node->bdev.zone_size == 0) {
|
||||
rc = -EINVAL;
|
||||
SPDK_ERRLOG("invalid zone size\n");
|
||||
goto roundup_failed;
|
||||
}
|
||||
|
||||
bdev_node->zone_capacity = name->zone_capacity;
|
||||
bdev_node->bdev.optimal_open_zones = name->optimal_open_zones;
|
||||
bdev_node->bdev.max_open_zones = 0;
|
||||
TAILQ_INSERT_TAIL(&g_bdev_nodes, bdev_node, link);
|
||||
|
||||
spdk_io_device_register(bdev_node, _zone_block_ch_create_cb, _zone_block_ch_destroy_cb,
|
||||
sizeof(struct zone_block_io_channel),
|
||||
name->vbdev_name);
|
||||
|
||||
rc = spdk_bdev_open(base_bdev, true, zone_block_base_bdev_hotremove_cb,
|
||||
base_bdev, &bdev_node->base_desc);
|
||||
if (rc) {
|
||||
SPDK_ERRLOG("could not open bdev %s\n", spdk_bdev_get_name(base_bdev));
|
||||
goto open_failed;
|
||||
}
|
||||
|
||||
rc = spdk_bdev_module_claim_bdev(base_bdev, bdev_node->base_desc, bdev_node->bdev.module);
|
||||
if (rc) {
|
||||
SPDK_ERRLOG("could not claim bdev %s\n", spdk_bdev_get_name(base_bdev));
|
||||
goto claim_failed;
|
||||
}
|
||||
|
||||
rc = spdk_bdev_register(&bdev_node->bdev);
|
||||
if (rc) {
|
||||
SPDK_ERRLOG("could not register zoned bdev\n");
|
||||
goto register_failed;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
register_failed:
|
||||
spdk_bdev_module_release_bdev(&bdev_node->bdev);
|
||||
claim_failed:
|
||||
spdk_bdev_close(bdev_node->base_desc);
|
||||
open_failed:
|
||||
TAILQ_REMOVE(&g_bdev_nodes, bdev_node, link);
|
||||
spdk_io_device_unregister(bdev_node, NULL);
|
||||
roundup_failed:
|
||||
free(bdev_node->bdev.name);
|
||||
strdup_failed:
|
||||
free(bdev_node);
|
||||
free_config:
|
||||
zone_block_remove_config(name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_vbdev_zone_block_create(const char *bdev_name, const char *vbdev_name, uint64_t zone_capacity,
|
||||
uint64_t optimal_open_zones)
|
||||
@ -47,18 +415,6 @@ spdk_vbdev_zone_block_create(const char *bdev_name, const char *vbdev_name, uint
|
||||
struct spdk_bdev *bdev = NULL;
|
||||
int rc = 0;
|
||||
|
||||
bdev = spdk_bdev_get_by_name(bdev_name);
|
||||
|
||||
if (!bdev) {
|
||||
SPDK_ERRLOG("Base bdev (%s) doesn't exist\n", bdev_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (spdk_bdev_is_zoned(bdev)) {
|
||||
SPDK_ERRLOG("Base bdev %s is already a zoned bdev\n", bdev_name);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if (zone_capacity == 0) {
|
||||
SPDK_ERRLOG("Zone capacity can't be 0\n");
|
||||
return -EINVAL;
|
||||
@ -69,13 +425,53 @@ spdk_vbdev_zone_block_create(const char *bdev_name, const char *vbdev_name, uint
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
/* Insert the bdev into our global name list even if it doesn't exist yet,
|
||||
* it may show up soon...
|
||||
*/
|
||||
rc = zone_block_insert_name(bdev_name, vbdev_name, zone_capacity, optimal_open_zones);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
bdev = spdk_bdev_get_by_name(bdev_name);
|
||||
if (!bdev) {
|
||||
/* This is not an error, even though the bdev is not present at this time it may
|
||||
* still show up later.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
return zone_block_register(bdev);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_vbdev_zone_block_delete(const char *name, spdk_bdev_unregister_cb cb_fn, void *cb_arg)
|
||||
{
|
||||
cb_fn(cb_arg, 0);
|
||||
struct bdev_zone_block_config *name_node;
|
||||
struct spdk_bdev *bdev = NULL;
|
||||
|
||||
bdev = spdk_bdev_get_by_name(name);
|
||||
if (!bdev || bdev->module != &bdev_zoned_if) {
|
||||
cb_fn(cb_arg, -ENODEV);
|
||||
return;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(name_node, &g_bdev_configs, link) {
|
||||
if (strcmp(name_node->vbdev_name, bdev->name) == 0) {
|
||||
zone_block_remove_config(name_node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spdk_bdev_unregister(bdev, cb_fn, cb_arg);
|
||||
}
|
||||
|
||||
static void
|
||||
zone_block_examine(struct spdk_bdev *bdev)
|
||||
{
|
||||
zone_block_register(bdev);
|
||||
|
||||
spdk_bdev_module_examine_done(&bdev_zoned_if);
|
||||
}
|
||||
|
||||
SPDK_LOG_REGISTER_COMPONENT("vbdev_zone_block", SPDK_LOG_VBDEV_ZONE_BLOCK)
|
||||
|
@ -34,7 +34,7 @@
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y = bdev.c part.c scsi_nvme.c gpt vbdev_lvol.c mt bdev_raid.c bdev_zone.c
|
||||
DIRS-y = bdev.c part.c scsi_nvme.c gpt vbdev_lvol.c mt bdev_raid.c bdev_zone.c vbdev_zone_block.c
|
||||
|
||||
DIRS-$(CONFIG_CRYPTO) += crypto.c
|
||||
|
||||
|
1
test/unit/lib/bdev/vbdev_zone_block.c/.gitignore
vendored
Normal file
1
test/unit/lib/bdev/vbdev_zone_block.c/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
vbdev_zone_block_ut
|
38
test/unit/lib/bdev/vbdev_zone_block.c/Makefile
Normal file
38
test/unit/lib/bdev/vbdev_zone_block.c/Makefile
Normal file
@ -0,0 +1,38 @@
|
||||
#
|
||||
# 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)/../../../../..)
|
||||
|
||||
TEST_FILE = vbdev_zone_block_ut.c
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk
|
569
test/unit/lib/bdev/vbdev_zone_block.c/vbdev_zone_block_ut.c
Normal file
569
test/unit/lib/bdev/vbdev_zone_block.c/vbdev_zone_block_ut.c
Normal file
@ -0,0 +1,569 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "spdk/stdinc.h"
|
||||
#include "spdk_cunit.h"
|
||||
#include "spdk/env.h"
|
||||
#include "spdk_internal/mock.h"
|
||||
#include "spdk/thread.h"
|
||||
#include "common/lib/test_env.c"
|
||||
#include "bdev/zone_block/vbdev_zone_block.c"
|
||||
#include "bdev/zone_block/vbdev_zone_block_rpc.c"
|
||||
|
||||
#define BLOCK_CNT (1024ul * 1024ul * 1024ul * 1024ul)
|
||||
#define BLOCK_SIZE 4096
|
||||
|
||||
/* Globals */
|
||||
uint32_t g_io_comp_status;
|
||||
uint8_t g_rpc_err;
|
||||
uint8_t g_json_decode_obj_construct;
|
||||
static TAILQ_HEAD(, spdk_bdev) g_bdev_list = TAILQ_HEAD_INITIALIZER(g_bdev_list);
|
||||
void *g_rpc_req = NULL;
|
||||
uint32_t g_rpc_req_size = 0;
|
||||
static struct spdk_thread *g_thread;
|
||||
|
||||
DEFINE_STUB_V(spdk_bdev_module_list_add, (struct spdk_bdev_module *bdev_module));
|
||||
DEFINE_STUB_V(spdk_bdev_close, (struct spdk_bdev_desc *desc));
|
||||
DEFINE_STUB(spdk_json_decode_string, int, (const struct spdk_json_val *val, void *out), 0);
|
||||
DEFINE_STUB(spdk_json_decode_uint64, int, (const struct spdk_json_val *val, void *out), 0);
|
||||
DEFINE_STUB_V(spdk_bdev_module_examine_done, (struct spdk_bdev_module *module));
|
||||
DEFINE_STUB(spdk_json_write_name, int, (struct spdk_json_write_ctx *w, const char *name), 0);
|
||||
DEFINE_STUB(spdk_json_write_object_begin, int, (struct spdk_json_write_ctx *w), 0);
|
||||
DEFINE_STUB(spdk_json_write_named_string, int, (struct spdk_json_write_ctx *w,
|
||||
const char *name, const char *val), 0);
|
||||
DEFINE_STUB(spdk_bdev_io_type_supported, bool, (struct spdk_bdev *bdev,
|
||||
enum spdk_bdev_io_type io_type), true);
|
||||
DEFINE_STUB(spdk_json_write_bool, int, (struct spdk_json_write_ctx *w, bool val), 0);
|
||||
DEFINE_STUB(spdk_json_write_named_object_begin, int, (struct spdk_json_write_ctx *w,
|
||||
const char *name), 0);
|
||||
DEFINE_STUB(spdk_json_write_object_end, int, (struct spdk_json_write_ctx *w), 0);
|
||||
DEFINE_STUB_V(spdk_rpc_register_method, (const char *method, spdk_rpc_method_handler func,
|
||||
uint32_t state_mask));
|
||||
DEFINE_STUB_V(spdk_jsonrpc_end_result, (struct spdk_jsonrpc_request *request,
|
||||
struct spdk_json_write_ctx *w));
|
||||
DEFINE_STUB(spdk_bdev_get_io_channel, struct spdk_io_channel *, (struct spdk_bdev_desc *desc),
|
||||
(void *)1);
|
||||
|
||||
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)
|
||||
{
|
||||
*_desc = (void *)bdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct spdk_bdev *
|
||||
spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc)
|
||||
{
|
||||
return (void *)desc;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_bdev_register(struct spdk_bdev *bdev)
|
||||
{
|
||||
CU_ASSERT_PTR_NULL(spdk_bdev_get_by_name(bdev->name));
|
||||
TAILQ_INSERT_TAIL(&g_bdev_list, bdev, internal.link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_bdev_unregister(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, void *cb_arg)
|
||||
{
|
||||
CU_ASSERT_EQUAL(spdk_bdev_get_by_name(bdev->name), bdev);
|
||||
TAILQ_REMOVE(&g_bdev_list, bdev, internal.link);
|
||||
|
||||
bdev->fn_table->destruct(bdev->ctxt);
|
||||
|
||||
if (cb_fn) {
|
||||
cb_fn(cb_arg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int spdk_json_write_named_uint64(struct spdk_json_write_ctx *w, const char *name, uint64_t val)
|
||||
{
|
||||
struct rpc_construct_zone_block *req = g_rpc_req;
|
||||
if (strcmp(name, "zone_capacity") == 0) {
|
||||
CU_ASSERT(req->zone_capacity == val);
|
||||
} else if (strcmp(name, "optimal_open_zones") == 0) {
|
||||
CU_ASSERT(req->optimal_open_zones == val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
spdk_bdev_get_name(const struct spdk_bdev *bdev)
|
||||
{
|
||||
return bdev->name;
|
||||
}
|
||||
|
||||
bool
|
||||
spdk_bdev_is_zoned(const struct spdk_bdev *bdev)
|
||||
{
|
||||
return bdev->zoned;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_json_write_string(struct spdk_json_write_ctx *w, const char *val)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_bdev_module_claim_bdev(struct spdk_bdev *bdev, struct spdk_bdev_desc *desc,
|
||||
struct spdk_bdev_module *module)
|
||||
{
|
||||
if (bdev->internal.claim_module != NULL) {
|
||||
return -1;
|
||||
}
|
||||
bdev->internal.claim_module = module;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_bdev_module_release_bdev(struct spdk_bdev *bdev)
|
||||
{
|
||||
CU_ASSERT(bdev->internal.claim_module != NULL);
|
||||
bdev->internal.claim_module = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_bdev_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status status)
|
||||
{
|
||||
g_io_comp_status = ((status == SPDK_BDEV_IO_STATUS_SUCCESS) ? true : false);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_json_decode_object(const struct spdk_json_val *values,
|
||||
const struct spdk_json_object_decoder *decoders, size_t num_decoders,
|
||||
void *out)
|
||||
{
|
||||
struct rpc_construct_zone_block *req, *_out;
|
||||
|
||||
if (g_json_decode_obj_construct) {
|
||||
req = g_rpc_req;
|
||||
_out = out;
|
||||
|
||||
_out->name = strdup(req->name);
|
||||
SPDK_CU_ASSERT_FATAL(_out->name != NULL);
|
||||
_out->base_bdev = strdup(req->base_bdev);
|
||||
SPDK_CU_ASSERT_FATAL(_out->base_bdev != NULL);
|
||||
_out->zone_capacity = req->zone_capacity;
|
||||
_out->optimal_open_zones = req->optimal_open_zones;
|
||||
} else {
|
||||
memcpy(out, g_rpc_req, g_rpc_req_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct spdk_json_write_ctx *
|
||||
spdk_jsonrpc_begin_result(struct spdk_jsonrpc_request *request)
|
||||
{
|
||||
return (void *)1;
|
||||
}
|
||||
|
||||
static struct spdk_bdev *
|
||||
create_nvme_bdev(void)
|
||||
{
|
||||
struct spdk_bdev *base_bdev;
|
||||
char *name = "Nvme0n1";
|
||||
base_bdev = calloc(1, sizeof(struct spdk_bdev));
|
||||
SPDK_CU_ASSERT_FATAL(base_bdev != NULL);
|
||||
base_bdev->name = strdup(name);
|
||||
SPDK_CU_ASSERT_FATAL(base_bdev->name != NULL);
|
||||
base_bdev->blocklen = BLOCK_SIZE;
|
||||
base_bdev->blockcnt = BLOCK_CNT;
|
||||
base_bdev->write_unit_size = 1;
|
||||
TAILQ_INSERT_TAIL(&g_bdev_list, base_bdev, internal.link);
|
||||
|
||||
return base_bdev;
|
||||
}
|
||||
|
||||
static void
|
||||
base_bdevs_cleanup(void)
|
||||
{
|
||||
struct spdk_bdev *bdev;
|
||||
struct spdk_bdev *bdev_next;
|
||||
|
||||
if (!TAILQ_EMPTY(&g_bdev_list)) {
|
||||
TAILQ_FOREACH_SAFE(bdev, &g_bdev_list, internal.link, bdev_next) {
|
||||
free(bdev->name);
|
||||
TAILQ_REMOVE(&g_bdev_list, bdev, internal.link);
|
||||
free(bdev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct spdk_bdev *
|
||||
spdk_bdev_get_by_name(const char *bdev_name)
|
||||
{
|
||||
struct spdk_bdev *bdev;
|
||||
|
||||
if (!TAILQ_EMPTY(&g_bdev_list)) {
|
||||
TAILQ_FOREACH(bdev, &g_bdev_list, internal.link) {
|
||||
if (strcmp(bdev_name, bdev->name) == 0) {
|
||||
return bdev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_jsonrpc_send_error_response(struct spdk_jsonrpc_request *request,
|
||||
int error_code, const char *msg)
|
||||
{
|
||||
g_rpc_err = 1;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_jsonrpc_send_error_response_fmt(struct spdk_jsonrpc_request *request,
|
||||
int error_code, const char *fmt, ...)
|
||||
{
|
||||
g_rpc_err = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
verify_config_present(const char *name, bool presence)
|
||||
{
|
||||
struct bdev_zone_block_config *cfg;
|
||||
bool cfg_found;
|
||||
|
||||
cfg_found = false;
|
||||
|
||||
TAILQ_FOREACH(cfg, &g_bdev_configs, link) {
|
||||
if (cfg->vbdev_name != NULL) {
|
||||
if (strcmp(name, cfg->vbdev_name) == 0) {
|
||||
cfg_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (presence == true) {
|
||||
CU_ASSERT(cfg_found == true);
|
||||
} else {
|
||||
CU_ASSERT(cfg_found == false);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
verify_bdev_present(const char *name, bool presence)
|
||||
{
|
||||
struct bdev_zone_block *bdev;
|
||||
bool bdev_found;
|
||||
|
||||
bdev_found = false;
|
||||
TAILQ_FOREACH(bdev, &g_bdev_nodes, link) {
|
||||
if (strcmp(bdev->bdev.name, name) == 0) {
|
||||
bdev_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (presence == true) {
|
||||
CU_ASSERT(bdev_found == true);
|
||||
} else {
|
||||
CU_ASSERT(bdev_found == false);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
create_test_req(struct rpc_construct_zone_block *r, const char *vbdev_name, const char *base_name,
|
||||
uint64_t zone_capacity, uint64_t optimal_open_zones, bool create_base_bdev)
|
||||
{
|
||||
r->name = strdup(vbdev_name);
|
||||
SPDK_CU_ASSERT_FATAL(r->name != NULL);
|
||||
r->base_bdev = strdup(base_name);
|
||||
SPDK_CU_ASSERT_FATAL(r->base_bdev != NULL);
|
||||
r->zone_capacity = zone_capacity;
|
||||
r->optimal_open_zones = optimal_open_zones;
|
||||
|
||||
if (create_base_bdev == true) {
|
||||
create_nvme_bdev();
|
||||
}
|
||||
g_rpc_req = r;
|
||||
g_rpc_req_size = sizeof(*r);
|
||||
}
|
||||
|
||||
static void
|
||||
free_test_req(struct rpc_construct_zone_block *r)
|
||||
{
|
||||
free(r->name);
|
||||
free(r->base_bdev);
|
||||
}
|
||||
|
||||
static void
|
||||
initialize_create_req(struct rpc_construct_zone_block *r, const char *vbdev_name,
|
||||
const char *base_name,
|
||||
uint64_t zone_capacity, uint64_t optimal_open_zones, bool create_base_bdev)
|
||||
{
|
||||
create_test_req(r, vbdev_name, base_name, zone_capacity, optimal_open_zones, create_base_bdev);
|
||||
|
||||
g_rpc_err = 0;
|
||||
g_json_decode_obj_construct = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
create_delete_req(struct rpc_delete_zone_block *r, const char *vbdev_name)
|
||||
{
|
||||
r->name = strdup(vbdev_name);
|
||||
SPDK_CU_ASSERT_FATAL(r->name != NULL);
|
||||
|
||||
g_rpc_req = r;
|
||||
g_rpc_req_size = sizeof(*r);
|
||||
g_rpc_err = 0;
|
||||
g_json_decode_obj_construct = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
verify_zone_config(struct rpc_construct_zone_block *r, bool presence)
|
||||
{
|
||||
struct bdev_zone_block_config *cfg = NULL;
|
||||
|
||||
TAILQ_FOREACH(cfg, &g_bdev_configs, link) {
|
||||
if (strcmp(r->name, cfg->vbdev_name) == 0) {
|
||||
if (presence == false) {
|
||||
break;
|
||||
}
|
||||
CU_ASSERT(strcmp(r->base_bdev, cfg->bdev_name) == 0);
|
||||
CU_ASSERT(r->zone_capacity == cfg->zone_capacity);
|
||||
CU_ASSERT(r->optimal_open_zones == cfg->optimal_open_zones);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (presence) {
|
||||
CU_ASSERT(cfg != NULL);
|
||||
} else {
|
||||
CU_ASSERT(cfg == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
verify_zone_bdev(struct rpc_construct_zone_block *r, bool presence)
|
||||
{
|
||||
struct bdev_zone_block *bdev;
|
||||
bool bdev_found;
|
||||
|
||||
bdev_found = false;
|
||||
TAILQ_FOREACH(bdev, &g_bdev_nodes, link) {
|
||||
if (strcmp(bdev->bdev.name, r->name) == 0) {
|
||||
bdev_found = true;
|
||||
if (presence == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
CU_ASSERT(bdev->bdev.zoned == true);
|
||||
CU_ASSERT(bdev->bdev.blockcnt == BLOCK_CNT);
|
||||
CU_ASSERT(bdev->bdev.blocklen == BLOCK_SIZE);
|
||||
CU_ASSERT(bdev->bdev.ctxt == bdev);
|
||||
CU_ASSERT(bdev->bdev.fn_table == &zone_block_fn_table);
|
||||
CU_ASSERT(bdev->bdev.module == &bdev_zoned_if);
|
||||
CU_ASSERT(bdev->bdev.write_unit_size == 1);
|
||||
CU_ASSERT(bdev->bdev.zone_size == spdk_align64pow2(r->zone_capacity));
|
||||
CU_ASSERT(bdev->bdev.optimal_open_zones == r->optimal_open_zones);
|
||||
CU_ASSERT(bdev->bdev.max_open_zones == 0);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (presence == true) {
|
||||
CU_ASSERT(bdev_found == true);
|
||||
} else {
|
||||
CU_ASSERT(bdev_found == false);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_zone_block_create(void)
|
||||
{
|
||||
struct rpc_construct_zone_block req;
|
||||
struct rpc_delete_zone_block delete_req;
|
||||
struct spdk_bdev *bdev;
|
||||
char *name = "Nvme0n1";
|
||||
size_t num_zones = 20;
|
||||
size_t zone_capacity = BLOCK_CNT / num_zones;
|
||||
|
||||
CU_ASSERT(zone_block_init() == 0);
|
||||
|
||||
/* Create zoned virtual device before nvme device */
|
||||
verify_config_present("zone_dev1", false);
|
||||
verify_bdev_present("zone_dev1", false);
|
||||
initialize_create_req(&req, "zone_dev1", name, zone_capacity, 1, false);
|
||||
rpc_zone_block_create(NULL, NULL);
|
||||
CU_ASSERT(g_rpc_err == 0);
|
||||
verify_zone_config(&req, true);
|
||||
verify_zone_bdev(&req, false);
|
||||
bdev = create_nvme_bdev();
|
||||
zone_block_examine(bdev);
|
||||
verify_zone_bdev(&req, true);
|
||||
free_test_req(&req);
|
||||
|
||||
/* Delete bdev */
|
||||
create_delete_req(&delete_req, "zone_dev1");
|
||||
rpc_zone_block_delete(NULL, NULL);
|
||||
verify_config_present("zone_dev1", false);
|
||||
verify_bdev_present("zone_dev1", false);
|
||||
CU_ASSERT(g_rpc_err == 0);
|
||||
|
||||
/* Create zoned virtual device and verify its correctness */
|
||||
verify_config_present("zone_dev1", false);
|
||||
verify_bdev_present("zone_dev1", false);
|
||||
initialize_create_req(&req, "zone_dev1", name, zone_capacity, 1, false);
|
||||
rpc_zone_block_create(NULL, NULL);
|
||||
CU_ASSERT(g_rpc_err == 0);
|
||||
verify_zone_config(&req, true);
|
||||
verify_zone_bdev(&req, true);
|
||||
free_test_req(&req);
|
||||
|
||||
/* Delete bdev */
|
||||
create_delete_req(&delete_req, "zone_dev1");
|
||||
rpc_zone_block_delete(NULL, NULL);
|
||||
verify_config_present("zone_dev1", false);
|
||||
verify_bdev_present("zone_dev1", false);
|
||||
CU_ASSERT(g_rpc_err == 0);
|
||||
|
||||
while (spdk_thread_poll(g_thread, 0, 0) > 0) {}
|
||||
zone_block_finish();
|
||||
base_bdevs_cleanup();
|
||||
SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&g_bdev_list));
|
||||
}
|
||||
|
||||
static void
|
||||
test_zone_block_create_invalid(void)
|
||||
{
|
||||
struct rpc_construct_zone_block req;
|
||||
struct rpc_delete_zone_block delete_req;
|
||||
char *name = "Nvme0n1";
|
||||
size_t num_zones = 10;
|
||||
size_t zone_capacity = BLOCK_CNT / num_zones;
|
||||
|
||||
CU_ASSERT(zone_block_init() == 0);
|
||||
|
||||
/* Create zoned virtual device and verify its correctness */
|
||||
verify_config_present("zone_dev1", false);
|
||||
verify_bdev_present("zone_dev1", false);
|
||||
initialize_create_req(&req, "zone_dev1", name, zone_capacity, 1, true);
|
||||
rpc_zone_block_create(NULL, NULL);
|
||||
CU_ASSERT(g_rpc_err == 0);
|
||||
verify_zone_config(&req, true);
|
||||
verify_zone_bdev(&req, true);
|
||||
free_test_req(&req);
|
||||
|
||||
/* Try to create another zoned virtual device on the same bdev */
|
||||
initialize_create_req(&req, "zone_dev2", name, zone_capacity, 1, false);
|
||||
rpc_zone_block_create(NULL, NULL);
|
||||
CU_ASSERT(g_rpc_err == 1);
|
||||
verify_config_present("zone_dev2", false);
|
||||
verify_bdev_present("zone_dev2", false);
|
||||
free_test_req(&req);
|
||||
|
||||
/* Try to create zoned virtual device on the zoned bdev */
|
||||
initialize_create_req(&req, "zone_dev2", "zone_dev1", zone_capacity, 1, false);
|
||||
rpc_zone_block_create(NULL, NULL);
|
||||
CU_ASSERT(g_rpc_err == 1);
|
||||
verify_config_present("zone_dev2", false);
|
||||
verify_bdev_present("zone_dev2", false);
|
||||
free_test_req(&req);
|
||||
|
||||
/* Unclaim the base bdev */
|
||||
create_delete_req(&delete_req, "zone_dev1");
|
||||
rpc_zone_block_delete(NULL, NULL);
|
||||
verify_config_present("zone_dev1", false);
|
||||
verify_bdev_present("zone_dev1", false);
|
||||
CU_ASSERT(g_rpc_err == 0);
|
||||
|
||||
/* Try to create zoned virtual device with 0 zone size */
|
||||
initialize_create_req(&req, "zone_dev2", name, 0, 1, false);
|
||||
rpc_zone_block_create(NULL, NULL);
|
||||
CU_ASSERT(g_rpc_err == 1);
|
||||
verify_config_present("zone_dev2", false);
|
||||
verify_bdev_present("zone_dev2", false);
|
||||
free_test_req(&req);
|
||||
|
||||
/* Try to create zoned virtual device with 0 optimal number of zones */
|
||||
initialize_create_req(&req, "zone_dev2", name, zone_capacity, 0, false);
|
||||
rpc_zone_block_create(NULL, NULL);
|
||||
verify_config_present("zone_dev2", false);
|
||||
verify_bdev_present("zone_dev2", false);
|
||||
CU_ASSERT(g_rpc_err == 1);
|
||||
free_test_req(&req);
|
||||
|
||||
while (spdk_thread_poll(g_thread, 0, 0) > 0) {}
|
||||
|
||||
zone_block_finish();
|
||||
base_bdevs_cleanup();
|
||||
SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&g_bdev_list));
|
||||
}
|
||||
|
||||
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("zone_block", NULL, NULL);
|
||||
if (suite == NULL) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
if (
|
||||
CU_add_test(suite, "test_zone_block_create", test_zone_block_create) == NULL ||
|
||||
CU_add_test(suite, "test_zone_block_create_invalid", test_zone_block_create_invalid) == NULL
|
||||
) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
g_thread = spdk_thread_create("test", NULL);
|
||||
spdk_set_thread(g_thread);
|
||||
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
CU_basic_run_tests();
|
||||
num_failures = CU_get_number_of_failures();
|
||||
|
||||
spdk_thread_exit(g_thread);
|
||||
spdk_thread_destroy(g_thread);
|
||||
|
||||
CU_cleanup_registry();
|
||||
|
||||
return num_failures;
|
||||
}
|
@ -61,6 +61,7 @@ $valgrind $testdir/lib/bdev/part.c/part_ut
|
||||
$valgrind $testdir/lib/bdev/scsi_nvme.c/scsi_nvme_ut
|
||||
$valgrind $testdir/lib/bdev/gpt/gpt.c/gpt_ut
|
||||
$valgrind $testdir/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut
|
||||
$valgrind $testdir/lib/bdev/vbdev_zone_block.c/vbdev_zone_block_ut
|
||||
|
||||
if grep -q '#define SPDK_CONFIG_CRYPTO 1' $rootdir/include/spdk/config.h; then
|
||||
$valgrind $testdir/lib/bdev/crypto.c/crypto_ut
|
||||
|
Loading…
x
Reference in New Issue
Block a user