bdev/error: Add support of "reset" for error injection bdev module.

Change-Id: If4cd8392a958eff7bda424b4bde3d48d833cef40
Signed-off-by: cunyinch <cunyin.chang@intel.com>
Reviewed-on: https://review.gerrithub.io/363682
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
cunyinch 2017-06-05 16:04:04 +08:00 committed by Daniel Verkamp
parent 2bdec64fbf
commit f2b26eb113
6 changed files with 65 additions and 27 deletions

View File

@ -351,6 +351,9 @@ struct spdk_bdev_io {
/** Member used for linking child I/Os together. */
TAILQ_ENTRY(spdk_bdev_io) link;
/** It may be used by modules to put the bdev_io into its own list. */
TAILQ_ENTRY(spdk_bdev_io) module_link;
/**
* Per I/O context for use by the blockdev module.
*

View File

@ -52,8 +52,10 @@ struct vbdev_error_disk {
struct spdk_bdev disk;
struct spdk_bdev *base_bdev;
uint32_t io_type_mask;
uint32_t error_type;
uint32_t error_num;
TAILQ_ENTRY(vbdev_error_disk) tailq;
TAILQ_HEAD(, spdk_bdev_io) pending_ios;
};
static pthread_mutex_t g_vbdev_error_mutex = PTHREAD_MUTEX_INITIALIZER;
@ -61,7 +63,7 @@ static TAILQ_HEAD(, vbdev_error_disk) g_vbdev_error_disks = TAILQ_HEAD_INITIALIZ
g_vbdev_error_disks);
int
spdk_vbdev_inject_error(char *name, uint32_t io_type_mask, uint32_t error_num)
spdk_vbdev_inject_error(char *name, uint32_t io_type_mask, uint32_t error_type, uint32_t error_num)
{
struct spdk_bdev *bdev;
struct vbdev_error_disk *error_disk;
@ -85,9 +87,12 @@ spdk_vbdev_inject_error(char *name, uint32_t io_type_mask, uint32_t error_num)
pthread_mutex_unlock(&g_vbdev_error_mutex);
return -1;
}
error_disk->io_type_mask = io_type_mask;
error_disk->error_num = error_num;
error_disk->error_type = error_type;
if (io_type_mask == 0) {
error_disk->error_num = 0;
}
pthread_mutex_unlock(&g_vbdev_error_mutex);
return 0;
}
@ -95,14 +100,13 @@ spdk_vbdev_inject_error(char *name, uint32_t io_type_mask, uint32_t error_num)
static void
vbdev_error_reset(struct vbdev_error_disk *error_disk, struct spdk_bdev_io *bdev_io)
{
/*
* pass the I/O through unmodified.
*
* However, we do need to increment the generation count for the error bdev,
* since the spdk_bdev_io_complete() path that normally updates it will not execute
* after we resubmit the I/O to the base_bdev.
*/
error_disk->disk.gencnt++;
struct spdk_bdev_io *pending_io, *tmp;
TAILQ_FOREACH_SAFE(pending_io, &error_disk->pending_ios, module_link, tmp) {
TAILQ_REMOVE(&error_disk->pending_ios, pending_io, module_link);
spdk_bdev_io_complete(pending_io, SPDK_BDEV_IO_STATUS_FAILED);
}
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
}
static void
@ -119,7 +123,8 @@ vbdev_error_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev
break;
case SPDK_BDEV_IO_TYPE_RESET:
vbdev_error_reset(error_disk, bdev_io);
break;
error_disk->error_num = 0;
return;
default:
SPDK_ERRLOG("Error Injection: unknown I/O type %d\n", bdev_io->type);
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
@ -133,8 +138,12 @@ vbdev_error_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev
return;
}
error_disk->error_num--;
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
if (error_disk->error_type == VBDEV_IO_FAILURE) {
error_disk->error_num--;
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
} else {
TAILQ_INSERT_TAIL(&error_disk->pending_ios, bdev_io, module_link);
}
}
static void
@ -233,9 +242,8 @@ spdk_vbdev_error_create(struct spdk_bdev *base_bdev)
disk->disk.product_name = "Error Injection Disk";
disk->disk.ctxt = disk;
disk->disk.fn_table = &vbdev_error_fn_table;
spdk_vbdev_register(&disk->disk, &base_bdev, 1);
TAILQ_INIT(&disk->pending_ios);
TAILQ_INSERT_TAIL(&g_vbdev_error_disks, disk, tailq);
rc = 0;

View File

@ -37,7 +37,13 @@
#include "spdk/stdinc.h"
#include "spdk/bdev.h"
enum vbdev_error_type {
VBDEV_IO_FAILURE = 1,
VBDEV_IO_PENDING,
};
int spdk_vbdev_error_create(struct spdk_bdev *base_bdev);
int spdk_vbdev_inject_error(char *name, uint32_t io_type_mask, uint32_t error_num);
int spdk_vbdev_inject_error(char *name, uint32_t io_type_mask, uint32_t error_type,
uint32_t error_num);
#endif // SPDK_BLOCKDEV_ERROR_H

View File

