bdev/error: Add config of error vbdev when the base bdev of it doesn't exist

Currently construct_error_bdev() fails if the base bdev doesn't exist.
This patch add configuration of the error vbdev for the base bdev instead,
and the configuration will be parsed at examine() when the base bdev is
created.

This will improve the usability of error injection for bdev and will be
usable for the upcoming JSON config file.

Change-Id: I550b7f6c74fd8ab6cbd424a192f12a0c0099028e
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/403914
Reviewed-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
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:
Shuhei Matsumoto 2018-03-30 08:11:53 +09:00 committed by Jim Harris
parent 070e72eda7
commit 22b8b92275
3 changed files with 85 additions and 17 deletions

View File

@ -82,6 +82,7 @@ static void vbdev_error_fini(void);
static void vbdev_error_examine(struct spdk_bdev *bdev);
static int vbdev_error_config_json(struct spdk_json_write_ctx *w);
static int vbdev_error_config_add(const char *base_bdev_name);
static int vbdev_error_config_remove(const char *base_bdev_name);
static struct spdk_bdev_module error_if = {
@ -259,8 +260,8 @@ spdk_vbdev_error_base_bdev_hotremove_cb(void *_base_bdev)
spdk_bdev_part_base_hotremove(_base_bdev, &g_error_disks);
}
int
spdk_vbdev_error_create(struct spdk_bdev *base_bdev)
static int
_spdk_vbdev_error_create(struct spdk_bdev *base_bdev)
{
struct spdk_bdev_part_base *base = NULL;
struct error_disk *disk = NULL;
@ -280,14 +281,14 @@ spdk_vbdev_error_create(struct spdk_bdev *base_bdev)
sizeof(struct error_channel), NULL, NULL);
if (rc) {
SPDK_ERRLOG("could not construct part base for bdev %s\n", spdk_bdev_get_name(base_bdev));
return -1;
return rc;
}
disk = calloc(1, sizeof(*disk));
if (!disk) {
SPDK_ERRLOG("Memory allocation failure\n");
spdk_error_free_base(base);
return -1;
return -ENOMEM;
}
name = spdk_sprintf_alloc("EE_%s", spdk_bdev_get_name(base_bdev));
@ -295,7 +296,7 @@ spdk_vbdev_error_create(struct spdk_bdev *base_bdev)
SPDK_ERRLOG("name allocation failure\n");
spdk_error_free_base(base);
free(disk);
return -1;
return -ENOMEM;
}
rc = spdk_bdev_part_construct(&disk->part, base, name, 0, base_bdev->blockcnt,
@ -305,7 +306,7 @@ spdk_vbdev_error_create(struct spdk_bdev *base_bdev)
/* spdk_bdev_part_construct will free name on failure */
spdk_error_free_base(base);
free(disk);
return -1;
return rc;
}
TAILQ_INIT(&disk->pending_ios);
@ -313,6 +314,34 @@ spdk_vbdev_error_create(struct spdk_bdev *base_bdev)
return 0;
}
int
spdk_vbdev_error_create(const char *base_bdev_name)
{
int rc;
struct spdk_bdev *base_bdev;
rc = vbdev_error_config_add(base_bdev_name);
if (rc != 0) {
SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n",
base_bdev_name, rc);
return rc;
}
base_bdev = spdk_bdev_get_by_name(base_bdev_name);
if (!base_bdev) {
return 0;
}
rc = _spdk_vbdev_error_create(base_bdev);
if (rc != 0) {
vbdev_error_config_remove(base_bdev_name);
SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n",
base_bdev_name, rc);
}
return rc;
}
static void
vbdev_error_clear_config(void)
{
@ -339,6 +368,36 @@ vbdev_error_config_find_by_base_name(const char *base_bdev_name)
return NULL;
}
static int
vbdev_error_config_add(const char *base_bdev_name)
{
struct spdk_vbdev_error_config *cfg;
cfg = vbdev_error_config_find_by_base_name(base_bdev_name);
if (cfg) {
SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n",
base_bdev_name);
return -EEXIST;
}
cfg = calloc(1, sizeof(*cfg));
if (!cfg) {
SPDK_ERRLOG("calloc() failed for vbdev_error_config\n");
return -ENOMEM;
}
cfg->base_bdev = strdup(base_bdev_name);
if (!cfg->base_bdev) {
free(cfg);
SPDK_ERRLOG("strdup() failed for base_bdev_name\n");
return -ENOMEM;
}
TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq);
return 0;
}
static int
vbdev_error_config_remove(const char *base_bdev_name)
{
@ -419,9 +478,10 @@ vbdev_error_examine(struct spdk_bdev *bdev)
cfg = vbdev_error_config_find_by_base_name(bdev->name);
if (cfg != NULL) {
rc = spdk_vbdev_error_create(bdev);
rc = _spdk_vbdev_error_create(bdev);
if (rc != 0) {
SPDK_ERRLOG("could not create error vbdev for bdev %s\n", bdev->name);
SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n",
bdev->name);
}
}

View File

@ -42,7 +42,22 @@ enum vbdev_error_type {
VBDEV_IO_PENDING,
};
int spdk_vbdev_error_create(struct spdk_bdev *base_bdev);
/**
* Create a vbdev on the base bdev to inject error into it.
*
* \param base_bdev_name Name of the base bdev.
* \return 0 on success or negative on failure.
*/
int spdk_vbdev_error_create(const char *base_bdev_name);
/**
* Inject error to the base bdev. Users can specify which IO type error is injected,
* what type of error is injected, and how many errors are injected.
*
* \param name Name of the base bdev into which error is injected.
* \param io_type IO type into which error is injected.
* \param error_num Count of injected errors
*/
int spdk_vbdev_inject_error(char *name, uint32_t io_type, uint32_t error_type,
uint32_t error_num);

View File

@ -92,7 +92,6 @@ spdk_rpc_construct_error_bdev(struct spdk_jsonrpc_request *request,
{
struct rpc_construct_error_bdev req = {};
struct spdk_json_write_ctx *w;
struct spdk_bdev *base_bdev;
if (spdk_json_decode_object(params, rpc_construct_error_bdev_decoders,
SPDK_COUNTOF(rpc_construct_error_bdev_decoders),
@ -101,13 +100,7 @@ spdk_rpc_construct_error_bdev(struct spdk_jsonrpc_request *request,
goto invalid;
}
base_bdev = spdk_bdev_get_by_name(req.base_name);
if (!base_bdev) {
SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", req.base_name);
goto invalid;
}
if (spdk_vbdev_error_create(base_bdev)) {
if (spdk_vbdev_error_create(req.base_name)) {
SPDK_ERRLOG("Could not create ErrorInjection bdev %s\n", req.base_name);
goto invalid;
}