1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 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 TAILQ_ENTRY(spdk_vbdev_error_config) tailq; 25 }; 26 27 static TAILQ_HEAD(, spdk_vbdev_error_config) g_error_config 28 = TAILQ_HEAD_INITIALIZER(g_error_config); 29 30 struct vbdev_error_info { 31 uint32_t error_type; 32 uint32_t error_num; 33 }; 34 35 /* Context for each error bdev */ 36 struct error_disk { 37 struct spdk_bdev_part part; 38 struct vbdev_error_info error_vector[SPDK_BDEV_IO_TYPE_RESET]; 39 TAILQ_HEAD(, spdk_bdev_io) pending_ios; 40 }; 41 42 struct error_channel { 43 struct spdk_bdev_part_channel part_ch; 44 }; 45 46 static pthread_mutex_t g_vbdev_error_mutex = PTHREAD_MUTEX_INITIALIZER; 47 static SPDK_BDEV_PART_TAILQ g_error_disks = TAILQ_HEAD_INITIALIZER(g_error_disks); 48 49 static int vbdev_error_init(void); 50 static void vbdev_error_fini(void); 51 52 static void vbdev_error_examine(struct spdk_bdev *bdev); 53 static int vbdev_error_config_json(struct spdk_json_write_ctx *w); 54 55 static int vbdev_error_config_add(const char *base_bdev_name); 56 static int vbdev_error_config_remove(const char *base_bdev_name); 57 58 static struct spdk_bdev_module error_if = { 59 .name = "error", 60 .module_init = vbdev_error_init, 61 .module_fini = vbdev_error_fini, 62 .examine_config = vbdev_error_examine, 63 .config_json = vbdev_error_config_json, 64 65 }; 66 67 SPDK_BDEV_MODULE_REGISTER(error, &error_if) 68 69 static void 70 dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 71 { 72 } 73 74 int 75 vbdev_error_inject_error(char *name, const struct vbdev_error_inject_opts *opts) 76 { 77 struct spdk_bdev_desc *desc; 78 struct spdk_bdev *bdev; 79 struct spdk_bdev_part *part; 80 struct error_disk *error_disk = NULL; 81 uint32_t i; 82 int rc = 0; 83 84 pthread_mutex_lock(&g_vbdev_error_mutex); 85 86 rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &desc); 87 if (rc != 0) { 88 SPDK_ERRLOG("Could not open ErrorInjection bdev %s\n", name); 89 pthread_mutex_unlock(&g_vbdev_error_mutex); 90 return rc; 91 } 92 93 bdev = spdk_bdev_desc_get_bdev(desc); 94 95 TAILQ_FOREACH(part, &g_error_disks, tailq) { 96 if (bdev == spdk_bdev_part_get_bdev(part)) { 97 error_disk = (struct error_disk *)part; 98 break; 99 } 100 } 101 102 if (error_disk == NULL) { 103 SPDK_ERRLOG("Could not find ErrorInjection bdev %s\n", name); 104 rc = -ENODEV; 105 goto exit; 106 } 107 108 if (0xffffffff == opts->io_type) { 109 for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) { 110 error_disk->error_vector[i].error_type = opts->error_type; 111 error_disk->error_vector[i].error_num = opts->error_num; 112 } 113 } else if (0 == opts->io_type) { 114 for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) { 115 error_disk->error_vector[i].error_num = 0; 116 } 117 } else { 118 error_disk->error_vector[opts->io_type].error_type = opts->error_type; 119 error_disk->error_vector[opts->io_type].error_num = opts->error_num; 120 } 121 122 exit: 123 spdk_bdev_close(desc); 124 pthread_mutex_unlock(&g_vbdev_error_mutex); 125 return rc; 126 } 127 128 static void 129 vbdev_error_reset(struct error_disk *error_disk, struct spdk_bdev_io *bdev_io) 130 { 131 struct spdk_bdev_io *pending_io, *tmp; 132 133 TAILQ_FOREACH_SAFE(pending_io, &error_disk->pending_ios, module_link, tmp) { 134 TAILQ_REMOVE(&error_disk->pending_ios, pending_io, module_link); 135 spdk_bdev_io_complete(pending_io, SPDK_BDEV_IO_STATUS_FAILED); 136 } 137 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 138 } 139 140 static uint32_t 141 vbdev_error_get_error_type(struct error_disk *error_disk, uint32_t io_type) 142 { 143 switch (io_type) { 144 case SPDK_BDEV_IO_TYPE_READ: 145 case SPDK_BDEV_IO_TYPE_WRITE: 146 case SPDK_BDEV_IO_TYPE_UNMAP: 147 case SPDK_BDEV_IO_TYPE_FLUSH: 148 break; 149 default: 150 return 0; 151 } 152 153 if (error_disk->error_vector[io_type].error_num) { 154 return error_disk->error_vector[io_type].error_type; 155 } 156 return 0; 157 } 158 159 static void 160 vbdev_error_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 161 { 162 struct error_channel *ch = spdk_io_channel_get_ctx(_ch); 163 struct error_disk *error_disk = bdev_io->bdev->ctxt; 164 uint32_t error_type; 165 int rc; 166 167 if (bdev_io->type == SPDK_BDEV_IO_TYPE_RESET) { 168 vbdev_error_reset(error_disk, bdev_io); 169 return; 170 } 171 172 error_type = vbdev_error_get_error_type(error_disk, bdev_io->type); 173 switch (error_type) { 174 case VBDEV_IO_FAILURE: 175 error_disk->error_vector[bdev_io->type].error_num--; 176 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 177 break; 178 case VBDEV_IO_PENDING: 179 TAILQ_INSERT_TAIL(&error_disk->pending_ios, bdev_io, module_link); 180 error_disk->error_vector[bdev_io->type].error_num--; 181 break; 182 case 0: 183 rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io); 184 185 if (rc) { 186 SPDK_ERRLOG("bdev_error: submit request failed, rc=%d\n", rc); 187 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 188 } 189 break; 190 default: 191 assert(false); 192 break; 193 } 194 } 195 196 static int 197 vbdev_error_destruct(void *ctx) 198 { 199 struct error_disk *error_disk = ctx; 200 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 201 int rc; 202 203 rc = vbdev_error_config_remove(base_bdev->name); 204 if (rc != 0) { 205 SPDK_ERRLOG("vbdev_error_config_remove() failed\n"); 206 } 207 208 return spdk_bdev_part_free(&error_disk->part); 209 } 210 211 static int 212 vbdev_error_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 213 { 214 struct error_disk *error_disk = ctx; 215 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 216 217 spdk_json_write_named_object_begin(w, "error_disk"); 218 219 spdk_json_write_named_string(w, "base_bdev", base_bdev->name); 220 221 spdk_json_write_object_end(w); 222 223 return 0; 224 } 225 226 static void 227 vbdev_error_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 228 { 229 /* No config per bdev. */ 230 } 231 232 233 static struct spdk_bdev_fn_table vbdev_error_fn_table = { 234 .destruct = vbdev_error_destruct, 235 .submit_request = vbdev_error_submit_request, 236 .dump_info_json = vbdev_error_dump_info_json, 237 .write_config_json = vbdev_error_write_config_json 238 }; 239 240 static void 241 vbdev_error_base_bdev_hotremove_cb(void *_part_base) 242 { 243 struct spdk_bdev_part_base *part_base = _part_base; 244 245 spdk_bdev_part_base_hotremove(part_base, &g_error_disks); 246 } 247 248 static int 249 _vbdev_error_create(const char *base_bdev_name) 250 { 251 struct spdk_bdev_part_base *base = NULL; 252 struct error_disk *disk = NULL; 253 struct spdk_bdev *base_bdev; 254 char *name; 255 int rc; 256 257 rc = spdk_bdev_part_base_construct_ext(base_bdev_name, 258 vbdev_error_base_bdev_hotremove_cb, 259 &error_if, &vbdev_error_fn_table, &g_error_disks, 260 NULL, NULL, sizeof(struct error_channel), 261 NULL, NULL, &base); 262 if (rc != 0) { 263 if (rc != -ENODEV) { 264 SPDK_ERRLOG("could not construct part base for bdev %s\n", base_bdev_name); 265 } 266 return rc; 267 } 268 269 base_bdev = spdk_bdev_part_base_get_bdev(base); 270 271 disk = calloc(1, sizeof(*disk)); 272 if (!disk) { 273 SPDK_ERRLOG("Memory allocation failure\n"); 274 spdk_bdev_part_base_free(base); 275 return -ENOMEM; 276 } 277 278 name = spdk_sprintf_alloc("EE_%s", base_bdev_name); 279 if (!name) { 280 SPDK_ERRLOG("name allocation failure\n"); 281 spdk_bdev_part_base_free(base); 282 free(disk); 283 return -ENOMEM; 284 } 285 286 rc = spdk_bdev_part_construct(&disk->part, base, name, 0, base_bdev->blockcnt, 287 "Error Injection Disk"); 288 free(name); 289 if (rc) { 290 SPDK_ERRLOG("could not construct part for bdev %s\n", base_bdev_name); 291 /* spdk_bdev_part_construct will free name on failure */ 292 spdk_bdev_part_base_free(base); 293 free(disk); 294 return rc; 295 } 296 297 TAILQ_INIT(&disk->pending_ios); 298 299 return 0; 300 } 301 302 int 303 vbdev_error_create(const char *base_bdev_name) 304 { 305 int rc; 306 307 rc = vbdev_error_config_add(base_bdev_name); 308 if (rc != 0) { 309 SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n", 310 base_bdev_name, rc); 311 return rc; 312 } 313 314 rc = _vbdev_error_create(base_bdev_name); 315 if (rc == -ENODEV) { 316 rc = 0; 317 } else if (rc != 0) { 318 vbdev_error_config_remove(base_bdev_name); 319 SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n", 320 base_bdev_name, rc); 321 } 322 323 return rc; 324 } 325 326 void 327 vbdev_error_delete(const char *error_vbdev_name, spdk_delete_error_complete cb_fn, void *cb_arg) 328 { 329 int rc; 330 331 rc = spdk_bdev_unregister_by_name(error_vbdev_name, &error_if, cb_fn, cb_arg); 332 if (rc != 0) { 333 cb_fn(cb_arg, rc); 334 } 335 } 336 337 static void 338 vbdev_error_clear_config(void) 339 { 340 struct spdk_vbdev_error_config *cfg; 341 342 while ((cfg = TAILQ_FIRST(&g_error_config))) { 343 TAILQ_REMOVE(&g_error_config, cfg, tailq); 344 free(cfg->base_bdev); 345 free(cfg); 346 } 347 } 348 349 static struct spdk_vbdev_error_config * 350 vbdev_error_config_find_by_base_name(const char *base_bdev_name) 351 { 352 struct spdk_vbdev_error_config *cfg; 353 354 TAILQ_FOREACH(cfg, &g_error_config, tailq) { 355 if (strcmp(cfg->base_bdev, base_bdev_name) == 0) { 356 return cfg; 357 } 358 } 359 360 return NULL; 361 } 362 363 static int 364 vbdev_error_config_add(const char *base_bdev_name) 365 { 366 struct spdk_vbdev_error_config *cfg; 367 368 cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 369 if (cfg) { 370 SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n", 371 base_bdev_name); 372 return -EEXIST; 373 } 374 375 cfg = calloc(1, sizeof(*cfg)); 376 if (!cfg) { 377 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n"); 378 return -ENOMEM; 379 } 380 381 cfg->base_bdev = strdup(base_bdev_name); 382 if (!cfg->base_bdev) { 383 free(cfg); 384 SPDK_ERRLOG("strdup() failed for base_bdev_name\n"); 385 return -ENOMEM; 386 } 387 388 TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq); 389 390 return 0; 391 } 392 393 static int 394 vbdev_error_config_remove(const char *base_bdev_name) 395 { 396 struct spdk_vbdev_error_config *cfg; 397 398 cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 399 if (!cfg) { 400 return -ENOENT; 401 } 402 403 TAILQ_REMOVE(&g_error_config, cfg, tailq); 404 free(cfg->base_bdev); 405 free(cfg); 406 return 0; 407 } 408 409 static int 410 vbdev_error_init(void) 411 { 412 return 0; 413 } 414 415 static void 416 vbdev_error_fini(void) 417 { 418 vbdev_error_clear_config(); 419 } 420 421 static void 422 vbdev_error_examine(struct spdk_bdev *bdev) 423 { 424 struct spdk_vbdev_error_config *cfg; 425 int rc; 426 427 cfg = vbdev_error_config_find_by_base_name(bdev->name); 428 if (cfg != NULL) { 429 rc = _vbdev_error_create(bdev->name); 430 if (rc != 0) { 431 SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n", 432 bdev->name); 433 } 434 } 435 436 spdk_bdev_module_examine_done(&error_if); 437 } 438 439 static int 440 vbdev_error_config_json(struct spdk_json_write_ctx *w) 441 { 442 struct spdk_vbdev_error_config *cfg; 443 444 TAILQ_FOREACH(cfg, &g_error_config, tailq) { 445 spdk_json_write_object_begin(w); 446 447 spdk_json_write_named_string(w, "method", "bdev_error_create"); 448 spdk_json_write_named_object_begin(w, "params"); 449 spdk_json_write_named_string(w, "base_name", cfg->base_bdev); 450 spdk_json_write_object_end(w); 451 452 spdk_json_write_object_end(w); 453 } 454 455 return 0; 456 } 457