1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2017 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 /* 7 * This is a module for test purpose which will simulate error cases for bdev. 8 */ 9 10 #include "spdk/stdinc.h" 11 #include "spdk/rpc.h" 12 #include "spdk/util.h" 13 #include "spdk/endian.h" 14 #include "spdk/nvme_spec.h" 15 #include "spdk/string.h" 16 17 #include "spdk/bdev_module.h" 18 #include "spdk/log.h" 19 20 #include "vbdev_error.h" 21 22 struct spdk_vbdev_error_config { 23 char *base_bdev; 24 struct spdk_uuid uuid; 25 TAILQ_ENTRY(spdk_vbdev_error_config) tailq; 26 }; 27 28 static TAILQ_HEAD(, spdk_vbdev_error_config) g_error_config 29 = TAILQ_HEAD_INITIALIZER(g_error_config); 30 31 struct vbdev_error_info { 32 uint32_t error_type; 33 uint32_t error_num; 34 uint64_t corrupt_offset; 35 uint8_t corrupt_value; 36 }; 37 38 /* Context for each error bdev */ 39 struct error_disk { 40 struct spdk_bdev_part part; 41 struct vbdev_error_info error_vector[SPDK_BDEV_IO_TYPE_RESET]; 42 TAILQ_HEAD(, spdk_bdev_io) pending_ios; 43 }; 44 45 struct error_channel { 46 struct spdk_bdev_part_channel part_ch; 47 }; 48 49 static pthread_mutex_t g_vbdev_error_mutex = PTHREAD_MUTEX_INITIALIZER; 50 static SPDK_BDEV_PART_TAILQ g_error_disks = TAILQ_HEAD_INITIALIZER(g_error_disks); 51 52 static int vbdev_error_init(void); 53 static void vbdev_error_fini(void); 54 55 static void vbdev_error_examine(struct spdk_bdev *bdev); 56 static int vbdev_error_config_json(struct spdk_json_write_ctx *w); 57 58 static int vbdev_error_config_add(const char *base_bdev_name, const struct spdk_uuid *uuid); 59 static int vbdev_error_config_remove(const char *base_bdev_name); 60 61 static struct spdk_bdev_module error_if = { 62 .name = "error", 63 .module_init = vbdev_error_init, 64 .module_fini = vbdev_error_fini, 65 .examine_config = vbdev_error_examine, 66 .config_json = vbdev_error_config_json, 67 68 }; 69 70 SPDK_BDEV_MODULE_REGISTER(error, &error_if) 71 72 static void 73 dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 74 { 75 } 76 77 int 78 vbdev_error_inject_error(char *name, const struct vbdev_error_inject_opts *opts) 79 { 80 struct spdk_bdev_desc *desc; 81 struct spdk_bdev *bdev; 82 struct spdk_bdev_part *part; 83 struct error_disk *error_disk = NULL; 84 uint32_t i; 85 int rc = 0; 86 87 if (opts->error_type == VBDEV_IO_CORRUPT_DATA) { 88 if (opts->corrupt_value == 0) { 89 /* If corrupt_value is 0, XOR cannot cause data corruption. */ 90 SPDK_ERRLOG("corrupt_value should be non-zero.\n"); 91 return -EINVAL; 92 } 93 } 94 95 pthread_mutex_lock(&g_vbdev_error_mutex); 96 97 rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &desc); 98 if (rc != 0) { 99 SPDK_ERRLOG("Could not open ErrorInjection bdev %s\n", name); 100 pthread_mutex_unlock(&g_vbdev_error_mutex); 101 return rc; 102 } 103 104 bdev = spdk_bdev_desc_get_bdev(desc); 105 106 TAILQ_FOREACH(part, &g_error_disks, tailq) { 107 if (bdev == spdk_bdev_part_get_bdev(part)) { 108 error_disk = (struct error_disk *)part; 109 break; 110 } 111 } 112 113 if (error_disk == NULL) { 114 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name); 115 rc = -ENODEV; 116 goto exit; 117 } 118 119 if (0xffffffff == opts->io_type) { 120 for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) { 121 error_disk->error_vector[i].error_type = opts->error_type; 122 error_disk->error_vector[i].error_num = opts->error_num; 123 error_disk->error_vector[i].corrupt_offset = opts->corrupt_offset; 124 error_disk->error_vector[i].corrupt_value = opts->corrupt_value; 125 } 126 } else if (0 == opts->io_type) { 127 for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) { 128 error_disk->error_vector[i].error_num = 0; 129 } 130 } else { 131 error_disk->error_vector[opts->io_type].error_type = opts->error_type; 132 error_disk->error_vector[opts->io_type].error_num = opts->error_num; 133 error_disk->error_vector[opts->io_type].corrupt_offset = opts->corrupt_offset; 134 error_disk->error_vector[opts->io_type].corrupt_value = opts->corrupt_value; 135 } 136 137 exit: 138 spdk_bdev_close(desc); 139 pthread_mutex_unlock(&g_vbdev_error_mutex); 140 return rc; 141 } 142 143 static void 144 vbdev_error_reset(struct error_disk *error_disk, struct spdk_bdev_io *bdev_io) 145 { 146 struct spdk_bdev_io *pending_io, *tmp; 147 148 TAILQ_FOREACH_SAFE(pending_io, &error_disk->pending_ios, module_link, tmp) { 149 TAILQ_REMOVE(&error_disk->pending_ios, pending_io, module_link); 150 spdk_bdev_io_complete(pending_io, SPDK_BDEV_IO_STATUS_FAILED); 151 } 152 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 153 } 154 155 static uint32_t 156 vbdev_error_get_error_type(struct error_disk *error_disk, uint32_t io_type) 157 { 158 switch (io_type) { 159 case SPDK_BDEV_IO_TYPE_READ: 160 case SPDK_BDEV_IO_TYPE_WRITE: 161 case SPDK_BDEV_IO_TYPE_UNMAP: 162 case SPDK_BDEV_IO_TYPE_FLUSH: 163 break; 164 default: 165 return 0; 166 } 167 168 if (error_disk->error_vector[io_type].error_num) { 169 return error_disk->error_vector[io_type].error_type; 170 } 171 return 0; 172 } 173 174 static void 175 vbdev_error_corrupt_io_data(struct spdk_bdev_io *bdev_io, uint64_t corrupt_offset, 176 uint8_t corrupt_value) 177 { 178 uint8_t *buf; 179 int i; 180 181 if (bdev_io->u.bdev.iovs == NULL || bdev_io->u.bdev.iovs[0].iov_base == NULL) { 182 return; 183 } 184 185 for (i = 0; i < bdev_io->u.bdev.iovcnt; i++) { 186 if (bdev_io->u.bdev.iovs[i].iov_len > corrupt_offset) { 187 buf = (uint8_t *)bdev_io->u.bdev.iovs[i].iov_base; 188 189 buf[corrupt_offset] ^= corrupt_value; 190 break; 191 } 192 193 corrupt_offset -= bdev_io->u.bdev.iovs[i].iov_len; 194 } 195 } 196 197 static void 198 vbdev_error_complete_request(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 199 { 200 int status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED; 201 struct error_disk *error_disk = bdev_io->bdev->ctxt; 202 uint32_t error_type; 203 204 if (success && bdev_io->type == SPDK_BDEV_IO_TYPE_READ) { 205 error_type = vbdev_error_get_error_type(error_disk, bdev_io->type); 206 if (error_type == VBDEV_IO_CORRUPT_DATA) { 207 error_disk->error_vector[bdev_io->type].error_num--; 208 209 vbdev_error_corrupt_io_data(bdev_io, 210 error_disk->error_vector[bdev_io->type].corrupt_offset, 211 error_disk->error_vector[bdev_io->type].corrupt_value); 212 } 213 } 214 215 spdk_bdev_io_complete(bdev_io, status); 216 } 217 218 static void 219 vbdev_error_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 220 { 221 struct error_channel *ch = spdk_io_channel_get_ctx(_ch); 222 struct error_disk *error_disk = bdev_io->bdev->ctxt; 223 uint32_t error_type; 224 int rc; 225 226 if (bdev_io->type == SPDK_BDEV_IO_TYPE_RESET) { 227 vbdev_error_reset(error_disk, bdev_io); 228 return; 229 } 230 231 error_type = vbdev_error_get_error_type(error_disk, bdev_io->type); 232 switch (error_type) { 233 case VBDEV_IO_FAILURE: 234 error_disk->error_vector[bdev_io->type].error_num--; 235 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 236 break; 237 case VBDEV_IO_PENDING: 238 TAILQ_INSERT_TAIL(&error_disk->pending_ios, bdev_io, module_link); 239 error_disk->error_vector[bdev_io->type].error_num--; 240 break; 241 case VBDEV_IO_CORRUPT_DATA: 242 if (bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) { 243 error_disk->error_vector[bdev_io->type].error_num--; 244 245 vbdev_error_corrupt_io_data(bdev_io, 246 error_disk->error_vector[bdev_io->type].corrupt_offset, 247 error_disk->error_vector[bdev_io->type].corrupt_value); 248 } 249 /* fallthrough */ 250 case 0: 251 rc = spdk_bdev_part_submit_request_ext(&ch->part_ch, bdev_io, 252 vbdev_error_complete_request); 253 254 if (rc) { 255 SPDK_ERRLOG("bdev_error: submit request failed, rc=%d\n", rc); 256 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 257 } 258 break; 259 default: 260 assert(false); 261 break; 262 } 263 } 264 265 static int 266 vbdev_error_destruct(void *ctx) 267 { 268 struct error_disk *error_disk = ctx; 269 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 270 int rc; 271 272 rc = vbdev_error_config_remove(base_bdev->name); 273 if (rc != 0) { 274 SPDK_ERRLOG("vbdev_error_config_remove() failed\n"); 275 } 276 277 return spdk_bdev_part_free(&error_disk->part); 278 } 279 280 static int 281 vbdev_error_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 282 { 283 struct error_disk *error_disk = ctx; 284 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 285 286 spdk_json_write_named_object_begin(w, "error_disk"); 287 288 spdk_json_write_named_string(w, "base_bdev", base_bdev->name); 289 290 spdk_json_write_object_end(w); 291 292 return 0; 293 } 294 295 static void 296 vbdev_error_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 297 { 298 /* No config per bdev. */ 299 } 300 301 302 static struct spdk_bdev_fn_table vbdev_error_fn_table = { 303 .destruct = vbdev_error_destruct, 304 .submit_request = vbdev_error_submit_request, 305 .dump_info_json = vbdev_error_dump_info_json, 306 .write_config_json = vbdev_error_write_config_json 307 }; 308 309 static void 310 vbdev_error_base_bdev_hotremove_cb(void *_part_base) 311 { 312 struct spdk_bdev_part_base *part_base = _part_base; 313 314 spdk_bdev_part_base_hotremove(part_base, &g_error_disks); 315 } 316 317 static int 318 _vbdev_error_create(const char *base_bdev_name, const struct spdk_uuid *uuid) 319 { 320 struct spdk_bdev_part_base *base = NULL; 321 struct error_disk *disk = NULL; 322 struct spdk_bdev *base_bdev, *bdev; 323 char *name; 324 int rc; 325 326 rc = spdk_bdev_part_base_construct_ext(base_bdev_name, 327 vbdev_error_base_bdev_hotremove_cb, 328 &error_if, &vbdev_error_fn_table, &g_error_disks, 329 NULL, NULL, sizeof(struct error_channel), 330 NULL, NULL, &base); 331 if (rc != 0) { 332 if (rc != -ENODEV) { 333 SPDK_ERRLOG("could not construct part base for bdev %s\n", base_bdev_name); 334 } 335 return rc; 336 } 337 338 base_bdev = spdk_bdev_part_base_get_bdev(base); 339 340 disk = calloc(1, sizeof(*disk)); 341 if (!disk) { 342 SPDK_ERRLOG("Memory allocation failure\n"); 343 spdk_bdev_part_base_free(base); 344 return -ENOMEM; 345 } 346 347 name = spdk_sprintf_alloc("EE_%s", base_bdev_name); 348 if (!name) { 349 SPDK_ERRLOG("name allocation failure\n"); 350 spdk_bdev_part_base_free(base); 351 free(disk); 352 return -ENOMEM; 353 } 354 355 if (uuid) { 356 bdev = spdk_bdev_part_get_bdev(&disk->part); 357 spdk_uuid_copy(&bdev->uuid, uuid); 358 } 359 360 rc = spdk_bdev_part_construct(&disk->part, base, name, 0, base_bdev->blockcnt, 361 "Error Injection Disk"); 362 free(name); 363 if (rc) { 364 SPDK_ERRLOG("could not construct part for bdev %s\n", base_bdev_name); 365 /* spdk_bdev_part_construct will free name on failure */ 366 spdk_bdev_part_base_free(base); 367 free(disk); 368 return rc; 369 } 370 371 TAILQ_INIT(&disk->pending_ios); 372 373 return 0; 374 } 375 376 int 377 vbdev_error_create(const char *base_bdev_name, const struct spdk_uuid *uuid) 378 { 379 int rc; 380 381 rc = vbdev_error_config_add(base_bdev_name, uuid); 382 if (rc != 0) { 383 SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n", 384 base_bdev_name, rc); 385 return rc; 386 } 387 388 rc = _vbdev_error_create(base_bdev_name, uuid); 389 if (rc == -ENODEV) { 390 rc = 0; 391 } else if (rc != 0) { 392 vbdev_error_config_remove(base_bdev_name); 393 SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n", 394 base_bdev_name, rc); 395 } 396 397 return rc; 398 } 399 400 void 401 vbdev_error_delete(const char *error_vbdev_name, spdk_delete_error_complete cb_fn, void *cb_arg) 402 { 403 int rc; 404 405 rc = spdk_bdev_unregister_by_name(error_vbdev_name, &error_if, cb_fn, cb_arg); 406 if (rc != 0) { 407 cb_fn(cb_arg, rc); 408 } 409 } 410 411 static void 412 vbdev_error_clear_config(void) 413 { 414 struct spdk_vbdev_error_config *cfg; 415 416 while ((cfg = TAILQ_FIRST(&g_error_config))) { 417 TAILQ_REMOVE(&g_error_config, cfg, tailq); 418 free(cfg->base_bdev); 419 free(cfg); 420 } 421 } 422 423 static struct spdk_vbdev_error_config * 424 vbdev_error_config_find_by_base_name(const char *base_bdev_name) 425 { 426 struct spdk_vbdev_error_config *cfg; 427 428 TAILQ_FOREACH(cfg, &g_error_config, tailq) { 429 if (strcmp(cfg->base_bdev, base_bdev_name) == 0) { 430 return cfg; 431 } 432 } 433 434 return NULL; 435 } 436 437 static int 438 vbdev_error_config_add(const char *base_bdev_name, const struct spdk_uuid *uuid) 439 { 440 struct spdk_vbdev_error_config *cfg; 441 442 cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 443 if (cfg) { 444 SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n", 445 base_bdev_name); 446 return -EEXIST; 447 } 448 449 cfg = calloc(1, sizeof(*cfg)); 450 if (!cfg) { 451 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n"); 452 return -ENOMEM; 453 } 454 455 cfg->base_bdev = strdup(base_bdev_name); 456 if (!cfg->base_bdev) { 457 free(cfg); 458 SPDK_ERRLOG("strdup() failed for base_bdev_name\n"); 459 return -ENOMEM; 460 } 461 462 if (uuid) { 463 spdk_uuid_copy(&cfg->uuid, uuid); 464 } 465 466 TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq); 467 468 return 0; 469 } 470 471 static int 472 vbdev_error_config_remove(const char *base_bdev_name) 473 { 474 struct spdk_vbdev_error_config *cfg; 475 476 cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 477 if (!cfg) { 478 return -ENOENT; 479 } 480 481 TAILQ_REMOVE(&g_error_config, cfg, tailq); 482 free(cfg->base_bdev); 483 free(cfg); 484 return 0; 485 } 486 487 static int 488 vbdev_error_init(void) 489 { 490 return 0; 491 } 492 493 static void 494 vbdev_error_fini(void) 495 { 496 vbdev_error_clear_config(); 497 } 498 499 static void 500 vbdev_error_examine(struct spdk_bdev *bdev) 501 { 502 struct spdk_vbdev_error_config *cfg; 503 int rc; 504 505 cfg = vbdev_error_config_find_by_base_name(bdev->name); 506 if (cfg != NULL) { 507 rc = _vbdev_error_create(bdev->name, &cfg->uuid); 508 if (rc != 0) { 509 SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n", 510 bdev->name); 511 } 512 } 513 514 spdk_bdev_module_examine_done(&error_if); 515 } 516 517 static int 518 vbdev_error_config_json(struct spdk_json_write_ctx *w) 519 { 520 struct spdk_vbdev_error_config *cfg; 521 char uuid_str[SPDK_UUID_STRING_LEN]; 522 523 TAILQ_FOREACH(cfg, &g_error_config, tailq) { 524 spdk_json_write_object_begin(w); 525 526 spdk_json_write_named_string(w, "method", "bdev_error_create"); 527 spdk_json_write_named_object_begin(w, "params"); 528 spdk_json_write_named_string(w, "base_name", cfg->base_bdev); 529 if (!spdk_uuid_is_null(&cfg->uuid)) { 530 spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &cfg->uuid); 531 spdk_json_write_named_string(w, "uuid", uuid_str); 532 } 533 spdk_json_write_object_end(w); 534 535 spdk_json_write_object_end(w); 536 } 537 538 return 0; 539 } 540