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