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, uint32_t io_type, uint32_t error_type, uint32_t error_num) 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 == io_type) { 109 for (i = 0; i < SPDK_COUNTOF(error_disk->error_vector); i++) { 110 error_disk->error_vector[i].error_type = error_type; 111 error_disk->error_vector[i].error_num = error_num; 112 } 113 } else if (0 == 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[io_type].error_type = error_type; 119 error_disk->error_vector[io_type].error_num = 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 if (error_disk->error_vector[io_type].error_num) { 144 return error_disk->error_vector[io_type].error_type; 145 } 146 return 0; 147 } 148 149 static void 150 vbdev_error_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 151 { 152 struct error_channel *ch = spdk_io_channel_get_ctx(_ch); 153 struct error_disk *error_disk = bdev_io->bdev->ctxt; 154 uint32_t error_type; 155 156 switch (bdev_io->type) { 157 case SPDK_BDEV_IO_TYPE_READ: 158 case SPDK_BDEV_IO_TYPE_WRITE: 159 case SPDK_BDEV_IO_TYPE_UNMAP: 160 case SPDK_BDEV_IO_TYPE_FLUSH: 161 break; 162 case SPDK_BDEV_IO_TYPE_RESET: 163 vbdev_error_reset(error_disk, bdev_io); 164 return; 165 default: 166 SPDK_ERRLOG("Error Injection: unknown I/O type %d\n", bdev_io->type); 167 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 168 return; 169 } 170 171 error_type = vbdev_error_get_error_type(error_disk, bdev_io->type); 172 if (error_type == 0) { 173 int rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io); 174 175 if (rc) { 176 SPDK_ERRLOG("bdev_error: submit request failed, rc=%d\n", rc); 177 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 178 } 179 return; 180 } else if (error_type == VBDEV_IO_FAILURE) { 181 error_disk->error_vector[bdev_io->type].error_num--; 182 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 183 } else if (error_type == VBDEV_IO_PENDING) { 184 TAILQ_INSERT_TAIL(&error_disk->pending_ios, bdev_io, module_link); 185 error_disk->error_vector[bdev_io->type].error_num--; 186 } 187 } 188 189 static int 190 vbdev_error_destruct(void *ctx) 191 { 192 struct error_disk *error_disk = ctx; 193 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 194 int rc; 195 196 rc = vbdev_error_config_remove(base_bdev->name); 197 if (rc != 0) { 198 SPDK_ERRLOG("vbdev_error_config_remove() failed\n"); 199 } 200 201 return spdk_bdev_part_free(&error_disk->part); 202 } 203 204 static int 205 vbdev_error_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 206 { 207 struct error_disk *error_disk = ctx; 208 struct spdk_bdev *base_bdev = spdk_bdev_part_get_base_bdev(&error_disk->part); 209 210 spdk_json_write_named_object_begin(w, "error_disk"); 211 212 spdk_json_write_named_string(w, "base_bdev", base_bdev->name); 213 214 spdk_json_write_object_end(w); 215 216 return 0; 217 } 218 219 static void 220 vbdev_error_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 221 { 222 /* No config per bdev. */ 223 } 224 225 226 static struct spdk_bdev_fn_table vbdev_error_fn_table = { 227 .destruct = vbdev_error_destruct, 228 .submit_request = vbdev_error_submit_request, 229 .dump_info_json = vbdev_error_dump_info_json, 230 .write_config_json = vbdev_error_write_config_json 231 }; 232 233 static void 234 vbdev_error_base_bdev_hotremove_cb(void *_part_base) 235 { 236 struct spdk_bdev_part_base *part_base = _part_base; 237 238 spdk_bdev_part_base_hotremove(part_base, &g_error_disks); 239 } 240 241 static int 242 _vbdev_error_create(const char *base_bdev_name) 243 { 244 struct spdk_bdev_part_base *base = NULL; 245 struct error_disk *disk = NULL; 246 struct spdk_bdev *base_bdev; 247 char *name; 248 int rc; 249 250 rc = spdk_bdev_part_base_construct_ext(base_bdev_name, 251 vbdev_error_base_bdev_hotremove_cb, 252 &error_if, &vbdev_error_fn_table, &g_error_disks, 253 NULL, NULL, sizeof(struct error_channel), 254 NULL, NULL, &base); 255 if (rc != 0) { 256 if (rc != -ENODEV) { 257 SPDK_ERRLOG("could not construct part base for bdev %s\n", base_bdev_name); 258 } 259 return rc; 260 } 261 262 base_bdev = spdk_bdev_part_base_get_bdev(base); 263 264 disk = calloc(1, sizeof(*disk)); 265 if (!disk) { 266 SPDK_ERRLOG("Memory allocation failure\n"); 267 spdk_bdev_part_base_free(base); 268 return -ENOMEM; 269 } 270 271 name = spdk_sprintf_alloc("EE_%s", base_bdev_name); 272 if (!name) { 273 SPDK_ERRLOG("name allocation failure\n"); 274 spdk_bdev_part_base_free(base); 275 free(disk); 276 return -ENOMEM; 277 } 278 279 rc = spdk_bdev_part_construct(&disk->part, base, name, 0, base_bdev->blockcnt, 280 "Error Injection Disk"); 281 free(name); 282 if (rc) { 283 SPDK_ERRLOG("could not construct part for bdev %s\n", base_bdev_name); 284 /* spdk_bdev_part_construct will free name on failure */ 285 spdk_bdev_part_base_free(base); 286 free(disk); 287 return rc; 288 } 289 290 TAILQ_INIT(&disk->pending_ios); 291 292 return 0; 293 } 294 295 int 296 vbdev_error_create(const char *base_bdev_name) 297 { 298 int rc; 299 300 rc = vbdev_error_config_add(base_bdev_name); 301 if (rc != 0) { 302 SPDK_ERRLOG("Adding config for ErrorInjection bdev %s failed (rc=%d)\n", 303 base_bdev_name, rc); 304 return rc; 305 } 306 307 rc = _vbdev_error_create(base_bdev_name); 308 if (rc == -ENODEV) { 309 rc = 0; 310 } else if (rc != 0) { 311 vbdev_error_config_remove(base_bdev_name); 312 SPDK_ERRLOG("Could not create ErrorInjection bdev %s (rc=%d)\n", 313 base_bdev_name, rc); 314 } 315 316 return rc; 317 } 318 319 void 320 vbdev_error_delete(const char *error_vbdev_name, spdk_delete_error_complete cb_fn, void *cb_arg) 321 { 322 int rc; 323 324 rc = spdk_bdev_unregister_by_name(error_vbdev_name, &error_if, cb_fn, cb_arg); 325 if (rc != 0) { 326 cb_fn(cb_arg, rc); 327 } 328 } 329 330 static void 331 vbdev_error_clear_config(void) 332 { 333 struct spdk_vbdev_error_config *cfg; 334 335 while ((cfg = TAILQ_FIRST(&g_error_config))) { 336 TAILQ_REMOVE(&g_error_config, cfg, tailq); 337 free(cfg->base_bdev); 338 free(cfg); 339 } 340 } 341 342 static struct spdk_vbdev_error_config * 343 vbdev_error_config_find_by_base_name(const char *base_bdev_name) 344 { 345 struct spdk_vbdev_error_config *cfg; 346 347 TAILQ_FOREACH(cfg, &g_error_config, tailq) { 348 if (strcmp(cfg->base_bdev, base_bdev_name) == 0) { 349 return cfg; 350 } 351 } 352 353 return NULL; 354 } 355 356 static int 357 vbdev_error_config_add(const char *base_bdev_name) 358 { 359 struct spdk_vbdev_error_config *cfg; 360 361 cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 362 if (cfg) { 363 SPDK_ERRLOG("vbdev_error_config for bdev %s already exists\n", 364 base_bdev_name); 365 return -EEXIST; 366 } 367 368 cfg = calloc(1, sizeof(*cfg)); 369 if (!cfg) { 370 SPDK_ERRLOG("calloc() failed for vbdev_error_config\n"); 371 return -ENOMEM; 372 } 373 374 cfg->base_bdev = strdup(base_bdev_name); 375 if (!cfg->base_bdev) { 376 free(cfg); 377 SPDK_ERRLOG("strdup() failed for base_bdev_name\n"); 378 return -ENOMEM; 379 } 380 381 TAILQ_INSERT_TAIL(&g_error_config, cfg, tailq); 382 383 return 0; 384 } 385 386 static int 387 vbdev_error_config_remove(const char *base_bdev_name) 388 { 389 struct spdk_vbdev_error_config *cfg; 390 391 cfg = vbdev_error_config_find_by_base_name(base_bdev_name); 392 if (!cfg) { 393 return -ENOENT; 394 } 395 396 TAILQ_REMOVE(&g_error_config, cfg, tailq); 397 free(cfg->base_bdev); 398 free(cfg); 399 return 0; 400 } 401 402 static int 403 vbdev_error_init(void) 404 { 405 return 0; 406 } 407 408 static void 409 vbdev_error_fini(void) 410 { 411 vbdev_error_clear_config(); 412 } 413 414 static void 415 vbdev_error_examine(struct spdk_bdev *bdev) 416 { 417 struct spdk_vbdev_error_config *cfg; 418 int rc; 419 420 cfg = vbdev_error_config_find_by_base_name(bdev->name); 421 if (cfg != NULL) { 422 rc = _vbdev_error_create(bdev->name); 423 if (rc != 0) { 424 SPDK_ERRLOG("could not create error vbdev for bdev %s at examine\n", 425 bdev->name); 426 } 427 } 428 429 spdk_bdev_module_examine_done(&error_if); 430 } 431 432 static int 433 vbdev_error_config_json(struct spdk_json_write_ctx *w) 434 { 435 struct spdk_vbdev_error_config *cfg; 436 437 TAILQ_FOREACH(cfg, &g_error_config, tailq) { 438 spdk_json_write_object_begin(w); 439 440 spdk_json_write_named_string(w, "method", "bdev_error_create"); 441 spdk_json_write_named_object_begin(w, "params"); 442 spdk_json_write_named_string(w, "base_name", cfg->base_bdev); 443 spdk_json_write_object_end(w); 444 445 spdk_json_write_object_end(w); 446 } 447 448 return 0; 449 } 450