From f2b26eb1138774355c20138b1d26c4859d5296b0 Mon Sep 17 00:00:00 2001 From: cunyinch Date: Mon, 5 Jun 2017 16:04:04 +0800 Subject: [PATCH] bdev/error: Add support of "reset" for error injection bdev module. Change-Id: If4cd8392a958eff7bda424b4bde3d48d833cef40 Signed-off-by: cunyinch Reviewed-on: https://review.gerrithub.io/363682 Tested-by: SPDK Automated Test System Reviewed-by: Jim Harris Reviewed-by: Daniel Verkamp --- include/spdk_internal/bdev.h | 3 +++ lib/bdev/error/vbdev_error.c | 38 +++++++++++++++++------------ lib/bdev/error/vbdev_error.h | 8 +++++- lib/bdev/error/vbdev_error_rpc.c | 33 +++++++++++++++++++------ scripts/rpc.py | 6 +++-- test/iscsi_tgt/ext4test/ext4test.sh | 4 +-- 6 files changed, 65 insertions(+), 27 deletions(-) diff --git a/include/spdk_internal/bdev.h b/include/spdk_internal/bdev.h index 73e1faee8..d5401e511 100644 --- a/include/spdk_internal/bdev.h +++ b/include/spdk_internal/bdev.h @@ -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. * diff --git a/lib/bdev/error/vbdev_error.c b/lib/bdev/error/vbdev_error.c index b633d706e..ac5fc74cd 100644 --- a/lib/bdev/error/vbdev_error.c +++ b/lib/bdev/error/vbdev_error.c @@ -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; diff --git a/lib/bdev/error/vbdev_error.h b/lib/bdev/error/vbdev_error.h index 3b29ca15c..cd8fe45f7 100644 --- a/lib/bdev/error/vbdev_error.h +++ b/lib/bdev/error/vbdev_error.h @@ -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 diff --git a/lib/bdev/error/vbdev_error_rpc.c b/lib/bdev/error/vbdev_error_rpc.c index 715b3f997..7e077d405 100644 --- a/lib/bdev/error/vbdev_error_rpc.c +++ b/lib/bdev/error/vbdev_error_rpc.c @@ -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; } diff --git a/scripts/rpc.py b/scripts/rpc.py index 3cd7640bb..1c45551fd 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -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) diff --git a/test/iscsi_tgt/ext4test/ext4test.sh b/test/iscsi_tgt/ext4test/ext4test.sh index 33a5e5e48..7b777613e 100755 --- a/test/iscsi_tgt/ext4test/ext4test.sh +++ b/test/iscsi_tgt/ext4test/ext4test.sh @@ -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