1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * This is a module for test purpose which will simulate error cases for bdev. 36 */ 37 38 #include "spdk/stdinc.h" 39 #include "spdk/rpc.h" 40 #include "spdk/conf.h" 41 #include "spdk/util.h" 42 #include "spdk/endian.h" 43 #include "spdk/nvme_spec.h" 44 #include "spdk/string.h" 45 46 #include "spdk/bdev_module.h" 47 #include "spdk_internal/log.h" 48 49 #include "vbdev_error.h" 50 51 struct spdk_vbdev_error_config { 52 char *base_bdev; 53 TAILQ_ENTRY(spdk_vbdev_error_config) tailq; 54 }; 55 56 static TAILQ_HEAD(, spdk_vbdev_error_config) g_error_config 57 = TAILQ_HEAD_INITIALIZER(g_error_config); 58 59 struct vbdev_error_info { 60 uint32_t error_type; 61 uint32_t error_num; 62 }; 63 64 /* Context for each error bdev */ 65 struct error_disk { 66 struct spdk_bdev_part part; 67 struct vbdev_error_info error_vector[SPDK_BDEV_IO_TYPE_RESET]; 68 TAILQ_HEAD(, spdk_bdev_io) pending_ios; 69 }; 70 71 struct error_channel { 72 struct spdk_bdev_part_channel part_ch; 73 }; 74 75 static pthread_mutex_t g_vbdev_error_mutex = PTHREAD_MUTEX_INITIALIZER; 76 static SPDK_BDEV_PART_TAILQ g_error_disks = TAILQ_HEAD_INITIALIZER(g_error_disks); 77 78 static int vbdev_error_init(void); 79 static void vbdev_error_fini(void); 80 81 static void vbdev_error_examine(struct spdk_bdev *bdev); 82 static int vbdev_error_config_json(struct spdk_json_write_ctx *w); 83 84 static int vbdev_error_config_add(const char *base_bdev_name); 85 static int vbdev_error_config_remove(const char *base_bdev_name); 86 87 static struct spdk_bdev_module error_if = { 88 .name = "error", 89 .module_init = vbdev_error_init, 90 .module_fini = vbdev_error_fini, 91 .examine_config = vbdev_error_examine, 92 .config_json = vbdev_error_config_json, 93 94 }; 95 96 SPDK_BDEV_MODULE_REGISTER(error, &error_if) 97 98 int 99 vbdev_error_inject_error(char *name, uint32_t io_type, uint32_t error_type, uint32_t error_num) 100 { 101 struct spdk_bdev *bdev; 102 struct spdk_bdev_part *part; 103 struct error_disk *error_disk = NULL; 104 uint32_t i; 105 106 pthread_mutex_lock(&g_vbdev_error_mutex); 107 bdev = spdk_bdev_get_by_name(name); 108 if (!bdev) { 109 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name); 110 pthread_mutex_unlock(&g_vbdev_error_mutex); 111 return -ENODEV; 112 } 113 114 TAILQ_FOREACH(part, &g_error_disks, tailq) { 115 if (bdev == spdk_bdev_part_get_bdev(part)) { 116 error_disk = (struct error_disk *)part; 117 break; 118 } 119 } 120 121 if (error_disk == NULL) { 122 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name); 123 pthread_mutex_unlock(&g_vbdev_error_mutex); 124 return -ENODEV; 125 } 126 127 if (0xffffffff == io_type) { 128 for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) { 129 error_disk->error_vector[i].error_type = error_type; 130 error_disk->error_vector[i].error_num = error_num; 131 } 132 } else if (0 == io_type) { 133 for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) { 134 error_disk->error_vector[i].error_num = 0; 135 } 136 } else { 137 error_disk->error_vector[io_type].error_type = error_type; 138 error_disk->error_vector[io_type].error_num = error_num; 139 } 140 pthread_mutex_unlock(&g_vbdev_error_mutex); 141 return 0; 142 } 143 144 static void 145 vbdev_error_reset(struct error_disk *error_disk, struct spdk_bdev_io *bdev_io) 146 { 147 struct spdk_bdev_io *pending_io, *tmp; 148 149 TAILQ_FOREACH_SAFE(pending_io, &error_disk->pending_ios, module_link, tmp) { 150 TAILQ_REMOVE(&error_disk->pending_ios, pending_io, module_link); 151 spdk_bdev_io_complete(pending_io, SPDK_BDEV_IO_STATUS_FAILED); 152 } 153 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 154 } 155 156 static uint32_t 157 vbdev_error_get_error_type(struct error_disk *error_disk, uint32_t io_type) 158 { 159 if (error_disk->error_vector[io_type].error_num) { 160 return error_disk->error_vector[io_type].error_type; 161 } 162 return 0; 163 } 164 165 static void 166 vbdev_error_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 167 { 168 struct error_channel *ch = spdk_io_channel_get_ctx(_ch); 169 struct error_disk *error_disk = bdev_io->bdev->ctxt; 170 uint32_t error_type; 171 172 switch (bdev_io->type) { 173 case SPDK_BDEV_IO_TYPE_READ: 174 case SPDK_BDEV_IO_TYPE_WRITE: 175 case SPDK_BDEV_IO_TYPE_UNMAP: 176 case SPDK_BDEV_IO_TYPE_FLUSH: 177 break; 178 case SPDK_BDEV_IO_TYPE_RESET: 179 vbdev_error_reset(error_disk, bdev_io); 180 return; 181 default: 182 SPDK_ERRLOG("Error Injection: unknown I/O type %d\n", bdev_io->type); 183 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 184 return; 185 } 186 187 error_type = vbdev_error_get_error_type(error_disk, bdev_io->type); 188 if (error_type == 0) { 189 int rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io); 190 191 if (rc) { 192 SPDK_ERRLOG("bdev_error: submit request failed, rc=%d\n", rc); 193 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 194 } 195 return; 196 } else if (error_type == VBDEV_IO_FAILURE) { 197 error_disk->error_vector[bdev_io->type].error_num--; 198 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 199 } else if (error_type == VBDEV_IO_PENDING) { 200 TAILQ_INSERT_TAIL(&error_disk->pending_ios, bdev_io, module_link); 201 error_disk->error_vector[bdev_io->type].error_num--; 202 } 203 } 204 205 static int 206 vbdev_error_destruct(void *ctx) 207 { 208 struct error_disk *error_disk = ctx; 209 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 210 int rc; 211 212 rc = vbdev_error_config_remove(base_bdev->name); 213 if (rc != 0) { 214 SPDK_ERRLOG("vbdev_error_config_remove() failed\n"); 215 } 216 217 return spdk_bdev_part_free(&error_disk->part); 218 } 219 220 static int 221 vbdev_error_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 222 { 223 struct error_disk *error_disk = ctx; 224 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 225 226 spdk_json_write_named_object_begin(w, "error_disk"); 227 228 spdk_json_write_named_string(w, "base_bdev", base_bdev->name); 229 230 spdk_json_write_object_end(w); 231 232 return 0; 233 } 234 235 static void 236 vbdev_error_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 237 { 238 /* No config per bdev. */ 239 } 240 241 242 static struct spdk_bdev_fn_table vbdev_error_fn_table = { 243 .destruct = vbdev_error_destruct, 244 .submit_request = vbdev_error_submit_request, 245 .dump_info_json = vbdev_error_dump_info_json, 246 .write_config_json = vbdev_error_write_config_json 247 }; 248 249 static void 250 vbdev_error_base_bdev_hotremove_cb(void *_part_base) 251 { 252 struct spdk_bdev_part_base *part_base = _part_base; 253 254 spdk_bdev_part_base_hotremove(part_base, &g_error_disks); 255 } 256 257 static int 258 _vbdev_error_create(struct spdk_bdev *base_bdev) 259 { 260 struct spdk_bdev_part_base *base = NULL; 261 struct error_disk *disk = NULL; 262 char *name; 263 int rc; 264 265 base = spdk_bdev_part_base_construct(base_bdev, 266 vbdev_error_base_bdev_hotremove_cb, 267 &error_if, &vbdev_error_fn_table, &g_error_disks, 268 NULL, NULL, sizeof(struct error_channel), 269 NULL, NULL); 270 if (!base) { 271 SPDK_ERRLOG("could not construct part base for bdev %s\n", spdk_bdev_get_name(base_bdev)); 272 return -ENOMEM; 273 } 274 275 disk = calloc(1, sizeof(*disk)); 276 if (!disk) { 277 SPDK_ERRLOG("Memory allocation failure\n"); 278 spdk_bdev_part_base_free(base); 279 return -ENOMEM; 280 } 281 282 name = spdk_sprintf_alloc("EE_%s", spdk_bdev_get_name(base_bdev)); 283 if (!name) { 284 SPDK_ERRLOG("name allocation failure\n"); 285 spdk_bdev_part_base_free(base); 286 free(disk); 287 return -ENOMEM; 288 } 289 290 rc = spdk_bdev_part_construct(&disk->part, base, name, 0, base_bdev->blockcnt, 291 "Error Injection Disk"); 292 free(name); 293 if (rc) { 294 SPDK_ERRLOG("could not construct part for bdev %s\n", spdk_bdev_get_name(base_bdev)); 295 /* spdk_bdev_part_construct will free name on failure */ 296 spdk_bdev_part_base_free(base); 297 free(disk); 298 return rc; 299 } 300 301 TAILQ_INIT(&disk->pending_ios); 302 303 return 0; 304 } 305 306 int 307 vbdev_error_create(const char *base_bdev_name) 308 { 309 int rc; 310 struct spdk_bdev *base_bdev; 311 312 rc = vbdev_error_config_add(base_bdev_name); 313 if (rc != 0) { 314 SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n", 315 base_bdev_name, rc); 316 return rc; 317 } 318 319 base_bdev = spdk_bdev_get_by_name(base_bdev_name); 320 if (!base_bdev) { 321 return 0; 322 } 323 324 rc = _vbdev_error_create(base_bdev); 325 if (rc != 0) { 326 vbdev_error_config_remove(base_bdev_name); 327 SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n", 328 base_bdev_name, rc); 329 } 330 331 return rc; 332 } 333 334 void 335 vbdev_error_delete(struct spdk_bdev *vbdev, spdk_delete_error_complete cb_fn, void *cb_arg) 336 { 337 if (!vbdev || vbdev->module != &error_if) { 338 cb_fn(cb_arg, -ENODEV); 339 return; 340 } 341 342 spdk_bdev_unregister(vbdev, cb_fn, cb_arg); 343 } 344 345 static void 346 vbdev_error_clear_config(void) 347 { 348 struct spdk_vbdev_error_config *cfg; 349 350 while ((cfg = TAILQ_FIRST(&g_error_config))) { 351 TAILQ_REMOVE(&g_error_config, cfg, tailq); 352 free(cfg->base_bdev); 353 free(cfg); 354 } 355 } 356 357 static struct spdk_vbdev_error_config * 358 vbdev_error_config_find_by_base_name(const char *base_bdev_name) 359 { 360 struct spdk_vbdev_error_config *cfg; 361 362 TAILQ_FOREACH(cfg, &g_error_config, tailq) { 363 if (strcmp(cfg->base_bdev, base_bdev_name) == 0) { 364 return cfg; 365 } 366 } 367 368 return NULL; 369 } 370 371 static int 372 vbdev_error_config_add(const char *base_bdev_name) 373 { 374 struct spdk_vbdev_error_config *cfg; 375 376 cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 377 if (cfg) { 378 SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n", 379 base_bdev_name); 380 return -EEXIST; 381 } 382 383 cfg = calloc(1, sizeof(*cfg)); 384 if (!cfg) { 385 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n"); 386 return -ENOMEM; 387 } 388 389 cfg->base_bdev = strdup(base_bdev_name); 390 if (!cfg->base_bdev) { 391 free(cfg); 392 SPDK_ERRLOG("strdup() failed for base_bdev_name\n"); 393 return -ENOMEM; 394 } 395 396 TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq); 397 398 return 0; 399 } 400 401 static int 402 vbdev_error_config_remove(const char *base_bdev_name) 403 { 404 struct spdk_vbdev_error_config *cfg; 405 406 cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 407 if (!cfg) { 408 return -ENOENT; 409 } 410 411 TAILQ_REMOVE(&g_error_config, cfg, tailq); 412 free(cfg->base_bdev); 413 free(cfg); 414 return 0; 415 } 416 417 static int 418 vbdev_error_init(void) 419 { 420 struct spdk_conf_section *sp; 421 struct spdk_vbdev_error_config *cfg; 422 const char *base_bdev_name; 423 int i, rc; 424 425 sp = spdk_conf_find_section(NULL, "BdevError"); 426 if (sp == NULL) { 427 return 0; 428 } 429 430 for (i = 0; ; i++) { 431 if (!spdk_conf_section_get_nval(sp, "BdevError", i)) { 432 break; 433 } 434 435 base_bdev_name = spdk_conf_section_get_nmval(sp, "BdevError", i, 0); 436 if (!base_bdev_name) { 437 SPDK_ERRLOG("ErrorInjection configuration missing bdev name\n"); 438 rc = -EINVAL; 439 goto error; 440 } 441 442 cfg = calloc(1, sizeof(*cfg)); 443 if (!cfg) { 444 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n"); 445 rc = -ENOMEM; 446 goto error; 447 } 448 449 cfg->base_bdev = strdup(base_bdev_name); 450 if (!cfg->base_bdev) { 451 free(cfg); 452 SPDK_ERRLOG("strdup() failed for bdev name\n"); 453 rc = -ENOMEM; 454 goto error; 455 } 456 457 TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq); 458 } 459 460 return 0; 461 462 error: 463 vbdev_error_clear_config(); 464 return rc; 465 } 466 467 static void 468 vbdev_error_fini(void) 469 { 470 vbdev_error_clear_config(); 471 } 472 473 static void 474 vbdev_error_examine(struct spdk_bdev *bdev) 475 { 476 struct spdk_vbdev_error_config *cfg; 477 int rc; 478 479 cfg = vbdev_error_config_find_by_base_name(bdev->name); 480 if (cfg != NULL) { 481 rc = _vbdev_error_create(bdev); 482 if (rc != 0) { 483 SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n", 484 bdev->name); 485 } 486 } 487 488 spdk_bdev_module_examine_done(&error_if); 489 } 490 491 static int 492 vbdev_error_config_json(struct spdk_json_write_ctx *w) 493 { 494 struct spdk_vbdev_error_config *cfg; 495 496 TAILQ_FOREACH(cfg, &g_error_config, tailq) { 497 spdk_json_write_object_begin(w); 498 499 spdk_json_write_named_string(w, "method", "bdev_error_create"); 500 spdk_json_write_named_object_begin(w, "params"); 501 spdk_json_write_named_string(w, "base_name", cfg->base_bdev); 502 spdk_json_write_object_end(w); 503 504 spdk_json_write_object_end(w); 505 } 506 507 return 0; 508 } 509