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