@ -40,6 +40,7 @@
#include "vbdev_error.h"
#define ERROR_BDEV_IO_TYPE_INVALID (1U << (SPDK_BDEV_IO_TYPE_RESET + 1))
#define ERROR_BDEV_ERROR_TYPE_INVALID (VBDEV_IO_PENDING + 1)
static uint32_t
spdk_rpc_error_bdev_io_type_parse(char *name)
@ -52,8 +53,6 @@ spdk_rpc_error_bdev_io_type_parse(char *name)
return 1U << SPDK_BDEV_IO_TYPE_FLUSH;
} else if (strcmp(name, "unmap") == 0) {
return 1U << SPDK_BDEV_IO_TYPE_UNMAP;
} else if (strcmp(name, "reset") == 0) {
return 1U << SPDK_BDEV_IO_TYPE_RESET;
} else if (strcmp(name, "all") == 0) {
return 0xffffffff;
} else if (strcmp(name, "clear") == 0) {
@ -62,6 +61,17 @@ spdk_rpc_error_bdev_io_type_parse(char *name)
return ERROR_BDEV_IO_TYPE_INVALID;
}
static uint32_t
spdk_rpc_error_bdev_error_type_parse(char *name)
{
if (strcmp(name, "failure") == 0) {
return VBDEV_IO_FAILURE;
} else if (strcmp(name, "pending") == 0) {
return VBDEV_IO_PENDING;
}
return ERROR_BDEV_ERROR_TYPE_INVALID;
}
struct rpc_construct_error_bdev {
char *base_name;
};
@ -123,13 +133,15 @@ SPDK_RPC_REGISTER("construct_error_bdev", spdk_rpc_construct_error_bdev)
struct rpc_error_information {
char *name;
char *type;
char *io_type;
char *error_type;
uint32_t num;
};
static const struct spdk_json_object_decoder rpc_error_information_decoders[] = {
{"name", offsetof(struct rpc_error_information, name), spdk_json_decode_string},
{"type", offsetof(struct rpc_error_information, type), spdk_json_decode_string},
{"io_type", offsetof(struct rpc_error_information, io_type), spdk_json_decode_string},
{"error_type", offsetof(struct rpc_error_information, error_type), spdk_json_decode_string},
{"num", offsetof(struct rpc_error_information, num), spdk_json_decode_uint32, true},
};
@ -137,7 +149,8 @@ static void
free_rpc_error_information(struct rpc_error_information *p)
{
free(p->name);
free(p->type);
free(p->io_type);
free(p->error_type);
}
static void
@ -147,6 +160,7 @@ spdk_rpc_bdev_inject_error(struct spdk_jsonrpc_request *request,
struct rpc_error_information req = {};
struct spdk_json_write_ctx *w;
uint32_t io_type;
uint32_t error_type;
int ret;
if (spdk_json_decode_object(params, rpc_error_information_decoders,
@ -156,12 +170,17 @@ spdk_rpc_bdev_inject_error(struct spdk_jsonrpc_request *request,
goto invalid;
}
io_type = spdk_rpc_error_bdev_io_type_parse(req.type);
io_type = spdk_rpc_error_bdev_io_type_parse(req.io_type);
if (io_type == ERROR_BDEV_IO_TYPE_INVALID) {
goto invalid;
}
ret = spdk_vbdev_inject_error(req.name, io_type, req.num);
error_type = spdk_rpc_error_bdev_error_type_parse(req.error_type);
if (error_type == ERROR_BDEV_ERROR_TYPE_INVALID) {
goto invalid;
}
ret = spdk_vbdev_inject_error(req.name, io_type, error_type, req.num);
if (ret) {
goto invalid;
}

View File

@ -456,7 +456,8 @@ p.set_defaults(func=delete_nvmf_subsystem)
def bdev_inject_error(args):
params = {
'name': args.name,
'type': args.type,
'io_type': args.io_type,
'error_type': args.error_type,
'num': args.num,
}
@ -464,7 +465,8 @@ def bdev_inject_error(args):
p = subparsers.add_parser('bdev_inject_error', help='bdev inject error')
p.add_argument('name', help="""the name of the error injection bdev""")
p.add_argument('type', help="""type: 'clear' 'read' 'write' 'unmap' 'flush' 'reset' 'all'""")
p.add_argument('io_type', help="""io_type: 'clear' 'read' 'write' 'unmap' 'flush' 'all'""")
p.add_argument('error_type', help="""error_type: 'failure' 'pending'""")
p.add_argument('-n', '--num', help='the number of commands you want to fail', type=int, default=1)
p.set_defaults(func=bdev_inject_error)

View File

@ -54,7 +54,7 @@ trap 'for new_dir in `dir -d /mnt/*dir`; do umount $new_dir; rm -rf $new_dir; do
sleep 1
echo "Test error injection"
$rpc_py bdev_inject_error EE_Malloc0 'all' -n 1000
$rpc_py bdev_inject_error EE_Malloc0 'all' 'failure' -n 1000
dev=$(iscsiadm -m session -P 3 | grep "Attached scsi disk" | awk '{print $4}')
@ -71,7 +71,7 @@ else
fi
set -e
$rpc_py bdev_inject_error EE_Malloc0 'clear'
$rpc_py bdev_inject_error EE_Malloc0 'clear' 'failure'
echo "Error injection test done"
iscsicleanup